From 6727f086cfe4ddcc651eb2bf4301abfcf619be06 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 11:39:17 +0000 Subject: clk: bcm2835: pll_off should only update CM_PLL_ANARST bcm2835_pll_off is currently assigning CM_PLL_ANARST to the control register, which may lose the other bits that are currently set by the clock dividers. It also now locks during the read/modify/write cycle of both registers. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index c74ed3f..adbaa55 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -910,8 +910,14 @@ static void bcm2835_pll_off(struct clk_hw *hw) struct bcm2835_cprman *cprman = pll->cprman; const struct bcm2835_pll_data *data = pll->data; - cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); - cprman_write(cprman, data->a2w_ctrl_reg, A2W_PLL_CTRL_PWRDN); + spin_lock(&cprman->regs_lock); + cprman_write(cprman, data->cm_ctrl_reg, + cprman_read(cprman, data->cm_ctrl_reg) | + CM_PLL_ANARST); + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) | + A2W_PLL_CTRL_PWRDN); + spin_unlock(&cprman->regs_lock); } static int bcm2835_pll_on(struct clk_hw *hw) -- cgit v0.10.2 From ec36a5c6682fdd5328abf15c3c67281bed0241d7 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 11:39:18 +0000 Subject: clk: bcm2835: add locking to pll*_on/off methods Add missing locking to: * bcm2835_pll_divider_on * bcm2835_pll_divider_off to protect the read modify write cycle for the register access protecting both cm_reg and a2w_reg registers. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index adbaa55..a39f8a7 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1085,10 +1085,12 @@ static void bcm2835_pll_divider_off(struct clk_hw *hw) struct bcm2835_cprman *cprman = divider->cprman; const struct bcm2835_pll_divider_data *data = divider->data; + spin_lock(&cprman->regs_lock); cprman_write(cprman, data->cm_reg, (cprman_read(cprman, data->cm_reg) & ~data->load_mask) | data->hold_mask); cprman_write(cprman, data->a2w_reg, A2W_PLL_CHANNEL_DISABLE); + spin_unlock(&cprman->regs_lock); } static int bcm2835_pll_divider_on(struct clk_hw *hw) @@ -1097,12 +1099,14 @@ static int bcm2835_pll_divider_on(struct clk_hw *hw) struct bcm2835_cprman *cprman = divider->cprman; const struct bcm2835_pll_divider_data *data = divider->data; + spin_lock(&cprman->regs_lock); cprman_write(cprman, data->a2w_reg, cprman_read(cprman, data->a2w_reg) & ~A2W_PLL_CHANNEL_DISABLE); cprman_write(cprman, data->cm_reg, cprman_read(cprman, data->cm_reg) & ~data->hold_mask); + spin_unlock(&cprman->regs_lock); return 0; } -- cgit v0.10.2 From 997f16bd5d2e9b3456027f96fcadfe1e2bf12f4e Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 11:39:20 +0000 Subject: clk: bcm2835: divider value has to be 1 or more Current clamping of a normal divider allows a value < 1 to be valid. A divider of < 1 would actually only be possible if we had a PLL... So this patch clamps the divider to 1. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index a39f8a7..1fee1fd 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1190,8 +1190,9 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw, div += unused_frac_mask + 1; div &= ~unused_frac_mask; - /* Clamp to the limits. */ - div = max(div, unused_frac_mask + 1); + /* clamp to min divider of 1 */ + div = max_t(u32, div, 1 << CM_DIV_FRAC_BITS); + /* clamp to the highest possible fractional divider */ div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, CM_DIV_FRAC_BITS - data->frac_bits)); -- cgit v0.10.2 From 959ca92a3235fc4b17c1e18483fc390b3d612254 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 11:39:21 +0000 Subject: clk: bcm2835: correctly enable fractional clock support The current driver calculates the clock divider with fractional support enabled. But it does not enable fractional support in the control register itself resulting in an integer only divider, but in clk_set_rate responds back the fractionally divided clock frequency. This patch enables fractional support in the control register whenever there is a fractional bit set in the requested clock divider. Mash clock limits are are also handled for the PWM clock applying the correct divider limits (2 and max_int) applicable to basic fractional divider support (mash order of 1). It also adds locking to protect the read/modify/write cycle of the register modification. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 1fee1fd..1ee9a35 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -51,6 +51,7 @@ #define CM_GNRICCTL 0x000 #define CM_GNRICDIV 0x004 # define CM_DIV_FRAC_BITS 12 +# define CM_DIV_FRAC_MASK GENMASK(CM_DIV_FRAC_BITS - 1, 0) #define CM_VPUCTL 0x008 #define CM_VPUDIV 0x00c @@ -128,6 +129,7 @@ # define CM_GATE BIT(CM_GATE_BIT) # define CM_BUSY BIT(7) # define CM_BUSYD BIT(8) +# define CM_FRAC BIT(9) # define CM_SRC_SHIFT 0 # define CM_SRC_BITS 4 # define CM_SRC_MASK 0xf @@ -644,6 +646,7 @@ struct bcm2835_clock_data { u32 frac_bits; bool is_vpu_clock; + bool is_mash_clock; }; static const char *const bcm2835_clock_per_parents[] = { @@ -825,6 +828,7 @@ static const struct bcm2835_clock_data bcm2835_clock_pwm_data = { .div_reg = CM_PWMDIV, .int_bits = 12, .frac_bits = 12, + .is_mash_clock = true, }; struct bcm2835_pll { @@ -1180,7 +1184,7 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw, GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1; u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS; u64 rem; - u32 div; + u32 div, mindiv, maxdiv; rem = do_div(temp, rate); div = temp; @@ -1190,11 +1194,23 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw, div += unused_frac_mask + 1; div &= ~unused_frac_mask; - /* clamp to min divider of 1 */ - div = max_t(u32, div, 1 << CM_DIV_FRAC_BITS); - /* clamp to the highest possible fractional divider */ - div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, - CM_DIV_FRAC_BITS - data->frac_bits)); + /* different clamping limits apply for a mash clock */ + if (data->is_mash_clock) { + /* clamp to min divider of 2 */ + mindiv = 2 << CM_DIV_FRAC_BITS; + /* clamp to the highest possible integer divider */ + maxdiv = (BIT(data->int_bits) - 1) << CM_DIV_FRAC_BITS; + } else { + /* clamp to min divider of 1 */ + mindiv = 1 << CM_DIV_FRAC_BITS; + /* clamp to the highest possible fractional divider */ + maxdiv = GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, + CM_DIV_FRAC_BITS - data->frac_bits); + } + + /* apply the clamping limits */ + div = max_t(u32, div, mindiv); + div = min_t(u32, div, maxdiv); return div; } @@ -1288,9 +1304,26 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, struct bcm2835_cprman *cprman = clock->cprman; const struct bcm2835_clock_data *data = clock->data; u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false); + u32 ctl; + + spin_lock(&cprman->regs_lock); + + /* + * Setting up frac support + * + * In principle it is recommended to stop/start the clock first, + * but as we set CLK_SET_RATE_GATE during registration of the + * clock this requirement should be take care of by the + * clk-framework. + */ + ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC; + ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; + cprman_write(cprman, data->ctl_reg, ctl); cprman_write(cprman, data->div_reg, div); + spin_unlock(&cprman->regs_lock); + return 0; } -- cgit v0.10.2 From 6e1e60dacee7b32aef1468ea461b02e4c7a90a45 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 11:39:22 +0000 Subject: clk: bcm2835: clean up coding style issues Fix all the checkpatch complaints for clk-bcm2835.c Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 1ee9a35..5e55b47 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -12,9 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** @@ -299,7 +296,7 @@ struct bcm2835_cprman { struct device *dev; void __iomem *regs; - spinlock_t regs_lock; + spinlock_t regs_lock; /* spinlock for all clocks */ const char *osc_name; struct clk_onecell_data onecell; @@ -1328,7 +1325,7 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, } static int bcm2835_clock_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) + struct clk_rate_request *req) { struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct clk_hw *parent, *best_parent = NULL; @@ -1386,7 +1383,6 @@ static u8 bcm2835_clock_get_parent(struct clk_hw *hw) return (src & CM_SRC_MASK) >> CM_SRC_SHIFT; } - static const struct clk_ops bcm2835_clock_clk_ops = { .is_prepared = bcm2835_clock_is_on, .prepare = bcm2835_clock_on, -- cgit v0.10.2 From 96bf9c69d5729781018a00f08e2ae395ec3346b4 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 14:20:15 +0000 Subject: clk: bcm2835: expose raw clock-registers via debugfs For debugging purposes under some circumstance it helps to be able to see the actual clock registers. E.g: when looking at the clock divider it is helpful to see what the actual clock divider is. This patch exposes all the clock registers specific to each clock/pll/pll-divider via debugfs. Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Acked-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 5e55b47..b3ab7f8 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -313,6 +314,27 @@ static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) return readl(cprman->regs + reg); } +static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base, + struct debugfs_reg32 *regs, size_t nregs, + struct dentry *dentry) +{ + struct dentry *regdump; + struct debugfs_regset32 *regset; + + regset = devm_kzalloc(cprman->dev, sizeof(*regset), GFP_KERNEL); + if (!regset) + return -ENOMEM; + + regset->regs = regs; + regset->nregs = nregs; + regset->base = cprman->regs + base; + + regdump = debugfs_create_regset32("regdump", S_IRUGO, dentry, + regset); + + return regdump ? 0 : -ENOMEM; +} + /* * These are fixed clocks. They're probably not all root clocks and it may * be possible to turn them on and off but until this is mapped out better @@ -1037,6 +1059,36 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw, return 0; } +static int bcm2835_pll_debug_init(struct clk_hw *hw, + struct dentry *dentry) +{ + struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); + struct bcm2835_cprman *cprman = pll->cprman; + const struct bcm2835_pll_data *data = pll->data; + struct debugfs_reg32 *regs; + + regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL); + if (!regs) + return -ENOMEM; + + regs[0].name = "cm_ctrl"; + regs[0].offset = data->cm_ctrl_reg; + regs[1].name = "a2w_ctrl"; + regs[1].offset = data->a2w_ctrl_reg; + regs[2].name = "frac"; + regs[2].offset = data->frac_reg; + regs[3].name = "ana0"; + regs[3].offset = data->ana_reg_base + 0 * 4; + regs[4].name = "ana1"; + regs[4].offset = data->ana_reg_base + 1 * 4; + regs[5].name = "ana2"; + regs[5].offset = data->ana_reg_base + 2 * 4; + regs[6].name = "ana3"; + regs[6].offset = data->ana_reg_base + 3 * 4; + + return bcm2835_debugfs_regset(cprman, 0, regs, 7, dentry); +} + static const struct clk_ops bcm2835_pll_clk_ops = { .is_prepared = bcm2835_pll_is_on, .prepare = bcm2835_pll_on, @@ -1044,6 +1096,7 @@ static const struct clk_ops bcm2835_pll_clk_ops = { .recalc_rate = bcm2835_pll_get_rate, .set_rate = bcm2835_pll_set_rate, .round_rate = bcm2835_pll_round_rate, + .debug_init = bcm2835_pll_debug_init, }; struct bcm2835_pll_divider { @@ -1135,6 +1188,26 @@ static int bcm2835_pll_divider_set_rate(struct clk_hw *hw, return 0; } +static int bcm2835_pll_divider_debug_init(struct clk_hw *hw, + struct dentry *dentry) +{ + struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); + struct bcm2835_cprman *cprman = divider->cprman; + const struct bcm2835_pll_divider_data *data = divider->data; + struct debugfs_reg32 *regs; + + regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL); + if (!regs) + return -ENOMEM; + + regs[0].name = "cm"; + regs[0].offset = data->cm_reg; + regs[1].name = "a2w"; + regs[1].offset = data->a2w_reg; + + return bcm2835_debugfs_regset(cprman, 0, regs, 2, dentry); +} + static const struct clk_ops bcm2835_pll_divider_clk_ops = { .is_prepared = bcm2835_pll_divider_is_on, .prepare = bcm2835_pll_divider_on, @@ -1142,6 +1215,7 @@ static const struct clk_ops bcm2835_pll_divider_clk_ops = { .recalc_rate = bcm2835_pll_divider_get_rate, .set_rate = bcm2835_pll_divider_set_rate, .round_rate = bcm2835_pll_divider_round_rate, + .debug_init = bcm2835_pll_divider_debug_init, }; /* @@ -1383,6 +1457,31 @@ static u8 bcm2835_clock_get_parent(struct clk_hw *hw) return (src & CM_SRC_MASK) >> CM_SRC_SHIFT; } +static struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = { + { + .name = "ctl", + .offset = 0, + }, + { + .name = "div", + .offset = 4, + }, +}; + +static int bcm2835_clock_debug_init(struct clk_hw *hw, + struct dentry *dentry) +{ + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; + const struct bcm2835_clock_data *data = clock->data; + + return bcm2835_debugfs_regset( + cprman, data->ctl_reg, + bcm2835_debugfs_clock_reg32, + ARRAY_SIZE(bcm2835_debugfs_clock_reg32), + dentry); +} + static const struct clk_ops bcm2835_clock_clk_ops = { .is_prepared = bcm2835_clock_is_on, .prepare = bcm2835_clock_on, @@ -1392,6 +1491,7 @@ static const struct clk_ops bcm2835_clock_clk_ops = { .determine_rate = bcm2835_clock_determine_rate, .set_parent = bcm2835_clock_set_parent, .get_parent = bcm2835_clock_get_parent, + .debug_init = bcm2835_clock_debug_init, }; static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) @@ -1410,6 +1510,7 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { .determine_rate = bcm2835_clock_determine_rate, .set_parent = bcm2835_clock_set_parent, .get_parent = bcm2835_clock_get_parent, + .debug_init = bcm2835_clock_debug_init, }; static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman, -- cgit v0.10.2 From 56eb3a2ed9726961e1bcfa69d4a3f86d68f0eb52 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 12:51:41 +0000 Subject: clk: bcm2835: remove use of BCM2835_CLOCK_COUNT in driver As the use of BCM2835_CLOCK_COUNT in include/dt-bindings/clock/bcm2835.h is frowned upon as it needs to get modified every time a new clock gets introduced this patch changes the clk-bcm2835 driver to use a different scheme for registration of clocks and pll, so that there is no more need for BCM2835_CLOCK_COUNT to be defined. Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index b3ab7f8..71504a8 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -301,7 +301,7 @@ struct bcm2835_cprman { const char *osc_name; struct clk_onecell_data onecell; - struct clk *clks[BCM2835_CLOCK_COUNT]; + struct clk *clks[]; }; static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val) @@ -850,6 +850,25 @@ static const struct bcm2835_clock_data bcm2835_clock_pwm_data = { .is_mash_clock = true, }; +struct bcm2835_gate_data { + const char *name; + const char *parent; + + u32 ctl_reg; +}; + +/* + * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if + * you have the debug bit set in the power manager, which we + * don't bother exposing) are individual gates off of the + * non-stop vpu clock. + */ +static const struct bcm2835_gate_data bcm2835_clock_peri_image_data = { + .name = "peri_image", + .parent = "vpu", + .ctl_reg = CM_PERIICTL, +}; + struct bcm2835_pll { struct clk_hw hw; struct bcm2835_cprman *cprman; @@ -1642,14 +1661,81 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, return devm_clk_register(cprman->dev, &clock->hw); } +static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman, + const struct bcm2835_gate_data *data) +{ + return clk_register_gate(cprman->dev, data->name, data->parent, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, + cprman->regs + data->ctl_reg, + CM_GATE_BIT, 0, &cprman->regs_lock); +} + +typedef struct clk *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman, + const void *data); +struct bcm2835_clk_desc { + bcm2835_clk_register clk_register; + const void *data; +}; + +#define _REGISTER(f, d) { .clk_register = (bcm2835_clk_register)f, \ + .data = d } +#define REGISTER_PLL(d) _REGISTER(&bcm2835_register_pll, d) +#define REGISTER_PLL_DIV(d) _REGISTER(&bcm2835_register_pll_divider, d) +#define REGISTER_CLK(d) _REGISTER(&bcm2835_register_clock, d) +#define REGISTER_GATE(d) _REGISTER(&bcm2835_register_gate, d) + +static const struct bcm2835_clk_desc clk_desc_array[] = { + /* register PLL */ + [BCM2835_PLLA] = REGISTER_PLL(&bcm2835_plla_data), + [BCM2835_PLLB] = REGISTER_PLL(&bcm2835_pllb_data), + [BCM2835_PLLC] = REGISTER_PLL(&bcm2835_pllc_data), + [BCM2835_PLLD] = REGISTER_PLL(&bcm2835_plld_data), + [BCM2835_PLLH] = REGISTER_PLL(&bcm2835_pllh_data), + /* the PLL dividers */ + [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV(&bcm2835_plla_core_data), + [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(&bcm2835_plla_per_data), + [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV(&bcm2835_pllc_core0_data), + [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV(&bcm2835_pllc_core1_data), + [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV(&bcm2835_pllc_core2_data), + [BCM2835_PLLC_PER] = REGISTER_PLL_DIV(&bcm2835_pllc_per_data), + [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV(&bcm2835_plld_core_data), + [BCM2835_PLLD_PER] = REGISTER_PLL_DIV(&bcm2835_plld_per_data), + [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV(&bcm2835_pllh_rcal_data), + [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV(&bcm2835_pllh_aux_data), + [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(&bcm2835_pllh_pix_data), + /* the clocks */ + [BCM2835_CLOCK_TIMER] = REGISTER_CLK(&bcm2835_clock_timer_data), + [BCM2835_CLOCK_OTP] = REGISTER_CLK(&bcm2835_clock_otp_data), + [BCM2835_CLOCK_TSENS] = REGISTER_CLK(&bcm2835_clock_tsens_data), + [BCM2835_CLOCK_VPU] = REGISTER_CLK(&bcm2835_clock_vpu_data), + [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data), + [BCM2835_CLOCK_ISP] = REGISTER_CLK(&bcm2835_clock_isp_data), + [BCM2835_CLOCK_H264] = REGISTER_CLK(&bcm2835_clock_h264_data), + [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data), + [BCM2835_CLOCK_SDRAM] = REGISTER_CLK(&bcm2835_clock_sdram_data), + [BCM2835_CLOCK_UART] = REGISTER_CLK(&bcm2835_clock_uart_data), + [BCM2835_CLOCK_VEC] = REGISTER_CLK(&bcm2835_clock_vec_data), + [BCM2835_CLOCK_HSM] = REGISTER_CLK(&bcm2835_clock_hsm_data), + [BCM2835_CLOCK_EMMC] = REGISTER_CLK(&bcm2835_clock_emmc_data), + [BCM2835_CLOCK_PWM] = REGISTER_CLK(&bcm2835_clock_pwm_data), + /* the gates */ + [BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE( + &bcm2835_clock_peri_image_data), +}; + static int bcm2835_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct clk **clks; struct bcm2835_cprman *cprman; struct resource *res; + const struct bcm2835_clk_desc *desc; + const size_t asize = ARRAY_SIZE(clk_desc_array); + size_t i; - cprman = devm_kzalloc(dev, sizeof(*cprman), GFP_KERNEL); + cprman = devm_kzalloc(dev, + sizeof(*cprman) + asize * sizeof(*clks), + GFP_KERNEL); if (!cprman) return -ENOMEM; @@ -1666,80 +1752,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cprman); - cprman->onecell.clk_num = BCM2835_CLOCK_COUNT; + cprman->onecell.clk_num = asize; cprman->onecell.clks = cprman->clks; clks = cprman->clks; - clks[BCM2835_PLLA] = bcm2835_register_pll(cprman, &bcm2835_plla_data); - clks[BCM2835_PLLB] = bcm2835_register_pll(cprman, &bcm2835_pllb_data); - clks[BCM2835_PLLC] = bcm2835_register_pll(cprman, &bcm2835_pllc_data); - clks[BCM2835_PLLD] = bcm2835_register_pll(cprman, &bcm2835_plld_data); - clks[BCM2835_PLLH] = bcm2835_register_pll(cprman, &bcm2835_pllh_data); - - clks[BCM2835_PLLA_CORE] = - bcm2835_register_pll_divider(cprman, &bcm2835_plla_core_data); - clks[BCM2835_PLLA_PER] = - bcm2835_register_pll_divider(cprman, &bcm2835_plla_per_data); - clks[BCM2835_PLLC_CORE0] = - bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core0_data); - clks[BCM2835_PLLC_CORE1] = - bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core1_data); - clks[BCM2835_PLLC_CORE2] = - bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core2_data); - clks[BCM2835_PLLC_PER] = - bcm2835_register_pll_divider(cprman, &bcm2835_pllc_per_data); - clks[BCM2835_PLLD_CORE] = - bcm2835_register_pll_divider(cprman, &bcm2835_plld_core_data); - clks[BCM2835_PLLD_PER] = - bcm2835_register_pll_divider(cprman, &bcm2835_plld_per_data); - clks[BCM2835_PLLH_RCAL] = - bcm2835_register_pll_divider(cprman, &bcm2835_pllh_rcal_data); - clks[BCM2835_PLLH_AUX] = - bcm2835_register_pll_divider(cprman, &bcm2835_pllh_aux_data); - clks[BCM2835_PLLH_PIX] = - bcm2835_register_pll_divider(cprman, &bcm2835_pllh_pix_data); - - clks[BCM2835_CLOCK_TIMER] = - bcm2835_register_clock(cprman, &bcm2835_clock_timer_data); - clks[BCM2835_CLOCK_OTP] = - bcm2835_register_clock(cprman, &bcm2835_clock_otp_data); - clks[BCM2835_CLOCK_TSENS] = - bcm2835_register_clock(cprman, &bcm2835_clock_tsens_data); - clks[BCM2835_CLOCK_VPU] = - bcm2835_register_clock(cprman, &bcm2835_clock_vpu_data); - clks[BCM2835_CLOCK_V3D] = - bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data); - clks[BCM2835_CLOCK_ISP] = - bcm2835_register_clock(cprman, &bcm2835_clock_isp_data); - clks[BCM2835_CLOCK_H264] = - bcm2835_register_clock(cprman, &bcm2835_clock_h264_data); - clks[BCM2835_CLOCK_V3D] = - bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data); - clks[BCM2835_CLOCK_SDRAM] = - bcm2835_register_clock(cprman, &bcm2835_clock_sdram_data); - clks[BCM2835_CLOCK_UART] = - bcm2835_register_clock(cprman, &bcm2835_clock_uart_data); - clks[BCM2835_CLOCK_VEC] = - bcm2835_register_clock(cprman, &bcm2835_clock_vec_data); - clks[BCM2835_CLOCK_HSM] = - bcm2835_register_clock(cprman, &bcm2835_clock_hsm_data); - clks[BCM2835_CLOCK_EMMC] = - bcm2835_register_clock(cprman, &bcm2835_clock_emmc_data); - - /* - * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if - * you have the debug bit set in the power manager, which we - * don't bother exposing) are individual gates off of the - * non-stop vpu clock. - */ - clks[BCM2835_CLOCK_PERI_IMAGE] = - clk_register_gate(dev, "peri_image", "vpu", - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - cprman->regs + CM_PERIICTL, CM_GATE_BIT, - 0, &cprman->regs_lock); - - clks[BCM2835_CLOCK_PWM] = - bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data); + for (i = 0; i < asize; i++) { + desc = &clk_desc_array[i]; + if (desc->clk_register && desc->data) + clks[i] = desc->clk_register(cprman, desc->data); + } return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, &cprman->onecell); diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h index 61f1d20..87235ac 100644 --- a/include/dt-bindings/clock/bcm2835.h +++ b/include/dt-bindings/clock/bcm2835.h @@ -44,5 +44,3 @@ #define BCM2835_CLOCK_EMMC 28 #define BCM2835_CLOCK_PERI_IMAGE 29 #define BCM2835_CLOCK_PWM 30 - -#define BCM2835_CLOCK_COUNT 31 -- cgit v0.10.2 From 3b15afefbef9b5952e3d68ad73d93f981b9faca8 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 12:51:42 +0000 Subject: clk: bcm2835: reorganize bcm2835_clock_array assignment Reorganize bcm2835_clock_array so that there is no more need for separate bcm2835_*_data structures to be defined. Instead the required structures are generated inline via helper macros. To allow this to also work for pll alone it was required that the parent_pll was changed from a pointer to bcm2835_pll_data to the name of the pll instead. Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 71504a8..a4b91a4 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -415,115 +415,10 @@ static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = { .fb_prediv_mask = BIT(11), }; -/* - * PLLA is the auxiliary PLL, used to drive the CCP2 (Compact Camera - * Port 2) transmitter clock. - * - * It is in the PX LDO power domain, which is on when the AUDIO domain - * is on. - */ -static const struct bcm2835_pll_data bcm2835_plla_data = { - .name = "plla", - .cm_ctrl_reg = CM_PLLA, - .a2w_ctrl_reg = A2W_PLLA_CTRL, - .frac_reg = A2W_PLLA_FRAC, - .ana_reg_base = A2W_PLLA_ANA0, - .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE, - .lock_mask = CM_LOCK_FLOCKA, - - .ana = &bcm2835_ana_default, - - .min_rate = 600000000u, - .max_rate = 2400000000u, - .max_fb_rate = BCM2835_MAX_FB_RATE, -}; - -/* PLLB is used for the ARM's clock. */ -static const struct bcm2835_pll_data bcm2835_pllb_data = { - .name = "pllb", - .cm_ctrl_reg = CM_PLLB, - .a2w_ctrl_reg = A2W_PLLB_CTRL, - .frac_reg = A2W_PLLB_FRAC, - .ana_reg_base = A2W_PLLB_ANA0, - .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE, - .lock_mask = CM_LOCK_FLOCKB, - - .ana = &bcm2835_ana_default, - - .min_rate = 600000000u, - .max_rate = 3000000000u, - .max_fb_rate = BCM2835_MAX_FB_RATE, -}; - -/* - * PLLC is the core PLL, used to drive the core VPU clock. - * - * It is in the PX LDO power domain, which is on when the AUDIO domain - * is on. -*/ -static const struct bcm2835_pll_data bcm2835_pllc_data = { - .name = "pllc", - .cm_ctrl_reg = CM_PLLC, - .a2w_ctrl_reg = A2W_PLLC_CTRL, - .frac_reg = A2W_PLLC_FRAC, - .ana_reg_base = A2W_PLLC_ANA0, - .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, - .lock_mask = CM_LOCK_FLOCKC, - - .ana = &bcm2835_ana_default, - - .min_rate = 600000000u, - .max_rate = 3000000000u, - .max_fb_rate = BCM2835_MAX_FB_RATE, -}; - -/* - * PLLD is the display PLL, used to drive DSI display panels. - * - * It is in the PX LDO power domain, which is on when the AUDIO domain - * is on. - */ -static const struct bcm2835_pll_data bcm2835_plld_data = { - .name = "plld", - .cm_ctrl_reg = CM_PLLD, - .a2w_ctrl_reg = A2W_PLLD_CTRL, - .frac_reg = A2W_PLLD_FRAC, - .ana_reg_base = A2W_PLLD_ANA0, - .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE, - .lock_mask = CM_LOCK_FLOCKD, - - .ana = &bcm2835_ana_default, - - .min_rate = 600000000u, - .max_rate = 2400000000u, - .max_fb_rate = BCM2835_MAX_FB_RATE, -}; - -/* - * PLLH is used to supply the pixel clock or the AUX clock for the TV - * encoder. - * - * It is in the HDMI power domain. - */ -static const struct bcm2835_pll_data bcm2835_pllh_data = { - "pllh", - .cm_ctrl_reg = CM_PLLH, - .a2w_ctrl_reg = A2W_PLLH_CTRL, - .frac_reg = A2W_PLLH_FRAC, - .ana_reg_base = A2W_PLLH_ANA0, - .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, - .lock_mask = CM_LOCK_FLOCKH, - - .ana = &bcm2835_ana_pllh, - - .min_rate = 600000000u, - .max_rate = 3000000000u, - .max_fb_rate = BCM2835_MAX_FB_RATE, -}; - struct bcm2835_pll_divider_data { const char *name; - const struct bcm2835_pll_data *source_pll; + const char *source_pll; + u32 cm_reg; u32 a2w_reg; @@ -532,124 +427,6 @@ struct bcm2835_pll_divider_data { u32 fixed_divider; }; -static const struct bcm2835_pll_divider_data bcm2835_plla_core_data = { - .name = "plla_core", - .source_pll = &bcm2835_plla_data, - .cm_reg = CM_PLLA, - .a2w_reg = A2W_PLLA_CORE, - .load_mask = CM_PLLA_LOADCORE, - .hold_mask = CM_PLLA_HOLDCORE, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_plla_per_data = { - .name = "plla_per", - .source_pll = &bcm2835_plla_data, - .cm_reg = CM_PLLA, - .a2w_reg = A2W_PLLA_PER, - .load_mask = CM_PLLA_LOADPER, - .hold_mask = CM_PLLA_HOLDPER, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllb_arm_data = { - .name = "pllb_arm", - .source_pll = &bcm2835_pllb_data, - .cm_reg = CM_PLLB, - .a2w_reg = A2W_PLLB_ARM, - .load_mask = CM_PLLB_LOADARM, - .hold_mask = CM_PLLB_HOLDARM, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllc_core0_data = { - .name = "pllc_core0", - .source_pll = &bcm2835_pllc_data, - .cm_reg = CM_PLLC, - .a2w_reg = A2W_PLLC_CORE0, - .load_mask = CM_PLLC_LOADCORE0, - .hold_mask = CM_PLLC_HOLDCORE0, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllc_core1_data = { - .name = "pllc_core1", .source_pll = &bcm2835_pllc_data, - .cm_reg = CM_PLLC, A2W_PLLC_CORE1, - .load_mask = CM_PLLC_LOADCORE1, - .hold_mask = CM_PLLC_HOLDCORE1, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllc_core2_data = { - .name = "pllc_core2", - .source_pll = &bcm2835_pllc_data, - .cm_reg = CM_PLLC, - .a2w_reg = A2W_PLLC_CORE2, - .load_mask = CM_PLLC_LOADCORE2, - .hold_mask = CM_PLLC_HOLDCORE2, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllc_per_data = { - .name = "pllc_per", - .source_pll = &bcm2835_pllc_data, - .cm_reg = CM_PLLC, - .a2w_reg = A2W_PLLC_PER, - .load_mask = CM_PLLC_LOADPER, - .hold_mask = CM_PLLC_HOLDPER, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_plld_core_data = { - .name = "plld_core", - .source_pll = &bcm2835_plld_data, - .cm_reg = CM_PLLD, - .a2w_reg = A2W_PLLD_CORE, - .load_mask = CM_PLLD_LOADCORE, - .hold_mask = CM_PLLD_HOLDCORE, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_plld_per_data = { - .name = "plld_per", - .source_pll = &bcm2835_plld_data, - .cm_reg = CM_PLLD, - .a2w_reg = A2W_PLLD_PER, - .load_mask = CM_PLLD_LOADPER, - .hold_mask = CM_PLLD_HOLDPER, - .fixed_divider = 1, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllh_rcal_data = { - .name = "pllh_rcal", - .source_pll = &bcm2835_pllh_data, - .cm_reg = CM_PLLH, - .a2w_reg = A2W_PLLH_RCAL, - .load_mask = CM_PLLH_LOADRCAL, - .hold_mask = 0, - .fixed_divider = 10, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllh_aux_data = { - .name = "pllh_aux", - .source_pll = &bcm2835_pllh_data, - .cm_reg = CM_PLLH, - .a2w_reg = A2W_PLLH_AUX, - .load_mask = CM_PLLH_LOADAUX, - .hold_mask = 0, - .fixed_divider = 10, -}; - -static const struct bcm2835_pll_divider_data bcm2835_pllh_pix_data = { - .name = "pllh_pix", - .source_pll = &bcm2835_pllh_data, - .cm_reg = CM_PLLH, - .a2w_reg = A2W_PLLH_PIX, - .load_mask = CM_PLLH_LOADPIX, - .hold_mask = 0, - .fixed_divider = 10, -}; - struct bcm2835_clock_data { const char *name; @@ -668,188 +445,6 @@ struct bcm2835_clock_data { bool is_mash_clock; }; -static const char *const bcm2835_clock_per_parents[] = { - "gnd", - "xosc", - "testdebug0", - "testdebug1", - "plla_per", - "pllc_per", - "plld_per", - "pllh_aux", -}; - -static const char *const bcm2835_clock_vpu_parents[] = { - "gnd", - "xosc", - "testdebug0", - "testdebug1", - "plla_core", - "pllc_core0", - "plld_core", - "pllh_aux", - "pllc_core1", - "pllc_core2", -}; - -static const char *const bcm2835_clock_osc_parents[] = { - "gnd", - "xosc", - "testdebug0", - "testdebug1" -}; - -/* - * Used for a 1Mhz clock for the system clocksource, and also used by - * the watchdog timer and the camera pulse generator. - */ -static const struct bcm2835_clock_data bcm2835_clock_timer_data = { - .name = "timer", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), - .parents = bcm2835_clock_osc_parents, - .ctl_reg = CM_TIMERCTL, - .div_reg = CM_TIMERDIV, - .int_bits = 6, - .frac_bits = 12, -}; - -/* One Time Programmable Memory clock. Maximum 10Mhz. */ -static const struct bcm2835_clock_data bcm2835_clock_otp_data = { - .name = "otp", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), - .parents = bcm2835_clock_osc_parents, - .ctl_reg = CM_OTPCTL, - .div_reg = CM_OTPDIV, - .int_bits = 4, - .frac_bits = 0, -}; - -/* - * VPU clock. This doesn't have an enable bit, since it drives the - * bus for everything else, and is special so it doesn't need to be - * gated for rate changes. It is also known as "clk_audio" in various - * hardware documentation. - */ -static const struct bcm2835_clock_data bcm2835_clock_vpu_data = { - .name = "vpu", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), - .parents = bcm2835_clock_vpu_parents, - .ctl_reg = CM_VPUCTL, - .div_reg = CM_VPUDIV, - .int_bits = 12, - .frac_bits = 8, - .is_vpu_clock = true, -}; - -static const struct bcm2835_clock_data bcm2835_clock_v3d_data = { - .name = "v3d", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), - .parents = bcm2835_clock_vpu_parents, - .ctl_reg = CM_V3DCTL, - .div_reg = CM_V3DDIV, - .int_bits = 4, - .frac_bits = 8, -}; - -static const struct bcm2835_clock_data bcm2835_clock_isp_data = { - .name = "isp", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), - .parents = bcm2835_clock_vpu_parents, - .ctl_reg = CM_ISPCTL, - .div_reg = CM_ISPDIV, - .int_bits = 4, - .frac_bits = 8, -}; - -static const struct bcm2835_clock_data bcm2835_clock_h264_data = { - .name = "h264", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), - .parents = bcm2835_clock_vpu_parents, - .ctl_reg = CM_H264CTL, - .div_reg = CM_H264DIV, - .int_bits = 4, - .frac_bits = 8, -}; - -/* TV encoder clock. Only operating frequency is 108Mhz. */ -static const struct bcm2835_clock_data bcm2835_clock_vec_data = { - .name = "vec", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), - .parents = bcm2835_clock_per_parents, - .ctl_reg = CM_VECCTL, - .div_reg = CM_VECDIV, - .int_bits = 4, - .frac_bits = 0, -}; - -static const struct bcm2835_clock_data bcm2835_clock_uart_data = { - .name = "uart", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), - .parents = bcm2835_clock_per_parents, - .ctl_reg = CM_UARTCTL, - .div_reg = CM_UARTDIV, - .int_bits = 10, - .frac_bits = 12, -}; - -/* HDMI state machine */ -static const struct bcm2835_clock_data bcm2835_clock_hsm_data = { - .name = "hsm", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), - .parents = bcm2835_clock_per_parents, - .ctl_reg = CM_HSMCTL, - .div_reg = CM_HSMDIV, - .int_bits = 4, - .frac_bits = 8, -}; - -/* - * Secondary SDRAM clock. Used for low-voltage modes when the PLL in - * the SDRAM controller can't be used. - */ -static const struct bcm2835_clock_data bcm2835_clock_sdram_data = { - .name = "sdram", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), - .parents = bcm2835_clock_vpu_parents, - .ctl_reg = CM_SDCCTL, - .div_reg = CM_SDCDIV, - .int_bits = 6, - .frac_bits = 0, -}; - -/* Clock for the temperature sensor. Generally run at 2Mhz, max 5Mhz. */ -static const struct bcm2835_clock_data bcm2835_clock_tsens_data = { - .name = "tsens", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), - .parents = bcm2835_clock_osc_parents, - .ctl_reg = CM_TSENSCTL, - .div_reg = CM_TSENSDIV, - .int_bits = 5, - .frac_bits = 0, -}; - -/* Arasan EMMC clock */ -static const struct bcm2835_clock_data bcm2835_clock_emmc_data = { - .name = "emmc", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), - .parents = bcm2835_clock_per_parents, - .ctl_reg = CM_EMMCCTL, - .div_reg = CM_EMMCDIV, - .int_bits = 4, - .frac_bits = 8, -}; - -static const struct bcm2835_clock_data bcm2835_clock_pwm_data = { - .name = "pwm", - .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), - .parents = bcm2835_clock_per_parents, - .ctl_reg = CM_PWMCTL, - .div_reg = CM_PWMDIV, - .int_bits = 12, - .frac_bits = 12, - .is_mash_clock = true, -}; - struct bcm2835_gate_data { const char *name; const char *parent; @@ -857,18 +452,6 @@ struct bcm2835_gate_data { u32 ctl_reg; }; -/* - * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if - * you have the debug bit set in the power manager, which we - * don't bother exposing) are individual gates off of the - * non-stop vpu clock. - */ -static const struct bcm2835_gate_data bcm2835_clock_peri_image_data = { - .name = "peri_image", - .parent = "vpu", - .ctl_reg = CM_PERIICTL, -}; - struct bcm2835_pll { struct clk_hw hw; struct bcm2835_cprman *cprman; @@ -1578,7 +1161,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, memset(&init, 0, sizeof(init)); - init.parent_names = &data->source_pll->name; + init.parent_names = &data->source_pll; init.num_parents = 1; init.name = divider_name; init.ops = &bcm2835_pll_divider_clk_ops; @@ -1677,50 +1260,401 @@ struct bcm2835_clk_desc { const void *data; }; -#define _REGISTER(f, d) { .clk_register = (bcm2835_clk_register)f, \ - .data = d } -#define REGISTER_PLL(d) _REGISTER(&bcm2835_register_pll, d) -#define REGISTER_PLL_DIV(d) _REGISTER(&bcm2835_register_pll_divider, d) -#define REGISTER_CLK(d) _REGISTER(&bcm2835_register_clock, d) -#define REGISTER_GATE(d) _REGISTER(&bcm2835_register_gate, d) +/* assignment helper macros for different clock types */ +#define _REGISTER(f, ...) { .clk_register = (bcm2835_clk_register)f, \ + .data = __VA_ARGS__ } +#define REGISTER_PLL(...) _REGISTER(&bcm2835_register_pll, \ + &(struct bcm2835_pll_data) \ + {__VA_ARGS__}) +#define REGISTER_PLL_DIV(...) _REGISTER(&bcm2835_register_pll_divider, \ + &(struct bcm2835_pll_divider_data) \ + {__VA_ARGS__}) +#define REGISTER_CLK(...) _REGISTER(&bcm2835_register_clock, \ + &(struct bcm2835_clock_data) \ + {__VA_ARGS__}) +#define REGISTER_GATE(...) _REGISTER(&bcm2835_register_gate, \ + &(struct bcm2835_gate_data) \ + {__VA_ARGS__}) + +/* parent mux arrays plus helper macros */ + +/* main oscillator parent mux */ +static const char *const bcm2835_clock_osc_parents[] = { + "gnd", + "xosc", + "testdebug0", + "testdebug1" +}; + +#define REGISTER_OSC_CLK(...) REGISTER_CLK( \ + .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), \ + .parents = bcm2835_clock_osc_parents, \ + __VA_ARGS__) + +/* main peripherial parent mux */ +static const char *const bcm2835_clock_per_parents[] = { + "gnd", + "xosc", + "testdebug0", + "testdebug1", + "plla_per", + "pllc_per", + "plld_per", + "pllh_aux", +}; + +#define REGISTER_PER_CLK(...) REGISTER_CLK( \ + .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), \ + .parents = bcm2835_clock_per_parents, \ + __VA_ARGS__) +/* main vpu parent mux */ +static const char *const bcm2835_clock_vpu_parents[] = { + "gnd", + "xosc", + "testdebug0", + "testdebug1", + "plla_core", + "pllc_core0", + "plld_core", + "pllh_aux", + "pllc_core1", + "pllc_core2", +}; + +#define REGISTER_VPU_CLK(...) REGISTER_CLK( \ + .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), \ + .parents = bcm2835_clock_vpu_parents, \ + __VA_ARGS__) + +/* + * the real definition of all the pll, pll_dividers and clocks + * these make use of the above REGISTER_* macros + */ static const struct bcm2835_clk_desc clk_desc_array[] = { - /* register PLL */ - [BCM2835_PLLA] = REGISTER_PLL(&bcm2835_plla_data), - [BCM2835_PLLB] = REGISTER_PLL(&bcm2835_pllb_data), - [BCM2835_PLLC] = REGISTER_PLL(&bcm2835_pllc_data), - [BCM2835_PLLD] = REGISTER_PLL(&bcm2835_plld_data), - [BCM2835_PLLH] = REGISTER_PLL(&bcm2835_pllh_data), - /* the PLL dividers */ - [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV(&bcm2835_plla_core_data), - [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(&bcm2835_plla_per_data), - [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV(&bcm2835_pllc_core0_data), - [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV(&bcm2835_pllc_core1_data), - [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV(&bcm2835_pllc_core2_data), - [BCM2835_PLLC_PER] = REGISTER_PLL_DIV(&bcm2835_pllc_per_data), - [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV(&bcm2835_plld_core_data), - [BCM2835_PLLD_PER] = REGISTER_PLL_DIV(&bcm2835_plld_per_data), - [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV(&bcm2835_pllh_rcal_data), - [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV(&bcm2835_pllh_aux_data), - [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(&bcm2835_pllh_pix_data), + /* the PLL + PLL dividers */ + + /* + * PLLA is the auxiliary PLL, used to drive the CCP2 + * (Compact Camera Port 2) transmitter clock. + * + * It is in the PX LDO power domain, which is on when the + * AUDIO domain is on. + */ + [BCM2835_PLLA] = REGISTER_PLL( + .name = "plla", + .cm_ctrl_reg = CM_PLLA, + .a2w_ctrl_reg = A2W_PLLA_CTRL, + .frac_reg = A2W_PLLA_FRAC, + .ana_reg_base = A2W_PLLA_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE, + .lock_mask = CM_LOCK_FLOCKA, + + .ana = &bcm2835_ana_default, + + .min_rate = 600000000u, + .max_rate = 2400000000u, + .max_fb_rate = BCM2835_MAX_FB_RATE), + [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV( + .name = "plla_core", + .source_pll = "plla", + .cm_reg = CM_PLLA, + .a2w_reg = A2W_PLLA_CORE, + .load_mask = CM_PLLA_LOADCORE, + .hold_mask = CM_PLLA_HOLDCORE, + .fixed_divider = 1), + [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( + .name = "plla_per", + .source_pll = "plla", + .cm_reg = CM_PLLA, + .a2w_reg = A2W_PLLA_PER, + .load_mask = CM_PLLA_LOADPER, + .hold_mask = CM_PLLA_HOLDPER, + .fixed_divider = 1), + + /* PLLB is used for the ARM's clock. */ + [BCM2835_PLLB] = REGISTER_PLL( + .name = "pllb", + .cm_ctrl_reg = CM_PLLB, + .a2w_ctrl_reg = A2W_PLLB_CTRL, + .frac_reg = A2W_PLLB_FRAC, + .ana_reg_base = A2W_PLLB_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE, + .lock_mask = CM_LOCK_FLOCKB, + + .ana = &bcm2835_ana_default, + + .min_rate = 600000000u, + .max_rate = 3000000000u, + .max_fb_rate = BCM2835_MAX_FB_RATE), + [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV( + .name = "pllb_arm", + .source_pll = "pllb", + .cm_reg = CM_PLLB, + .a2w_reg = A2W_PLLB_ARM, + .load_mask = CM_PLLB_LOADARM, + .hold_mask = CM_PLLB_HOLDARM, + .fixed_divider = 1), + + /* + * PLLC is the core PLL, used to drive the core VPU clock. + * + * It is in the PX LDO power domain, which is on when the + * AUDIO domain is on. + */ + [BCM2835_PLLC] = REGISTER_PLL( + .name = "pllc", + .cm_ctrl_reg = CM_PLLC, + .a2w_ctrl_reg = A2W_PLLC_CTRL, + .frac_reg = A2W_PLLC_FRAC, + .ana_reg_base = A2W_PLLC_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, + .lock_mask = CM_LOCK_FLOCKC, + + .ana = &bcm2835_ana_default, + + .min_rate = 600000000u, + .max_rate = 3000000000u, + .max_fb_rate = BCM2835_MAX_FB_RATE), + [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV( + .name = "pllc_core0", + .source_pll = "pllc", + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_CORE0, + .load_mask = CM_PLLC_LOADCORE0, + .hold_mask = CM_PLLC_HOLDCORE0, + .fixed_divider = 1), + [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV( + .name = "pllc_core1", + .source_pll = "pllc", + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_CORE1, + .load_mask = CM_PLLC_LOADCORE1, + .hold_mask = CM_PLLC_HOLDCORE1, + .fixed_divider = 1), + [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV( + .name = "pllc_core2", + .source_pll = "pllc", + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_CORE2, + .load_mask = CM_PLLC_LOADCORE2, + .hold_mask = CM_PLLC_HOLDCORE2, + .fixed_divider = 1), + [BCM2835_PLLC_PER] = REGISTER_PLL_DIV( + .name = "pllc_per", + .source_pll = "pllc", + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_PER, + .load_mask = CM_PLLC_LOADPER, + .hold_mask = CM_PLLC_HOLDPER, + .fixed_divider = 1), + + /* + * PLLD is the display PLL, used to drive DSI display panels. + * + * It is in the PX LDO power domain, which is on when the + * AUDIO domain is on. + */ + [BCM2835_PLLD] = REGISTER_PLL( + .name = "plld", + .cm_ctrl_reg = CM_PLLD, + .a2w_ctrl_reg = A2W_PLLD_CTRL, + .frac_reg = A2W_PLLD_FRAC, + .ana_reg_base = A2W_PLLD_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE, + .lock_mask = CM_LOCK_FLOCKD, + + .ana = &bcm2835_ana_default, + + .min_rate = 600000000u, + .max_rate = 2400000000u, + .max_fb_rate = BCM2835_MAX_FB_RATE), + [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV( + .name = "plld_core", + .source_pll = "plld", + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_CORE, + .load_mask = CM_PLLD_LOADCORE, + .hold_mask = CM_PLLD_HOLDCORE, + .fixed_divider = 1), + [BCM2835_PLLD_PER] = REGISTER_PLL_DIV( + .name = "plld_per", + .source_pll = "plld", + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_PER, + .load_mask = CM_PLLD_LOADPER, + .hold_mask = CM_PLLD_HOLDPER, + .fixed_divider = 1), + + /* + * PLLH is used to supply the pixel clock or the AUX clock for the + * TV encoder. + * + * It is in the HDMI power domain. + */ + [BCM2835_PLLH] = REGISTER_PLL( + "pllh", + .cm_ctrl_reg = CM_PLLH, + .a2w_ctrl_reg = A2W_PLLH_CTRL, + .frac_reg = A2W_PLLH_FRAC, + .ana_reg_base = A2W_PLLH_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, + .lock_mask = CM_LOCK_FLOCKH, + + .ana = &bcm2835_ana_pllh, + + .min_rate = 600000000u, + .max_rate = 3000000000u, + .max_fb_rate = BCM2835_MAX_FB_RATE), + [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV( + .name = "pllh_rcal", + .source_pll = "pllh", + .cm_reg = CM_PLLH, + .a2w_reg = A2W_PLLH_RCAL, + .load_mask = CM_PLLH_LOADRCAL, + .hold_mask = 0, + .fixed_divider = 10), + [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV( + .name = "pllh_aux", + .source_pll = "pllh", + .cm_reg = CM_PLLH, + .a2w_reg = A2W_PLLH_AUX, + .load_mask = CM_PLLH_LOADAUX, + .hold_mask = 0, + .fixed_divider = 10), + [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV( + .name = "pllh_pix", + .source_pll = "pllh", + .cm_reg = CM_PLLH, + .a2w_reg = A2W_PLLH_PIX, + .load_mask = CM_PLLH_LOADPIX, + .hold_mask = 0, + .fixed_divider = 10), + /* the clocks */ - [BCM2835_CLOCK_TIMER] = REGISTER_CLK(&bcm2835_clock_timer_data), - [BCM2835_CLOCK_OTP] = REGISTER_CLK(&bcm2835_clock_otp_data), - [BCM2835_CLOCK_TSENS] = REGISTER_CLK(&bcm2835_clock_tsens_data), - [BCM2835_CLOCK_VPU] = REGISTER_CLK(&bcm2835_clock_vpu_data), - [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data), - [BCM2835_CLOCK_ISP] = REGISTER_CLK(&bcm2835_clock_isp_data), - [BCM2835_CLOCK_H264] = REGISTER_CLK(&bcm2835_clock_h264_data), - [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data), - [BCM2835_CLOCK_SDRAM] = REGISTER_CLK(&bcm2835_clock_sdram_data), - [BCM2835_CLOCK_UART] = REGISTER_CLK(&bcm2835_clock_uart_data), - [BCM2835_CLOCK_VEC] = REGISTER_CLK(&bcm2835_clock_vec_data), - [BCM2835_CLOCK_HSM] = REGISTER_CLK(&bcm2835_clock_hsm_data), - [BCM2835_CLOCK_EMMC] = REGISTER_CLK(&bcm2835_clock_emmc_data), - [BCM2835_CLOCK_PWM] = REGISTER_CLK(&bcm2835_clock_pwm_data), + + /* clocks with oscillator parent mux */ + + /* One Time Programmable Memory clock. Maximum 10Mhz. */ + [BCM2835_CLOCK_OTP] = REGISTER_OSC_CLK( + .name = "otp", + .ctl_reg = CM_OTPCTL, + .div_reg = CM_OTPDIV, + .int_bits = 4, + .frac_bits = 0), + /* + * Used for a 1Mhz clock for the system clocksource, and also used + * bythe watchdog timer and the camera pulse generator. + */ + [BCM2835_CLOCK_TIMER] = REGISTER_OSC_CLK( + .name = "timer", + .ctl_reg = CM_TIMERCTL, + .div_reg = CM_TIMERDIV, + .int_bits = 6, + .frac_bits = 12), + /* + * Clock for the temperature sensor. + * Generally run at 2Mhz, max 5Mhz. + */ + [BCM2835_CLOCK_TSENS] = REGISTER_OSC_CLK( + .name = "tsens", + .ctl_reg = CM_TSENSCTL, + .div_reg = CM_TSENSDIV, + .int_bits = 5, + .frac_bits = 0), + + /* clocks with vpu parent mux */ + [BCM2835_CLOCK_H264] = REGISTER_VPU_CLK( + .name = "h264", + .ctl_reg = CM_H264CTL, + .div_reg = CM_H264DIV, + .int_bits = 4, + .frac_bits = 8), + [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK( + .name = "isp", + .ctl_reg = CM_ISPCTL, + .div_reg = CM_ISPDIV, + .int_bits = 4, + .frac_bits = 8), + /* + * Secondary SDRAM clock. Used for low-voltage modes when the PLL + * in the SDRAM controller can't be used. + */ + [BCM2835_CLOCK_SDRAM] = REGISTER_VPU_CLK( + .name = "sdram", + .ctl_reg = CM_SDCCTL, + .div_reg = CM_SDCDIV, + .int_bits = 6, + .frac_bits = 0), + [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( + .name = "v3d", + .ctl_reg = CM_V3DCTL, + .div_reg = CM_V3DDIV, + .int_bits = 4, + .frac_bits = 8), + /* + * VPU clock. This doesn't have an enable bit, since it drives + * the bus for everything else, and is special so it doesn't need + * to be gated for rate changes. It is also known as "clk_audio" + * in various hardware documentation. + */ + [BCM2835_CLOCK_VPU] = REGISTER_VPU_CLK( + .name = "vpu", + .ctl_reg = CM_VPUCTL, + .div_reg = CM_VPUDIV, + .int_bits = 12, + .frac_bits = 8, + .is_vpu_clock = true), + + /* clocks with per parent mux */ + + /* Arasan EMMC clock */ + [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK( + .name = "emmc", + .ctl_reg = CM_EMMCCTL, + .div_reg = CM_EMMCDIV, + .int_bits = 4, + .frac_bits = 8), + /* HDMI state machine */ + [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK( + .name = "hsm", + .ctl_reg = CM_HSMCTL, + .div_reg = CM_HSMDIV, + .int_bits = 4, + .frac_bits = 8), + [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( + .name = "pwm", + .ctl_reg = CM_PWMCTL, + .div_reg = CM_PWMDIV, + .int_bits = 12, + .frac_bits = 12, + .is_mash_clock = true), + [BCM2835_CLOCK_UART] = REGISTER_PER_CLK( + .name = "uart", + .ctl_reg = CM_UARTCTL, + .div_reg = CM_UARTDIV, + .int_bits = 10, + .frac_bits = 12), + /* TV encoder clock. Only operating frequency is 108Mhz. */ + [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( + .name = "vec", + .ctl_reg = CM_VECCTL, + .div_reg = CM_VECDIV, + .int_bits = 4, + .frac_bits = 0), + /* the gates */ + + /* + * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if + * you have the debug bit set in the power manager, which we + * don't bother exposing) are individual gates off of the + * non-stop vpu clock. + */ [BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE( - &bcm2835_clock_peri_image_data), + .name = "peri_image", + .parent = "vpu", + .ctl_reg = CM_PERIICTL), }; static int bcm2835_clk_probe(struct platform_device *pdev) -- cgit v0.10.2 From 33b689600f43094a9316a1b582f2286d17bc737b Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 12:51:43 +0000 Subject: clk: bcm2835: enable management of PCM clock Enable the PCM clock in the SOC, which is used by the bcm2835-i2s driver. Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index a4b91a4..156ce54 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1622,6 +1622,13 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_HSMDIV, .int_bits = 4, .frac_bits = 8), + [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK( + .name = "pcm", + .ctl_reg = CM_PCMCTL, + .div_reg = CM_PCMDIV, + .int_bits = 12, + .frac_bits = 12, + .is_mash_clock = true), [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( .name = "pwm", .ctl_reg = CM_PWMCTL, diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h index 87235ac..9a7b4a5 100644 --- a/include/dt-bindings/clock/bcm2835.h +++ b/include/dt-bindings/clock/bcm2835.h @@ -44,3 +44,4 @@ #define BCM2835_CLOCK_EMMC 28 #define BCM2835_CLOCK_PERI_IMAGE 29 #define BCM2835_CLOCK_PWM 30 +#define BCM2835_CLOCK_PCM 31 -- cgit v0.10.2 From 728436956aa172b24a3212295f8b53feb6479f32 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 15:43:56 +0000 Subject: clk: bcm2835: add missing PLL clock dividers Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 156ce54..fa444d0 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1371,6 +1371,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .load_mask = CM_PLLA_LOADPER, .hold_mask = CM_PLLA_HOLDPER, .fixed_divider = 1), + [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( + .name = "plla_dsi0", + .source_pll = "plla", + .cm_reg = CM_PLLA, + .a2w_reg = A2W_PLLA_DSI0, + .load_mask = CM_PLLA_LOADDSI0, + .hold_mask = CM_PLLA_HOLDDSI0, + .fixed_divider = 1), + [BCM2835_PLLA_CCP2] = REGISTER_PLL_DIV( + .name = "plla_ccp2", + .source_pll = "plla", + .cm_reg = CM_PLLA, + .a2w_reg = A2W_PLLA_CCP2, + .load_mask = CM_PLLA_LOADCCP2, + .hold_mask = CM_PLLA_HOLDCCP2, + .fixed_divider = 1), /* PLLB is used for the ARM's clock. */ [BCM2835_PLLB] = REGISTER_PLL( @@ -1485,6 +1501,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .load_mask = CM_PLLD_LOADPER, .hold_mask = CM_PLLD_HOLDPER, .fixed_divider = 1), + [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV( + .name = "plld_dsi0", + .source_pll = "plld", + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_DSI0, + .load_mask = CM_PLLD_LOADDSI0, + .hold_mask = CM_PLLD_HOLDDSI0, + .fixed_divider = 1), + [BCM2835_PLLD_DSI1] = REGISTER_PLL_DIV( + .name = "plld_dsi1", + .source_pll = "plld", + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_DSI1, + .load_mask = CM_PLLD_LOADDSI1, + .hold_mask = CM_PLLD_HOLDDSI1, + .fixed_divider = 1), /* * PLLH is used to supply the pixel clock or the AUX clock for the diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h index 9a7b4a5..a001e38 100644 --- a/include/dt-bindings/clock/bcm2835.h +++ b/include/dt-bindings/clock/bcm2835.h @@ -45,3 +45,8 @@ #define BCM2835_CLOCK_PERI_IMAGE 29 #define BCM2835_CLOCK_PWM 30 #define BCM2835_CLOCK_PCM 31 + +#define BCM2835_PLLA_DSI0 32 +#define BCM2835_PLLA_CCP2 33 +#define BCM2835_PLLD_DSI0 34 +#define BCM2835_PLLD_DSI1 35 -- cgit v0.10.2 From d3d6f15fd376e3dbba851724057b112558c70b79 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 29 Feb 2016 15:43:57 +0000 Subject: clk: bcm2835: add missing osc and per clocks Add AVE0, DFT, GP0, GP1, GP2, SLIM, SMI, TEC, DPI, CAM0, CAM1, DSI0E, and DSI1E. PULSE is not added because it has an extra divider. Signed-off-by: Martin Sperl Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index fa444d0..4c0f1b5 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -117,6 +117,8 @@ #define CM_SDCCTL 0x1a8 #define CM_SDCDIV 0x1ac #define CM_ARMCTL 0x1b0 +#define CM_AVEOCTL 0x1b8 +#define CM_AVEODIV 0x1bc #define CM_EMMCCTL 0x1c0 #define CM_EMMCDIV 0x1c4 @@ -1594,6 +1596,12 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_TSENSDIV, .int_bits = 5, .frac_bits = 0), + [BCM2835_CLOCK_TEC] = REGISTER_OSC_CLK( + .name = "tec", + .ctl_reg = CM_TECCTL, + .div_reg = CM_TECDIV, + .int_bits = 6, + .frac_bits = 0), /* clocks with vpu parent mux */ [BCM2835_CLOCK_H264] = REGISTER_VPU_CLK( @@ -1608,6 +1616,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_ISPDIV, .int_bits = 4, .frac_bits = 8), + /* * Secondary SDRAM clock. Used for low-voltage modes when the PLL * in the SDRAM controller can't be used. @@ -1639,6 +1648,36 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .is_vpu_clock = true), /* clocks with per parent mux */ + [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK( + .name = "aveo", + .ctl_reg = CM_AVEOCTL, + .div_reg = CM_AVEODIV, + .int_bits = 4, + .frac_bits = 0), + [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK( + .name = "cam0", + .ctl_reg = CM_CAM0CTL, + .div_reg = CM_CAM0DIV, + .int_bits = 4, + .frac_bits = 8), + [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK( + .name = "cam1", + .ctl_reg = CM_CAM1CTL, + .div_reg = CM_CAM1DIV, + .int_bits = 4, + .frac_bits = 8), + [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK( + .name = "dft", + .ctl_reg = CM_DFTCTL, + .div_reg = CM_DFTDIV, + .int_bits = 5, + .frac_bits = 0), + [BCM2835_CLOCK_DPI] = REGISTER_PER_CLK( + .name = "dpi", + .ctl_reg = CM_DPICTL, + .div_reg = CM_DPIDIV, + .int_bits = 4, + .frac_bits = 8), /* Arasan EMMC clock */ [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK( @@ -1647,6 +1686,29 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_EMMCDIV, .int_bits = 4, .frac_bits = 8), + + /* General purpose (GPIO) clocks */ + [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK( + .name = "gp0", + .ctl_reg = CM_GP0CTL, + .div_reg = CM_GP0DIV, + .int_bits = 12, + .frac_bits = 12, + .is_mash_clock = true), + [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK( + .name = "gp1", + .ctl_reg = CM_GP1CTL, + .div_reg = CM_GP1DIV, + .int_bits = 12, + .frac_bits = 12, + .is_mash_clock = true), + [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( + .name = "gp2", + .ctl_reg = CM_GP2CTL, + .div_reg = CM_GP2DIV, + .int_bits = 12, + .frac_bits = 12), + /* HDMI state machine */ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK( .name = "hsm", @@ -1668,12 +1730,26 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .int_bits = 12, .frac_bits = 12, .is_mash_clock = true), + [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK( + .name = "slim", + .ctl_reg = CM_SLIMCTL, + .div_reg = CM_SLIMDIV, + .int_bits = 12, + .frac_bits = 12, + .is_mash_clock = true), + [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK( + .name = "smi", + .ctl_reg = CM_SMICTL, + .div_reg = CM_SMIDIV, + .int_bits = 4, + .frac_bits = 8), [BCM2835_CLOCK_UART] = REGISTER_PER_CLK( .name = "uart", .ctl_reg = CM_UARTCTL, .div_reg = CM_UARTDIV, .int_bits = 10, .frac_bits = 12), + /* TV encoder clock. Only operating frequency is 108Mhz. */ [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( .name = "vec", @@ -1682,6 +1758,20 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .int_bits = 4, .frac_bits = 0), + /* dsi clocks */ + [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( + .name = "dsi0e", + .ctl_reg = CM_DSI0ECTL, + .div_reg = CM_DSI0EDIV, + .int_bits = 4, + .frac_bits = 8), + [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK( + .name = "dsi1e", + .ctl_reg = CM_DSI1ECTL, + .div_reg = CM_DSI1EDIV, + .int_bits = 4, + .frac_bits = 8), + /* the gates */ /* diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h index a001e38..360e00c 100644 --- a/include/dt-bindings/clock/bcm2835.h +++ b/include/dt-bindings/clock/bcm2835.h @@ -50,3 +50,17 @@ #define BCM2835_PLLA_CCP2 33 #define BCM2835_PLLD_DSI0 34 #define BCM2835_PLLD_DSI1 35 + +#define BCM2835_CLOCK_AVEO 36 +#define BCM2835_CLOCK_DFT 37 +#define BCM2835_CLOCK_GP0 38 +#define BCM2835_CLOCK_GP1 39 +#define BCM2835_CLOCK_GP2 40 +#define BCM2835_CLOCK_SLIM 41 +#define BCM2835_CLOCK_SMI 42 +#define BCM2835_CLOCK_TEC 43 +#define BCM2835_CLOCK_DPI 44 +#define BCM2835_CLOCK_CAM0 45 +#define BCM2835_CLOCK_CAM1 46 +#define BCM2835_CLOCK_DSI0E 47 +#define BCM2835_CLOCK_DSI1E 48 -- cgit v0.10.2 From 9387bfd19b457085189d918ef117ffd63c4d67a0 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 9 Mar 2016 10:43:31 +0800 Subject: clk: rockchip: add a COMPOSITE_FRACMUX_NOGATE type Because there are some frac clock mux nodes don't have a gate node on the RK3399. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 39c198b..f3da205 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -428,6 +428,22 @@ struct rockchip_clk_branch { .child = ch, \ } +#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch) \ + { \ + .id = _id, \ + .branch_type = branch_fraction_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = mo, \ + .div_shift = 16, \ + .div_width = 16, \ + .div_flags = df, \ + .gate_offset = -1, \ + .child = ch, \ + } + #define MUX(_id, cname, pnames, f, o, s, w, mf) \ { \ .id = _id, \ -- cgit v0.10.2 From 268aebaa2410152bf91ea1ede6b284ff8138822d Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 9 Mar 2016 10:37:03 +0800 Subject: clk: rockchip: allow varying mux parameters for cpuclk pll-sources Thers are only two parent PLLs that APLL and GPLL for core on the previous SoCs (RK3066/RK3188/RK3288/RK3368). Hence, we set fixed GPLL as alternate parent when core is switching freq. Since RK3399 big.LITTLE architecture, we need to select and adapt more PLLs (ALPLL/ABPLL/DPLL/GPLL) sources. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c index 4e73ed5..4bb130c 100644 --- a/drivers/clk/rockchip/clk-cpu.c +++ b/drivers/clk/rockchip/clk-cpu.c @@ -158,12 +158,16 @@ static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk, writel(HIWORD_UPDATE(alt_div, reg_data->div_core_mask, reg_data->div_core_shift) | - HIWORD_UPDATE(1, 1, reg_data->mux_core_shift), + HIWORD_UPDATE(reg_data->mux_core_alt, + reg_data->mux_core_mask, + reg_data->mux_core_shift), cpuclk->reg_base + reg_data->core_reg); } else { /* select alternate parent */ - writel(HIWORD_UPDATE(1, 1, reg_data->mux_core_shift), - cpuclk->reg_base + reg_data->core_reg); + writel(HIWORD_UPDATE(reg_data->mux_core_alt, + reg_data->mux_core_mask, + reg_data->mux_core_shift), + cpuclk->reg_base + reg_data->core_reg); } spin_unlock_irqrestore(cpuclk->lock, flags); @@ -198,7 +202,9 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk, writel(HIWORD_UPDATE(0, reg_data->div_core_mask, reg_data->div_core_shift) | - HIWORD_UPDATE(0, 1, reg_data->mux_core_shift), + HIWORD_UPDATE(reg_data->mux_core_main, + reg_data->mux_core_mask, + reg_data->mux_core_shift), cpuclk->reg_base + reg_data->core_reg); if (ndata->old_rate > ndata->new_rate) @@ -252,7 +258,7 @@ struct clk *rockchip_clk_register_cpuclk(const char *name, return ERR_PTR(-ENOMEM); init.name = name; - init.parent_names = &parent_names[0]; + init.parent_names = &parent_names[reg_data->mux_core_main]; init.num_parents = 1; init.ops = &rockchip_cpuclk_ops; @@ -270,10 +276,10 @@ struct clk *rockchip_clk_register_cpuclk(const char *name, cpuclk->clk_nb.notifier_call = rockchip_cpuclk_notifier_cb; cpuclk->hw.init = &init; - cpuclk->alt_parent = __clk_lookup(parent_names[1]); + cpuclk->alt_parent = __clk_lookup(parent_names[reg_data->mux_core_alt]); if (!cpuclk->alt_parent) { - pr_err("%s: could not lookup alternate parent\n", - __func__); + pr_err("%s: could not lookup alternate parent: (%d)\n", + __func__, reg_data->mux_core_alt); ret = -EINVAL; goto free_cpuclk; } @@ -285,10 +291,11 @@ struct clk *rockchip_clk_register_cpuclk(const char *name, goto free_cpuclk; } - clk = __clk_lookup(parent_names[0]); + clk = __clk_lookup(parent_names[reg_data->mux_core_main]); if (!clk) { - pr_err("%s: could not lookup parent clock %s\n", - __func__, parent_names[0]); + pr_err("%s: could not lookup parent clock: (%d) %s\n", + __func__, reg_data->mux_core_main, + parent_names[reg_data->mux_core_main]); ret = -EINVAL; goto free_alt_parent; } diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c index 7cdb2d6..f9cbba0 100644 --- a/drivers/clk/rockchip/clk-rk3036.c +++ b/drivers/clk/rockchip/clk-rk3036.c @@ -113,7 +113,10 @@ static const struct rockchip_cpuclk_reg_data rk3036_cpuclk_data = { .core_reg = RK2928_CLKSEL_CON(0), .div_core_shift = 0, .div_core_mask = 0x1f, + .mux_core_alt = 1, + .mux_core_main = 0, .mux_core_shift = 7, + .mux_core_mask = 0x1, }; PNAME(mux_pll_p) = { "xin24m", "xin24m" }; diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 40bab39..e832403 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -155,7 +155,10 @@ static const struct rockchip_cpuclk_reg_data rk3066_cpuclk_data = { .core_reg = RK2928_CLKSEL_CON(0), .div_core_shift = 0, .div_core_mask = 0x1f, + .mux_core_alt = 1, + .mux_core_main = 0, .mux_core_shift = 8, + .mux_core_mask = 0x1, }; #define RK3188_DIV_ACLK_CORE_MASK 0x7 @@ -191,7 +194,10 @@ static const struct rockchip_cpuclk_reg_data rk3188_cpuclk_data = { .core_reg = RK2928_CLKSEL_CON(0), .div_core_shift = 9, .div_core_mask = 0x1f, + .mux_core_alt = 1, + .mux_core_main = 0, .mux_core_shift = 8, + .mux_core_mask = 0x1, }; PNAME(mux_pll_p) = { "xin24m", "xin32k" }; diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index 7702d28..4b4137e 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -111,7 +111,10 @@ static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = { .core_reg = RK2928_CLKSEL_CON(0), .div_core_shift = 0, .div_core_mask = 0x1f, + .mux_core_alt = 1, + .mux_core_main = 0, .mux_core_shift = 6, + .mux_core_mask = 0x1, }; PNAME(mux_pll_p) = { "clk_24m", "xin24m" }; diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 3cb7216..00faf3f 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -165,7 +165,10 @@ static const struct rockchip_cpuclk_reg_data rk3288_cpuclk_data = { .core_reg = RK3288_CLKSEL_CON(0), .div_core_shift = 8, .div_core_mask = 0x1f, + .mux_core_alt = 1, + .mux_core_main = 0, .mux_core_shift = 15, + .mux_core_mask = 0x1, }; PNAME(mux_pll_p) = { "xin24m", "xin32k" }; diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c index a2bb122..c26ff4a 100644 --- a/drivers/clk/rockchip/clk-rk3368.c +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -165,14 +165,20 @@ static const struct rockchip_cpuclk_reg_data rk3368_cpuclkb_data = { .core_reg = RK3368_CLKSEL_CON(0), .div_core_shift = 0, .div_core_mask = 0x1f, + .mux_core_alt = 1, + .mux_core_main = 0, .mux_core_shift = 7, + .mux_core_mask = 0x1, }; static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = { .core_reg = RK3368_CLKSEL_CON(2), .div_core_shift = 0, + .mux_core_alt = 1, + .mux_core_main = 0, .div_core_mask = 0x1f, .mux_core_shift = 7, + .mux_core_mask = 0x1, }; #define RK3368_DIV_ACLKM_MASK 0x1f diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index f3da205..4133bfc 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -217,14 +217,20 @@ struct rockchip_cpuclk_rate_table { * @core_reg: register offset of the core settings register * @div_core_shift: core divider offset used to divide the pll value * @div_core_mask: core divider mask + * @mux_core_alt: mux value to select alternate parent + * @mux_core_main: mux value to select main parent of core * @mux_core_shift: offset of the core multiplexer + * @mux_core_mask: core multiplexer mask */ struct rockchip_cpuclk_reg_data { int core_reg; u8 div_core_shift; u32 div_core_mask; int mux_core_reg; + u8 mux_core_alt; + u8 mux_core_main; u8 mux_core_shift; + u32 mux_core_mask; }; struct clk *rockchip_clk_register_cpuclk(const char *name, -- cgit v0.10.2 From ef1d9feeccc094f59b72bb11fe14ec886eb574d3 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 9 Mar 2016 10:37:04 +0800 Subject: clk: rockchip: Add support for multiple clock providers There are need to support Multi-CRUs probability in future, but it is not supported on the current Rockchip Clock Framework. Therefore, this patch add support a provider as the parameter handler when we call the clock register functions for per CRU. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 5de797e..27be66a 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -46,6 +46,8 @@ struct rockchip_clk_pll { const struct rockchip_pll_rate_table *rate_table; unsigned int rate_count; spinlock_t *lock; + + struct rockchip_clk_provider *ctx; }; #define to_rockchip_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw) @@ -90,7 +92,7 @@ static long rockchip_pll_round_rate(struct clk_hw *hw, */ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) { - struct regmap *grf = rockchip_clk_get_grf(); + struct regmap *grf = rockchip_clk_get_grf(pll->ctx); unsigned int val; int delay = 24000000, ret; @@ -251,7 +253,7 @@ static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate, struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate); - struct regmap *grf = rockchip_clk_get_grf(); + struct regmap *grf = rockchip_clk_get_grf(pll->ctx); if (IS_ERR(grf)) { pr_debug("%s: grf regmap not available, aborting rate change\n", @@ -490,7 +492,7 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); - struct regmap *grf = rockchip_clk_get_grf(); + struct regmap *grf = rockchip_clk_get_grf(pll->ctx); if (IS_ERR(grf)) { pr_debug("%s: grf regmap not available, aborting rate change\n", @@ -563,7 +565,7 @@ static void rockchip_rk3066_pll_init(struct clk_hw *hw) rate->no, cur.no, rate->nf, cur.nf, rate->nb, cur.nb); if (rate->nr != cur.nr || rate->no != cur.no || rate->nf != cur.nf || rate->nb != cur.nb) { - struct regmap *grf = rockchip_clk_get_grf(); + struct regmap *grf = rockchip_clk_get_grf(pll->ctx); if (IS_ERR(grf)) return; @@ -595,12 +597,13 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = { * Common registering of pll clocks */ -struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, +struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, + enum rockchip_pll_type pll_type, const char *name, const char *const *parent_names, - u8 num_parents, void __iomem *base, int con_offset, - int grf_lock_offset, int lock_shift, int mode_offset, - int mode_shift, struct rockchip_pll_rate_table *rate_table, - u8 clk_pll_flags, spinlock_t *lock) + u8 num_parents, int con_offset, int grf_lock_offset, + int lock_shift, int mode_offset, int mode_shift, + struct rockchip_pll_rate_table *rate_table, + u8 clk_pll_flags) { const char *pll_parents[3]; struct clk_init_data init; @@ -624,11 +627,11 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, /* create the mux on top of the real pll */ pll->pll_mux_ops = &clk_mux_ops; pll_mux = &pll->pll_mux; - pll_mux->reg = base + mode_offset; + pll_mux->reg = ctx->reg_base + mode_offset; pll_mux->shift = mode_shift; pll_mux->mask = PLL_MODE_MASK; pll_mux->flags = 0; - pll_mux->lock = lock; + pll_mux->lock = &ctx->lock; pll_mux->hw.init = &init; if (pll_type == pll_rk3036 || pll_type == pll_rk3066) @@ -695,11 +698,12 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, pll->hw.init = &init; pll->type = pll_type; - pll->reg_base = base + con_offset; + pll->reg_base = ctx->reg_base + con_offset; pll->lock_offset = grf_lock_offset; pll->lock_shift = lock_shift; pll->flags = clk_pll_flags; - pll->lock = lock; + pll->lock = &ctx->lock; + pll->ctx = ctx; pll_clk = clk_register(NULL, &pll->hw); if (IS_ERR(pll_clk)) { diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c index f9cbba0..c7c8260 100644 --- a/drivers/clk/rockchip/clk-rk3036.c +++ b/drivers/clk/rockchip/clk-rk3036.c @@ -440,6 +440,7 @@ static const char *const rk3036_critical_clocks[] __initconst = { static void __init rk3036_clk_init(struct device_node *np) { + struct rockchip_clk_provider *ctx; void __iomem *reg_base; struct clk *clk; @@ -449,22 +450,26 @@ static void __init rk3036_clk_init(struct device_node *np) return; } - rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + return; + } clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1); if (IS_ERR(clk)) pr_warn("%s: could not register clock usb480m: %ld\n", __func__, PTR_ERR(clk)); - rockchip_clk_register_plls(rk3036_pll_clks, + rockchip_clk_register_plls(ctx, rk3036_pll_clks, ARRAY_SIZE(rk3036_pll_clks), RK3036_GRF_SOC_STATUS0); - rockchip_clk_register_branches(rk3036_clk_branches, + rockchip_clk_register_branches(ctx, rk3036_clk_branches, ARRAY_SIZE(rk3036_clk_branches)); rockchip_clk_protect_critical(rk3036_critical_clocks, ARRAY_SIZE(rk3036_critical_clocks)); - rockchip_clk_register_armclk(ARMCLK, "armclk", + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", mux_armclk_p, ARRAY_SIZE(mux_armclk_p), &rk3036_cpuclk_data, rk3036_cpuclk_rates, ARRAY_SIZE(rk3036_cpuclk_rates)); @@ -472,6 +477,8 @@ static void __init rk3036_clk_init(struct device_node *np) rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); - rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL); + rockchip_register_restart_notifier(ctx, RK2928_GLB_SRST_FST, NULL); + + rockchip_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(rk3036_cru, "rockchip,rk3036-cru", rk3036_clk_init); diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index e832403..0fcce22 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -759,57 +759,74 @@ static const char *const rk3188_critical_clocks[] __initconst = { "hclk_cpubus" }; -static void __init rk3188_common_clk_init(struct device_node *np) +static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np) { + struct rockchip_clk_provider *ctx; void __iomem *reg_base; reg_base = of_iomap(np, 0); if (!reg_base) { pr_err("%s: could not map cru region\n", __func__); - return; + return ERR_PTR(-ENOMEM); } - rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + return ERR_PTR(-ENOMEM); + } - rockchip_clk_register_branches(common_clk_branches, + rockchip_clk_register_branches(ctx, common_clk_branches, ARRAY_SIZE(common_clk_branches)); rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); - rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL); + rockchip_register_restart_notifier(ctx, RK2928_GLB_SRST_FST, NULL); + + return ctx; } static void __init rk3066a_clk_init(struct device_node *np) { - rk3188_common_clk_init(np); - rockchip_clk_register_plls(rk3066_pll_clks, + struct rockchip_clk_provider *ctx; + + ctx = rk3188_common_clk_init(np); + if (IS_ERR(ctx)) + return; + + rockchip_clk_register_plls(ctx, rk3066_pll_clks, ARRAY_SIZE(rk3066_pll_clks), RK3066_GRF_SOC_STATUS); - rockchip_clk_register_branches(rk3066a_clk_branches, + rockchip_clk_register_branches(ctx, rk3066a_clk_branches, ARRAY_SIZE(rk3066a_clk_branches)); - rockchip_clk_register_armclk(ARMCLK, "armclk", + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", mux_armclk_p, ARRAY_SIZE(mux_armclk_p), &rk3066_cpuclk_data, rk3066_cpuclk_rates, ARRAY_SIZE(rk3066_cpuclk_rates)); rockchip_clk_protect_critical(rk3188_critical_clocks, ARRAY_SIZE(rk3188_critical_clocks)); + rockchip_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init); static void __init rk3188a_clk_init(struct device_node *np) { + struct rockchip_clk_provider *ctx; struct clk *clk1, *clk2; unsigned long rate; int ret; - rk3188_common_clk_init(np); - rockchip_clk_register_plls(rk3188_pll_clks, + ctx = rk3188_common_clk_init(np); + if (IS_ERR(ctx)) + return; + + rockchip_clk_register_plls(ctx, rk3188_pll_clks, ARRAY_SIZE(rk3188_pll_clks), RK3188_GRF_SOC_STATUS); - rockchip_clk_register_branches(rk3188_clk_branches, + rockchip_clk_register_branches(ctx, rk3188_clk_branches, ARRAY_SIZE(rk3188_clk_branches)); - rockchip_clk_register_armclk(ARMCLK, "armclk", + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", mux_armclk_p, ARRAY_SIZE(mux_armclk_p), &rk3188_cpuclk_data, rk3188_cpuclk_rates, ARRAY_SIZE(rk3188_cpuclk_rates)); @@ -833,6 +850,7 @@ static void __init rk3188a_clk_init(struct device_node *np) rockchip_clk_protect_critical(rk3188_critical_clocks, ARRAY_SIZE(rk3188_critical_clocks)); + rockchip_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init); diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index 4b4137e..c112b2f 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -628,6 +628,7 @@ static const char *const rk3228_critical_clocks[] __initconst = { static void __init rk3228_clk_init(struct device_node *np) { + struct rockchip_clk_provider *ctx; void __iomem *reg_base; reg_base = of_iomap(np, 0); @@ -636,17 +637,21 @@ static void __init rk3228_clk_init(struct device_node *np) return; } - rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + return; + } - rockchip_clk_register_plls(rk3228_pll_clks, + rockchip_clk_register_plls(ctx, rk3228_pll_clks, ARRAY_SIZE(rk3228_pll_clks), RK3228_GRF_SOC_STATUS0); - rockchip_clk_register_branches(rk3228_clk_branches, + rockchip_clk_register_branches(ctx, rk3228_clk_branches, ARRAY_SIZE(rk3228_clk_branches)); rockchip_clk_protect_critical(rk3228_critical_clocks, ARRAY_SIZE(rk3228_critical_clocks)); - rockchip_clk_register_armclk(ARMCLK, "armclk", + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", mux_armclk_p, ARRAY_SIZE(mux_armclk_p), &rk3228_cpuclk_data, rk3228_cpuclk_rates, ARRAY_SIZE(rk3228_cpuclk_rates)); @@ -654,6 +659,8 @@ static void __init rk3228_clk_init(struct device_node *np) rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); - rockchip_register_restart_notifier(RK3228_GLB_SRST_FST, NULL); + rockchip_register_restart_notifier(ctx, RK3228_GLB_SRST_FST, NULL); + + rockchip_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(rk3228_cru, "rockchip,rk3228-cru", rk3228_clk_init); diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 00faf3f..d1031d1 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -881,6 +881,7 @@ static struct syscore_ops rk3288_clk_syscore_ops = { static void __init rk3288_clk_init(struct device_node *np) { + struct rockchip_clk_provider *ctx; struct clk *clk; rk3288_cru_base = of_iomap(np, 0); @@ -889,7 +890,11 @@ static void __init rk3288_clk_init(struct device_node *np) return; } - rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS); + ctx = rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + return; + } /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1); @@ -897,17 +902,17 @@ static void __init rk3288_clk_init(struct device_node *np) pr_warn("%s: could not register clock pclk_wdt: %ld\n", __func__, PTR_ERR(clk)); else - rockchip_clk_add_lookup(clk, PCLK_WDT); + rockchip_clk_add_lookup(ctx, clk, PCLK_WDT); - rockchip_clk_register_plls(rk3288_pll_clks, + rockchip_clk_register_plls(ctx, rk3288_pll_clks, ARRAY_SIZE(rk3288_pll_clks), RK3288_GRF_SOC_STATUS1); - rockchip_clk_register_branches(rk3288_clk_branches, + rockchip_clk_register_branches(ctx, rk3288_clk_branches, ARRAY_SIZE(rk3288_clk_branches)); rockchip_clk_protect_critical(rk3288_critical_clocks, ARRAY_SIZE(rk3288_critical_clocks)); - rockchip_clk_register_armclk(ARMCLK, "armclk", + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", mux_armclk_p, ARRAY_SIZE(mux_armclk_p), &rk3288_cpuclk_data, rk3288_cpuclk_rates, ARRAY_SIZE(rk3288_cpuclk_rates)); @@ -916,8 +921,10 @@ static void __init rk3288_clk_init(struct device_node *np) rk3288_cru_base + RK3288_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); - rockchip_register_restart_notifier(RK3288_GLB_SRST_FST, + rockchip_register_restart_notifier(ctx, RK3288_GLB_SRST_FST, rk3288_clk_shutdown); register_syscore_ops(&rk3288_clk_syscore_ops); + + rockchip_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c index c26ff4a..3121414 100644 --- a/drivers/clk/rockchip/clk-rk3368.c +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -862,6 +862,7 @@ static const char *const rk3368_critical_clocks[] __initconst = { static void __init rk3368_clk_init(struct device_node *np) { + struct rockchip_clk_provider *ctx; void __iomem *reg_base; struct clk *clk; @@ -871,7 +872,11 @@ static void __init rk3368_clk_init(struct device_node *np) return; } - rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + return; + } /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1); @@ -879,22 +884,22 @@ static void __init rk3368_clk_init(struct device_node *np) pr_warn("%s: could not register clock pclk_wdt: %ld\n", __func__, PTR_ERR(clk)); else - rockchip_clk_add_lookup(clk, PCLK_WDT); + rockchip_clk_add_lookup(ctx, clk, PCLK_WDT); - rockchip_clk_register_plls(rk3368_pll_clks, + rockchip_clk_register_plls(ctx, rk3368_pll_clks, ARRAY_SIZE(rk3368_pll_clks), RK3368_GRF_SOC_STATUS0); - rockchip_clk_register_branches(rk3368_clk_branches, + rockchip_clk_register_branches(ctx, rk3368_clk_branches, ARRAY_SIZE(rk3368_clk_branches)); rockchip_clk_protect_critical(rk3368_critical_clocks, ARRAY_SIZE(rk3368_critical_clocks)); - rockchip_clk_register_armclk(ARMCLKB, "armclkb", + rockchip_clk_register_armclk(ctx, ARMCLKB, "armclkb", mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p), &rk3368_cpuclkb_data, rk3368_cpuclkb_rates, ARRAY_SIZE(rk3368_cpuclkb_rates)); - rockchip_clk_register_armclk(ARMCLKL, "armclkl", + rockchip_clk_register_armclk(ctx, ARMCLKL, "armclkl", mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p), &rk3368_cpuclkl_data, rk3368_cpuclkl_rates, ARRAY_SIZE(rk3368_cpuclkl_rates)); @@ -902,6 +907,8 @@ static void __init rk3368_clk_init(struct device_node *np) rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); - rockchip_register_restart_notifier(RK3368_GLB_SRST_FST, NULL); + rockchip_register_restart_notifier(ctx, RK3368_GLB_SRST_FST, NULL); + + rockchip_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index ec06350..5618a87 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -2,6 +2,9 @@ * Copyright (c) 2014 MundoReader S.L. * Author: Heiko Stuebner * + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Xing Zheng + * * based on * * samsung/clk.c @@ -157,7 +160,8 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb, return notifier_from_errno(ret); } -static struct clk *rockchip_clk_register_frac_branch(const char *name, +static struct clk *rockchip_clk_register_frac_branch( + struct rockchip_clk_provider *ctx, const char *name, const char *const *parent_names, u8 num_parents, void __iomem *base, int muxdiv_offset, u8 div_flags, int gate_offset, u8 gate_shift, u8 gate_flags, @@ -250,7 +254,7 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name, if (IS_ERR(mux_clk)) return clk; - rockchip_clk_add_lookup(mux_clk, child->id); + rockchip_clk_add_lookup(ctx, mux_clk, child->id); /* notifier on the fraction divider to catch rate changes */ if (frac->mux_frac_idx >= 0) { @@ -314,66 +318,94 @@ static struct clk *rockchip_clk_register_factor_branch(const char *name, return clk; } -static DEFINE_SPINLOCK(clk_lock); -static struct clk **clk_table; -static void __iomem *reg_base; -static struct clk_onecell_data clk_data; -static struct device_node *cru_node; -static struct regmap *grf; - -void __init rockchip_clk_init(struct device_node *np, void __iomem *base, - unsigned long nr_clks) +struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np, + void __iomem *base, unsigned long nr_clks) { - reg_base = base; - cru_node = np; - grf = ERR_PTR(-EPROBE_DEFER); + struct rockchip_clk_provider *ctx; + struct clk **clk_table; + int i; + + ctx = kzalloc(sizeof(struct rockchip_clk_provider), GFP_KERNEL); + if (!ctx) { + pr_err("%s: Could not allocate clock provider context\n", + __func__); + return ERR_PTR(-ENOMEM); + } clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); - if (!clk_table) - pr_err("%s: could not allocate clock lookup table\n", __func__); + if (!clk_table) { + pr_err("%s: Could not allocate clock lookup table\n", + __func__); + goto err_free; + } + + for (i = 0; i < nr_clks; ++i) + clk_table[i] = ERR_PTR(-ENOENT); - clk_data.clks = clk_table; - clk_data.clk_num = nr_clks; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + ctx->reg_base = base; + ctx->clk_data.clks = clk_table; + ctx->clk_data.clk_num = nr_clks; + ctx->cru_node = np; + ctx->grf = ERR_PTR(-EPROBE_DEFER); + spin_lock_init(&ctx->lock); + + return ctx; + +err_free: + kfree(ctx); + return ERR_PTR(-ENOMEM); +} + +void __init rockchip_clk_of_add_provider(struct device_node *np, + struct rockchip_clk_provider *ctx) +{ + if (np) { + if (of_clk_add_provider(np, of_clk_src_onecell_get, + &ctx->clk_data)) + pr_err("%s: could not register clk provider\n", __func__); + } } -struct regmap *rockchip_clk_get_grf(void) +struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx) { - if (IS_ERR(grf)) - grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf"); - return grf; + if (IS_ERR(ctx->grf)) + ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, "rockchip,grf"); + return ctx->grf; } -void rockchip_clk_add_lookup(struct clk *clk, unsigned int id) +void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, + struct clk *clk, unsigned int id) { - if (clk_table && id) - clk_table[id] = clk; + if (ctx->clk_data.clks && id) + ctx->clk_data.clks[id] = clk; } -void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list, +void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, + struct rockchip_pll_clock *list, unsigned int nr_pll, int grf_lock_offset) { struct clk *clk; int idx; for (idx = 0; idx < nr_pll; idx++, list++) { - clk = rockchip_clk_register_pll(list->type, list->name, + clk = rockchip_clk_register_pll(ctx, list->type, list->name, list->parent_names, list->num_parents, - reg_base, list->con_offset, grf_lock_offset, + list->con_offset, grf_lock_offset, list->lock_shift, list->mode_offset, list->mode_shift, list->rate_table, - list->pll_flags, &clk_lock); + list->pll_flags); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, list->name); continue; } - rockchip_clk_add_lookup(clk, list->id); + rockchip_clk_add_lookup(ctx, clk, list->id); } } void __init rockchip_clk_register_branches( + struct rockchip_clk_provider *ctx, struct rockchip_clk_branch *list, unsigned int nr_clk) { @@ -389,56 +421,56 @@ void __init rockchip_clk_register_branches( case branch_mux: clk = clk_register_mux(NULL, list->name, list->parent_names, list->num_parents, - flags, reg_base + list->muxdiv_offset, + flags, ctx->reg_base + list->muxdiv_offset, list->mux_shift, list->mux_width, - list->mux_flags, &clk_lock); + list->mux_flags, &ctx->lock); break; case branch_divider: if (list->div_table) clk = clk_register_divider_table(NULL, list->name, list->parent_names[0], - flags, reg_base + list->muxdiv_offset, + flags, ctx->reg_base + list->muxdiv_offset, list->div_shift, list->div_width, list->div_flags, list->div_table, - &clk_lock); + &ctx->lock); else clk = clk_register_divider(NULL, list->name, list->parent_names[0], flags, - reg_base + list->muxdiv_offset, + ctx->reg_base + list->muxdiv_offset, list->div_shift, list->div_width, - list->div_flags, &clk_lock); + list->div_flags, &ctx->lock); break; case branch_fraction_divider: - clk = rockchip_clk_register_frac_branch(list->name, + clk = rockchip_clk_register_frac_branch(ctx, list->name, list->parent_names, list->num_parents, - reg_base, list->muxdiv_offset, list->div_flags, + ctx->reg_base, list->muxdiv_offset, list->div_flags, list->gate_offset, list->gate_shift, list->gate_flags, flags, list->child, - &clk_lock); + &ctx->lock); break; case branch_gate: flags |= CLK_SET_RATE_PARENT; clk = clk_register_gate(NULL, list->name, list->parent_names[0], flags, - reg_base + list->gate_offset, - list->gate_shift, list->gate_flags, &clk_lock); + ctx->reg_base + list->gate_offset, + list->gate_shift, list->gate_flags, &ctx->lock); break; case branch_composite: clk = rockchip_clk_register_branch(list->name, list->parent_names, list->num_parents, - reg_base, list->muxdiv_offset, list->mux_shift, + ctx->reg_base, list->muxdiv_offset, list->mux_shift, list->mux_width, list->mux_flags, list->div_shift, list->div_width, list->div_flags, list->div_table, list->gate_offset, list->gate_shift, - list->gate_flags, flags, &clk_lock); + list->gate_flags, flags, &ctx->lock); break; case branch_mmc: clk = rockchip_clk_register_mmc( list->name, list->parent_names, list->num_parents, - reg_base + list->muxdiv_offset, + ctx->reg_base + list->muxdiv_offset, list->div_shift ); break; @@ -446,16 +478,16 @@ void __init rockchip_clk_register_branches( clk = rockchip_clk_register_inverter( list->name, list->parent_names, list->num_parents, - reg_base + list->muxdiv_offset, - list->div_shift, list->div_flags, &clk_lock); + ctx->reg_base + list->muxdiv_offset, + list->div_shift, list->div_flags, &ctx->lock); break; case branch_factor: clk = rockchip_clk_register_factor_branch( list->name, list->parent_names, - list->num_parents, reg_base, + list->num_parents, ctx->reg_base, list->div_shift, list->div_width, list->gate_offset, list->gate_shift, - list->gate_flags, flags, &clk_lock); + list->gate_flags, flags, &ctx->lock); break; } @@ -472,11 +504,12 @@ void __init rockchip_clk_register_branches( continue; } - rockchip_clk_add_lookup(clk, list->id); + rockchip_clk_add_lookup(ctx, clk, list->id); } } -void __init rockchip_clk_register_armclk(unsigned int lookup_id, +void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, + unsigned int lookup_id, const char *name, const char *const *parent_names, u8 num_parents, const struct rockchip_cpuclk_reg_data *reg_data, @@ -486,15 +519,15 @@ void __init rockchip_clk_register_armclk(unsigned int lookup_id, struct clk *clk; clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents, - reg_data, rates, nrates, reg_base, - &clk_lock); + reg_data, rates, nrates, ctx->reg_base, + &ctx->lock); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s: %ld\n", __func__, name, PTR_ERR(clk)); return; } - rockchip_clk_add_lookup(clk, lookup_id); + rockchip_clk_add_lookup(ctx, clk, lookup_id); } void __init rockchip_clk_protect_critical(const char *const clocks[], @@ -511,6 +544,7 @@ void __init rockchip_clk_protect_critical(const char *const clocks[], } } +static void __iomem *rst_base; static unsigned int reg_restart; static void (*cb_restart)(void); static int rockchip_restart_notify(struct notifier_block *this, @@ -519,7 +553,7 @@ static int rockchip_restart_notify(struct notifier_block *this, if (cb_restart) cb_restart(); - writel(0xfdb9, reg_base + reg_restart); + writel(0xfdb9, rst_base + reg_restart); return NOTIFY_DONE; } @@ -528,10 +562,12 @@ static struct notifier_block rockchip_restart_handler = { .priority = 128, }; -void __init rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void)) +void __init rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, + unsigned int reg, void (*cb)(void)) { int ret; + rst_base = ctx->reg_base; reg_restart = reg; cb_restart = cb; ret = register_restart_handler(&rockchip_restart_handler); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 4133bfc..e243d50 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -27,6 +27,7 @@ #define CLK_ROCKCHIP_CLK_H #include +#include struct clk; @@ -127,6 +128,22 @@ enum rockchip_pll_type { .nb = _nb, \ } +/** + * struct rockchip_clk_provider: information about clock provider + * @reg_base: virtual address for the register base. + * @clk_data: holds clock related data like clk* and number of clocks. + * @cru_node: device-node of the clock-provider + * @grf: regmap of the general-register-files syscon + * @lock: maintains exclusion between callbacks for a given clock-provider. + */ +struct rockchip_clk_provider { + void __iomem *reg_base; + struct clk_onecell_data clk_data; + struct device_node *cru_node; + struct regmap *grf; + spinlock_t lock; +}; + struct rockchip_pll_rate_table { unsigned long rate; unsigned int nr; @@ -194,12 +211,13 @@ struct rockchip_pll_clock { .rate_table = _rtable, \ } -struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, +struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, + enum rockchip_pll_type pll_type, const char *name, const char *const *parent_names, - u8 num_parents, void __iomem *base, int con_offset, - int grf_lock_offset, int lock_shift, int reg_mode, - int mode_shift, struct rockchip_pll_rate_table *rate_table, - u8 clk_pll_flags, spinlock_t *lock); + u8 num_parents, int con_offset, int grf_lock_offset, + int lock_shift, int mode_offset, int mode_shift, + struct rockchip_pll_rate_table *rate_table, + u8 clk_pll_flags); struct rockchip_cpuclk_clksel { int reg; @@ -558,21 +576,28 @@ struct rockchip_clk_branch { .gate_flags = gf, \ } -void rockchip_clk_init(struct device_node *np, void __iomem *base, - unsigned long nr_clks); -struct regmap *rockchip_clk_get_grf(void); -void rockchip_clk_add_lookup(struct clk *clk, unsigned int id); -void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, +struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, + void __iomem *base, unsigned long nr_clks); +void rockchip_clk_of_add_provider(struct device_node *np, + struct rockchip_clk_provider *ctx); +struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx); +void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, + struct clk *clk, unsigned int id); +void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, unsigned int nr_clk); -void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, +void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, + struct rockchip_pll_clock *pll_list, unsigned int nr_pll, int grf_lock_offset); -void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name, +void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, + unsigned int lookup_id, const char *name, const char *const *parent_names, u8 num_parents, const struct rockchip_cpuclk_reg_data *reg_data, const struct rockchip_cpuclk_rate_table *rates, int nrates); void rockchip_clk_protect_critical(const char *const clocks[], int nclocks); -void rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void)); +void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, + unsigned int reg, void (*cb)(void)); #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) -- cgit v0.10.2 From b40baccd236a9a91fbb077efb8dadb41fdfb55ab Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Thu, 10 Mar 2016 11:47:01 +0800 Subject: clk: rockchip: add new pll-type for rk3399 and similar socs The rk3399's pll and clock are similar with rk3036's, it different with base on the rk3066(rk3188, rk3288, rk3368 use it), there are different adjust foctors and control registers, so these should be independent and separate from the series of rk3066s. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 27be66a..128a6b2 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -593,6 +593,267 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = { .init = rockchip_rk3066_pll_init, }; +/** + * PLL used in RK3399 + */ + +#define RK3399_PLLCON(i) (i * 0x4) +#define RK3399_PLLCON0_FBDIV_MASK 0xfff +#define RK3399_PLLCON0_FBDIV_SHIFT 0 +#define RK3399_PLLCON1_REFDIV_MASK 0x3f +#define RK3399_PLLCON1_REFDIV_SHIFT 0 +#define RK3399_PLLCON1_POSTDIV1_MASK 0x7 +#define RK3399_PLLCON1_POSTDIV1_SHIFT 8 +#define RK3399_PLLCON1_POSTDIV2_MASK 0x7 +#define RK3399_PLLCON1_POSTDIV2_SHIFT 12 +#define RK3399_PLLCON2_FRAC_MASK 0xffffff +#define RK3399_PLLCON2_FRAC_SHIFT 0 +#define RK3399_PLLCON2_LOCK_STATUS BIT(31) +#define RK3399_PLLCON3_PWRDOWN BIT(0) +#define RK3399_PLLCON3_DSMPD_MASK 0x1 +#define RK3399_PLLCON3_DSMPD_SHIFT 3 + +static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll) +{ + u32 pllcon; + int delay = 24000000; + + /* poll check the lock status in rk3399 xPLLCON2 */ + while (delay > 0) { + pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); + if (pllcon & RK3399_PLLCON2_LOCK_STATUS) + return 0; + + delay--; + } + + pr_err("%s: timeout waiting for pll to lock\n", __func__); + return -ETIMEDOUT; +} + +static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll, + struct rockchip_pll_rate_table *rate) +{ + u32 pllcon; + + pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(0)); + rate->fbdiv = ((pllcon >> RK3399_PLLCON0_FBDIV_SHIFT) + & RK3399_PLLCON0_FBDIV_MASK); + + pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(1)); + rate->refdiv = ((pllcon >> RK3399_PLLCON1_REFDIV_SHIFT) + & RK3399_PLLCON1_REFDIV_MASK); + rate->postdiv1 = ((pllcon >> RK3399_PLLCON1_POSTDIV1_SHIFT) + & RK3399_PLLCON1_POSTDIV1_MASK); + rate->postdiv2 = ((pllcon >> RK3399_PLLCON1_POSTDIV2_SHIFT) + & RK3399_PLLCON1_POSTDIV2_MASK); + + pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); + rate->frac = ((pllcon >> RK3399_PLLCON2_FRAC_SHIFT) + & RK3399_PLLCON2_FRAC_MASK); + + pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(3)); + rate->dsmpd = ((pllcon >> RK3399_PLLCON3_DSMPD_SHIFT) + & RK3399_PLLCON3_DSMPD_MASK); +} + +static unsigned long rockchip_rk3399_pll_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + struct rockchip_pll_rate_table cur; + u64 rate64 = prate; + + rockchip_rk3399_pll_get_params(pll, &cur); + + rate64 *= cur.fbdiv; + do_div(rate64, cur.refdiv); + + if (cur.dsmpd == 0) { + /* fractional mode */ + u64 frac_rate64 = prate * cur.frac; + + do_div(frac_rate64, cur.refdiv); + rate64 += frac_rate64 >> 24; + } + + do_div(rate64, cur.postdiv1); + do_div(rate64, cur.postdiv2); + + return (unsigned long)rate64; +} + +static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll, + const struct rockchip_pll_rate_table *rate) +{ + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; + struct clk_mux *pll_mux = &pll->pll_mux; + struct rockchip_pll_rate_table cur; + u32 pllcon; + int rate_change_remuxed = 0; + int cur_parent; + int ret; + + pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", + __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv, + rate->postdiv2, rate->dsmpd, rate->frac); + + rockchip_rk3399_pll_get_params(pll, &cur); + cur.rate = 0; + + cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); + if (cur_parent == PLL_MODE_NORM) { + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); + rate_change_remuxed = 1; + } + + /* update pll values */ + writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3399_PLLCON0_FBDIV_MASK, + RK3399_PLLCON0_FBDIV_SHIFT), + pll->reg_base + RK3399_PLLCON(0)); + + writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3399_PLLCON1_REFDIV_MASK, + RK3399_PLLCON1_REFDIV_SHIFT) | + HIWORD_UPDATE(rate->postdiv1, RK3399_PLLCON1_POSTDIV1_MASK, + RK3399_PLLCON1_POSTDIV1_SHIFT) | + HIWORD_UPDATE(rate->postdiv2, RK3399_PLLCON1_POSTDIV2_MASK, + RK3399_PLLCON1_POSTDIV2_SHIFT), + pll->reg_base + RK3399_PLLCON(1)); + + /* xPLL CON2 is not HIWORD_MASK */ + pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); + pllcon &= ~(RK3399_PLLCON2_FRAC_MASK << RK3399_PLLCON2_FRAC_SHIFT); + pllcon |= rate->frac << RK3399_PLLCON2_FRAC_SHIFT; + writel_relaxed(pllcon, pll->reg_base + RK3399_PLLCON(2)); + + writel_relaxed(HIWORD_UPDATE(rate->dsmpd, RK3399_PLLCON3_DSMPD_MASK, + RK3399_PLLCON3_DSMPD_SHIFT), + pll->reg_base + RK3399_PLLCON(3)); + + /* wait for the pll to lock */ + ret = rockchip_rk3399_pll_wait_lock(pll); + if (ret) { + pr_warn("%s: pll update unsuccessful, trying to restore old params\n", + __func__); + rockchip_rk3399_pll_set_params(pll, &cur); + } + + if (rate_change_remuxed) + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); + + return ret; +} + +static int rockchip_rk3399_pll_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + const struct rockchip_pll_rate_table *rate; + unsigned long old_rate = rockchip_rk3399_pll_recalc_rate(hw, prate); + + pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", + __func__, __clk_get_name(hw->clk), old_rate, drate, prate); + + /* Get required rate settings from table */ + rate = rockchip_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, __clk_get_name(hw->clk)); + return -EINVAL; + } + + return rockchip_rk3399_pll_set_params(pll, rate); +} + +static int rockchip_rk3399_pll_enable(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + + writel(HIWORD_UPDATE(0, RK3399_PLLCON3_PWRDOWN, 0), + pll->reg_base + RK3399_PLLCON(3)); + + return 0; +} + +static void rockchip_rk3399_pll_disable(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + + writel(HIWORD_UPDATE(RK3399_PLLCON3_PWRDOWN, + RK3399_PLLCON3_PWRDOWN, 0), + pll->reg_base + RK3399_PLLCON(3)); +} + +static int rockchip_rk3399_pll_is_enabled(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + u32 pllcon = readl(pll->reg_base + RK3399_PLLCON(3)); + + return !(pllcon & RK3399_PLLCON3_PWRDOWN); +} + +static void rockchip_rk3399_pll_init(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + const struct rockchip_pll_rate_table *rate; + struct rockchip_pll_rate_table cur; + unsigned long drate; + + if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) + return; + + drate = clk_hw_get_rate(hw); + rate = rockchip_get_pll_settings(pll, drate); + + /* when no rate setting for the current rate, rely on clk_set_rate */ + if (!rate) + return; + + rockchip_rk3399_pll_get_params(pll, &cur); + + pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk), + drate); + pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", + cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2, + cur.dsmpd, cur.frac); + pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", + rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2, + rate->dsmpd, rate->frac); + + if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 || + rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 || + rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) { + struct clk *parent = clk_get_parent(hw->clk); + + if (!parent) { + pr_warn("%s: parent of %s not available\n", + __func__, __clk_get_name(hw->clk)); + return; + } + + pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", + __func__, __clk_get_name(hw->clk)); + rockchip_rk3399_pll_set_params(pll, rate); + } +} + +static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = { + .recalc_rate = rockchip_rk3399_pll_recalc_rate, + .enable = rockchip_rk3399_pll_enable, + .disable = rockchip_rk3399_pll_disable, + .is_enabled = rockchip_rk3399_pll_is_enabled, +}; + +static const struct clk_ops rockchip_rk3399_pll_clk_ops = { + .recalc_rate = rockchip_rk3399_pll_recalc_rate, + .round_rate = rockchip_pll_round_rate, + .set_rate = rockchip_rk3399_pll_set_rate, + .enable = rockchip_rk3399_pll_enable, + .disable = rockchip_rk3399_pll_disable, + .is_enabled = rockchip_rk3399_pll_is_enabled, + .init = rockchip_rk3399_pll_init, +}; + /* * Common registering of pll clocks */ @@ -634,7 +895,9 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, pll_mux->lock = &ctx->lock; pll_mux->hw.init = &init; - if (pll_type == pll_rk3036 || pll_type == pll_rk3066) + if (pll_type == pll_rk3036 || + pll_type == pll_rk3066 || + pll_type == pll_rk3399) pll_mux->flags |= CLK_MUX_HIWORD_MASK; /* the actual muxing is xin24m, pll-output, xin32k */ @@ -691,6 +954,12 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, else init.ops = &rockchip_rk3066_pll_clk_ops; break; + case pll_rk3399: + if (!pll->rate_table) + init.ops = &rockchip_rk3399_pll_clk_norate_ops; + else + init.ops = &rockchip_rk3399_pll_clk_ops; + break; default: pr_warn("%s: Unknown pll type for pll clk %s\n", __func__, name); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index e243d50..4798786 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -96,6 +96,7 @@ struct clk; enum rockchip_pll_type { pll_rk3036, pll_rk3066, + pll_rk3399, }; #define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \ @@ -150,7 +151,7 @@ struct rockchip_pll_rate_table { unsigned int nf; unsigned int no; unsigned int nb; - /* for RK3036 */ + /* for RK3036/RK3399 */ unsigned int fbdiv; unsigned int postdiv1; unsigned int refdiv; -- cgit v0.10.2 From cb3abdd628abe8583c81b07d5bb8b6d1dbd12227 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sun, 13 Mar 2016 00:25:00 +0800 Subject: clk: rockchip: remove mux_core_reg from rockchip_cpuclk_reg_data mux_core_reg isn't been used anywhere, let's remove it. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 4798786..b298f99 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -245,7 +245,6 @@ struct rockchip_cpuclk_reg_data { int core_reg; u8 div_core_shift; u32 div_core_mask; - int mux_core_reg; u8 mux_core_alt; u8 mux_core_main; u8 mux_core_shift; -- cgit v0.10.2 From 2af2544d60f007277a98f66391a521ec377a6a67 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sun, 13 Mar 2016 00:25:14 +0800 Subject: clk: rockchip: fix warning reported by kernel-doc ./scripts/kernel-doc -man -v drivers/clk/rockchip/clk.h > /dev/null drivers/clk/rockchip/clk.h:133: warning: missing initial short description on line: * struct rockchip_clk_provider: information about clock provider drivers/clk/rockchip/clk.h:133: info: Scanning doc for struct drivers/clk/rockchip/clk.h:164: warning: missing initial short description on line: * struct rockchip_pll_clock: information about pll clock drivers/clk/rockchip/clk.h:164: info: Scanning doc for struct drivers/clk/rockchip/clk.h:194: warning: No description found for parameter 'parent_names' drivers/clk/rockchip/clk.h:194: warning: No description found for parameter 'num_parents' drivers/clk/rockchip/clk.h:194: warning: Excess struct/union/enum/typedef member 'parent_name' description in 'rockchip_pll_clock' drivers/clk/rockchip/clk.h:235: warning: missing initial short description on line: * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index b298f99..cb6a639 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -130,7 +130,7 @@ enum rockchip_pll_type { } /** - * struct rockchip_clk_provider: information about clock provider + * struct rockchip_clk_provider - information about clock provider * @reg_base: virtual address for the register base. * @clk_data: holds clock related data like clk* and number of clocks. * @cru_node: device-node of the clock-provider @@ -161,10 +161,11 @@ struct rockchip_pll_rate_table { }; /** - * struct rockchip_pll_clock: information about pll clock + * struct rockchip_pll_clock - information about pll clock * @id: platform specific id of the clock. * @name: name of this pll clock. - * @parent_name: name of the parent clock. + * @parent_names: name of the parent clock. + * @num_parents: number of parents * @flags: optional flags for basic clock. * @con_offset: offset of the register for configuring the PLL. * @mode_offset: offset of the register for configuring the PLL-mode. @@ -232,7 +233,7 @@ struct rockchip_cpuclk_rate_table { }; /** - * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock + * struct rockchip_cpuclk_reg_data - describes register offsets and masks of the cpuclock * @core_reg: register offset of the core settings register * @div_core_shift: core divider offset used to divide the pll value * @div_core_mask: core divider mask -- cgit v0.10.2 From ff1ae209617cb31a5297bd103709d6b9e2db77d2 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sun, 13 Mar 2016 00:25:53 +0800 Subject: clk: rockchip: remove redundant checking of device_node rockchip_clk_of_add_provider is used by sub-clk driver which already call of_iomap before calling it. If device_node does not exist, of_iomap returns NULL which will fail to init the sub-clk driver. So really it's redundant. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 5618a87..277f927 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -359,11 +359,9 @@ err_free: void __init rockchip_clk_of_add_provider(struct device_node *np, struct rockchip_clk_provider *ctx) { - if (np) { - if (of_clk_add_provider(np, of_clk_src_onecell_get, - &ctx->clk_data)) - pr_err("%s: could not register clk provider\n", __func__); - } + if (of_clk_add_provider(np, of_clk_src_onecell_get, + &ctx->clk_data)) + pr_err("%s: could not register clk provider\n", __func__); } struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx) -- cgit v0.10.2 From 1d003eb0805ac5b549e76202a1e95da33f62cb9a Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sun, 13 Mar 2016 12:13:22 +0800 Subject: clk: rockchip: release io resource when failing to init clk We should call iounmap to relase reg_base since it's not going to be used any more if failing to init clk. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c index c7c8260..924f560 100644 --- a/drivers/clk/rockchip/clk-rk3036.c +++ b/drivers/clk/rockchip/clk-rk3036.c @@ -453,6 +453,7 @@ static void __init rk3036_clk_init(struct device_node *np) ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); if (IS_ERR(ctx)) { pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); return; } diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 0fcce22..d0e722a 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -773,6 +773,7 @@ static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); if (IS_ERR(ctx)) { pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); return ERR_PTR(-ENOMEM); } diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index c112b2f..016bdb0 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -640,6 +640,7 @@ static void __init rk3228_clk_init(struct device_node *np) ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); if (IS_ERR(ctx)) { pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); return; } diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index d1031d1..39af05a 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -893,6 +893,7 @@ static void __init rk3288_clk_init(struct device_node *np) ctx = rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS); if (IS_ERR(ctx)) { pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(rk3288_cru_base); return; } diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c index 3121414..6cb474c 100644 --- a/drivers/clk/rockchip/clk-rk3368.c +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -875,6 +875,7 @@ static void __init rk3368_clk_init(struct device_node *np) ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); if (IS_ERR(ctx)) { pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); return; } -- cgit v0.10.2 From 485a40d7cd4aab5ae939320278809776388f5c06 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Mon, 28 Mar 2016 17:51:35 +0800 Subject: dt-bindings: add bindings for rk3399 clock controller Add devicetree bindings for Rockchip cru which found on Rockchip SoCs. Signed-off-by: Xing Zheng Signed-off-by: Jianqun Xu Acked-by: Rob Herring Signed-off-by: Heiko Stuebner diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt new file mode 100644 index 0000000..3888dd3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt @@ -0,0 +1,62 @@ +* Rockchip RK3399 Clock and Reset Unit + +The RK3399 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: PMU for CRU should be "rockchip,rk3399-pmucru" +- compatible: CRU should be "rockchip,rk3399-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3399-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "clkin_gmac" - external GMAC clock - optional, + - "clkin_i2s" - external I2S clock - optional, + - "pclkin_cif" - external ISP clock - optional, + - "clk_usbphy0_480m" - output clock of the pll in the usbphy0 + - "clk_usbphy1_480m" - output clock of the pll in the usbphy1 + +Example: Clock controller node: + + pmucru: pmu-clock-controller@ff750000 { + compatible = "rockchip,rk3399-pmucru"; + reg = <0x0 0xff750000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cru: clock-controller@ff760000 { + compatible = "rockchip,rk3399-cru"; + reg = <0x0 0xff760000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@ff1a0000 { + compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff180000 0x0 0x100>; + clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; + clock-names = "baudclk", "apb_pclk"; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; -- cgit v0.10.2 From 115510053e5e5872f1f19a2220b04aab5542c5c4 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Mon, 28 Mar 2016 17:51:37 +0800 Subject: clk: rockchip: add clock controller for the RK3399 Add the clock tree definition for the new RK3399 SoC. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 80b9a37..f47a2fa 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -15,3 +15,4 @@ obj-y += clk-rk3188.o obj-y += clk-rk3228.o obj-y += clk-rk3288.o obj-y += clk-rk3368.o +obj-y += clk-rk3399.o diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c new file mode 100644 index 0000000..356e132 --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -0,0 +1,1540 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Xing Zheng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include "clk.h" + +enum rk3399_plls { + lpll, bpll, dpll, cpll, gpll, npll, vpll, +}; + +enum rk3399_pmu_plls { + ppll, +}; + +static struct rockchip_pll_rate_table rk3399_pll_rates[] = { + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + RK3036_PLL_RATE(2208000000, 1, 92, 1, 1, 1, 0), + RK3036_PLL_RATE(2184000000, 1, 91, 1, 1, 1, 0), + RK3036_PLL_RATE(2160000000, 1, 90, 1, 1, 1, 0), + RK3036_PLL_RATE(2136000000, 1, 89, 1, 1, 1, 0), + RK3036_PLL_RATE(2112000000, 1, 88, 1, 1, 1, 0), + RK3036_PLL_RATE(2088000000, 1, 87, 1, 1, 1, 0), + RK3036_PLL_RATE(2064000000, 1, 86, 1, 1, 1, 0), + RK3036_PLL_RATE(2040000000, 1, 85, 1, 1, 1, 0), + RK3036_PLL_RATE(2016000000, 1, 84, 1, 1, 1, 0), + RK3036_PLL_RATE(1992000000, 1, 83, 1, 1, 1, 0), + RK3036_PLL_RATE(1968000000, 1, 82, 1, 1, 1, 0), + RK3036_PLL_RATE(1944000000, 1, 81, 1, 1, 1, 0), + RK3036_PLL_RATE(1920000000, 1, 80, 1, 1, 1, 0), + RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0), + RK3036_PLL_RATE(1872000000, 1, 78, 1, 1, 1, 0), + RK3036_PLL_RATE(1848000000, 1, 77, 1, 1, 1, 0), + RK3036_PLL_RATE(1824000000, 1, 76, 1, 1, 1, 0), + RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0), + RK3036_PLL_RATE(1776000000, 1, 74, 1, 1, 1, 0), + RK3036_PLL_RATE(1752000000, 1, 73, 1, 1, 1, 0), + RK3036_PLL_RATE(1728000000, 1, 72, 1, 1, 1, 0), + RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0), + RK3036_PLL_RATE(1680000000, 1, 70, 1, 1, 1, 0), + RK3036_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0), + RK3036_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0), + RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0), + RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0), + RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0), + RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), + RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0), + RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0), + RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0), + RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), + RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0), + RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0), + RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0), + RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0), + RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), + RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0), + RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0), + RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), + RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), + RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0), + RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), + RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), + RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), + RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0), + RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0), + RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0), + RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0), + RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0), + RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0), + RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0), + RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0), + RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0), + RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0), + RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0), + RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0), + RK3036_PLL_RATE( 676000000, 3, 169, 2, 1, 1, 0), + RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0), + RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0), + RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0), + RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0), + RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0), + RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0), + RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0), + RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0), + { /* sentinel */ }, +}; + +/* CRU parents */ +PNAME(mux_pll_p) = { "xin24m", "xin32k" }; + +PNAME(mux_armclkl_p) = { "clk_core_l_lpll_src", + "clk_core_l_bpll_src", + "clk_core_l_dpll_src", + "clk_core_l_gpll_src" }; +PNAME(mux_armclkb_p) = { "clk_core_b_lpll_src", + "clk_core_b_bpll_src", + "clk_core_b_dpll_src", + "clk_core_b_gpll_src" }; +PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", + "gpll_aclk_cci_src", + "npll_aclk_cci_src", + "vpll_aclk_cci_src" }; +PNAME(mux_cci_trace_p) = { "cpll_cci_trace", "gpll_cci_trace" }; +PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs", "npll_cs"}; +PNAME(mux_aclk_perihp_p) = { "cpll_aclk_perihp_src", "gpll_aclk_perihp_src" }; + +PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; +PNAME(mux_pll_src_cpll_gpll_ppll_p) = { "cpll", "gpll", "ppll" }; +PNAME(mux_pll_src_cpll_gpll_upll_p) = { "cpll", "gpll", "upll" }; +PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_npll_ppll_p) = { "cpll", "gpll", "npll", "ppll" }; +PNAME(mux_pll_src_cpll_gpll_npll_24m_p) = { "cpll", "gpll", "npll", "xin24m" }; +PNAME(mux_pll_src_cpll_gpll_npll_usbphy480m_p) = { "cpll", "gpll", "npll", "clk_usbphy_480m" }; +PNAME(mux_pll_src_ppll_cpll_gpll_npll_p) = { "ppll", "cpll", "gpll", "npll", "upll" }; +PNAME(mux_pll_src_cpll_gpll_npll_upll_24m_p) = { "cpll", "gpll", "npll", "upll", "xin24m" }; +PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll", "ppll", "upll", "xin24m" }; + +PNAME(mux_pll_src_vpll_cpll_gpll_p) = { "vpll", "cpll", "gpll" }; +PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll", "npll" }; +PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll", "xin24m" }; + +PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", "dclk_vop0_frac" }; +PNAME(mux_dclk_vop1_p) = { "dclk_vop1_div", "dclk_vop1_frac" }; + +PNAME(mux_clk_cif_p) = { "clk_cifout_div", "xin24m" }; + +PNAME(mux_pll_src_24m_usbphy480m_p) = { "xin24m", "clk_usbphy_480m" }; +PNAME(mux_pll_src_24m_pciephy_p) = { "xin24m", "clk_pciephy_ref100m" }; +PNAME(mux_pll_src_24m_32k_cpll_gpll_p) = { "xin24m", "xin32k", "cpll", "gpll" }; +PNAME(mux_pciecore_cru_phy_p) = { "clk_pcie_core_cru", "clk_pcie_core_phy" }; + +PNAME(mux_aclk_emmc_p) = { "cpll_aclk_emmc_src", "gpll_aclk_emmc_src" }; + +PNAME(mux_aclk_perilp0_p) = { "cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src" }; + +PNAME(mux_fclk_cm0s_p) = { "cpll_fclk_cm0s_src", "gpll_fclk_cm0s_src" }; + +PNAME(mux_hclk_perilp1_p) = { "cpll_hclk_perilp1_src", "gpll_hclk_perilp1_src" }; + +PNAME(mux_clk_testout1_p) = { "clk_testout1_pll_src", "xin24m" }; +PNAME(mux_clk_testout2_p) = { "clk_testout2_pll_src", "xin24m" }; + +PNAME(mux_usbphy_480m_p) = { "clk_usbphy0_480m_src", "clk_usbphy1_480m_src" }; +PNAME(mux_aclk_gmac_p) = { "cpll_aclk_gmac_src", "gpll_aclk_gmac_src" }; +PNAME(mux_rmii_p) = { "clk_gmac", "clkin_gmac" }; +PNAME(mux_spdif_p) = { "clk_spdif_div", "clk_spdif_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s0_p) = { "clk_i2s0_div", "clk_i2s0_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s1_p) = { "clk_i2s1_div", "clk_i2s1_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s2_p) = { "clk_i2s2_div", "clk_i2s2_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2sch_p) = { "clk_i2s0", "clk_i2s1", "clk_i2s2" }; +PNAME(mux_i2sout_p) = { "clk_i2sout_src", "xin12m" }; + +PNAME(mux_uart0_p) = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; +PNAME(mux_uart1_p) = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; +PNAME(mux_uart2_p) = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; +PNAME(mux_uart3_p) = { "clk_uart3_div", "clk_uart3_frac", "xin24m" }; + +/* PMU CRU parents */ +PNAME(mux_ppll_24m_p) = { "ppll", "xin24m" }; +PNAME(mux_24m_ppll_p) = { "xin24m", "ppll" }; +PNAME(mux_fclk_cm0s_pmu_ppll_p) = { "fclk_cm0s_pmu_ppll_src", "xin24m" }; +PNAME(mux_wifi_pmu_p) = { "clk_wifi_div", "clk_wifi_frac" }; +PNAME(mux_uart4_pmu_p) = { "clk_uart4_div", "clk_uart4_frac", "xin24m" }; +PNAME(mux_clk_testout2_2io_p) = { "clk_testout2", "clk_32k_suspend_pmu" }; + +static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = { + [lpll] = PLL(pll_rk3399, PLL_APLLL, "lpll", mux_pll_p, 0, RK3399_PLL_CON(0), + RK3399_PLL_CON(3), 8, 31, 0, rk3399_pll_rates), + [bpll] = PLL(pll_rk3399, PLL_APLLB, "bpll", mux_pll_p, 0, RK3399_PLL_CON(8), + RK3399_PLL_CON(11), 8, 31, 0, rk3399_pll_rates), + [dpll] = PLL(pll_rk3399, PLL_DPLL, "dpll", mux_pll_p, 0, RK3399_PLL_CON(16), + RK3399_PLL_CON(19), 8, 31, 0, NULL), + [cpll] = PLL(pll_rk3399, PLL_CPLL, "cpll", mux_pll_p, 0, RK3399_PLL_CON(24), + RK3399_PLL_CON(27), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [gpll] = PLL(pll_rk3399, PLL_GPLL, "gpll", mux_pll_p, 0, RK3399_PLL_CON(32), + RK3399_PLL_CON(35), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [npll] = PLL(pll_rk3399, PLL_NPLL, "npll", mux_pll_p, 0, RK3399_PLL_CON(40), + RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll", mux_pll_p, 0, RK3399_PLL_CON(48), + RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), +}; + +static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = { + [ppll] = PLL(pll_rk3399, PLL_PPLL, "ppll", mux_pll_p, 0, RK3399_PMU_PLL_CON(0), + RK3399_PMU_PLL_CON(3), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) +#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK + +static struct rockchip_clk_branch rk3399_spdif_fracmux __initdata = + MUX(0, "clk_spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(32), 13, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_i2s0_fracmux __initdata = + MUX(0, "clk_i2s0_mux", mux_i2s0_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(28), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_i2s1_fracmux __initdata = + MUX(0, "clk_i2s1_mux", mux_i2s1_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(29), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_i2s2_fracmux __initdata = + MUX(0, "clk_i2s2_mux", mux_i2s2_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(30), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart0_fracmux __initdata = + MUX(SCLK_UART0, "clk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(33), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart1_fracmux __initdata = + MUX(SCLK_UART1, "clk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(34), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart2_fracmux __initdata = + MUX(SCLK_UART2, "clk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(35), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart3_fracmux __initdata = + MUX(SCLK_UART3, "clk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(36), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata = + MUX(SCLK_UART4_PMU, "clk_uart4_pmu", mux_uart4_pmu_p, CLK_SET_RATE_PARENT, + RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata = + MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(49), 11, 1, MFLAGS); + +static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata = + MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(50), 11, 1, MFLAGS); + +static struct rockchip_clk_branch rk3399_pmuclk_wifi_fracmux __initdata = + MUX(SCLK_WIFI_PMU, "clk_wifi_pmu", mux_wifi_pmu_p, CLK_SET_RATE_PARENT, + RK3399_PMU_CLKSEL_CON(1), 14, 1, MFLAGS); + +static const struct rockchip_cpuclk_reg_data rk3399_cpuclkl_data = { + .core_reg = RK3399_CLKSEL_CON(0), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_alt = 3, + .mux_core_main = 0, + .mux_core_shift = 6, + .mux_core_mask = 0x3, +}; + +static const struct rockchip_cpuclk_reg_data rk3399_cpuclkb_data = { + .core_reg = RK3399_CLKSEL_CON(2), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_alt = 3, + .mux_core_main = 1, + .mux_core_shift = 6, + .mux_core_mask = 0x3, +}; + +#define RK3399_DIV_ACLKM_MASK 0x1f +#define RK3399_DIV_ACLKM_SHIFT 8 +#define RK3399_DIV_ATCLK_MASK 0x1f +#define RK3399_DIV_ATCLK_SHIFT 0 +#define RK3399_DIV_PCLK_DBG_MASK 0x1f +#define RK3399_DIV_PCLK_DBG_SHIFT 8 + +#define RK3399_CLKSEL0(_offs, _aclkm) \ + { \ + .reg = RK3399_CLKSEL_CON(0 + _offs), \ + .val = HIWORD_UPDATE(_aclkm, RK3399_DIV_ACLKM_MASK, \ + RK3399_DIV_ACLKM_SHIFT), \ + } +#define RK3399_CLKSEL1(_offs, _atclk, _pdbg) \ + { \ + .reg = RK3399_CLKSEL_CON(1 + _offs), \ + .val = HIWORD_UPDATE(_atclk, RK3399_DIV_ATCLK_MASK, \ + RK3399_DIV_ATCLK_SHIFT) | \ + HIWORD_UPDATE(_pdbg, RK3399_DIV_PCLK_DBG_MASK, \ + RK3399_DIV_PCLK_DBG_SHIFT), \ + } + +/* cluster_l: aclkm in clksel0, rest in clksel1 */ +#define RK3399_CPUCLKL_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate##U, \ + .divs = { \ + RK3399_CLKSEL0(0, _aclkm), \ + RK3399_CLKSEL1(0, _atclk, _pdbg), \ + }, \ + } + +/* cluster_b: aclkm in clksel2, rest in clksel3 */ +#define RK3399_CPUCLKB_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate##U, \ + .divs = { \ + RK3399_CLKSEL0(2, _aclkm), \ + RK3399_CLKSEL1(2, _atclk, _pdbg), \ + }, \ + } + +static struct rockchip_cpuclk_rate_table rk3399_cpuclkl_rates[] __initdata = { + RK3399_CPUCLKL_RATE(1800000000, 1, 8, 8), + RK3399_CPUCLKL_RATE(1704000000, 1, 8, 8), + RK3399_CPUCLKL_RATE(1608000000, 1, 7, 7), + RK3399_CPUCLKL_RATE(1512000000, 1, 7, 7), + RK3399_CPUCLKL_RATE(1488000000, 1, 6, 6), + RK3399_CPUCLKL_RATE(1416000000, 1, 6, 6), + RK3399_CPUCLKL_RATE(1200000000, 1, 5, 5), + RK3399_CPUCLKL_RATE(1008000000, 1, 5, 5), + RK3399_CPUCLKL_RATE( 816000000, 1, 4, 4), + RK3399_CPUCLKL_RATE( 696000000, 1, 3, 3), + RK3399_CPUCLKL_RATE( 600000000, 1, 3, 3), + RK3399_CPUCLKL_RATE( 408000000, 1, 2, 2), + RK3399_CPUCLKL_RATE( 312000000, 1, 1, 1), +}; + +static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = { + RK3399_CPUCLKB_RATE(2208000000, 1, 11, 11), + RK3399_CPUCLKB_RATE(2184000000, 1, 11, 11), + RK3399_CPUCLKB_RATE(2088000000, 1, 10, 10), + RK3399_CPUCLKB_RATE(2040000000, 1, 10, 10), + RK3399_CPUCLKB_RATE(1992000000, 1, 9, 9), + RK3399_CPUCLKB_RATE(1896000000, 1, 9, 9), + RK3399_CPUCLKB_RATE(1800000000, 1, 8, 8), + RK3399_CPUCLKB_RATE(1704000000, 1, 8, 8), + RK3399_CPUCLKB_RATE(1608000000, 1, 7, 7), + RK3399_CPUCLKB_RATE(1512000000, 1, 7, 7), + RK3399_CPUCLKB_RATE(1488000000, 1, 6, 6), + RK3399_CPUCLKB_RATE(1416000000, 1, 6, 6), + RK3399_CPUCLKB_RATE(1200000000, 1, 5, 5), + RK3399_CPUCLKB_RATE(1008000000, 1, 5, 5), + RK3399_CPUCLKB_RATE( 816000000, 1, 4, 4), + RK3399_CPUCLKB_RATE( 696000000, 1, 3, 3), + RK3399_CPUCLKB_RATE( 600000000, 1, 3, 3), + RK3399_CPUCLKB_RATE( 408000000, 1, 2, 2), + RK3399_CPUCLKB_RATE( 312000000, 1, 1, 1), +}; + +static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { + /* + * CRU Clock-Architecture + */ + + /* usbphy */ + GATE(SCLK_USB2PHY0_REF, "clk_usb2phy0_ref", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 5, GFLAGS), + GATE(SCLK_USB2PHY1_REF, "clk_usb2phy1_ref", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 6, GFLAGS), + + GATE(0, "clk_usbphy0_480m_src", "clk_usbphy0_480m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(13), 12, GFLAGS), + GATE(0, "clk_usbphy1_480m_src", "clk_usbphy1_480m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(13), 12, GFLAGS), + MUX(0, "clk_usbphy_480m", mux_usbphy_480m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(14), 6, 1, MFLAGS), + + MUX(0, "upll", mux_pll_src_24m_usbphy480m_p, 0, + RK3399_CLKSEL_CON(14), 15, 1, MFLAGS), + + COMPOSITE_NODIV(SCLK_HSICPHY, "clk_hsicphy", mux_pll_src_cpll_gpll_npll_usbphy480m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(19), 0, 2, MFLAGS, + RK3399_CLKGATE_CON(6), 4, GFLAGS), + + COMPOSITE(ACLK_USB3, "aclk_usb3", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 0, GFLAGS), + GATE(ACLK_USB3_NOC, "aclk_usb3_noc", "aclk_usb3", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 0, GFLAGS), + GATE(ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_usb3", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 1, GFLAGS), + GATE(ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_usb3", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 2, GFLAGS), + GATE(ACLK_USB3_RKSOC_AXI_PERF, "aclk_usb3_rksoc_axi_perf", "aclk_usb3", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 3, GFLAGS), + GATE(ACLK_USB3_GRF, "aclk_usb3_grf", "aclk_usb3", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 4, GFLAGS), + + GATE(SCLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(12), 1, GFLAGS), + GATE(SCLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(12), 2, GFLAGS), + + COMPOSITE(SCLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(40), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(12), 3, GFLAGS), + + COMPOSITE(SCLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(41), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(12), 4, GFLAGS), + + COMPOSITE(SCLK_UPHY0_TCPDPHY_REF, "clk_uphy0_tcpdphy_ref", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(64), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 4, GFLAGS), + + COMPOSITE(SCLK_UPHY0_TCPDCORE, "clk_uphy0_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(64), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 5, GFLAGS), + + COMPOSITE(SCLK_UPHY1_TCPDPHY_REF, "clk_uphy1_tcpdphy_ref", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(65), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 6, GFLAGS), + + COMPOSITE(SCLK_UPHY1_TCPDCORE, "clk_uphy1_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(65), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 7, GFLAGS), + + /* little core */ + GATE(0, "clk_core_l_lpll_src", "lpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 0, GFLAGS), + GATE(0, "clk_core_l_bpll_src", "bpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 1, GFLAGS), + GATE(0, "clk_core_l_dpll_src", "dpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 2, GFLAGS), + GATE(0, "clk_core_l_gpll_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 3, GFLAGS), + + COMPOSITE_NOMUX(0, "aclkm_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(0), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(0), 4, GFLAGS), + COMPOSITE_NOMUX(0, "atclk_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(0), 5, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(1), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(0), 6, GFLAGS), + + GATE(ACLK_CORE_ADB400_CORE_L_2_CCI500, "aclk_core_adb400_core_l_2_cci500", "aclkm_core_l", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 12, GFLAGS), + GATE(ACLK_PERF_CORE_L, "aclk_perf_core_l", "aclkm_core_l", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 13, GFLAGS), + + GATE(0, "clk_dbg_pd_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 9, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_core_adb400_gic_2_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 10, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_core_adb400_core_l_2_gic", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 11, GFLAGS), + GATE(SCLK_PVTM_CORE_L, "clk_pvtm_core_l", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 7, GFLAGS), + + /* big core */ + GATE(0, "clk_core_b_lpll_src", "lpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 0, GFLAGS), + GATE(0, "clk_core_b_bpll_src", "bpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 1, GFLAGS), + GATE(0, "clk_core_b_dpll_src", "dpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 2, GFLAGS), + GATE(0, "clk_core_b_gpll_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 3, GFLAGS), + + COMPOSITE_NOMUX(0, "aclkm_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(2), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(1), 4, GFLAGS), + COMPOSITE_NOMUX(0, "atclk_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(3), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(1), 5, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(3), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(1), 6, GFLAGS), + + GATE(ACLK_CORE_ADB400_CORE_B_2_CCI500, "aclk_core_adb400_core_b_2_cci500", "aclkm_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 5, GFLAGS), + GATE(ACLK_PERF_CORE_B, "aclk_perf_core_b", "aclkm_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 6, GFLAGS), + + GATE(0, "clk_dbg_pd_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 1, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_core_adb400_gic_2_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 3, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_core_adb400_core_b_2_gic", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 4, GFLAGS), + + DIV(0, "pclken_dbg_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(3), 13, 2, DFLAGS | CLK_DIVIDER_READ_ONLY), + + GATE(0, "pclk_dbg_cxcs_pd_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 2, GFLAGS), + + GATE(SCLK_PVTM_CORE_B, "clk_pvtm_core_b", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 7, GFLAGS), + + /* gmac */ + GATE(0, "cpll_aclk_gmac_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 9, GFLAGS), + GATE(0, "gpll_aclk_gmac_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 8, GFLAGS), + COMPOSITE(0, "aclk_gmac_pre", mux_aclk_gmac_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(6), 10, GFLAGS), + + GATE(ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 0, GFLAGS), + GATE(ACLK_GMAC_NOC, "aclk_gmac_noc", "aclk_gmac_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 1, GFLAGS), + GATE(ACLK_PERF_GMAC, "aclk_perf_gmac", "aclk_gmac_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 4, GFLAGS), + + COMPOSITE_NOMUX(0, "pclk_gmac_pre", "aclk_gmac_pre", 0, + RK3399_CLKSEL_CON(19), 8, 3, DFLAGS, + RK3399_CLKGATE_CON(6), 11, GFLAGS), + GATE(PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 2, GFLAGS), + GATE(PCLK_GMAC_NOC, "pclk_gmac_noc", "pclk_gmac_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 3, GFLAGS), + + COMPOSITE(SCLK_MAC, "clk_gmac", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(5), 5, GFLAGS), + + MUX(0, "clk_rmii_src", mux_rmii_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(19), 4, 1, MFLAGS), + GATE(SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 6, GFLAGS), + GATE(SCLK_MACREF, "clk_mac_ref", "clk_rmii_src", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 7, GFLAGS), + GATE(SCLK_MAC_RX, "clk_rmii_rx", "clk_rmii_src", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 8, GFLAGS), + GATE(SCLK_MAC_TX, "clk_rmii_tx", "clk_rmii_src", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 9, GFLAGS), + + /* spdif */ + COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 13, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(99), 0, + RK3399_CLKGATE_CON(8), 14, GFLAGS, + &rk3399_spdif_fracmux), + GATE(SCLK_SPDIF_8CH, "clk_spdif", "clk_spdif_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 15, GFLAGS), + + COMPOSITE(SCLK_SPDIF_REC_DPTX, "clk_spdif_rec_dptx", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(32), 15, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 6, GFLAGS), + /* i2s */ + COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(28), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 3, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(96), 0, + RK3399_CLKGATE_CON(8), 4, GFLAGS, + &rk3399_i2s0_fracmux), + GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 5, GFLAGS), + + COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(29), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 6, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(97), 0, + RK3399_CLKGATE_CON(8), 7, GFLAGS, + &rk3399_i2s1_fracmux), + GATE(SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 8, GFLAGS), + + COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(30), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 9, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(98), 0, + RK3399_CLKGATE_CON(8), 10, GFLAGS, + &rk3399_i2s2_fracmux), + GATE(SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 11, GFLAGS), + + MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(31), 0, 2, MFLAGS), + COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(30), 8, 2, MFLAGS, + RK3399_CLKGATE_CON(8), 12, GFLAGS), + + /* uart */ + MUX(0, "clk_uart0_src", mux_pll_src_cpll_gpll_upll_p, 0, + RK3399_CLKSEL_CON(33), 12, 2, MFLAGS), + COMPOSITE_NOMUX(0, "clk_uart0_div", "clk_uart0_src", 0, + RK3399_CLKSEL_CON(33), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 0, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(100), 0, + RK3399_CLKGATE_CON(9), 1, GFLAGS, + &rk3399_uart0_fracmux), + + MUX(0, "clk_uart_src", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(33), 15, 1, MFLAGS), + COMPOSITE_NOMUX(0, "clk_uart1_div", "clk_uart_src", 0, + RK3399_CLKSEL_CON(34), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 2, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(101), 0, + RK3399_CLKGATE_CON(9), 3, GFLAGS, + &rk3399_uart1_fracmux), + + COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0, + RK3399_CLKSEL_CON(35), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 4, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(102), 0, + RK3399_CLKGATE_CON(9), 5, GFLAGS, + &rk3399_uart2_fracmux), + + COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0, + RK3399_CLKSEL_CON(36), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 6, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(103), 0, + RK3399_CLKGATE_CON(9), 7, GFLAGS, + &rk3399_uart3_fracmux), + + COMPOSITE(0, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(3), 4, GFLAGS), + + GATE(PCLK_CENTER_MAIN_NOC, "pclk_center_main_noc", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(18), 10, GFLAGS), + GATE(PCLK_DDR_MON, "pclk_ddr_mon", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(18), 12, GFLAGS), + GATE(PCLK_CIC, "pclk_cic", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(18), 15, GFLAGS), + GATE(PCLK_DDR_SGRF, "pclk_ddr_sgrf", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(19), 2, GFLAGS), + + GATE(SCLK_PVTM_DDR, "clk_pvtm_ddr", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(4), 11, GFLAGS), + GATE(SCLK_DFIMON0_TIMER, "clk_dfimon0_timer", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(3), 5, GFLAGS), + GATE(SCLK_DFIMON1_TIMER, "clk_dfimon1_timer", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(3), 6, GFLAGS), + + /* cci */ + GATE(0, "cpll_aclk_cci_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 0, GFLAGS), + GATE(0, "gpll_aclk_cci_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 1, GFLAGS), + GATE(0, "npll_aclk_cci_src", "npll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 2, GFLAGS), + GATE(0, "vpll_aclk_cci_src", "vpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 3, GFLAGS), + + COMPOSITE(0, "aclk_cci_pre", mux_aclk_cci_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(2), 4, GFLAGS), + + GATE(ACLK_ADB400M_PD_CORE_L, "aclk_adb400m_pd_core_l", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 0, GFLAGS), + GATE(ACLK_ADB400M_PD_CORE_B, "aclk_adb400m_pd_core_b", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 1, GFLAGS), + GATE(ACLK_CCI, "aclk_cci", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 2, GFLAGS), + GATE(ACLK_CCI_NOC0, "aclk_cci_noc0", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 3, GFLAGS), + GATE(ACLK_CCI_NOC1, "aclk_cci_noc1", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 4, GFLAGS), + GATE(ACLK_CCI_GRF, "aclk_cci_grf", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 7, GFLAGS), + + GATE(0, "cpll_cci_trace", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 5, GFLAGS), + GATE(0, "gpll_cci_trace", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 6, GFLAGS), + COMPOSITE(SCLK_CCI_TRACE, "clk_cci_trace", mux_cci_trace_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(5), 15, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(2), 7, GFLAGS), + + GATE(0, "cpll_cs", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 8, GFLAGS), + GATE(0, "gpll_cs", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 9, GFLAGS), + GATE(0, "npll_cs", "npll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 10, GFLAGS), + COMPOSITE_NOGATE(0, "clk_cs", mux_cs_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS), + GATE(0, "clk_dbg_cxcs", "clk_cs", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 5, GFLAGS), + GATE(0, "clk_dbg_noc", "clk_cs", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 6, GFLAGS), + + /* vcodec */ + COMPOSITE(0, "aclk_vcodec_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, + RK3399_CLKSEL_CON(7), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 0, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vcodec_pre", "aclk_vcodec_pre", 0, + RK3399_CLKSEL_CON(7), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 1, GFLAGS), + GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 2, GFLAGS), + GATE(0, "hclk_vcodec_noc", "hclk_vcodec_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 3, GFLAGS), + + GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 0, GFLAGS), + GATE(0, "aclk_vcodec_noc", "aclk_vcodec_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 1, GFLAGS), + + /* vdu */ + COMPOSITE(SCLK_VDU_CORE, "clk_vdu_core", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(9), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 4, GFLAGS), + COMPOSITE(SCLK_VDU_CA, "clk_vdu_ca", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(9), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 5, GFLAGS), + + COMPOSITE(0, "aclk_vdu_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, + RK3399_CLKSEL_CON(8), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 2, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vdu_pre", "aclk_vdu_pre", 0, + RK3399_CLKSEL_CON(8), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 3, GFLAGS), + GATE(HCLK_VDU, "hclk_vdu", "hclk_vdu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 10, GFLAGS), + GATE(HCLK_VDU_NOC, "hclk_vdu_noc", "hclk_vdu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 11, GFLAGS), + + GATE(ACLK_VDU, "aclk_vdu", "aclk_vdu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 8, GFLAGS), + GATE(ACLK_VDU_NOC, "aclk_vdu_noc", "aclk_vdu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 9, GFLAGS), + + /* iep */ + COMPOSITE(0, "aclk_iep_pre", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(10), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 6, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_iep_pre", "aclk_iep_pre", 0, + RK3399_CLKSEL_CON(10), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 7, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_iep_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 2, GFLAGS), + GATE(HCLK_IEP_NOC, "hclk_iep_noc", "hclk_iep_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 3, GFLAGS), + + GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 0, GFLAGS), + GATE(ACLK_IEP_NOC, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 1, GFLAGS), + + /* rga */ + COMPOSITE(0, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 10, GFLAGS), + + COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 8, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_rga_pre", "aclk_rga_pre", 0, + RK3399_CLKSEL_CON(11), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 9, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_rga_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 10, GFLAGS), + GATE(HCLK_RGA_NOC, "hclk_rga_noc", "hclk_rga_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 11, GFLAGS), + + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 8, GFLAGS), + GATE(ACLK_RGA_NOC, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 9, GFLAGS), + + /* center */ + COMPOSITE(0, "aclk_center", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(3), 7, GFLAGS), + GATE(ACLK_CENTER_MAIN_NOC, "aclk_center_main_noc", "aclk_center", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(19), 0, GFLAGS), + GATE(ACLK_CENTER_PERI_NOC, "aclk_center_peri_noc", "aclk_center", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(19), 1, GFLAGS), + + /* gpu */ + COMPOSITE(0, "aclk_gpu_pre", mux_pll_src_ppll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(13), 5, 3, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 0, GFLAGS), + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 8, GFLAGS), + GATE(ACLK_PERF_GPU, "aclk_perf_gpu", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 10, GFLAGS), + GATE(ACLK_GPU_GRF, "aclk_gpu_grf", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 11, GFLAGS), + GATE(SCLK_PVTM_GPU, "aclk_pvtm_gpu", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(13), 1, GFLAGS), + + /* perihp */ + GATE(0, "cpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 0, GFLAGS), + GATE(0, "gpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 1, GFLAGS), + COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(5), 2, GFLAGS), + COMPOSITE_NOMUX(HCLK_PERIHP, "hclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(14), 8, 2, DFLAGS, + RK3399_CLKGATE_CON(5), 3, GFLAGS), + COMPOSITE_NOMUX(PCLK_PERIHP, "pclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(14), 12, 2, DFLAGS, + RK3399_CLKGATE_CON(5), 4, GFLAGS), + + GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 2, GFLAGS), + GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 10, GFLAGS), + GATE(0, "aclk_perihp_noc", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 12, GFLAGS), + + GATE(HCLK_HOST0, "hclk_host0", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 5, GFLAGS), + GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 6, GFLAGS), + GATE(HCLK_HOST1, "hclk_host1", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 7, GFLAGS), + GATE(HCLK_HOST1_ARB, "hclk_host1_arb", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 8, GFLAGS), + GATE(HCLK_HSIC, "hclk_hsic", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 9, GFLAGS), + GATE(0, "hclk_perihp_noc", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 13, GFLAGS), + GATE(0, "hclk_ahb1tom", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 15, GFLAGS), + + GATE(PCLK_PERIHP_GRF, "pclk_perihp_grf", "pclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 4, GFLAGS), + GATE(PCLK_PCIE, "pclk_pcie", "pclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 11, GFLAGS), + GATE(0, "pclk_perihp_noc", "pclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 14, GFLAGS), + GATE(PCLK_HSICPHY, "pclk_hsicphy", "pclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(31), 8, GFLAGS), + + /* sdio & sdmmc */ + COMPOSITE(0, "hclk_sd", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(13), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 13, GFLAGS), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(33), 8, GFLAGS), + GATE(0, "hclk_sdmmc_noc", "hclk_sd", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(33), 9, GFLAGS), + + COMPOSITE(SCLK_SDIO, "clk_sdio", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(15), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 0, GFLAGS), + + COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 1, GFLAGS), + + MMC(SCLK_SDMMC_DRV, "emmc_drv", "clk_sdmmc", RK3399_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "emmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", RK3399_SDIO_CON0, 1), + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", RK3399_SDIO_CON1, 1), + + /* pcie */ + COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(17), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 2, GFLAGS), + + COMPOSITE_NOMUX(0, "clk_pciephy_ref100m", "npll", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(18), 11, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 6, GFLAGS), + MUX(SCLK_PCIEPHY_REF, "clk_pciephy_ref", mux_pll_src_24m_pciephy_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(18), 10, 1, MFLAGS), + + COMPOSITE(0, "clk_pcie_core_cru", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(18), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 3, GFLAGS), + MUX(SCLK_PCIE_CORE, "clk_pcie_core", mux_pciecore_cru_phy_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(18), 7, 1, MFLAGS), + + /* emmc */ + COMPOSITE(SCLK_EMMC, "clk_emmc", mux_pll_src_cpll_gpll_npll_upll_24m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(22), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 14, GFLAGS), + + GATE(0, "cpll_aclk_emmc_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 12, GFLAGS), + GATE(0, "gpll_aclk_emmc_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 13, GFLAGS), + COMPOSITE_NOGATE(ACLK_EMMC, "aclk_emmc", mux_aclk_emmc_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(21), 7, 1, MFLAGS, 0, 5, DFLAGS), + GATE(ACLK_EMMC_CORE, "aclk_emmccore", "aclk_emmc", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 8, GFLAGS), + GATE(ACLK_EMMC_NOC, "aclk_emmc_noc", "aclk_emmc", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 9, GFLAGS), + GATE(ACLK_EMMC_GRF, "aclk_emmcgrf", "aclk_emmc", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 10, GFLAGS), + + /* perilp0 */ + GATE(0, "cpll_aclk_perilp0_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(7), 1, GFLAGS), + GATE(0, "gpll_aclk_perilp0_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(7), 0, GFLAGS), + COMPOSITE(ACLK_PERILP0, "aclk_perilp0", mux_aclk_perilp0_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(23), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 2, GFLAGS), + COMPOSITE_NOMUX(HCLK_PERILP0, "hclk_perilp0", "aclk_perilp0", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(23), 8, 2, DFLAGS, + RK3399_CLKGATE_CON(7), 3, GFLAGS), + COMPOSITE_NOMUX(PCLK_PERILP0, "pclk_perilp0", "aclk_perilp0", 0, + RK3399_CLKSEL_CON(23), 12, 3, DFLAGS, + RK3399_CLKGATE_CON(7), 4, GFLAGS), + + /* aclk_perilp0 gates */ + GATE(ACLK_INTMEM, "aclk_intmem", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 0, GFLAGS), + GATE(ACLK_TZMA, "aclk_tzma", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 1, GFLAGS), + GATE(SCLK_INTMEM0, "clk_intmem0", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 2, GFLAGS), + GATE(SCLK_INTMEM1, "clk_intmem1", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 3, GFLAGS), + GATE(SCLK_INTMEM2, "clk_intmem2", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 4, GFLAGS), + GATE(SCLK_INTMEM3, "clk_intmem3", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 5, GFLAGS), + GATE(SCLK_INTMEM4, "clk_intmem4", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 6, GFLAGS), + GATE(SCLK_INTMEM5, "clk_intmem5", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 7, GFLAGS), + GATE(ACLK_DCF, "aclk_dcf", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 8, GFLAGS), + GATE(ACLK_DMAC0_PERILP, "aclk_dmac0_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 5, GFLAGS), + GATE(ACLK_DMAC1_PERILP, "aclk_dmac1_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 6, GFLAGS), + GATE(ACLK_PERILP0_NOC, "aclk_perilp0_noc", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 7, GFLAGS), + + /* hclk_perilp0 gates */ + GATE(HCLK_ROM, "hclk_rom", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 4, GFLAGS), + GATE(HCLK_M_CRYPTO0, "hclk_m_crypto0", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 5, GFLAGS), + GATE(HCLK_S_CRYPTO0, "hclk_s_crypto0", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 6, GFLAGS), + GATE(HCLK_M_CRYPTO1, "hclk_m_crypto1", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 14, GFLAGS), + GATE(HCLK_S_CRYPTO1, "hclk_s_crypto1", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 15, GFLAGS), + GATE(HCLK_PERILP0_NOC, "hclk_perilp0_noc", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 8, GFLAGS), + + /* pclk_perilp0 gates */ + GATE(PCLK_DCF, "pclk_dcf", "pclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 9, GFLAGS), + + /* crypto */ + COMPOSITE(SCLK_CRYPTO0, "clk_crypto0", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(24), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 7, GFLAGS), + + COMPOSITE(SCLK_CRYPTO1, "clk_crypto1", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(26), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 8, GFLAGS), + + /* cm0s_perilp */ + GATE(0, "cpll_fclk_cm0s_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(7), 6, GFLAGS), + GATE(0, "gpll_fclk_cm0s_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(7), 5, GFLAGS), + COMPOSITE(FCLK_CM0S, "fclk_cm0s", mux_fclk_cm0s_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 9, GFLAGS), + + /* fclk_cm0s gates */ + GATE(SCLK_M0_PERILP, "sclk_m0_perilp", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 8, GFLAGS), + GATE(HCLK_M0_PERILP, "hclk_m0_perilp", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 9, GFLAGS), + GATE(DCLK_M0_PERILP, "dclk_m0_perilp", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 10, GFLAGS), + GATE(SCLK_M0_PERILP_DEC, "clk_m0_perilp_dec", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 11, GFLAGS), + GATE(HCLK_M0_PERILP_NOC, "hclk_m0_perilp_noc", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 11, GFLAGS), + + /* perilp1 */ + GATE(0, "cpll_hclk_perilp1_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(8), 1, GFLAGS), + GATE(0, "gpll_hclk_perilp1_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(8), 0, GFLAGS), + COMPOSITE_NOGATE(HCLK_PERILP1, "hclk_perilp1", mux_hclk_perilp1_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(25), 7, 1, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(PCLK_PERILP1, "pclk_perilp1", "hclk_perilp1", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(25), 8, 3, DFLAGS, + RK3399_CLKGATE_CON(8), 2, GFLAGS), + + /* hclk_perilp1 gates */ + GATE(0, "hclk_perilp1_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 9, GFLAGS), + GATE(0, "hclk_sdio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 12, GFLAGS), + GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 0, GFLAGS), + GATE(HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 1, GFLAGS), + GATE(HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 2, GFLAGS), + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 3, GFLAGS), + GATE(HCLK_SDIO, "hclk_sdio", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 4, GFLAGS), + GATE(PCLK_SPI5, "pclk_spi5", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 5, GFLAGS), + GATE(0, "hclk_sdioaudio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 6, GFLAGS), + + /* pclk_perilp1 gates */ + GATE(PCLK_UART0, "pclk_uart0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 0, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 1, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 2, GFLAGS), + GATE(PCLK_UART3, "pclk_uart3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 3, GFLAGS), + GATE(PCLK_I2C7, "pclk_rki2c7", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 5, GFLAGS), + GATE(PCLK_I2C1, "pclk_rki2c1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 6, GFLAGS), + GATE(PCLK_I2C5, "pclk_rki2c5", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 7, GFLAGS), + GATE(PCLK_I2C6, "pclk_rki2c6", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 8, GFLAGS), + GATE(PCLK_I2C2, "pclk_rki2c2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 9, GFLAGS), + GATE(PCLK_I2C3, "pclk_rki2c3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 10, GFLAGS), + GATE(PCLK_MAILBOX0, "pclk_mailbox0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 11, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 12, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 13, GFLAGS), + GATE(PCLK_EFUSE1024NS, "pclk_efuse1024ns", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 14, GFLAGS), + GATE(PCLK_EFUSE1024S, "pclk_efuse1024s", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 15, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 10, GFLAGS), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 11, GFLAGS), + GATE(PCLK_SPI2, "pclk_spi2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 12, GFLAGS), + GATE(PCLK_SPI4, "pclk_spi4", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 13, GFLAGS), + GATE(PCLK_PERIHP_GRF, "pclk_perilp_sgrf", "pclk_perilp1", 0, RK3399_CLKGATE_CON(24), 13, GFLAGS), + GATE(0, "pclk_perilp1_noc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(25), 10, GFLAGS), + + /* saradc */ + COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "xin24m", 0, + RK3399_CLKSEL_CON(26), 8, 8, DFLAGS, + RK3399_CLKGATE_CON(9), 11, GFLAGS), + + /* tsadc */ + COMPOSITE(SCLK_TSADC, "clk_tsadc", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(27), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(9), 10, GFLAGS), + + /* cif_testout */ + MUX(0, "clk_testout1_pll_src", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(38), 6, 2, MFLAGS), + COMPOSITE(0, "clk_testout1", mux_clk_testout1_p, 0, + RK3399_CLKSEL_CON(38), 5, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 14, GFLAGS), + + MUX(0, "clk_testout2_pll_src", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(38), 14, 2, MFLAGS), + COMPOSITE(0, "clk_testout2", mux_clk_testout2_p, 0, + RK3399_CLKSEL_CON(38), 13, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 15, GFLAGS), + + /* vio */ + COMPOSITE(ACLK_VIO, "aclk_vio", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 10, GFLAGS), + COMPOSITE_NOMUX(PCLK_VIO, "pclk_vio", "aclk_vio", 0, + RK3399_CLKSEL_CON(43), 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 1, GFLAGS), + + GATE(ACLK_VIO_NOC, "aclk_vio_noc", "aclk_vio", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 0, GFLAGS), + + GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "pclk_vio", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 1, GFLAGS), + GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "pclk_vio", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 2, GFLAGS), + GATE(PCLK_VIO_GRF, "pclk_vio_grf", "pclk_vio", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 12, GFLAGS), + + /* hdcp */ + COMPOSITE(ACLK_HDCP, "aclk_hdcp", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 12, GFLAGS), + COMPOSITE_NOMUX(HCLK_HDCP, "hclk_hdcp", "aclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(43), 5, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 3, GFLAGS), + COMPOSITE_NOMUX(PCLK_HDCP, "pclk_hdcp", "aclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(43), 10, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 10, GFLAGS), + + GATE(ACLK_HDCP_NOC, "aclk_hdcp_noc", "aclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 4, GFLAGS), + GATE(ACLK_HDCP22, "aclk_hdcp22", "aclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 10, GFLAGS), + + GATE(HCLK_HDCP_NOC, "hclk_hdcp_noc", "hclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 5, GFLAGS), + GATE(HCLK_HDCP22, "hclk_hdcp22", "hclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 9, GFLAGS), + + GATE(PCLK_HDCP_NOC, "pclk_hdcp_noc", "pclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 3, GFLAGS), + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 6, GFLAGS), + GATE(PCLK_DP_CTRL, "pclk_dp_ctrl", "pclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 7, GFLAGS), + GATE(PCLK_HDCP22, "pclk_hdcp22", "pclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 8, GFLAGS), + GATE(PCLK_GASKET, "pclk_gasket", "pclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 11, GFLAGS), + + /* edp */ + COMPOSITE(SCLK_DP_CORE, "clk_dp_core", mux_pll_src_npll_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 8, GFLAGS), + + COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 11, GFLAGS), + GATE(PCLK_EDP_NOC, "pclk_edp_noc", "pclk_edp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 12, GFLAGS), + GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "pclk_edp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 13, GFLAGS), + + /* hdmi */ + GATE(SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(11), 6, GFLAGS), + + COMPOSITE(SCLK_HDMI_CEC, "clk_hdmi_cec", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(45), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(11), 7, GFLAGS), + + /* vop0 */ + COMPOSITE(ACLK_VOP0_PRE, "aclk_vop0_pre", mux_pll_src_vpll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(47), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 8, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vop0_pre", "aclk_vop0_pre", 0, + RK3399_CLKSEL_CON(47), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 9, GFLAGS), + + GATE(ACLK_VOP0, "aclk_vop0", "aclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 3, GFLAGS), + GATE(ACLK_VOP0_NOC, "aclk_vop0_noc", "aclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 1, GFLAGS), + + GATE(HCLK_VOP0, "hclk_vop0", "hclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 2, GFLAGS), + GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 0, GFLAGS), + + COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3399_CLKGATE_CON(10), 12, GFLAGS), + + COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop0_frac", "dclk_vop0_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(106), 0, + &rk3399_dclk_vop0_fracmux), + + COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 14, GFLAGS), + + /* vop1 */ + COMPOSITE(ACLK_VOP1_PRE, "aclk_vop1_pre", mux_pll_src_vpll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 10, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vop1_pre", "aclk_vop1_pre", 0, + RK3399_CLKSEL_CON(48), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 11, GFLAGS), + + GATE(ACLK_VOP1, "aclk_vop1", "aclk_vop1_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 7, GFLAGS), + GATE(ACLK_VOP1_NOC, "aclk_vop1_noc", "aclk_vop1_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 5, GFLAGS), + + GATE(HCLK_VOP1, "hclk_vop1", "hclk_vop1_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 6, GFLAGS), + GATE(HCLK_VOP1_NOC, "hclk_vop1_noc", "hclk_vop1_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 4, GFLAGS), + + COMPOSITE(DCLK_VOP1_DIV, "dclk_vop1_div", mux_pll_src_vpll_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3399_CLKGATE_CON(10), 13, GFLAGS), + + COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop1_frac", "dclk_vop1_div", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(107), 0, + &rk3399_dclk_vop1_fracmux), + + COMPOSITE(SCLK_VOP1_PWM, "clk_vop1_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 15, GFLAGS), + + /* isp */ + COMPOSITE(0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(53), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 8, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_isp0", "aclk_isp0", 0, + RK3399_CLKSEL_CON(53), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 9, GFLAGS), + + GATE(ACLK_ISP0_NOC, "aclk_isp0_noc", "aclk_isp0", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 1, GFLAGS), + GATE(ACLK_ISP0_WRAPPER, "aclk_isp0_wrapper", "aclk_isp0", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 5, GFLAGS), + GATE(HCLK_ISP1_WRAPPER, "hclk_isp1_wrapper", "aclk_isp0", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 7, GFLAGS), + + GATE(HCLK_ISP0_NOC, "hclk_isp0_noc", "hclk_isp0", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 0, GFLAGS), + GATE(HCLK_ISP0_WRAPPER, "hclk_isp0_wrapper", "hclk_isp0", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 4, GFLAGS), + + COMPOSITE(SCLK_ISP0, "clk_isp0", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 4, GFLAGS), + + COMPOSITE(ACLK_ISP1, "aclk_isp1", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(54), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 10, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_isp1", "aclk_isp1", 0, + RK3399_CLKSEL_CON(54), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 11, GFLAGS), + + GATE(ACLK_ISP1_NOC, "aclk_isp1_noc", "aclk_isp1", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 3, GFLAGS), + + GATE(HCLK_ISP1_NOC, "hclk_isp1_noc", "hclk_isp1", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 2, GFLAGS), + GATE(ACLK_ISP1_WRAPPER, "aclk_isp1_wrapper", "hclk_isp1", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 8, GFLAGS), + + COMPOSITE(SCLK_ISP1, "clk_isp1", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(55), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 5, GFLAGS), + + /* + * We use pclkin_cifinv by default GRF_SOC_CON20[9] (GSC20_9) setting in system, + * so we ignore the mux and make clocks nodes as following, + * + * pclkin_cifinv --|-------\ + * |GSC20_9|-- pclkin_cifmux -- |G27_6| -- pclkin_isp1_wrapper + * pclkin_cif --|-------/ + */ + GATE(PCLK_ISP1_WRAPPER, "pclkin_isp1_wrapper", "pclkin_cif", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 6, GFLAGS), + + /* cif */ + COMPOSITE(0, "clk_cifout_div", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(56), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 7, GFLAGS), + MUX(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(56), 5, 1, MFLAGS), + + /* gic */ + COMPOSITE(ACLK_GIC_PRE, "aclk_gic_pre", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(56), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 12, GFLAGS), + + GATE(ACLK_GIC, "aclk_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 0, GFLAGS), + GATE(ACLK_GIC_NOC, "aclk_gic_noc", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 1, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_gic_adb400_core_l_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 2, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_gic_adb400_core_b_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 3, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_gic_adb400_gic_2_core_l", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 4, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_gic_adb400_gic_2_core_b", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 5, GFLAGS), + + /* alive */ + /* pclk_alive_gpll_src is controlled by PMUGRF_SOC_CON0[6] */ + DIV(PCLK_ALIVE, "pclk_alive", "gpll", 0, + RK3399_CLKSEL_CON(57), 0, 5, DFLAGS), + + GATE(PCLK_USBPHY_MUX_G, "pclk_usbphy_mux_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 4, GFLAGS), + GATE(PCLK_UPHY0_TCPHY_G, "pclk_uphy0_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 5, GFLAGS), + GATE(PCLK_UPHY0_TCPD_G, "pclk_uphy0_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 6, GFLAGS), + GATE(PCLK_UPHY1_TCPHY_G, "pclk_uphy1_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 8, GFLAGS), + GATE(PCLK_UPHY1_TCPD_G, "pclk_uphy1_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 9, GFLAGS), + + GATE(PCLK_GRF, "pclk_grf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 1, GFLAGS), + GATE(PCLK_INTR_ARB, "pclk_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 2, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 3, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 4, GFLAGS), + GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 5, GFLAGS), + GATE(PCLK_TIMER0, "pclk_timer0", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 6, GFLAGS), + GATE(PCLK_TIMER1, "pclk_timer1", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 7, GFLAGS), + GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS), + + GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(11), 14, GFLAGS), + GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS), + + GATE(SCLK_MIPIDPHY_CFG, "clk_mipidphy_cfg", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(11), 15, GFLAGS), + GATE(SCLK_DPHY_TX0_CFG, "clk_dphy_tx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 1, GFLAGS), + GATE(SCLK_DPHY_TX1RX1_CFG, "clk_dphy_tx1rx1_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 2, GFLAGS), + GATE(SCLK_DPHY_RX0_CFG, "clk_dphy_rx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 3, GFLAGS), + + /* testout */ + MUX(0, "clk_test_pre", mux_pll_src_cpll_gpll_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(58), 7, 1, MFLAGS), + COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(105), 0, + RK3399_CLKGATE_CON(13), 9, GFLAGS), + + DIV(0, "clk_test_24m", "xin24m", 0, + RK3399_CLKSEL_CON(57), 6, 10, DFLAGS), + + /* spi */ + COMPOSITE(SCLK_SPI0, "clk_spi0", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(59), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 12, GFLAGS), + + COMPOSITE(SCLK_SPI1, "clk_spi1", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(59), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 13, GFLAGS), + + COMPOSITE(SCLK_SPI2, "clk_spi2", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(60), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 14, GFLAGS), + + COMPOSITE(SCLK_SPI4, "clk_spi4", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(60), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 15, GFLAGS), + + COMPOSITE(SCLK_SPI5, "clk_spi5", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(58), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(13), 13, GFLAGS), + + /* i2c */ + COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(61), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 0, GFLAGS), + + COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(62), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 2, GFLAGS), + + COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(63), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 4, GFLAGS), + + COMPOSITE(SCLK_I2C5, "clk_i2c5", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(61), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 1, GFLAGS), + + COMPOSITE(SCLK_I2C6, "clk_i2c6", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(62), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 3, GFLAGS), + + COMPOSITE(SCLK_I2C7, "clk_i2c7", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(63), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 5, GFLAGS), + + /* timer */ + GATE(SCLK_TIMER00, "clk_timer00", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 0, GFLAGS), + GATE(SCLK_TIMER01, "clk_timer01", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 1, GFLAGS), + GATE(SCLK_TIMER02, "clk_timer02", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 2, GFLAGS), + GATE(SCLK_TIMER03, "clk_timer03", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 3, GFLAGS), + GATE(SCLK_TIMER04, "clk_timer04", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 4, GFLAGS), + GATE(SCLK_TIMER05, "clk_timer05", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 5, GFLAGS), + GATE(SCLK_TIMER06, "clk_timer06", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 6, GFLAGS), + GATE(SCLK_TIMER07, "clk_timer07", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 7, GFLAGS), + GATE(SCLK_TIMER08, "clk_timer08", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 8, GFLAGS), + GATE(SCLK_TIMER09, "clk_timer09", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 9, GFLAGS), + GATE(SCLK_TIMER10, "clk_timer10", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 10, GFLAGS), + GATE(SCLK_TIMER11, "clk_timer11", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 11, GFLAGS), + + /* clk_test */ + /* clk_test_pre is controlled by CRU_MISC_CON[3] */ + COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(58), 0, 5, DFLAGS, + RK3368_CLKGATE_CON(13), 11, GFLAGS), +}; + +static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { + /* + * PMU CRU Clock-Architecture + */ + + GATE(0, "fclk_cm0s_pmu_ppll_src", "ppll", CLK_IGNORE_UNUSED, + RK3399_PMU_CLKGATE_CON(0), 1, GFLAGS), + + COMPOSITE_NOGATE(FCLK_CM0S_SRC_PMU, "fclk_cm0s_src_pmu", mux_fclk_cm0s_pmu_ppll_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS), + + COMPOSITE(SCLK_SPI3_PMU, "clk_spi3_pmu", mux_24m_ppll_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(1), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 2, GFLAGS), + + COMPOSITE(0, "clk_wifi_div", mux_ppll_24m_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(1), 13, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 8, GFLAGS), + + COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", CLK_SET_RATE_PARENT, + RK3399_PMU_CLKSEL_CON(7), 0, + &rk3399_pmuclk_wifi_fracmux), + + MUX(0, "clk_timer_src_pmu", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(1), 15, 1, MFLAGS), + + COMPOSITE_NOMUX(SCLK_I2C0_PMU, "clk_i2c0_pmu", "ppll", 0, + RK3399_PMU_CLKSEL_CON(2), 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 9, GFLAGS), + + COMPOSITE_NOMUX(SCLK_I2C4_PMU, "clk_i2c4_pmu", "ppll", 0, + RK3399_PMU_CLKSEL_CON(3), 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 11, GFLAGS), + + COMPOSITE_NOMUX(SCLK_I2C8_PMU, "clk_i2c8_pmu", "ppll", 0, + RK3399_PMU_CLKSEL_CON(2), 8, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 10, GFLAGS), + + DIV(0, "clk_32k_suspend_pmu", "xin24m", CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(4), 0, 10, DFLAGS), + MUX(0, "clk_testout_2io", mux_clk_testout2_2io_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(4), 15, 1, MFLAGS), + + COMPOSITE(0, "clk_uart4_div", mux_24m_ppll_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(5), 10, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 5, GFLAGS), + + COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", CLK_SET_RATE_PARENT, + RK3399_PMU_CLKSEL_CON(6), 0, + RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS, + &rk3399_uart4_pmu_fracmux), + + DIV(PCLK_SRC_PMU, "pclk_pmu_src", "ppll", CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(0), 0, 5, DFLAGS), + + /* pmu clock gates */ + GATE(SCLK_TIMER12_PMU, "clk_timer0_pmu", "clk_timer_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 3, GFLAGS), + GATE(SCLK_TIMER13_PMU, "clk_timer1_pmu", "clk_timer_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 4, GFLAGS), + + GATE(SCLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 7, GFLAGS), + + GATE(PCLK_PMU, "pclk_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 0, GFLAGS), + GATE(PCLK_PMUGRF_PMU, "pclk_pmugrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 1, GFLAGS), + GATE(PCLK_INTMEM1_PMU, "pclk_intmem1_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 2, GFLAGS), + GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 3, GFLAGS), + GATE(PCLK_GPIO1_PMU, "pclk_gpio1_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 4, GFLAGS), + GATE(PCLK_SGRF_PMU, "pclk_sgrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 5, GFLAGS), + GATE(PCLK_NOC_PMU, "pclk_noc_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 6, GFLAGS), + GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 7, GFLAGS), + GATE(PCLK_I2C4_PMU, "pclk_i2c4_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 8, GFLAGS), + GATE(PCLK_I2C8_PMU, "pclk_i2c8_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 9, GFLAGS), + GATE(PCLK_RKPWM_PMU, "pclk_rkpwm_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 10, GFLAGS), + GATE(PCLK_SPI3_PMU, "pclk_spi3_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 11, GFLAGS), + GATE(PCLK_TIMER_PMU, "pclk_timer_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 12, GFLAGS), + GATE(PCLK_MAILBOX_PMU, "pclk_mailbox_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 13, GFLAGS), + GATE(PCLK_UART4_PMU, "pclk_uart4_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 14, GFLAGS), + GATE(PCLK_WDT_M0_PMU, "pclk_wdt_m0_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 15, GFLAGS), + + GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS), + GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS), + GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS), + GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS), + GATE(HCLK_NOC_PMU, "hclk_noc_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 5, GFLAGS), +}; + +static const char *const rk3399_cru_critical_clocks[] __initconst = { + "aclk_cci_pre", + "pclk_perilp0", + "pclk_perilp0", + "hclk_perilp0", + "hclk_perilp0_noc", + "pclk_perilp1", + "pclk_perilp1_noc", + "pclk_perihp", + "pclk_perihp_noc", + "hclk_perihp", + "aclk_perihp", + "aclk_perihp_noc", + "aclk_perilp0", + "aclk_perilp0_noc", + "hclk_perilp1", + "hclk_perilp1_noc", + "aclk_dmac0_perilp", + "gpll_hclk_perilp1_src", + "gpll_aclk_perilp0_src", + "gpll_aclk_perihp_src", +}; + +static const char *const rk3399_pmucru_critical_clocks[] __initconst = { + "ppll", + "pclk_pmu_src", + "fclk_cm0s_src_pmu", + "clk_timer_src_pmu", +}; + +static void __init rk3399_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + return; + } + + rockchip_clk_register_plls(ctx, rk3399_pll_clks, + ARRAY_SIZE(rk3399_pll_clks), -1); + + rockchip_clk_register_branches(ctx, rk3399_clk_branches, + ARRAY_SIZE(rk3399_clk_branches)); + + rockchip_clk_protect_critical(rk3399_cru_critical_clocks, + ARRAY_SIZE(rk3399_cru_critical_clocks)); + + rockchip_clk_register_armclk(ctx, ARMCLKL, "armclkl", + mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p), + &rk3399_cpuclkl_data, rk3399_cpuclkl_rates, + ARRAY_SIZE(rk3399_cpuclkl_rates)); + + rockchip_clk_register_armclk(ctx, ARMCLKB, "armclkb", + mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p), + &rk3399_cpuclkb_data, rk3399_cpuclkb_rates, + ARRAY_SIZE(rk3399_cpuclkb_rates)); + + rockchip_register_softrst(np, 21, reg_base + RK3399_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_register_restart_notifier(ctx, RK3399_GLB_SRST_FST, NULL); + + rockchip_clk_of_add_provider(np, ctx); +} +CLK_OF_DECLARE(rk3399_cru, "rockchip,rk3399-cru", rk3399_clk_init); + +static void __init rk3399_pmu_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru pmu region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, CLKPMU_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip pmu clk init failed\n", __func__); + return; + } + + rockchip_clk_register_plls(ctx, rk3399_pmu_pll_clks, + ARRAY_SIZE(rk3399_pmu_pll_clks), -1); + + rockchip_clk_register_branches(ctx, rk3399_clk_pmu_branches, + ARRAY_SIZE(rk3399_clk_pmu_branches)); + + rockchip_clk_protect_critical(rk3399_pmucru_critical_clocks, + ARRAY_SIZE(rk3399_pmucru_critical_clocks)); + + rockchip_register_softrst(np, 2, reg_base + RK3399_PMU_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_clk_of_add_provider(np, ctx); +} +CLK_OF_DECLARE(rk3399_cru_pmu, "rockchip,rk3399-pmucru", rk3399_pmu_clk_init); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index cb6a639..880349f 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -34,7 +34,7 @@ struct clk; #define HIWORD_UPDATE(val, mask, shift) \ ((val) << (shift) | (mask) << ((shift) + 16)) -/* register positions shared by RK2928, RK3036, RK3066, RK3188 and RK3228 */ +/* register positions shared by RK2928, RK3036, RK3066, RK3188, RK3228, RK3399 */ #define RK2928_PLL_CON(x) ((x) * 0x4) #define RK2928_MODE_CON 0x40 #define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44) @@ -93,6 +93,26 @@ struct clk; #define RK3368_EMMC_CON0 0x418 #define RK3368_EMMC_CON1 0x41c +#define RK3399_PLL_CON(x) RK2928_PLL_CON(x) +#define RK3399_CLKSEL_CON(x) ((x) * 0x4 + 0x100) +#define RK3399_CLKGATE_CON(x) ((x) * 0x4 + 0x300) +#define RK3399_SOFTRST_CON(x) ((x) * 0x4 + 0x400) +#define RK3399_GLB_SRST_FST 0x500 +#define RK3399_GLB_SRST_SND 0x504 +#define RK3399_GLB_CNT_TH 0x508 +#define RK3399_MISC_CON 0x50c +#define RK3399_RST_CON 0x510 +#define RK3399_RST_ST 0x514 +#define RK3399_SDMMC_CON0 0x580 +#define RK3399_SDMMC_CON1 0x584 +#define RK3399_SDIO_CON0 0x588 +#define RK3399_SDIO_CON1 0x58c + +#define RK3399_PMU_PLL_CON(x) RK2928_PLL_CON(x) +#define RK3399_PMU_CLKSEL_CON(x) ((x) * 0x4 + 0x80) +#define RK3399_PMU_CLKGATE_CON(x) ((x) * 0x4 + 0x100) +#define RK3399_PMU_SOFTRST_CON(x) ((x) * 0x4 + 0x110) + enum rockchip_pll_type { pll_rk3036, pll_rk3066, -- cgit v0.10.2 From 0b55257ebc66d333e86415b0fdf46450ca807059 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 8 Mar 2016 09:33:39 -0300 Subject: clk: imx6sx: Register SAI clocks as shared clocks SAIx and SAIx_IPG share the same bit fields in the CCM registers, so we should better register them via imx_clk_gate2_shared(). Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index fea125e..97e742a 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -134,6 +134,8 @@ static u32 share_count_esai; static u32 share_count_ssi1; static u32 share_count_ssi2; static u32 share_count_ssi3; +static u32 share_count_sai1; +static u32 share_count_sai2; static struct clk ** const uart_clks[] __initconst = { &clks[IMX6SX_CLK_UART_IPG], @@ -469,10 +471,10 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3); clks[IMX6SX_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); clks[IMX6SX_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_podf", base + 0x7c, 26); - clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2("sai1_ipg", "ipg", base + 0x7c, 28); - clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2("sai2_ipg", "ipg", base + 0x7c, 30); - clks[IMX6SX_CLK_SAI1] = imx_clk_gate2("sai1", "ssi1_podf", base + 0x7c, 28); - clks[IMX6SX_CLK_SAI2] = imx_clk_gate2("sai2", "ssi2_podf", base + 0x7c, 30); + clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1); + clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2); + clks[IMX6SX_CLK_SAI1] = imx_clk_gate2_shared("sai1", "ssi1_podf", base + 0x7c, 28, &share_count_sai1); + clks[IMX6SX_CLK_SAI2] = imx_clk_gate2_shared("sai2", "ssi2_podf", base + 0x7c, 30, &share_count_sai2); /* CCGR6 */ clks[IMX6SX_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); -- cgit v0.10.2 From 456829228f96702ca281b65e11d11e8c09ca9da0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 9 Mar 2016 18:16:47 -0800 Subject: clk: imx: clk-gate2: allow custom gate configuration The 2-bit gates found i.MX and Vybrid SoC support different clock configuration: 0b00: clk disabled 0b01: clk enabled in RUN mode but disabled in WAIT and STOP mode 0b10: clk enabled in RUN, WAIT and STOP mode (only Vybrid) 0b11: clk enabled in RUN and WAIT mode For some clocks, we might want to configure different behaviour, e.g. a memory clock should be on even in STOP mode. Add a new function imx_clk_gate2_cgr which allow to configure specific gate values through the cgr_val parameter. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 8935bff..db44a19 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -31,6 +31,7 @@ struct clk_gate2 { struct clk_hw hw; void __iomem *reg; u8 bit_idx; + u8 cgr_val; u8 flags; spinlock_t *lock; unsigned int *share_count; @@ -50,7 +51,8 @@ static int clk_gate2_enable(struct clk_hw *hw) goto out; reg = readl(gate->reg); - reg |= 3 << gate->bit_idx; + reg &= ~(3 << gate->bit_idx); + reg |= gate->cgr_val << gate->bit_idx; writel(reg, gate->reg); out: @@ -125,7 +127,7 @@ static struct clk_ops clk_gate2_ops = { struct clk *clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, + void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 clk_gate2_flags, spinlock_t *lock, unsigned int *share_count) { @@ -140,6 +142,7 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, /* struct clk_gate2 assignments */ gate->reg = reg; gate->bit_idx = bit_idx; + gate->cgr_val = cgr_val; gate->flags = clk_gate2_flags; gate->lock = lock; gate->share_count = share_count; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index d942f57..508d0fa 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -41,7 +41,7 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, struct clk *clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, + void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 clk_gate_flags, spinlock_t *lock, unsigned int *share_count); @@ -55,7 +55,7 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, - shift, 0, &imx_ccm_lock, NULL); + shift, 0x3, 0, &imx_ccm_lock, NULL); } static inline struct clk *imx_clk_gate2_shared(const char *name, @@ -63,7 +63,14 @@ static inline struct clk *imx_clk_gate2_shared(const char *name, unsigned int *share_count) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, - shift, 0, &imx_ccm_lock, share_count); + shift, 0x3, 0, &imx_ccm_lock, share_count); +} + +static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 cgr_val) +{ + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, cgr_val, 0, &imx_ccm_lock, NULL); } struct clk *imx_clk_pfd(const char *name, const char *parent_name, -- cgit v0.10.2 From 0da15d36a90f405541773e884b3264e0f94debd3 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 9 Mar 2016 18:16:48 -0800 Subject: clk: imx: vf610: leave DDR clock on To use STOP mode without putting DDR3 into self-refresh mode, we need to keep the DDR clock enabled. Use the new gate configuration with a value of 2 to make sure that the clock is enabled in RUN, WAIT and STOP mode. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 0a94d96..f0ff458 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -119,6 +119,7 @@ static unsigned int const clks_init_on[] __initconst = { VF610_CLK_SYS_BUS, VF610_CLK_DDR_SEL, VF610_CLK_DAP, + VF610_CLK_DDRMC, }; static struct clk * __init vf610_get_fixed_clock( @@ -233,6 +234,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_PLL4_MAIN_DIV] = clk_register_divider_table(NULL, "pll4_audio_div", "pll4_audio", 0, CCM_CACRR, 6, 3, 0, pll4_audio_div_table, &imx_ccm_lock); clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1); + clk[VF610_CLK_DDRMC] = imx_clk_gate2_cgr("ddrmc", "ddr_sel", CCM_CCGR6, CCM_CCGRx_CGn(14), 0x2); + clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6); clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6); diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index 56c16aa..cf2c00a 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -195,6 +195,7 @@ #define VF610_CLK_SNVS 182 #define VF610_CLK_DAP 183 #define VF610_CLK_OCOTP 184 -#define VF610_CLK_END 185 +#define VF610_CLK_DDRMC 185 +#define VF610_CLK_END 186 #endif /* __DT_BINDINGS_CLOCK_VF610_H */ -- cgit v0.10.2 From 349efbeedb2b79292eee12cf6b9a2422ef93853d Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 9 Mar 2016 18:16:49 -0800 Subject: clk: imx: vf610: add WKPU unit Signed-off-by: Stefan Agner Acked-by: Stephen Boyd Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index f0ff458..610a724 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -120,6 +120,7 @@ static unsigned int const clks_init_on[] __initconst = { VF610_CLK_DDR_SEL, VF610_CLK_DAP, VF610_CLK_DDRMC, + VF610_CLK_WKPU, }; static struct clk * __init vf610_get_fixed_clock( @@ -235,6 +236,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1); clk[VF610_CLK_DDRMC] = imx_clk_gate2_cgr("ddrmc", "ddr_sel", CCM_CCGR6, CCM_CCGRx_CGn(14), 0x2); + clk[VF610_CLK_WKPU] = imx_clk_gate2_cgr("wkpu", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(10), 0x2); clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6); clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6); diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index cf2c00a..7dc1b84 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -196,6 +196,7 @@ #define VF610_CLK_DAP 183 #define VF610_CLK_OCOTP 184 #define VF610_CLK_DDRMC 185 -#define VF610_CLK_END 186 +#define VF610_CLK_WKPU 186 +#define VF610_CLK_END 187 #endif /* __DT_BINDINGS_CLOCK_VF610_H */ -- cgit v0.10.2 From 4cfe6aebb272d7c75a2c21ce5db3a9e10f57901a Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 9 Mar 2016 18:16:50 -0800 Subject: clk: imx: vf610: add suspend/resume support The clock register are lost when enterying LPSTOPx, hence provide suspend/resume functions restoring them. The clock gates get restored by the individual driver, hence we do not need to restore them here. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 610a724..66e6fae 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "clk.h" @@ -40,6 +41,7 @@ #define CCM_CCGR9 (ccm_base + 0x64) #define CCM_CCGR10 (ccm_base + 0x68) #define CCM_CCGR11 (ccm_base + 0x6c) +#define CCM_CCGRx(x) (CCM_CCGR0 + (x) * 4) #define CCM_CMEOR0 (ccm_base + 0x70) #define CCM_CMEOR1 (ccm_base + 0x74) #define CCM_CMEOR2 (ccm_base + 0x78) @@ -115,6 +117,13 @@ static struct clk_div_table pll4_audio_div_table[] = { static struct clk *clk[VF610_CLK_END]; static struct clk_onecell_data clk_data; +static u32 cscmr1; +static u32 cscmr2; +static u32 cscdr1; +static u32 cscdr2; +static u32 cscdr3; +static u32 ccgr[12]; + static unsigned int const clks_init_on[] __initconst = { VF610_CLK_SYS_BUS, VF610_CLK_DDR_SEL, @@ -134,6 +143,43 @@ static struct clk * __init vf610_get_fixed_clock( return clk; }; +static int vf610_clk_suspend(void) +{ + int i; + + cscmr1 = readl_relaxed(CCM_CSCMR1); + cscmr2 = readl_relaxed(CCM_CSCMR2); + + cscdr1 = readl_relaxed(CCM_CSCDR1); + cscdr2 = readl_relaxed(CCM_CSCDR2); + cscdr3 = readl_relaxed(CCM_CSCDR3); + + for (i = 0; i < 12; i++) + ccgr[i] = readl_relaxed(CCM_CCGRx(i)); + + return 0; +} + +static void vf610_clk_resume(void) +{ + int i; + + writel_relaxed(cscmr1, CCM_CSCMR1); + writel_relaxed(cscmr2, CCM_CSCMR2); + + writel_relaxed(cscdr1, CCM_CSCDR1); + writel_relaxed(cscdr2, CCM_CSCDR2); + writel_relaxed(cscdr3, CCM_CSCDR3); + + for (i = 0; i < 12; i++) + writel_relaxed(ccgr[i], CCM_CCGRx(i)); +} + +static struct syscore_ops vf610_clk_syscore_ops = { + .suspend = vf610_clk_suspend, + .resume = vf610_clk_resume, +}; + static void __init vf610_clocks_init(struct device_node *ccm_node) { struct device_node *np; @@ -414,6 +460,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) clk_prepare_enable(clk[clks_init_on[i]]); + register_syscore_ops(&vf610_clk_syscore_ops); + /* Add the clocks to provider list */ clk_data.clks = clk; clk_data.clk_num = ARRAY_SIZE(clk); -- cgit v0.10.2 From a454018505f2e875441603b18dbbb912d422f7d1 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 27 Mar 2016 11:26:13 +0200 Subject: clk: unconditionally recurse into clk/mvebu/ The drivers/clk/mvebu directory is only being built when CONFIG_PLAT_ORION=y. As we are going to support additional mvebu platforms in drivers/clk/mvebu, which don't have CONFIG_PLAT_ORION=y, we need to recurse into this directory regardless of the value of CONFIG_PLAT_ORION. Since all files in drivers/clk/mvebu/ are already conditionally compiled depending on various Kconfig options, we can recurse unconditionally into drivers/clk/mvebu without any other change. Signed-off-by: Thomas Petazzoni Signed-off-by: Stephen Boyd diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 46869d6..f9ad66e 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -61,7 +61,7 @@ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ endif -obj-$(CONFIG_PLAT_ORION) += mvebu/ +obj-y += mvebu/ obj-$(CONFIG_ARCH_MESON) += meson/ obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ -- cgit v0.10.2 From c0553d04f8d35bf9706e20ba392ffa61ab2b6f5c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 27 Mar 2016 11:26:14 +0200 Subject: dt-bindings: arm: add DT binding for Marvell AP806 system controller This commit adds the Device Tree binding documentation for the system controller found in Marvell AP806 HW block, which is one of the core HW blocks of the 64-bits Marvell Armada 7K/8K family. Signed-off-by: Thomas Petazzoni Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt new file mode 100644 index 0000000..8968371 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt @@ -0,0 +1,35 @@ +Marvell Armada AP806 System Controller +====================================== + +The AP806 is one of the two core HW blocks of the Marvell Armada 7K/8K +SoCs. It contains a system controller, which provides a number +registers giving access to numerous features: clocks, pin-muxing and +many other SoC configuration items. This DT binding allows to describe +this system controller. + +The Device Tree node representing the AP806 system controller provides +a number of clocks: + + - 0: clock of CPU cluster 0 + - 1: clock of CPU cluster 1 + - 2: fixed PLL at 1200 Mhz + - 3: MSS clock, derived from the fixed PLL + +Required properties: + + - compatible: must be: + "marvell,ap806-system-controller", "syscon" + - reg: register area of the AP806 system controller + - #clock-cells: must be set to 1 + - clock-output-names: must be defined to: + "ap-cpu-cluster-0", "ap-cpu-cluster-1", "ap-fixed", "ap-mss" + +Example: + + syscon: system-controller@6f4000 { + compatible = "marvell,ap806-system-controller", "syscon"; + #clock-cells = <1>; + clock-output-names = "ap-cpu-cluster-0", "ap-cpu-cluster-1", + "ap-fixed", "ap-mss"; + reg = <0x6f4000 0x1000>; + }; -- cgit v0.10.2 From 4aba2755b8e8abbe29a12d18523d97c27bf53183 Mon Sep 17 00:00:00 2001 From: Gary Bisson Date: Sat, 2 Apr 2016 18:25:45 +0200 Subject: clk: imx: add ckil clock for i.MX7 Add the necessary clock to use the ckil on i.MX7. Inspired from the following patch: https://github.com/boundarydevices/linux-imx6/commit/b80e8271 Signed-off-by: Troy Kisky Signed-off-by: Gary Bisson Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index fbb6a8c..7912be8 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -342,7 +342,7 @@ static const char *clko1_sel[] = { "osc", "pll_sys_main_clk", static const char *clko2_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_166m_clk", "pll_sys_pfd4_clk", - "pll_audio_main_clk", "pll_video_main_clk", "osc_32k_clk", }; + "pll_audio_main_clk", "pll_video_main_clk", "ckil", }; static const char *lvds1_sel[] = { "pll_arm_main_clk", "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_332m_clk", @@ -382,6 +382,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0); clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc"); + clks[IMX7D_CKIL] = of_clk_get_by_name(ccm_node, "ckil"); np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop"); base = of_iomap(np, 0); diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h index edca8985c..1183347 100644 --- a/include/dt-bindings/clock/imx7d-clock.h +++ b/include/dt-bindings/clock/imx7d-clock.h @@ -448,5 +448,6 @@ #define IMX7D_PLL_DRAM_TEST_DIV 435 #define IMX7D_ADC_ROOT_CLK 436 #define IMX7D_CLK_ARM 437 -#define IMX7D_CLK_END 438 +#define IMX7D_CKIL 438 +#define IMX7D_CLK_END 439 #endif /* __DT_BINDINGS_CLOCK_IMX7D_H */ -- cgit v0.10.2 From 32b9b10961860860268961d9aad0c56a73018c37 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Feb 2016 13:19:09 -0800 Subject: clk: Allow clocks to be marked as CRITICAL Critical clocks are those which must not be gated, else undefined or catastrophic failure would occur. Here we have chosen to ensure the prepare/enable counts are correctly incremented, so as not to confuse users with enabled clocks with no visible users. Signed-off-by: Lee Jones Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1455225554-13267-2-git-send-email-mturquette@baylibre.com diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fb74dc1..275201f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2397,6 +2397,11 @@ static int __clk_core_init(struct clk_core *core) if (core->ops->init) core->ops->init(core->hw); + if (core->flags & CLK_IS_CRITICAL) { + clk_core_prepare(core); + clk_core_enable(core); + } + kref_init(&core->ref); out: clk_prepare_unlock(); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index da95258..0638b41 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -32,6 +32,7 @@ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ #define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */ #define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */ +#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ struct clk; struct clk_hw; -- cgit v0.10.2 From 2e20fbf592621b2c2aeddd82e0fa3dad053cce03 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Feb 2016 13:19:10 -0800 Subject: clk: WARN_ON about to disable a critical clock Signed-off-by: Lee Jones Reviewed-by: Stephen Boyd Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1455225554-13267-3-git-send-email-mturquette@baylibre.com diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 275201f..dede0ce 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -574,6 +574,9 @@ static void clk_core_unprepare(struct clk_core *core) if (WARN_ON(core->prepare_count == 0)) return; + if (WARN_ON(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL)) + return; + if (--core->prepare_count > 0) return; @@ -679,6 +682,9 @@ static void clk_core_disable(struct clk_core *core) if (WARN_ON(core->enable_count == 0)) return; + if (WARN_ON(core->enable_count == 1 && core->flags & CLK_IS_CRITICAL)) + return; + if (--core->enable_count > 0) return; -- cgit v0.10.2 From d56f8994b6fb928f59481fabc25bcd1c2f9bd06d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 11 Feb 2016 13:19:11 -0800 Subject: clk: Provide OF helper to mark clocks as CRITICAL This call matches clocks which have been marked as critical in DT and sets the appropriate flag. These flags can then be used to mark the clock core flags appropriately prior to registration. Legacy bindings requiring this feature must add the clock-critical property to their binding descriptions, as it is not a part of common-clock binding. Cc: devicetree@vger.kernel.org Signed-off-by: Lee Jones Reviewed-by: Stephen Boyd Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1455225554-13267-4-git-send-email-mturquette@baylibre.com diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index dede0ce..9f77cc6 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3138,6 +3138,41 @@ static int parent_ready(struct device_node *np) } /** + * of_clk_detect_critical() - set CLK_IS_CRITICAL flag from Device Tree + * @np: Device node pointer associated with clock provider + * @index: clock index + * @flags: pointer to clk_core->flags + * + * Detects if the clock-critical property exists and, if so, sets the + * corresponding CLK_IS_CRITICAL flag. + * + * Do not use this function. It exists only for legacy Device Tree + * bindings, such as the one-clock-per-node style that are outdated. + * Those bindings typically put all clock data into .dts and the Linux + * driver has no clock data, thus making it impossible to set this flag + * correctly from the driver. Only those drivers may call + * of_clk_detect_critical from their setup functions. + * + * Return: error code or zero on success + */ +int of_clk_detect_critical(struct device_node *np, + int index, unsigned long *flags) +{ + struct property *prop; + const __be32 *cur; + uint32_t idx; + + if (!np || !flags) + return -EINVAL; + + of_property_for_each_u32(np, "clock-critical", prop, cur, idx) + if (index == idx) + *flags |= CLK_IS_CRITICAL; + + return 0; +} + +/** * of_clk_init() - Scan and init clock providers from the DT * @matches: array of compatible values and init functions for providers. * diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 0638b41..15628644 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -721,7 +721,8 @@ unsigned int of_clk_get_parent_count(struct device_node *np); int of_clk_parent_fill(struct device_node *np, const char **parents, unsigned int size); const char *of_clk_get_parent_name(struct device_node *np, int index); - +int of_clk_detect_critical(struct device_node *np, int index, + unsigned long *flags); void of_clk_init(const struct of_device_id *matches); #else /* !CONFIG_OF */ @@ -758,6 +759,11 @@ static inline const char *of_clk_get_parent_name(struct device_node *np, { return NULL; } +static inline int of_clk_detect_critical(struct device_node *np, int index, + unsigned long *flags) +{ + return 0; +} static inline void of_clk_init(const struct of_device_id *matches) {} #endif /* CONFIG_OF */ -- cgit v0.10.2 From 3218b21ab07f066c99537fbbf2b4dc331b842246 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 4 Apr 2016 22:28:33 -0700 Subject: clk: imx: vf610: fix DCU clock tree Similar to an earlier fix for the SAI clocks, the DCU clock hierarchy mixes the bus clock with the display controllers pixel clock. Tests have shown that the gates in CCM_CCGR3/9 registers do not control the DCU pixel clock, but only the register access clock (bus clock). Fix this by defining the parent clock of VF610_CLK_DCUx to be the bus clock (ipg_bus). Since the clock has not been used far, there are no further changes needed. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 66e6fae..60f14b9 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -372,11 +372,11 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_DCU0_SEL] = imx_clk_mux("dcu0_sel", CCM_CSCMR1, 28, 1, dcu_sels, 2); clk[VF610_CLK_DCU0_EN] = imx_clk_gate("dcu0_en", "dcu0_sel", CCM_CSCDR3, 19); clk[VF610_CLK_DCU0_DIV] = imx_clk_divider("dcu0_div", "dcu0_en", CCM_CSCDR3, 16, 3); - clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "dcu0_div", CCM_CCGR3, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "ipg_bus", CCM_CCGR3, CCM_CCGRx_CGn(8)); clk[VF610_CLK_DCU1_SEL] = imx_clk_mux("dcu1_sel", CCM_CSCMR1, 29, 1, dcu_sels, 2); clk[VF610_CLK_DCU1_EN] = imx_clk_gate("dcu1_en", "dcu1_sel", CCM_CSCDR3, 23); clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3); - clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(8)); clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4); clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30); -- cgit v0.10.2 From afd7350a9ac08da87eb9f38a432a05eca99c10f2 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 12 Apr 2016 08:59:38 +0800 Subject: clk: imx: vf610: add TCON ipg clock Add the ipg (bus) clock for the TCON modules (Timing Controller). This module is required by the new DCU DRM driver, since the display signals pass through TCON. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 60f14b9..3a1f244 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -378,6 +378,9 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3); clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13)); + clk[VF610_CLK_TCON1] = imx_clk_gate2("tcon1", "platform_bus", CCM_CCGR7, CCM_CCGRx_CGn(13)); + clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4); clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30); clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4); diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index 7dc1b84..dc5e179 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -197,6 +197,8 @@ #define VF610_CLK_OCOTP 184 #define VF610_CLK_DDRMC 185 #define VF610_CLK_WKPU 186 -#define VF610_CLK_END 187 +#define VF610_CLK_TCON0 187 +#define VF610_CLK_TCON1 188 +#define VF610_CLK_END 189 #endif /* __DT_BINDINGS_CLOCK_VF610_H */ -- cgit v0.10.2 From 69c542e8022ca53c5fee664548163809eb1777c3 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 12 Apr 2016 09:22:49 +0800 Subject: clk: imx: vf610: fix whitespace in vf610-clock.h There is whitespace in VF610_CLK_OCOTP line. Fix it. Signed-off-by: Shawn Guo diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index dc5e179..4599775 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -194,7 +194,7 @@ #define VF610_PLL7_BYPASS 181 #define VF610_CLK_SNVS 182 #define VF610_CLK_DAP 183 -#define VF610_CLK_OCOTP 184 +#define VF610_CLK_OCOTP 184 #define VF610_CLK_DDRMC 185 #define VF610_CLK_WKPU 186 #define VF610_CLK_TCON0 187 -- cgit v0.10.2 From 72b67b3fcb5f500e73dfd42dce3a4749ba84e4bf Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 15 Apr 2016 15:32:52 +0900 Subject: dt-bindings: clock: Add the clock id for ACLK clock of Exynos542x SoC This patch adds the clock id for ACLK clock of Exynos542x SoC. ACLK clock means the source clock of AMBA AXI bus. This clock id should be used for Bus frequency scaling. Signed-off-by: Chanwoo Choi Tested-by: Markus Reichl Tested-by: Anand Moon Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h index 7699ee9..17ab839 100644 --- a/include/dt-bindings/clock/exynos5420.h +++ b/include/dt-bindings/clock/exynos5420.h @@ -217,8 +217,30 @@ /* divider clocks */ #define CLK_DOUT_PIXEL 768 +#define CLK_DOUT_ACLK400_WCORE 769 +#define CLK_DOUT_ACLK400_ISP 770 +#define CLK_DOUT_ACLK400_MSCL 771 +#define CLK_DOUT_ACLK200 772 +#define CLK_DOUT_ACLK200_FSYS2 773 +#define CLK_DOUT_ACLK100_NOC 774 +#define CLK_DOUT_PCLK200_FSYS 775 +#define CLK_DOUT_ACLK200_FSYS 776 +#define CLK_DOUT_ACLK333_432_GSCL 777 +#define CLK_DOUT_ACLK333_432_ISP 778 +#define CLK_DOUT_ACLK66 779 +#define CLK_DOUT_ACLK333_432_ISP0 780 +#define CLK_DOUT_ACLK266 781 +#define CLK_DOUT_ACLK166 782 +#define CLK_DOUT_ACLK333 783 +#define CLK_DOUT_ACLK333_G2D 784 +#define CLK_DOUT_ACLK266_G2D 785 +#define CLK_DOUT_ACLK_G3D 786 +#define CLK_DOUT_ACLK300_JPEG 787 +#define CLK_DOUT_ACLK300_DISP1 788 +#define CLK_DOUT_ACLK300_GSCL 789 +#define CLK_DOUT_ACLK400_DISP1 790 /* must be greater than maximal clock id */ -#define CLK_NR_CLKS 769 +#define CLK_NR_CLKS 791 #endif /* _DT_BINDINGS_CLOCK_EXYNOS_5420_H */ -- cgit v0.10.2 From 81fed6e342c04a4ecb0650c914d24bd57c6c168f Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 15 Apr 2016 15:32:53 +0900 Subject: clk: samsung: exynos542x: Add the clock id for ACLK This patch adds the clock id for ACLK clock which is source clock of AMBA AXI bus. This clock should be handled in the bus frequency scaling driver. Signed-off-by: Chanwoo Choi Tested-by: Markus Reichl Tested-by: Anand Moon Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index be03ed0..92382ce 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -554,8 +554,8 @@ static struct samsung_mux_clock exynos5800_mux_clks[] __initdata = { }; static struct samsung_div_clock exynos5800_div_clks[] __initdata = { - DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore", DIV_TOP0, 16, 3), - + DIV(CLK_DOUT_ACLK400_WCORE, "dout_aclk400_wcore", + "mout_aclk400_wcore", DIV_TOP0, 16, 3), DIV(0, "dout_aclk550_cam", "mout_aclk550_cam", DIV_TOP8, 16, 3), DIV(0, "dout_aclkfl1_550_cam", "mout_aclkfl1_550_cam", @@ -607,8 +607,8 @@ static struct samsung_mux_clock exynos5420_mux_clks[] __initdata = { }; static struct samsung_div_clock exynos5420_div_clks[] __initdata = { - DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore_bpll", - DIV_TOP0, 16, 3), + DIV(CLK_DOUT_ACLK400_WCORE, "dout_aclk400_wcore", + "mout_aclk400_wcore_bpll", DIV_TOP0, 16, 3), }; static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = { @@ -785,31 +785,47 @@ static struct samsung_div_clock exynos5x_div_clks[] __initdata = { DIV(0, "div_kfc", "mout_kfc", DIV_KFC0, 0, 3), DIV(0, "sclk_kpll", "mout_kpll", DIV_KFC0, 24, 3), - DIV(0, "dout_aclk400_isp", "mout_aclk400_isp", DIV_TOP0, 0, 3), - DIV(0, "dout_aclk400_mscl", "mout_aclk400_mscl", DIV_TOP0, 4, 3), - DIV(0, "dout_aclk200", "mout_aclk200", DIV_TOP0, 8, 3), - DIV(0, "dout_aclk200_fsys2", "mout_aclk200_fsys2", DIV_TOP0, 12, 3), - DIV(0, "dout_aclk100_noc", "mout_aclk100_noc", DIV_TOP0, 20, 3), - DIV(0, "dout_pclk200_fsys", "mout_pclk200_fsys", DIV_TOP0, 24, 3), - DIV(0, "dout_aclk200_fsys", "mout_aclk200_fsys", DIV_TOP0, 28, 3), - - DIV(0, "dout_aclk333_432_gscl", "mout_aclk333_432_gscl", - DIV_TOP1, 0, 3), - DIV(0, "dout_aclk333_432_isp", "mout_aclk333_432_isp", - DIV_TOP1, 4, 3), - DIV(0, "dout_aclk66", "mout_aclk66", DIV_TOP1, 8, 6), - DIV(0, "dout_aclk333_432_isp0", "mout_aclk333_432_isp0", - DIV_TOP1, 16, 3), - DIV(0, "dout_aclk266", "mout_aclk266", DIV_TOP1, 20, 3), - DIV(0, "dout_aclk166", "mout_aclk166", DIV_TOP1, 24, 3), - DIV(0, "dout_aclk333", "mout_aclk333", DIV_TOP1, 28, 3), - - DIV(0, "dout_aclk333_g2d", "mout_aclk333_g2d", DIV_TOP2, 8, 3), - DIV(0, "dout_aclk266_g2d", "mout_aclk266_g2d", DIV_TOP2, 12, 3), - DIV(0, "dout_aclk_g3d", "mout_aclk_g3d", DIV_TOP2, 16, 3), - DIV(0, "dout_aclk300_jpeg", "mout_aclk300_jpeg", DIV_TOP2, 20, 3), - DIV(0, "dout_aclk300_disp1", "mout_aclk300_disp1", DIV_TOP2, 24, 3), - DIV(0, "dout_aclk300_gscl", "mout_aclk300_gscl", DIV_TOP2, 28, 3), + DIV(CLK_DOUT_ACLK400_ISP, "dout_aclk400_isp", "mout_aclk400_isp", + DIV_TOP0, 0, 3), + DIV(CLK_DOUT_ACLK400_MSCL, "dout_aclk400_mscl", "mout_aclk400_mscl", + DIV_TOP0, 4, 3), + DIV(CLK_DOUT_ACLK200, "dout_aclk200", "mout_aclk200", + DIV_TOP0, 8, 3), + DIV(CLK_DOUT_ACLK200_FSYS2, "dout_aclk200_fsys2", "mout_aclk200_fsys2", + DIV_TOP0, 12, 3), + DIV(CLK_DOUT_ACLK100_NOC, "dout_aclk100_noc", "mout_aclk100_noc", + DIV_TOP0, 20, 3), + DIV(CLK_DOUT_PCLK200_FSYS, "dout_pclk200_fsys", "mout_pclk200_fsys", + DIV_TOP0, 24, 3), + DIV(CLK_DOUT_ACLK200_FSYS, "dout_aclk200_fsys", "mout_aclk200_fsys", + DIV_TOP0, 28, 3), + DIV(CLK_DOUT_ACLK333_432_GSCL, "dout_aclk333_432_gscl", + "mout_aclk333_432_gscl", DIV_TOP1, 0, 3), + DIV(CLK_DOUT_ACLK333_432_ISP, "dout_aclk333_432_isp", + "mout_aclk333_432_isp", DIV_TOP1, 4, 3), + DIV(CLK_DOUT_ACLK66, "dout_aclk66", "mout_aclk66", + DIV_TOP1, 8, 6), + DIV(CLK_DOUT_ACLK333_432_ISP0, "dout_aclk333_432_isp0", + "mout_aclk333_432_isp0", DIV_TOP1, 16, 3), + DIV(CLK_DOUT_ACLK266, "dout_aclk266", "mout_aclk266", + DIV_TOP1, 20, 3), + DIV(CLK_DOUT_ACLK166, "dout_aclk166", "mout_aclk166", + DIV_TOP1, 24, 3), + DIV(CLK_DOUT_ACLK333, "dout_aclk333", "mout_aclk333", + DIV_TOP1, 28, 3), + + DIV(CLK_DOUT_ACLK333_G2D, "dout_aclk333_g2d", "mout_aclk333_g2d", + DIV_TOP2, 8, 3), + DIV(CLK_DOUT_ACLK266_G2D, "dout_aclk266_g2d", "mout_aclk266_g2d", + DIV_TOP2, 12, 3), + DIV(CLK_DOUT_ACLK_G3D, "dout_aclk_g3d", "mout_aclk_g3d", DIV_TOP2, + 16, 3), + DIV(CLK_DOUT_ACLK300_JPEG, "dout_aclk300_jpeg", "mout_aclk300_jpeg", + DIV_TOP2, 20, 3), + DIV(CLK_DOUT_ACLK300_DISP1, "dout_aclk300_disp1", + "mout_aclk300_disp1", DIV_TOP2, 24, 3), + DIV(CLK_DOUT_ACLK300_GSCL, "dout_aclk300_gscl", "mout_aclk300_gscl", + DIV_TOP2, 28, 3), /* DISP1 Block */ DIV(0, "dout_fimd1", "mout_fimd1_final", DIV_DISP10, 0, 4), @@ -817,7 +833,8 @@ static struct samsung_div_clock exynos5x_div_clks[] __initdata = { DIV(0, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4), DIV(CLK_DOUT_PIXEL, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4), DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2), - DIV(0, "dout_aclk400_disp1", "mout_aclk400_disp1", DIV_TOP2, 4, 3), + DIV(CLK_DOUT_ACLK400_DISP1, "dout_aclk400_disp1", + "mout_aclk400_disp1", DIV_TOP2, 4, 3), /* Audio Block */ DIV(0, "dout_maudio0", "mout_maudio0", DIV_MAU, 20, 4), -- cgit v0.10.2 From 9e52cec04fd3b9b686f9256151b47fe61f7c28ef Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Tue, 12 Apr 2016 16:43:39 +0800 Subject: clk: Add clk_composite_set_rate_and_parent When changing the clock-rate, currently a new parent is set first and a divider adapted thereafter. This may result in the clock-rate overflowing its target rate for a short time if the new parent has a higher rate than the old parent. While this often doesn't produce negative effects, it can affect components in a voltage-scaling environment, like the GPU on the rk3399 socs, where the voltage than simply is to low for the temporarily to high clock rate. For general clock hirarchies this may need more extensive adaptions to the common clock-framework, but at least for composite clocks having both parent and rate settings it is easy to create a short-term solution to make sure the clock-rate does not overflow the target. Signed-off-by: Finley Xiao Reviewed-by: Heiko Stuebner Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 1f903e1f8..4d4b5ab 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -151,6 +151,33 @@ static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate, return rate_ops->set_rate(rate_hw, rate, parent_rate); } +static int clk_composite_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *rate_ops = composite->rate_ops; + const struct clk_ops *mux_ops = composite->mux_ops; + struct clk_hw *rate_hw = composite->rate_hw; + struct clk_hw *mux_hw = composite->mux_hw; + unsigned long temp_rate; + + __clk_hw_set_clk(rate_hw, hw); + __clk_hw_set_clk(mux_hw, hw); + + temp_rate = rate_ops->recalc_rate(rate_hw, parent_rate); + if (temp_rate > rate) { + rate_ops->set_rate(rate_hw, rate, parent_rate); + mux_ops->set_parent(mux_hw, index); + } else { + mux_ops->set_parent(mux_hw, index); + rate_ops->set_rate(rate_hw, rate, parent_rate); + } + + return 0; +} + static int clk_composite_is_enabled(struct clk_hw *hw) { struct clk_composite *composite = to_clk_composite(hw); @@ -250,6 +277,12 @@ struct clk *clk_register_composite(struct device *dev, const char *name, composite->rate_ops = rate_ops; } + if (mux_hw && mux_ops && rate_hw && rate_ops) { + if (mux_ops->set_parent && rate_ops->set_rate) + clk_composite_ops->set_rate_and_parent = + clk_composite_set_rate_and_parent; + } + if (gate_hw && gate_ops) { if (!gate_ops->is_enabled || !gate_ops->enable || !gate_ops->disable) { -- cgit v0.10.2 From c02b73c943d723511abecde7909d0818638d1bc2 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 5 Apr 2016 13:28:57 -0500 Subject: clk: ti: dflt: remove redundant unlikely Commit 7aba4f5201d1 ("clk: ti: dflt: fix enable_reg validity check") fixed a validation check by using an IS_ERR() macro within the existing unlikely expression, but IS_ERR() macro already has an unlikely inside it, so get rid of the redundant unlikely macro from the validation check. Reported-by: Stephen Boyd Signed-off-by: Suman Anna Signed-off-by: Stephen Boyd diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c index 1ddc288..c6ae563 100644 --- a/drivers/clk/ti/clkt_dflt.c +++ b/drivers/clk/ti/clkt_dflt.c @@ -222,7 +222,7 @@ int omap2_dflt_clk_enable(struct clk_hw *hw) } } - if (unlikely(IS_ERR(clk->enable_reg))) { + if (IS_ERR(clk->enable_reg)) { pr_err("%s: %s missing enable_reg\n", __func__, clk_hw_get_name(hw)); ret = -EINVAL; -- cgit v0.10.2 From 67bad3e5ce82b9eea2428118d909b2c8b80a71cf Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Mon, 4 Apr 2016 11:23:22 +0200 Subject: clk: add device tree binding for Artpec-6 clock controller Add device tree documentation for the main clock controller in the Artpec-6 SoC. Acked-by: Rob Herring Signed-off-by: Lars Persson [sboyd@codeaurora.org: Added unit address to binding example] Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/artpec6.txt b/Documentation/devicetree/bindings/clock/artpec6.txt new file mode 100644 index 0000000..dff9cdf --- /dev/null +++ b/Documentation/devicetree/bindings/clock/artpec6.txt @@ -0,0 +1,41 @@ +* Clock bindings for Axis ARTPEC-6 chip + +The bindings are based on the clock provider binding in +Documentation/devicetree/bindings/clock/clock-bindings.txt + +External clocks: +---------------- + +There are two external inputs to the main clock controller which should be +provided using the common clock bindings. +- "sys_refclk": External 50 Mhz oscillator (required) +- "i2s_refclk": Alternate audio reference clock (optional). + +Main clock controller +--------------------- + +Required properties: +- #clock-cells: Should be <1> + See dt-bindings/clock/axis,artpec6-clkctrl.h for the list of valid identifiers. +- compatible: Should be "axis,artpec6-clkctrl" +- reg: Must contain the base address and length of the system controller +- clocks: Must contain a phandle entry for each clock in clock-names +- clock-names: Must include the external oscillator ("sys_refclk"). Optional + ones are the audio reference clock ("i2s_refclk") and the audio fractional + dividers ("frac_clk0" and "frac_clk1"). + +Examples: + +ext_clk: ext_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; +}; + +clkctrl: clkctrl@f8000000 { + #clock-cells = <1>; + compatible = "axis,artpec6-clkctrl"; + reg = <0xf8000000 0x48>; + clocks = <&ext_clk>; + clock-names = "sys_refclk"; +}; diff --git a/include/dt-bindings/clock/axis,artpec6-clkctrl.h b/include/dt-bindings/clock/axis,artpec6-clkctrl.h new file mode 100644 index 0000000..f9f04dc --- /dev/null +++ b/include/dt-bindings/clock/axis,artpec6-clkctrl.h @@ -0,0 +1,38 @@ +/* + * ARTPEC-6 clock controller indexes + * + * Copyright 2016 Axis Comunications AB. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H +#define DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H + +#define ARTPEC6_CLK_CPU 0 +#define ARTPEC6_CLK_CPU_PERIPH 1 +#define ARTPEC6_CLK_NAND_CLKA 2 +#define ARTPEC6_CLK_NAND_CLKB 3 +#define ARTPEC6_CLK_ETH_ACLK 4 +#define ARTPEC6_CLK_DMA_ACLK 5 +#define ARTPEC6_CLK_PTP_REF 6 +#define ARTPEC6_CLK_SD_PCLK 7 +#define ARTPEC6_CLK_SD_IMCLK 8 +#define ARTPEC6_CLK_I2S_HST 9 +#define ARTPEC6_CLK_I2S0_CLK 10 +#define ARTPEC6_CLK_I2S1_CLK 11 +#define ARTPEC6_CLK_UART_PCLK 12 +#define ARTPEC6_CLK_UART_REFCLK 13 +#define ARTPEC6_CLK_I2C 14 +#define ARTPEC6_CLK_SPI_PCLK 15 +#define ARTPEC6_CLK_SPI_SSPCLK 16 +#define ARTPEC6_CLK_SYS_TIMER 17 +#define ARTPEC6_CLK_FRACDIV_IN 18 +#define ARTPEC6_CLK_DBG_PCLK 19 + +/* This must be the highest clock index plus one. */ +#define ARTPEC6_CLK_NUMCLOCKS 20 + +#endif -- cgit v0.10.2 From 33b8ac917a8f7a22fa3d779f875646201d0097a0 Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Mon, 4 Apr 2016 11:23:23 +0200 Subject: clk: add artpec-6 clock controller Add a driver for the main clock controller of the Artpec-6 Soc. Signed-off-by: Lars Persson [sboyd@codeaurora.org: Reformatted driver structure and of match] Signed-off-by: Stephen Boyd diff --git a/MAINTAINERS b/MAINTAINERS index 03e00c7..05aeee0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -973,7 +973,7 @@ S: Maintained L: linux-arm-kernel@axis.com F: arch/arm/mach-artpec F: arch/arm/boot/dts/artpec6* -F: drivers/clk/clk-artpec6.c +F: drivers/clk/axis ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT M: Nicolas Ferre diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 46869d6..ca9aa7b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +obj-$(CONFIG_ARCH_ARTPEC) += axis/ obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/clk/axis/Makefile b/drivers/clk/axis/Makefile new file mode 100644 index 0000000..628c9d3 --- /dev/null +++ b/drivers/clk/axis/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MACH_ARTPEC6) += clk-artpec6.o diff --git a/drivers/clk/axis/clk-artpec6.c b/drivers/clk/axis/clk-artpec6.c new file mode 100644 index 0000000..ffc988b --- /dev/null +++ b/drivers/clk/axis/clk-artpec6.c @@ -0,0 +1,242 @@ +/* + * ARTPEC-6 clock initialization + * + * Copyright 2015-2016 Axis Comunications AB. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NUM_I2S_CLOCKS 2 + +struct artpec6_clkctrl_drvdata { + struct clk *clk_table[ARTPEC6_CLK_NUMCLOCKS]; + void __iomem *syscon_base; + struct clk_onecell_data clk_data; + spinlock_t i2scfg_lock; +}; + +static struct artpec6_clkctrl_drvdata *clkdata; + +static const char *const i2s_clk_names[NUM_I2S_CLOCKS] = { + "i2s0", + "i2s1", +}; + +static const int i2s_clk_indexes[NUM_I2S_CLOCKS] = { + ARTPEC6_CLK_I2S0_CLK, + ARTPEC6_CLK_I2S1_CLK, +}; + +static void of_artpec6_clkctrl_setup(struct device_node *np) +{ + int i; + const char *sys_refclk_name; + u32 pll_mode, pll_m, pll_n; + struct clk **clks; + + /* Mandatory parent clock. */ + i = of_property_match_string(np, "clock-names", "sys_refclk"); + if (i < 0) + return; + + sys_refclk_name = of_clk_get_parent_name(np, i); + + clkdata = kzalloc(sizeof(*clkdata), GFP_KERNEL); + if (!clkdata) + return; + + clks = clkdata->clk_table; + + for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i) + clks[i] = ERR_PTR(-EPROBE_DEFER); + + clkdata->syscon_base = of_iomap(np, 0); + BUG_ON(clkdata->syscon_base == NULL); + + /* Read PLL1 factors configured by boot strap pins. */ + pll_mode = (readl(clkdata->syscon_base) >> 6) & 3; + switch (pll_mode) { + case 0: /* DDR3-2133 mode */ + pll_m = 4; + pll_n = 85; + break; + case 1: /* DDR3-1866 mode */ + pll_m = 6; + pll_n = 112; + break; + case 2: /* DDR3-1600 mode */ + pll_m = 4; + pll_n = 64; + break; + case 3: /* DDR3-1333 mode */ + pll_m = 8; + pll_n = 106; + break; + } + + clks[ARTPEC6_CLK_CPU] = + clk_register_fixed_factor(NULL, "cpu", sys_refclk_name, 0, pll_n, + pll_m); + clks[ARTPEC6_CLK_CPU_PERIPH] = + clk_register_fixed_factor(NULL, "cpu_periph", "cpu", 0, 1, 2); + + /* EPROBE_DEFER on the apb_clock is not handled in amba devices. */ + clks[ARTPEC6_CLK_UART_PCLK] = + clk_register_fixed_factor(NULL, "uart_pclk", "cpu", 0, 1, 8); + clks[ARTPEC6_CLK_UART_REFCLK] = + clk_register_fixed_rate(NULL, "uart_ref", sys_refclk_name, 0, + 50000000); + + clks[ARTPEC6_CLK_SPI_PCLK] = + clk_register_fixed_factor(NULL, "spi_pclk", "cpu", 0, 1, 8); + clks[ARTPEC6_CLK_SPI_SSPCLK] = + clk_register_fixed_rate(NULL, "spi_sspclk", sys_refclk_name, 0, + 50000000); + + clks[ARTPEC6_CLK_DBG_PCLK] = + clk_register_fixed_factor(NULL, "dbg_pclk", "cpu", 0, 1, 8); + + clkdata->clk_data.clks = clkdata->clk_table; + clkdata->clk_data.clk_num = ARTPEC6_CLK_NUMCLOCKS; + + of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data); +} + +CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl", + of_artpec6_clkctrl_setup); + +static int artpec6_clkctrl_probe(struct platform_device *pdev) +{ + int propidx; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct clk **clks = clkdata->clk_table; + const char *sys_refclk_name; + const char *i2s_refclk_name = NULL; + const char *frac_clk_name[2] = { NULL, NULL }; + const char *i2s_mux_parents[2]; + u32 muxreg; + int i; + int err = 0; + + /* Mandatory parent clock. */ + propidx = of_property_match_string(np, "clock-names", "sys_refclk"); + if (propidx < 0) + return -EINVAL; + + sys_refclk_name = of_clk_get_parent_name(np, propidx); + + /* Find clock names of optional parent clocks. */ + propidx = of_property_match_string(np, "clock-names", "i2s_refclk"); + if (propidx >= 0) + i2s_refclk_name = of_clk_get_parent_name(np, propidx); + + propidx = of_property_match_string(np, "clock-names", "frac_clk0"); + if (propidx >= 0) + frac_clk_name[0] = of_clk_get_parent_name(np, propidx); + propidx = of_property_match_string(np, "clock-names", "frac_clk1"); + if (propidx >= 0) + frac_clk_name[1] = of_clk_get_parent_name(np, propidx); + + spin_lock_init(&clkdata->i2scfg_lock); + + clks[ARTPEC6_CLK_NAND_CLKA] = + clk_register_fixed_factor(dev, "nand_clka", "cpu", 0, 1, 8); + clks[ARTPEC6_CLK_NAND_CLKB] = + clk_register_fixed_rate(dev, "nand_clkb", sys_refclk_name, 0, + 100000000); + clks[ARTPEC6_CLK_ETH_ACLK] = + clk_register_fixed_factor(dev, "eth_aclk", "cpu", 0, 1, 4); + clks[ARTPEC6_CLK_DMA_ACLK] = + clk_register_fixed_factor(dev, "dma_aclk", "cpu", 0, 1, 4); + clks[ARTPEC6_CLK_PTP_REF] = + clk_register_fixed_rate(dev, "ptp_ref", sys_refclk_name, 0, + 100000000); + clks[ARTPEC6_CLK_SD_PCLK] = + clk_register_fixed_rate(dev, "sd_pclk", sys_refclk_name, 0, + 100000000); + clks[ARTPEC6_CLK_SD_IMCLK] = + clk_register_fixed_rate(dev, "sd_imclk", sys_refclk_name, 0, + 100000000); + clks[ARTPEC6_CLK_I2S_HST] = + clk_register_fixed_factor(dev, "i2s_hst", "cpu", 0, 1, 8); + + for (i = 0; i < NUM_I2S_CLOCKS; ++i) { + if (i2s_refclk_name && frac_clk_name[i]) { + i2s_mux_parents[0] = frac_clk_name[i]; + i2s_mux_parents[1] = i2s_refclk_name; + + clks[i2s_clk_indexes[i]] = + clk_register_mux(dev, i2s_clk_names[i], + i2s_mux_parents, 2, + CLK_SET_RATE_NO_REPARENT | + CLK_SET_RATE_PARENT, + clkdata->syscon_base + 0x14, i, 1, + 0, &clkdata->i2scfg_lock); + } else if (frac_clk_name[i]) { + /* Lock the mux for internal clock reference. */ + muxreg = readl(clkdata->syscon_base + 0x14); + muxreg &= ~BIT(i); + writel(muxreg, clkdata->syscon_base + 0x14); + clks[i2s_clk_indexes[i]] = + clk_register_fixed_factor(dev, i2s_clk_names[i], + frac_clk_name[i], 0, 1, + 1); + } else if (i2s_refclk_name) { + /* Lock the mux for external clock reference. */ + muxreg = readl(clkdata->syscon_base + 0x14); + muxreg |= BIT(i); + writel(muxreg, clkdata->syscon_base + 0x14); + clks[i2s_clk_indexes[i]] = + clk_register_fixed_factor(dev, i2s_clk_names[i], + i2s_refclk_name, 0, 1, 1); + } + } + + clks[ARTPEC6_CLK_I2C] = + clk_register_fixed_rate(dev, "i2c", sys_refclk_name, 0, 100000000); + + clks[ARTPEC6_CLK_SYS_TIMER] = + clk_register_fixed_rate(dev, "timer", sys_refclk_name, 0, + 100000000); + clks[ARTPEC6_CLK_FRACDIV_IN] = + clk_register_fixed_rate(dev, "fracdiv_in", sys_refclk_name, 0, + 600000000); + + for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i) { + if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -EPROBE_DEFER) { + dev_err(dev, + "Failed to register clock at index %d err=%ld\n", + i, PTR_ERR(clks[i])); + err = PTR_ERR(clks[i]); + } + } + + return err; +} + +static const struct of_device_id artpec_clkctrl_of_match[] = { + { .compatible = "axis,artpec6-clkctrl" }, + {} +}; + +static struct platform_driver artpec6_clkctrl_driver = { + .probe = artpec6_clkctrl_probe, + .driver = { + .name = "artpec6_clkctrl", + .of_match_table = artpec_clkctrl_of_match, + }, +}; + +builtin_platform_driver(artpec6_clkctrl_driver); -- cgit v0.10.2 From f2d32b623c774ee63151a308a6bd79b4e543a4ee Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 10:59:51 -0800 Subject: clk: meson: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Carlo Caione Signed-off-by: Stephen Boyd diff --git a/drivers/clk/meson/meson8b-clkc.c b/drivers/clk/meson/meson8b-clkc.c index 61f6d55..4d057b3 100644 --- a/drivers/clk/meson/meson8b-clkc.c +++ b/drivers/clk/meson/meson8b-clkc.c @@ -141,11 +141,11 @@ static const struct composite_conf mali_conf __initconst = { }; static const struct clk_conf meson8b_xtal_conf __initconst = - FIXED_RATE_P(MESON8B_REG_CTL0_ADDR, CLKID_XTAL, "xtal", - CLK_IS_ROOT, PARM(0x00, 4, 7)); + FIXED_RATE_P(MESON8B_REG_CTL0_ADDR, CLKID_XTAL, "xtal", 0, + PARM(0x00, 4, 7)); static const struct clk_conf meson8b_clk_confs[] __initconst = { - FIXED_RATE(CLKID_ZERO, "zero", CLK_IS_ROOT, 0), + FIXED_RATE(CLKID_ZERO, "zero", 0, 0), PLL(MESON8B_REG_PLL_FIXED, CLKID_PLL_FIXED, "fixed_pll", p_xtal, 0, &pll_confs), PLL(MESON8B_REG_PLL_VID, CLKID_PLL_VID, "vid_pll", -- cgit v0.10.2 From 536630ddbffb97e5a9de76a2d793ec118413e758 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 10:59:52 -0800 Subject: clk: mmp: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Chao Xie Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c index 38931db..383f6a4 100644 --- a/drivers/clk/mmp/clk-mmp2.c +++ b/drivers/clk/mmp/clk-mmp2.c @@ -99,23 +99,19 @@ void __init mmp2_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys, return; } - clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); + clk = clk_register_fixed_rate(NULL, "clk32", NULL, 0, 3200); clk_register_clkdev(clk, "clk32", NULL); - vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, - 26000000); + vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, 0, 26000000); clk_register_clkdev(vctcxo, "vctcxo", NULL); - clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, - 800000000); + clk = clk_register_fixed_rate(NULL, "pll1", NULL, 0, 800000000); clk_register_clkdev(clk, "pll1", NULL); - clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, CLK_IS_ROOT, - 480000000); + clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, 0, 480000000); clk_register_clkdev(clk, "usb_pll", NULL); - clk = clk_register_fixed_rate(NULL, "pll2", NULL, CLK_IS_ROOT, - 960000000); + clk = clk_register_fixed_rate(NULL, "pll2", NULL, 0, 960000000); clk_register_clkdev(clk, "pll2", NULL); clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 251533d..3a51fff 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -63,11 +63,11 @@ struct mmp2_clk_unit { }; static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { - {MMP2_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, - {MMP2_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, - {MMP2_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 800000000}, - {MMP2_CLK_PLL2, "pll2", NULL, CLK_IS_ROOT, 960000000}, - {MMP2_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, + {MMP2_CLK_CLK32, "clk32", NULL, 0, 32768}, + {MMP2_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000}, + {MMP2_CLK_PLL1, "pll1", NULL, 0, 800000000}, + {MMP2_CLK_PLL2, "pll2", NULL, 0, 960000000}, + {MMP2_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000}, }; static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c index 64eaf41..87f2317 100644 --- a/drivers/clk/mmp/clk-of-pxa168.c +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -56,10 +56,10 @@ struct pxa168_clk_unit { }; static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { - {PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, - {PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, - {PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, - {PXA168_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, + {PXA168_CLK_CLK32, "clk32", NULL, 0, 32768}, + {PXA168_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000}, + {PXA168_CLK_PLL1, "pll1", NULL, 0, 624000000}, + {PXA168_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000}, }; static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { diff --git a/drivers/clk/mmp/clk-of-pxa1928.c b/drivers/clk/mmp/clk-of-pxa1928.c index 433a5ae..e478ff4 100644 --- a/drivers/clk/mmp/clk-of-pxa1928.c +++ b/drivers/clk/mmp/clk-of-pxa1928.c @@ -34,12 +34,12 @@ struct pxa1928_clk_unit { }; static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { - {0, "clk32", NULL, CLK_IS_ROOT, 32768}, - {0, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, - {0, "pll1_624", NULL, CLK_IS_ROOT, 624000000}, - {0, "pll5p", NULL, CLK_IS_ROOT, 832000000}, - {0, "pll5", NULL, CLK_IS_ROOT, 1248000000}, - {0, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, + {0, "clk32", NULL, 0, 32768}, + {0, "vctcxo", NULL, 0, 26000000}, + {0, "pll1_624", NULL, 0, 624000000}, + {0, "pll5p", NULL, 0, 832000000}, + {0, "pll5", NULL, 0, 1248000000}, + {0, "usb_pll", NULL, 0, 480000000}, }; static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c index 13d6173..e22a67f 100644 --- a/drivers/clk/mmp/clk-of-pxa910.c +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -56,10 +56,10 @@ struct pxa910_clk_unit { }; static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { - {PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, - {PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, - {PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, - {PXA910_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, + {PXA910_CLK_CLK32, "clk32", NULL, 0, 32768}, + {PXA910_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000}, + {PXA910_CLK_PLL1, "pll1", NULL, 0, 624000000}, + {PXA910_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000}, }; static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c index 0dd83fb..a9ef920 100644 --- a/drivers/clk/mmp/clk-pxa168.c +++ b/drivers/clk/mmp/clk-pxa168.c @@ -92,15 +92,13 @@ void __init pxa168_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys, return; } - clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); + clk = clk_register_fixed_rate(NULL, "clk32", NULL, 0, 3200); clk_register_clkdev(clk, "clk32", NULL); - clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, - 26000000); + clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, 0, 26000000); clk_register_clkdev(clk, "vctcxo", NULL); - clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, - 624000000); + clk = clk_register_fixed_rate(NULL, "pll1", NULL, 0, 624000000); clk_register_clkdev(clk, "pll1", NULL); clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c index e1d2ce2..a520cf7 100644 --- a/drivers/clk/mmp/clk-pxa910.c +++ b/drivers/clk/mmp/clk-pxa910.c @@ -97,15 +97,13 @@ void __init pxa910_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys, return; } - clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); + clk = clk_register_fixed_rate(NULL, "clk32", NULL, 0, 3200); clk_register_clkdev(clk, "clk32", NULL); - clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, - 26000000); + clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, 0, 26000000); clk_register_clkdev(clk, "vctcxo", NULL); - clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, - 624000000); + clk = clk_register_fixed_rate(NULL, "pll1", NULL, 0, 624000000); clk_register_clkdev(clk, "pll1", NULL); clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", -- cgit v0.10.2 From 23ced2711bcdd26163f1188f693d6379ab0c6bf3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 10:59:59 -0800 Subject: clk: sirf: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Guo Zeng Cc: Barry Song Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c index c5eaa9d..665fa68 100644 --- a/drivers/clk/sirf/clk-atlas6.c +++ b/drivers/clk/sirf/clk-atlas6.c @@ -130,10 +130,9 @@ static void __init atlas6_clk_init(struct device_node *np) panic("unable to map clkc registers\n"); /* These are always available (RTC and 26MHz OSC)*/ - atlas6_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL, - CLK_IS_ROOT, 32768); - atlas6_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL, - CLK_IS_ROOT, 26000000); + atlas6_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL, 0, 32768); + atlas6_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL, 0, + 26000000); for (i = pll1; i < maxclk; i++) { atlas6_clks[i] = clk_register(NULL, atlas6_clk_hw_array[i]); diff --git a/drivers/clk/sirf/clk-prima2.c b/drivers/clk/sirf/clk-prima2.c index f92c402..aac1c8ec 100644 --- a/drivers/clk/sirf/clk-prima2.c +++ b/drivers/clk/sirf/clk-prima2.c @@ -129,10 +129,9 @@ static void __init prima2_clk_init(struct device_node *np) panic("unable to map clkc registers\n"); /* These are always available (RTC and 26MHz OSC)*/ - prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL, - CLK_IS_ROOT, 32768); - prima2_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL, - CLK_IS_ROOT, 26000000); + prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL, 0, 32768); + prima2_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL, 0, + 26000000); for (i = pll1; i < maxclk; i++) { prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]); -- cgit v0.10.2 From 260c37f92a420958c25ab404e7f03a1cd3b04843 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:01 -0800 Subject: clk: sunxi: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Maxime Ripard Cc: Chen-Yu Tsai Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi/clk-a10-hosc.c b/drivers/clk/sunxi/clk-a10-hosc.c index 6b598c6..dca5324 100644 --- a/drivers/clk/sunxi/clk-a10-hosc.c +++ b/drivers/clk/sunxi/clk-a10-hosc.c @@ -54,8 +54,7 @@ static void __init sun4i_osc_clk_setup(struct device_node *node) NULL, 0, NULL, NULL, &fixed->hw, &clk_fixed_rate_ops, - &gate->hw, &clk_gate_ops, - CLK_IS_ROOT); + &gate->hw, &clk_gate_ops, 0); if (IS_ERR(clk)) goto err_free_gate; -- cgit v0.10.2 From c9bb8a4f3db60342ad97f7eb77965a6ae30851bb Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:08 -0800 Subject: clk: zte: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Jun Nie Signed-off-by: Stephen Boyd diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c index ebd20d8..76e967c 100644 --- a/drivers/clk/zte/clk-zx296702.c +++ b/drivers/clk/zte/clk-zx296702.c @@ -234,8 +234,7 @@ static void __init zx296702_top_clocks_init(struct device_node *np) WARN_ON(!topcrm_base); clk[ZX296702_OSC] = - clk_register_fixed_rate(NULL, "osc", NULL, CLK_IS_ROOT, - 30000000); + clk_register_fixed_rate(NULL, "osc", NULL, 0, 30000000); clk[ZX296702_PLL_A9] = clk_register_zx_pll("pll_a9", "osc", 0, topcrm_base + 0x01c, pll_a9_config, -- cgit v0.10.2 From 26659ada14cece0d0705f4e020dab634db2f95cc Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:10 -0800 Subject: clk: clps711x: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Alexander Shiyan Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index ff4ef4f..1f60b02 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -107,16 +107,15 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, writel(tmp, base + CLPS711X_SYSCON1); clps711x_clk->clks[CLPS711X_CLK_DUMMY] = - clk_register_fixed_rate(NULL, "dummy", NULL, CLK_IS_ROOT, 0); + clk_register_fixed_rate(NULL, "dummy", NULL, 0, 0); clps711x_clk->clks[CLPS711X_CLK_CPU] = - clk_register_fixed_rate(NULL, "cpu", NULL, CLK_IS_ROOT, f_cpu); + clk_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu); clps711x_clk->clks[CLPS711X_CLK_BUS] = - clk_register_fixed_rate(NULL, "bus", NULL, CLK_IS_ROOT, f_bus); + clk_register_fixed_rate(NULL, "bus", NULL, 0, f_bus); clps711x_clk->clks[CLPS711X_CLK_PLL] = - clk_register_fixed_rate(NULL, "pll", NULL, CLK_IS_ROOT, f_pll); + clk_register_fixed_rate(NULL, "pll", NULL, 0, f_pll); clps711x_clk->clks[CLPS711X_CLK_TIMERREF] = - clk_register_fixed_rate(NULL, "timer_ref", NULL, CLK_IS_ROOT, - f_tim); + clk_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim); clps711x_clk->clks[CLPS711X_CLK_TIMER1] = clk_register_divider_table(NULL, "timer1", "timer_ref", 0, base + CLPS711X_SYSCON1, 5, 1, 0, @@ -126,10 +125,9 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, base + CLPS711X_SYSCON1, 7, 1, 0, timer_div_table, &clps711x_clk->lock); clps711x_clk->clks[CLPS711X_CLK_PWM] = - clk_register_fixed_rate(NULL, "pwm", NULL, CLK_IS_ROOT, f_pwm); + clk_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm); clps711x_clk->clks[CLPS711X_CLK_SPIREF] = - clk_register_fixed_rate(NULL, "spi_ref", NULL, CLK_IS_ROOT, - f_spi); + clk_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi); clps711x_clk->clks[CLPS711X_CLK_SPI] = clk_register_divider_table(NULL, "spi", "spi_ref", 0, base + CLPS711X_SYSCON1, 16, 2, 0, @@ -137,8 +135,7 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, clps711x_clk->clks[CLPS711X_CLK_UART] = clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); clps711x_clk->clks[CLPS711X_CLK_TICK] = - clk_register_fixed_rate(NULL, "tick", NULL, CLK_IS_ROOT, 64); - + clk_register_fixed_rate(NULL, "tick", NULL, 0, 64); for (i = 0; i < CLPS711X_CLK_MAX; i++) if (IS_ERR(clps711x_clk->clks[i])) pr_err("clk %i: register failed with %ld\n", -- cgit v0.10.2 From 3be32b79a1c3b99d5f0d266eaa2e727a672f62db Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:13 -0800 Subject: clk: ls1x: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Kelvin Cheung Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c index d4c6198..5097831 100644 --- a/drivers/clk/clk-ls1x.c +++ b/drivers/clk/clk-ls1x.c @@ -88,8 +88,7 @@ void __init ls1x_clk_init(void) { struct clk *clk; - clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, CLK_IS_ROOT, - OSC); + clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); clk_register_clkdev(clk, "osc_33m_clk", NULL); /* clock derived from 33 MHz OSC clk */ -- cgit v0.10.2 From 1efee90d275fe7b22ae0320adb6c9bb49937a9d8 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:16 -0800 Subject: clk: nspire: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Daniel Tang Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c index a378db7..64f196a 100644 --- a/drivers/clk/clk-nspire.c +++ b/drivers/clk/clk-nspire.c @@ -125,8 +125,7 @@ static void __init nspire_clk_setup(struct device_node *node, of_property_read_string(node, "clock-output-names", &clk_name); - clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, - info.base_clock); + clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, info.base_clock); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); else -- cgit v0.10.2 From 1fb4742a268726293f022097f85f13fa3856ea49 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:17 -0800 Subject: clk: palmas: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Peter Ujfalusi Cc: Nishanth Menon Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index 9c0b8e6..8328863 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c @@ -132,7 +132,7 @@ static const struct palmas_clks_of_match_data palmas_of_clk32kg = { .init = { .name = "clk32kg", .ops = &palmas_clks_ops, - .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED, + .flags = CLK_IGNORE_UNUSED, }, .desc = { .clk_name = "clk32kg", @@ -148,7 +148,7 @@ static const struct palmas_clks_of_match_data palmas_of_clk32kgaudio = { .init = { .name = "clk32kgaudio", .ops = &palmas_clks_ops, - .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED, + .flags = CLK_IGNORE_UNUSED, }, .desc = { .clk_name = "clk32kgaudio", -- cgit v0.10.2 From ec3f2fcb32060f3f31ffc778879553367e71ceaf Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:19 -0800 Subject: clk: qoriq: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Hou Zhiqiang Cc: Scott Wood Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 7bc1c45..d247b75 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -876,7 +876,7 @@ static struct clk *sysclk_from_fixed(struct device_node *node, const char *name) if (of_property_read_u32(node, "clock-frequency", &rate)) return ERR_PTR(-ENODEV); - return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); + return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } static struct clk *sysclk_from_parent(const char *name) -- cgit v0.10.2 From 7ecf47c2c292e25947c2aa95293c52145997f67f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:20 -0800 Subject: clk: rk808: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Chris Zhong Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c index 0fee2f4..7438303 100644 --- a/drivers/clk/clk-rk808.c +++ b/drivers/clk/clk-rk808.c @@ -106,7 +106,6 @@ static int rk808_clkout_probe(struct platform_device *pdev) if (!clk_table) return -ENOMEM; - init.flags = CLK_IS_ROOT; init.parent_names = NULL; init.num_parents = 0; init.name = "rk808-clkout1"; -- cgit v0.10.2 From d4da52c38c38366689db437327fe8385957b970c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:24 -0800 Subject: clk: twl6040: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Peter Ujfalusi Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 8e5ed64..697c667 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -74,7 +74,6 @@ static const struct clk_ops twl6040_mcpdm_ops = { static struct clk_init_data wm831x_clkout_init = { .name = "mcpdm_fclk", .ops = &twl6040_mcpdm_ops, - .flags = CLK_IS_ROOT, }; static int twl6040_clk_probe(struct platform_device *pdev) -- cgit v0.10.2 From 4c211eaad6202ffae10f4dd476db2f6173f880c7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:25 -0800 Subject: clk: wm831x: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Mark Brown Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 43f9d15..88def4b 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -58,7 +58,6 @@ static const struct clk_ops wm831x_xtal_ops = { static struct clk_init_data wm831x_xtal_init = { .name = "xtal", .ops = &wm831x_xtal_ops, - .flags = CLK_IS_ROOT, }; static const unsigned long wm831x_fll_auto_rates[] = { -- cgit v0.10.2 From d31d56ec17431d3883d5f4b60d407fa5e75add06 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 1 Mar 2016 11:00:26 -0800 Subject: clk: xgene: Remove CLK_IS_ROOT This flag is a no-op now. Remove usage of the flag. Cc: Loc Ho Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index d73450b..3433132 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -198,7 +198,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty of_property_read_string(np, "clock-output-names", &clk_name); clk = xgene_register_clk_pll(NULL, clk_name, of_clk_get_parent_name(np, 0), - CLK_IS_ROOT, reg, 0, pll_type, &clk_lock, + 0, reg, 0, pll_type, &clk_lock, version); if (!IS_ERR(clk)) { of_clk_add_provider(np, of_clk_src_simple_get, clk); -- cgit v0.10.2 From cb0ceaf77d93964a0d00477c79f4499123f6159c Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Tue, 8 Mar 2016 01:41:29 +0200 Subject: clk: at91: fix check of clk_register() returned value The clk_register() function returns a valid pointer to struct clk or ERR_PTR() error code, this makes a check for returned NULL value useless and may lead to oops on error path. Signed-off-by: Vladimir Zapolskiy Acked-by: Alexandre Belloni Acked-by: Boris Brezillon Fixes: bcc5fd49a0fd ("clk: at91: add a driver for the h32mx clock") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 819f584..8e20c8a 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -114,7 +114,7 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) h32mxclk->regmap = regmap; clk = clk_register(NULL, &h32mxclk->hw); - if (!clk) { + if (IS_ERR(clk)) { kfree(h32mxclk); return; } -- cgit v0.10.2 From fefe0535b74f7d577af9310cf3741b4960a6687f Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Mon, 4 Apr 2016 11:21:09 +0200 Subject: clk: tango4: improve clkgen driver Add support for USB and SDIO clocks. Report unsupported setups and panic. Signed-off-by: Marc Gonzalez Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-tango4.c b/drivers/clk/clk-tango4.c index 004ab7d..eef75e3 100644 --- a/drivers/clk/clk-tango4.c +++ b/drivers/clk/clk-tango4.c @@ -4,17 +4,19 @@ #include #include -static struct clk *out[2]; -static struct clk_onecell_data clk_data = { out, 2 }; +#define CLK_COUNT 4 /* cpu_clk, sys_clk, usb_clk, sdio_clk */ +static struct clk *clks[CLK_COUNT]; +static struct clk_onecell_data clk_data = { clks, CLK_COUNT }; -#define SYSCLK_CTRL 0x20 -#define CPUCLK_CTRL 0x24 -#define LEGACY_DIV 0x3c +#define SYSCLK_DIV 0x20 +#define CPUCLK_DIV 0x24 +#define DIV_BYPASS BIT(23) -#define PLL_N(val) (((val) >> 0) & 0x7f) -#define PLL_K(val) (((val) >> 13) & 0x7) -#define PLL_M(val) (((val) >> 16) & 0x7) -#define DIV_INDEX(val) (((val) >> 8) & 0xf) +/*** CLKGEN_PLL ***/ +#define extract_pll_n(val) ((val >> 0) & ((1u << 7) - 1)) +#define extract_pll_k(val) ((val >> 13) & ((1u << 3) - 1)) +#define extract_pll_m(val) ((val >> 16) & ((1u << 3) - 1)) +#define extract_pll_isel(val) ((val >> 24) & ((1u << 3) - 1)) static void __init make_pll(int idx, const char *parent, void __iomem *base) { @@ -22,40 +24,61 @@ static void __init make_pll(int idx, const char *parent, void __iomem *base) u32 val, mul, div; sprintf(name, "pll%d", idx); - val = readl_relaxed(base + idx*8); - mul = PLL_N(val) + 1; - div = (PLL_M(val) + 1) << PLL_K(val); + val = readl(base + idx * 8); + mul = extract_pll_n(val) + 1; + div = (extract_pll_m(val) + 1) << extract_pll_k(val); clk_register_fixed_factor(NULL, name, parent, 0, mul, div); + if (extract_pll_isel(val) != 1) + panic("%s: input not set to XTAL_IN\n", name); } -static int __init get_div(void __iomem *base) +static void __init make_cd(int idx, void __iomem *base) { - u8 sysclk_tab[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 }; - int idx = DIV_INDEX(readl_relaxed(base + LEGACY_DIV)); + char name[8]; + u32 val, mul, div; - return sysclk_tab[idx]; + sprintf(name, "cd%d", idx); + val = readl(base + idx * 8); + mul = 1 << 27; + div = (2 << 27) + val; + clk_register_fixed_factor(NULL, name, "pll2", 0, mul, div); + if (val > 0xf0000000) + panic("%s: unsupported divider %x\n", name, val); } static void __init tango4_clkgen_setup(struct device_node *np) { - int div, ret; + struct clk **pp = clk_data.clks; void __iomem *base = of_iomap(np, 0); const char *parent = of_clk_get_parent_name(np, 0); if (!base) - panic("%s: invalid address\n", np->full_name); + panic("%s: invalid address\n", np->name); + + if (readl(base + CPUCLK_DIV) & DIV_BYPASS) + panic("%s: unsupported cpuclk setup\n", np->name); + + if (readl(base + SYSCLK_DIV) & DIV_BYPASS) + panic("%s: unsupported sysclk setup\n", np->name); + + writel(0x100, base + CPUCLK_DIV); /* disable frequency ramping */ make_pll(0, parent, base); make_pll(1, parent, base); + make_pll(2, parent, base); + make_cd(2, base + 0x80); + make_cd(6, base + 0x80); - out[0] = clk_register_divider(NULL, "cpuclk", "pll0", 0, - base + CPUCLK_CTRL, 8, 8, CLK_DIVIDER_ONE_BASED, NULL); + pp[0] = clk_register_divider(NULL, "cpu_clk", "pll0", 0, + base + CPUCLK_DIV, 8, 8, CLK_DIVIDER_ONE_BASED, NULL); + pp[1] = clk_register_fixed_factor(NULL, "sys_clk", "pll1", 0, 1, 4); + pp[2] = clk_register_fixed_factor(NULL, "usb_clk", "cd2", 0, 1, 2); + pp[3] = clk_register_fixed_factor(NULL, "sdio_clk", "cd6", 0, 1, 2); - div = readl_relaxed(base + SYSCLK_CTRL) & BIT(23) ? get_div(base) : 4; - out[1] = clk_register_fixed_factor(NULL, "sysclk", "pll1", 0, 1, div); + if (IS_ERR(pp[0]) || IS_ERR(pp[1]) || IS_ERR(pp[2]) || IS_ERR(pp[3])) + panic("%s: clk registration failed\n", np->name); - ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); - if (IS_ERR(out[0]) || IS_ERR(out[1]) || ret < 0) - panic("%s: clk registration failed\n", np->full_name); + if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) + panic("%s: clk provider registration failed\n", np->name); } CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup); -- cgit v0.10.2 From c5cc2a0bc930f1ae00b198aeb752acc3bdd4d5a7 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 16 Mar 2016 21:54:55 +0200 Subject: clk: ti: dpll: add support for specifying max rate for DPLLs DPLLs typically have a maximum rate they can support, and this varies from DPLL to DPLL. Add support of the maximum rate value to the DPLL data struct, and also add check for this in the DPLL round_rate function. Signed-off-by: Tero Kristo Reviewed-by: Nishanth Menon Cc: Tomi Valkeinen Cc: Lokesh Vutla Signed-off-by: Stephen Boyd diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c index 032c658..b919fdf 100644 --- a/drivers/clk/ti/clkt_dpll.c +++ b/drivers/clk/ti/clkt_dpll.c @@ -301,6 +301,9 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, dd = clk->dpll_data; + if (dd->max_rate && target_rate > dd->max_rate) + target_rate = dd->max_rate; + ref_rate = clk_hw_get_rate(dd->clk_ref); clk_name = clk_hw_get_name(hw); pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n", diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index dc5164a..6110fe0 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -37,6 +37,7 @@ * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate() * @min_divider: minimum valid non-bypass divider value (actual) * @max_divider: maximum valid non-bypass divider value (actual) + * @max_rate: maximum clock rate for the DPLL * @modes: possible values of @enable_mask * @autoidle_reg: register containing the DPLL autoidle mode bitfield * @idlest_reg: register containing the DPLL idle status bitfield @@ -81,6 +82,7 @@ struct dpll_data { u8 last_rounded_n; u8 min_divider; u16 max_divider; + unsigned long max_rate; u8 modes; void __iomem *autoidle_reg; void __iomem *idlest_reg; -- cgit v0.10.2 From 3db5ca27c80c15d20d0f1152dc34a5bcfa432ae6 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 16 Mar 2016 21:54:56 +0200 Subject: clk: ti: amx3xx: limit the maximum frequency of DPLLs based on spec AM33xx/AM43xx devices use the same DPLL IP blocks, which only support maximum rate of 1GHz [1] for the default and 2GHz for the low-jitter type DPLLs [2]. Reflect this limitation in the DPLL init code by adding the max-rate parameter based on the DPLL types. [1] Functional, integration & test specification for GS70 ADPLLS, Rev 1.0-01 [2] Functional, integration & test specification for GS70 ADPLLLJ, Rev 0.8-02 Signed-off-by: Tero Kristo Cc: Nishanth Menon Cc: Tomi Valkeinen Cc: Lokesh Vutla Signed-off-by: Stephen Boyd diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 3bc9959..9fc8754 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -655,6 +655,7 @@ static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node) .max_multiplier = 2047, .max_divider = 128, .min_divider = 1, + .max_rate = 1000000000, .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; @@ -674,6 +675,7 @@ static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node) .max_divider = 256, .min_divider = 2, .flags = DPLL_J_TYPE, + .max_rate = 2000000000, .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; @@ -692,6 +694,7 @@ static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node) .max_multiplier = 2047, .max_divider = 128, .min_divider = 1, + .max_rate = 2000000000, .flags = DPLL_J_TYPE, .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; @@ -712,6 +715,7 @@ static void __init of_ti_am3_dpll_setup(struct device_node *node) .max_multiplier = 2047, .max_divider = 128, .min_divider = 1, + .max_rate = 1000000000, .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; @@ -729,6 +733,7 @@ static void __init of_ti_am3_core_dpll_setup(struct device_node *node) .max_multiplier = 2047, .max_divider = 128, .min_divider = 1, + .max_rate = 1000000000, .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; -- cgit v0.10.2 From d5630b7a557aff4d107e5af2e73fb91ed707f442 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 10 Dec 2015 19:03:45 +0200 Subject: clk: ti: dra7: fix kernel boot with arg 'clocksource=gp_timer' The OMAP Platform code provides possibility to select GP Timer as default clocksource instead of counter_32K by using bootcmd parameter 'clocksource', but the system will crash during early boot when this option is used on dra7 or omap5 platforms, because it will hit BUG() statement: omap2_gptimer_clocksource_init ->BUG_ON(res); This happens because clk_dev alias "sys_clkin_ck" is not registered. Hence, fix it by adding missing "sys_clkin_ck" clk_dev aliases definitions for omap5 and dra7. Acked-by: Tero Kristo Cc: Tony Lindgren Signed-off-by: Grygorii Strashko Signed-off-by: Stephen Boyd diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index 59ce2fa..294bc03 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -210,6 +210,7 @@ static struct ti_dt_clk omap54xx_clks[] = { DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), DT_CLK("omap_wdt", "ick", "dummy_ck"), DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin"), DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin"), DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin"), DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin"), diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index a911d7d..87a87b5 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -289,6 +289,7 @@ static struct ti_dt_clk dra7xx_clks[] = { DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), DT_CLK("omap_wdt", "ick", "dummy_ck"), DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "sys_clkin_ck", "timer_sys_clk_div"), DT_CLK("4ae18000.timer", "timer_sys_ck", "timer_sys_clk_div"), DT_CLK("48032000.timer", "timer_sys_ck", "timer_sys_clk_div"), DT_CLK("48034000.timer", "timer_sys_ck", "timer_sys_clk_div"), -- cgit v0.10.2 From 3397c2c45b1b6f54834dfeae30a73046f33ca943 Mon Sep 17 00:00:00 2001 From: Alexander Kurz Date: Thu, 14 Apr 2016 23:30:49 +0200 Subject: ARM: dts: imx35: restore existing used clock enumeration A new element got inserted into enum mx35_clks with commit 3713e3f5e927 ("clk: imx35: define two clocks for rtc"). This insertion shifted most nummerical clock assignments to a new nummerical value which in turn rendered most hardcoded nummeric values in imx35.dtsi incorrect. Restore the existing order by moving the newly introduced clock to the end of the enum. Update the dts documentation accordingly. Signed-off-by: Alexander Kurz Fixes: 3713e3f5e927 ("clk: imx35: define two clocks for rtc") Cc: Signed-off-by: Shawn Guo diff --git a/Documentation/devicetree/bindings/clock/imx35-clock.txt b/Documentation/devicetree/bindings/clock/imx35-clock.txt index a703564..f497832 100644 --- a/Documentation/devicetree/bindings/clock/imx35-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx35-clock.txt @@ -94,6 +94,7 @@ clocks and IDs. csi_sel 79 iim_gate 80 gpu2d_gate 81 + ckli_gate 82 Examples: diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index a71d24c..b0978d3 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -66,7 +66,7 @@ static const char *std_sel[] = {"ppll", "arm"}; static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"}; enum mx35_clks { - ckih, ckil, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, + ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel, esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre, spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre, @@ -79,7 +79,7 @@ enum mx35_clks { rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate, ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate, wdog_gate, max_gate, admux_gate, csi_gate, csi_div, csi_sel, iim_gate, - gpu2d_gate, clk_max + gpu2d_gate, ckil, clk_max }; static struct clk *clk[clk_max]; -- cgit v0.10.2 From 995d3fdeb2f2d362b1b6bf26656c417452939a1a Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 19 Apr 2016 21:07:01 +0200 Subject: clk: rockchip: reign in some overly long lines in the rk3399 controller We allow overlong lines in the array portitions describing the clock trees to ease readability by having each element always at the same position. But the rest of the code should honor the 80 char limit. Fix the newly added rk3399 clock code to respect that. Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 356e132..e8f040b 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -117,73 +117,96 @@ PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", "vpll_aclk_cci_src" }; -PNAME(mux_cci_trace_p) = { "cpll_cci_trace", "gpll_cci_trace" }; -PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs", "npll_cs"}; -PNAME(mux_aclk_perihp_p) = { "cpll_aclk_perihp_src", "gpll_aclk_perihp_src" }; +PNAME(mux_cci_trace_p) = { "cpll_cci_trace", + "gpll_cci_trace" }; +PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs", + "npll_cs"}; +PNAME(mux_aclk_perihp_p) = { "cpll_aclk_perihp_src", + "gpll_aclk_perihp_src" }; PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; PNAME(mux_pll_src_cpll_gpll_ppll_p) = { "cpll", "gpll", "ppll" }; PNAME(mux_pll_src_cpll_gpll_upll_p) = { "cpll", "gpll", "upll" }; PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; -PNAME(mux_pll_src_cpll_gpll_npll_ppll_p) = { "cpll", "gpll", "npll", "ppll" }; -PNAME(mux_pll_src_cpll_gpll_npll_24m_p) = { "cpll", "gpll", "npll", "xin24m" }; -PNAME(mux_pll_src_cpll_gpll_npll_usbphy480m_p) = { "cpll", "gpll", "npll", "clk_usbphy_480m" }; -PNAME(mux_pll_src_ppll_cpll_gpll_npll_p) = { "ppll", "cpll", "gpll", "npll", "upll" }; -PNAME(mux_pll_src_cpll_gpll_npll_upll_24m_p) = { "cpll", "gpll", "npll", "upll", "xin24m" }; -PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll", "ppll", "upll", "xin24m" }; +PNAME(mux_pll_src_cpll_gpll_npll_ppll_p) = { "cpll", "gpll", "npll", + "ppll" }; +PNAME(mux_pll_src_cpll_gpll_npll_24m_p) = { "cpll", "gpll", "npll", + "xin24m" }; +PNAME(mux_pll_src_cpll_gpll_npll_usbphy480m_p) = { "cpll", "gpll", "npll", + "clk_usbphy_480m" }; +PNAME(mux_pll_src_ppll_cpll_gpll_npll_p) = { "ppll", "cpll", "gpll", + "npll", "upll" }; +PNAME(mux_pll_src_cpll_gpll_npll_upll_24m_p) = { "cpll", "gpll", "npll", + "upll", "xin24m" }; +PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll", + "ppll", "upll", "xin24m" }; PNAME(mux_pll_src_vpll_cpll_gpll_p) = { "vpll", "cpll", "gpll" }; -PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll", "npll" }; -PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll", "xin24m" }; - -PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", "dclk_vop0_frac" }; -PNAME(mux_dclk_vop1_p) = { "dclk_vop1_div", "dclk_vop1_frac" }; - -PNAME(mux_clk_cif_p) = { "clk_cifout_div", "xin24m" }; - -PNAME(mux_pll_src_24m_usbphy480m_p) = { "xin24m", "clk_usbphy_480m" }; -PNAME(mux_pll_src_24m_pciephy_p) = { "xin24m", "clk_pciephy_ref100m" }; -PNAME(mux_pll_src_24m_32k_cpll_gpll_p) = { "xin24m", "xin32k", "cpll", "gpll" }; -PNAME(mux_pciecore_cru_phy_p) = { "clk_pcie_core_cru", "clk_pcie_core_phy" }; - -PNAME(mux_aclk_emmc_p) = { "cpll_aclk_emmc_src", "gpll_aclk_emmc_src" }; - -PNAME(mux_aclk_perilp0_p) = { "cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src" }; - -PNAME(mux_fclk_cm0s_p) = { "cpll_fclk_cm0s_src", "gpll_fclk_cm0s_src" }; - -PNAME(mux_hclk_perilp1_p) = { "cpll_hclk_perilp1_src", "gpll_hclk_perilp1_src" }; - -PNAME(mux_clk_testout1_p) = { "clk_testout1_pll_src", "xin24m" }; -PNAME(mux_clk_testout2_p) = { "clk_testout2_pll_src", "xin24m" }; - -PNAME(mux_usbphy_480m_p) = { "clk_usbphy0_480m_src", "clk_usbphy1_480m_src" }; -PNAME(mux_aclk_gmac_p) = { "cpll_aclk_gmac_src", "gpll_aclk_gmac_src" }; -PNAME(mux_rmii_p) = { "clk_gmac", "clkin_gmac" }; -PNAME(mux_spdif_p) = { "clk_spdif_div", "clk_spdif_frac", - "clkin_i2s", "xin12m" }; -PNAME(mux_i2s0_p) = { "clk_i2s0_div", "clk_i2s0_frac", - "clkin_i2s", "xin12m" }; -PNAME(mux_i2s1_p) = { "clk_i2s1_div", "clk_i2s1_frac", - "clkin_i2s", "xin12m" }; -PNAME(mux_i2s2_p) = { "clk_i2s2_div", "clk_i2s2_frac", - "clkin_i2s", "xin12m" }; -PNAME(mux_i2sch_p) = { "clk_i2s0", "clk_i2s1", "clk_i2s2" }; -PNAME(mux_i2sout_p) = { "clk_i2sout_src", "xin12m" }; - -PNAME(mux_uart0_p) = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; -PNAME(mux_uart1_p) = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; -PNAME(mux_uart2_p) = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; -PNAME(mux_uart3_p) = { "clk_uart3_div", "clk_uart3_frac", "xin24m" }; +PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll", + "npll" }; +PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll", + "xin24m" }; + +PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", + "dclk_vop0_frac" }; +PNAME(mux_dclk_vop1_p) = { "dclk_vop1_div", + "dclk_vop1_frac" }; + +PNAME(mux_clk_cif_p) = { "clk_cifout_div", "xin24m" }; + +PNAME(mux_pll_src_24m_usbphy480m_p) = { "xin24m", "clk_usbphy_480m" }; +PNAME(mux_pll_src_24m_pciephy_p) = { "xin24m", "clk_pciephy_ref100m" }; +PNAME(mux_pll_src_24m_32k_cpll_gpll_p) = { "xin24m", "xin32k", + "cpll", "gpll" }; +PNAME(mux_pciecore_cru_phy_p) = { "clk_pcie_core_cru", + "clk_pcie_core_phy" }; + +PNAME(mux_aclk_emmc_p) = { "cpll_aclk_emmc_src", + "gpll_aclk_emmc_src" }; + +PNAME(mux_aclk_perilp0_p) = { "cpll_aclk_perilp0_src", + "gpll_aclk_perilp0_src" }; + +PNAME(mux_fclk_cm0s_p) = { "cpll_fclk_cm0s_src", + "gpll_fclk_cm0s_src" }; + +PNAME(mux_hclk_perilp1_p) = { "cpll_hclk_perilp1_src", + "gpll_hclk_perilp1_src" }; + +PNAME(mux_clk_testout1_p) = { "clk_testout1_pll_src", "xin24m" }; +PNAME(mux_clk_testout2_p) = { "clk_testout2_pll_src", "xin24m" }; + +PNAME(mux_usbphy_480m_p) = { "clk_usbphy0_480m_src", + "clk_usbphy1_480m_src" }; +PNAME(mux_aclk_gmac_p) = { "cpll_aclk_gmac_src", + "gpll_aclk_gmac_src" }; +PNAME(mux_rmii_p) = { "clk_gmac", "clkin_gmac" }; +PNAME(mux_spdif_p) = { "clk_spdif_div", "clk_spdif_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s0_p) = { "clk_i2s0_div", "clk_i2s0_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s1_p) = { "clk_i2s1_div", "clk_i2s1_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s2_p) = { "clk_i2s2_div", "clk_i2s2_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2sch_p) = { "clk_i2s0", "clk_i2s1", + "clk_i2s2" }; +PNAME(mux_i2sout_p) = { "clk_i2sout_src", "xin12m" }; + +PNAME(mux_uart0_p) = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; +PNAME(mux_uart1_p) = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; +PNAME(mux_uart2_p) = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; +PNAME(mux_uart3_p) = { "clk_uart3_div", "clk_uart3_frac", "xin24m" }; /* PMU CRU parents */ -PNAME(mux_ppll_24m_p) = { "ppll", "xin24m" }; -PNAME(mux_24m_ppll_p) = { "xin24m", "ppll" }; -PNAME(mux_fclk_cm0s_pmu_ppll_p) = { "fclk_cm0s_pmu_ppll_src", "xin24m" }; -PNAME(mux_wifi_pmu_p) = { "clk_wifi_div", "clk_wifi_frac" }; -PNAME(mux_uart4_pmu_p) = { "clk_uart4_div", "clk_uart4_frac", "xin24m" }; -PNAME(mux_clk_testout2_2io_p) = { "clk_testout2", "clk_32k_suspend_pmu" }; +PNAME(mux_ppll_24m_p) = { "ppll", "xin24m" }; +PNAME(mux_24m_ppll_p) = { "xin24m", "ppll" }; +PNAME(mux_fclk_cm0s_pmu_ppll_p) = { "fclk_cm0s_pmu_ppll_src", "xin24m" }; +PNAME(mux_wifi_pmu_p) = { "clk_wifi_div", "clk_wifi_frac" }; +PNAME(mux_uart4_pmu_p) = { "clk_uart4_div", "clk_uart4_frac", + "xin24m" }; +PNAME(mux_clk_testout2_2io_p) = { "clk_testout2", "clk_32k_suspend_pmu" }; static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = { [lpll] = PLL(pll_rk3399, PLL_APLLL, "lpll", mux_pll_p, 0, RK3399_PLL_CON(0), @@ -1530,7 +1553,7 @@ static void __init rk3399_pmu_clk_init(struct device_node *np) ARRAY_SIZE(rk3399_clk_pmu_branches)); rockchip_clk_protect_critical(rk3399_pmucru_critical_clocks, - ARRAY_SIZE(rk3399_pmucru_critical_clocks)); + ARRAY_SIZE(rk3399_pmucru_critical_clocks)); rockchip_register_softrst(np, 2, reg_base + RK3399_PMU_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); -- cgit v0.10.2 From 2b4e6286484c3eeae2c80063c510166c63d7cb85 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 19 Apr 2016 21:17:55 +0200 Subject: clk: rockchip: drop unnecessary header comment The internal clk header did contain a comment indicating that some of the defined registers were shared over multiple clock controller variants. In recent times, it was simply extended all the time and stopped providing any meaningful information, so drop it and it's overlong line. Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 880349f..4a355bf 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -34,7 +34,6 @@ struct clk; #define HIWORD_UPDATE(val, mask, shift) \ ((val) << (shift) | (mask) << ((shift) + 16)) -/* register positions shared by RK2928, RK3036, RK3066, RK3188, RK3228, RK3399 */ #define RK2928_PLL_CON(x) ((x) * 0x4) #define RK2928_MODE_CON 0x40 #define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44) -- cgit v0.10.2 From a14b9e0512404ed7d4415b888dc9f1f9785a4fa3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 5 Feb 2016 16:40:47 -0800 Subject: clkdev: Remove clk_register_clkdevs() Now that we've converted the only caller over to another clkdev API, remove this one. Reviewed-by: Andy Shevchenko Cc: Russell King Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index eb20b94..ae8e40a 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -402,30 +402,3 @@ int clk_register_clkdev(struct clk *clk, const char *con_id, return cl ? 0 : -ENOMEM; } EXPORT_SYMBOL(clk_register_clkdev); - -/** - * clk_register_clkdevs - register a set of clk_lookup for a struct clk - * @clk: struct clk to associate with all clk_lookups - * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized - * @num: number of clk_lookup structures to register - * - * To make things easier for mass registration, we detect error clks - * from a previous clk_register() call, and return the error code for - * those. This is to permit this function to be called immediately - * after clk_register(). - */ -int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num) -{ - unsigned i; - - if (IS_ERR(clk)) - return PTR_ERR(clk); - - for (i = 0; i < num; i++, cl++) { - cl->clk_hw = __clk_get_hw(clk); - __clkdev_add(cl); - } - - return 0; -} -EXPORT_SYMBOL(clk_register_clkdevs); diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index c2c04f7..e6f8eb1 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -45,7 +45,6 @@ void clkdev_add_table(struct clk_lookup *, size_t); int clk_add_alias(const char *, const char *, const char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *); -int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); #ifdef CONFIG_COMMON_CLK int __clk_get(struct clk *clk); -- cgit v0.10.2 From 4143804c4fdef40358c654d1fb2271a1a0f1fedf Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 5 Feb 2016 17:02:52 -0800 Subject: clk: Add {devm_}clk_hw_{register,unregister}() APIs We've largely split the clk consumer and provider APIs along struct clk and struct clk_hw, but clk_register() still returns a struct clk pointer for each struct clk_hw that's registered. Eventually we'd like to only allocate struct clks when there's a user, because struct clk is per-user now, so clk_register() needs to change. Let's add new APIs to register struct clk_hws, but this time we'll hide the struct clk from the caller by returning an int error code. Also add an unregistration API that takes the clk_hw structure that was passed to the registration API. This way provider drivers never have to deal with a struct clk pointer unless they're using the clk consumer APIs. Signed-off-by: Stephen Boyd diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 73b98df..108d455 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -236,6 +236,7 @@ certainly invest a bit more effort into libata core layer). CLOCK devm_clk_get() devm_clk_put() + devm_clk_hw_register() DMA dmam_alloc_coherent() diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fb74dc1..0ef9196 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2536,6 +2536,22 @@ fail_out: } EXPORT_SYMBOL_GPL(clk_register); +/** + * clk_hw_register - register a clk_hw and return an error code + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * clk_hw_register is the primary interface for populating the clock tree with + * new clock nodes. It returns an integer equal to zero indicating success or + * less than zero indicating failure. Drivers must test for an error code after + * calling clk_hw_register(). + */ +int clk_hw_register(struct device *dev, struct clk_hw *hw) +{ + return PTR_ERR_OR_ZERO(clk_register(dev, hw)); +} +EXPORT_SYMBOL_GPL(clk_hw_register); + /* Free memory allocated for a clock. */ static void __clk_release(struct kref *ref) { @@ -2637,11 +2653,26 @@ unlock: } EXPORT_SYMBOL_GPL(clk_unregister); +/** + * clk_hw_unregister - unregister a currently registered clk_hw + * @hw: hardware-specific clock data to unregister + */ +void clk_hw_unregister(struct clk_hw *hw) +{ + clk_unregister(hw->clk); +} +EXPORT_SYMBOL_GPL(clk_hw_unregister); + static void devm_clk_release(struct device *dev, void *res) { clk_unregister(*(struct clk **)res); } +static void devm_clk_hw_release(struct device *dev, void *res) +{ + clk_hw_unregister(*(struct clk_hw **)res); +} + /** * devm_clk_register - resource managed clk_register() * @dev: device that is registering this clock @@ -2672,6 +2703,36 @@ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw) } EXPORT_SYMBOL_GPL(devm_clk_register); +/** + * devm_clk_hw_register - resource managed clk_hw_register() + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * Managed clk_hw_register(). Clocks returned from this function are + * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register() + * for more information. + */ +int devm_clk_hw_register(struct device *dev, struct clk_hw *hw) +{ + struct clk_hw **hwp; + int ret; + + hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL); + if (!hwp) + return -ENOMEM; + + ret = clk_hw_register(dev, hw); + if (!ret) { + *hwp = hw; + devres_add(dev, hwp); + } else { + devres_free(hwp); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_clk_hw_register); + static int devm_clk_match(struct device *dev, void *res, void *data) { struct clk *c = res; @@ -2680,6 +2741,15 @@ static int devm_clk_match(struct device *dev, void *res, void *data) return c == data; } +static int devm_clk_hw_match(struct device *dev, void *res, void *data) +{ + struct clk_hw *hw = res; + + if (WARN_ON(!hw)) + return 0; + return hw == data; +} + /** * devm_clk_unregister - resource managed clk_unregister() * @clk: clock to unregister @@ -2694,6 +2764,22 @@ void devm_clk_unregister(struct device *dev, struct clk *clk) } EXPORT_SYMBOL_GPL(devm_clk_unregister); +/** + * devm_clk_hw_unregister - resource managed clk_hw_unregister() + * @dev: device that is unregistering the hardware-specific clock data + * @hw: link to hardware-specific clock data + * + * Unregister a clk_hw registered with devm_clk_hw_register(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw) +{ + WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match, + hw)); +} +EXPORT_SYMBOL_GPL(devm_clk_hw_unregister); + /* * clkdev helpers */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index da95258..bc6c8de 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -655,9 +655,15 @@ struct clk *clk_register_gpio_mux(struct device *dev, const char *name, struct clk *clk_register(struct device *dev, struct clk_hw *hw); struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw); +int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw); +int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw); + void clk_unregister(struct clk *clk); void devm_clk_unregister(struct device *dev, struct clk *clk); +void clk_hw_unregister(struct clk_hw *hw); +void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw); + /* helper functions */ const char *__clk_get_name(const struct clk *clk); const char *clk_hw_get_name(const struct clk_hw *hw); -- cgit v0.10.2 From 0861e5b8cf80038e91942f1005c8dfce79d18c38 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 5 Feb 2016 17:38:26 -0800 Subject: clk: Add clk_hw OF clk providers Now that we have a clk registration API that doesn't return struct clks, we need to have some way to hand out struct clks via the clk_get() APIs that doesn't involve associating struct clk pointers with an OF node. Currently we ask the OF provider to give us a struct clk pointer for some clkspec, turn that struct clk into a struct clk_hw and then allocate a new struct clk to return to the caller. Let's add a clk_hw based OF provider hook that returns a struct clk_hw directly, so that we skip the intermediate step of converting from struct clk to struct clk_hw. Eventually when we've converted all OF clk providers to struct clk_hw based APIs we can remove the struct clk based ones. It should also be noted that we change the onecell provider to have a flex array instead of a pointer for the array of clk_hw pointers. This allows providers to allocate one structure of the correct length in one step instead of two. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0ef9196..e813b2a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2941,6 +2941,7 @@ struct of_clk_provider { struct device_node *node; struct clk *(*get)(struct of_phandle_args *clkspec, void *data); + struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data); void *data; }; @@ -2957,6 +2958,12 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, } EXPORT_SYMBOL_GPL(of_clk_src_simple_get); +struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data) +{ + return data; +} +EXPORT_SYMBOL_GPL(of_clk_hw_simple_get); + struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data) { struct clk_onecell_data *clk_data = data; @@ -2971,6 +2978,21 @@ struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data) } EXPORT_SYMBOL_GPL(of_clk_src_onecell_get); +struct clk_hw * +of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data) +{ + struct clk_hw_onecell_data *hw_data = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= hw_data->num) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return hw_data->hws[idx]; +} +EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get); + /** * of_clk_add_provider() - Register a clock provider for a node * @np: Device node pointer associated with clock provider @@ -3007,6 +3029,41 @@ int of_clk_add_provider(struct device_node *np, EXPORT_SYMBOL_GPL(of_clk_add_provider); /** + * of_clk_add_hw_provider() - Register a clock provider for a node + * @np: Device node pointer associated with clock provider + * @get: callback for decoding clk_hw + * @data: context pointer for @get callback. + */ +int of_clk_add_hw_provider(struct device_node *np, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data) +{ + struct of_clk_provider *cp; + int ret; + + cp = kzalloc(sizeof(*cp), GFP_KERNEL); + if (!cp) + return -ENOMEM; + + cp->node = of_node_get(np); + cp->data = data; + cp->get_hw = get; + + mutex_lock(&of_clk_mutex); + list_add(&cp->link, &of_clk_providers); + mutex_unlock(&of_clk_mutex); + pr_debug("Added clk_hw provider from %s\n", np->full_name); + + ret = of_clk_set_defaults(np, true); + if (ret < 0) + of_clk_del_provider(np); + + return ret; +} +EXPORT_SYMBOL_GPL(of_clk_add_hw_provider); + +/** * of_clk_del_provider() - Remove a previously registered clock provider * @np: Device node pointer associated with clock provider */ @@ -3027,11 +3084,32 @@ void of_clk_del_provider(struct device_node *np) } EXPORT_SYMBOL_GPL(of_clk_del_provider); +static struct clk_hw * +__of_clk_get_hw_from_provider(struct of_clk_provider *provider, + struct of_phandle_args *clkspec) +{ + struct clk *clk; + struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); + + if (provider->get_hw) { + hw = provider->get_hw(clkspec, provider->data); + } else if (provider->get) { + clk = provider->get(clkspec, provider->data); + if (!IS_ERR(clk)) + hw = __clk_get_hw(clk); + else + hw = ERR_CAST(clk); + } + + return hw; +} + struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, const char *dev_id, const char *con_id) { struct of_clk_provider *provider; struct clk *clk = ERR_PTR(-EPROBE_DEFER); + struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); if (!clkspec) return ERR_PTR(-EINVAL); @@ -3040,10 +3118,9 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, mutex_lock(&of_clk_mutex); list_for_each_entry(provider, &of_clk_providers, link) { if (provider->node == clkspec->np) - clk = provider->get(clkspec, provider->data); - if (!IS_ERR(clk)) { - clk = __clk_create_clk(__clk_get_hw(clk), dev_id, - con_id); + hw = __of_clk_get_hw_from_provider(provider, clkspec); + if (!IS_ERR(hw)) { + clk = __clk_create_clk(hw, dev_id, con_id); if (!IS_ERR(clk) && !__clk_get(clk)) { __clk_free_clk(clk); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index bc6c8de..bf8c8bb 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -709,6 +709,11 @@ struct clk_onecell_data { unsigned int clk_num; }; +struct clk_hw_onecell_data { + size_t num; + struct clk_hw *hws[]; +}; + extern struct of_device_id __clk_of_table; #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn) @@ -718,10 +723,18 @@ int of_clk_add_provider(struct device_node *np, struct clk *(*clk_src_get)(struct of_phandle_args *args, void *data), void *data); +int of_clk_add_hw_provider(struct device_node *np, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data); void of_clk_del_provider(struct device_node *np); struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, void *data); +struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, + void *data); struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data); +struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec, + void *data); unsigned int of_clk_get_parent_count(struct device_node *np); int of_clk_parent_fill(struct device_node *np, const char **parents, unsigned int size); @@ -738,17 +751,34 @@ static inline int of_clk_add_provider(struct device_node *np, { return 0; } +static inline int of_clk_add_hw_provider(struct device_node *np, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data) +{ + return 0; +} static inline void of_clk_del_provider(struct device_node *np) {} static inline struct clk *of_clk_src_simple_get( struct of_phandle_args *clkspec, void *data) { return ERR_PTR(-ENOENT); } +static inline struct clk_hw * +of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data) +{ + return ERR_PTR(-ENOENT); +} static inline struct clk *of_clk_src_onecell_get( struct of_phandle_args *clkspec, void *data) { return ERR_PTR(-ENOENT); } +static inline struct clk_hw * +of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data) +{ + return ERR_PTR(-ENOENT); +} static inline int of_clk_get_parent_count(struct device_node *np) { return 0; -- cgit v0.10.2 From e4f1b49bda6d6aa2e13730ff7eeccbe65a6271f1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 8 Feb 2016 14:59:49 -0800 Subject: clkdev: Add clk_hw based registration APIs Now that we have a clk registration API that doesn't return struct clks, we need to have some way to hand out struct clks via the clk_get() APIs that doesn't involve associating struct clk pointers with a struct clk_lookup. Luckily, clkdev already operates on struct clk_hw pointers, except for the registration facing APIs where it converts struct clk pointers into struct clk_hw pointers almost immediately. Let's add clk_hw based registration APIs so that we can skip the conversion step and provide a way for clk provider drivers to operate exclusively on clk_hw structs. This way we clearly split the API between consumers and providers. Cc: Russell King Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index ae8e40a..89cc700 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -301,6 +301,20 @@ clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) } EXPORT_SYMBOL(clkdev_alloc); +struct clk_lookup * +clkdev_hw_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, ...) +{ + struct clk_lookup *cl; + va_list ap; + + va_start(ap, dev_fmt); + cl = vclkdev_alloc(hw, con_id, dev_fmt, ap); + va_end(ap); + + return cl; +} +EXPORT_SYMBOL(clkdev_hw_alloc); + /** * clkdev_create - allocate and add a clkdev lookup structure * @clk: struct clk to associate with all clk_lookups @@ -324,6 +338,29 @@ struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id, } EXPORT_SYMBOL_GPL(clkdev_create); +/** + * clkdev_hw_create - allocate and add a clkdev lookup structure + * @hw: struct clk_hw to associate with all clk_lookups + * @con_id: connection ID string on device + * @dev_fmt: format string describing device name + * + * Returns a clk_lookup structure, which can be later unregistered and + * freed. + */ +struct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id, + const char *dev_fmt, ...) +{ + struct clk_lookup *cl; + va_list ap; + + va_start(ap, dev_fmt); + cl = vclkdev_create(hw, con_id, dev_fmt, ap); + va_end(ap); + + return cl; +} +EXPORT_SYMBOL_GPL(clkdev_hw_create); + int clk_add_alias(const char *alias, const char *alias_dev_name, const char *con_id, struct device *dev) { @@ -402,3 +439,30 @@ int clk_register_clkdev(struct clk *clk, const char *con_id, return cl ? 0 : -ENOMEM; } EXPORT_SYMBOL(clk_register_clkdev); + +/** + * clk_hw_register_clkdev - register one clock lookup for a struct clk_hw + * @hw: struct clk_hw to associate with all clk_lookups + * @con_id: connection ID string on device + * @dev_id: format string describing device name + * + * con_id or dev_id may be NULL as a wildcard, just as in the rest of + * clkdev. + */ +int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id, + const char *dev_id) +{ + struct clk_lookup *cl; + + /* + * Since dev_id can be NULL, and NULL is handled specially, we must + * pass it as either a NULL format string, or with "%s". + */ + if (dev_id) + cl = __clk_register_clkdev(hw, con_id, "%s", dev_id); + else + cl = __clk_register_clkdev(hw, con_id, NULL); + + return cl ? 0 : -ENOMEM; +} +EXPORT_SYMBOL(clk_hw_register_clkdev); diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index e6f8eb1..2eabc86 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -15,6 +15,7 @@ #include struct clk; +struct clk_hw; struct device; struct clk_lookup { @@ -34,17 +35,22 @@ struct clk_lookup { struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) __printf(3, 4); +struct clk_lookup *clkdev_hw_alloc(struct clk_hw *hw, const char *con_id, + const char *dev_fmt, ...) __printf(3, 4); void clkdev_add(struct clk_lookup *cl); void clkdev_drop(struct clk_lookup *cl); struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id, const char *dev_fmt, ...) __printf(3, 4); +struct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id, + const char *dev_fmt, ...) __printf(3, 4); void clkdev_add_table(struct clk_lookup *, size_t); int clk_add_alias(const char *, const char *, const char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *); +int clk_hw_register_clkdev(struct clk_hw *, const char *, const char *); #ifdef CONFIG_COMMON_CLK int __clk_get(struct clk *clk); -- cgit v0.10.2 From eb7d264f3bf9ca7c093efb77bdde557c6c6e826f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 6 Feb 2016 23:26:37 -0800 Subject: clk: divider: Add hw based registration APIs Add registration APIs in the clk divider code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 00e035b..a0f55bc 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -426,15 +426,16 @@ const struct clk_ops clk_divider_ro_ops = { }; EXPORT_SYMBOL_GPL(clk_divider_ro_ops); -static struct clk *_register_divider(struct device *dev, const char *name, +static struct clk_hw *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_divider *div; - struct clk *clk; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { if (width + shift > 16) { @@ -467,12 +468,14 @@ static struct clk *_register_divider(struct device *dev, const char *name, div->table = table; /* register the clock */ - clk = clk_register(dev, &div->hw); - - if (IS_ERR(clk)) + hw = &div->hw; + ret = clk_hw_register(dev, hw); + if (ret) { kfree(div); + hw = ERR_PTR(ret); + } - return clk; + return hw; } /** @@ -492,12 +495,39 @@ struct clk *clk_register_divider(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, spinlock_t *lock) { - return _register_divider(dev, name, parent_name, flags, reg, shift, + struct clk_hw *hw; + + hw = _register_divider(dev, name, parent_name, flags, reg, shift, width, clk_divider_flags, NULL, lock); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } EXPORT_SYMBOL_GPL(clk_register_divider); /** + * clk_hw_register_divider - register a divider clock with the clock framework + * @dev: device registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @reg: register address to adjust divider + * @shift: number of bits to shift the bitfield + * @width: width of the bitfield + * @clk_divider_flags: divider-specific flags for this clock + * @lock: shared register lock for this clock + */ +struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, spinlock_t *lock) +{ + return _register_divider(dev, name, parent_name, flags, reg, shift, + width, clk_divider_flags, NULL, lock); +} +EXPORT_SYMBOL_GPL(clk_hw_register_divider); + +/** * clk_register_divider_table - register a table based divider clock with * the clock framework * @dev: device registering this clock @@ -517,11 +547,41 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { - return _register_divider(dev, name, parent_name, flags, reg, shift, + struct clk_hw *hw; + + hw = _register_divider(dev, name, parent_name, flags, reg, shift, width, clk_divider_flags, table, lock); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } EXPORT_SYMBOL_GPL(clk_register_divider_table); +/** + * clk_hw_register_divider_table - register a table based divider clock with + * the clock framework + * @dev: device registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @reg: register address to adjust divider + * @shift: number of bits to shift the bitfield + * @width: width of the bitfield + * @clk_divider_flags: divider-specific flags for this clock + * @table: array of divider/value pairs ending with a div set to 0 + * @lock: shared register lock for this clock + */ +struct clk_hw *clk_hw_register_divider_table(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, const struct clk_div_table *table, + spinlock_t *lock) +{ + return _register_divider(dev, name, parent_name, flags, reg, shift, + width, clk_divider_flags, table, lock); +} +EXPORT_SYMBOL_GPL(clk_hw_register_divider_table); + void clk_unregister_divider(struct clk *clk) { struct clk_divider *div; @@ -537,3 +597,18 @@ void clk_unregister_divider(struct clk *clk) kfree(div); } EXPORT_SYMBOL_GPL(clk_unregister_divider); + +/** + * clk_hw_unregister_divider - unregister a clk divider + * @hw: hardware-specific clock data to unregister + */ +void clk_hw_unregister_divider(struct clk_hw *hw) +{ + struct clk_divider *div; + + div = to_clk_divider(hw); + + clk_hw_unregister(hw); + kfree(div); +} +EXPORT_SYMBOL_GPL(clk_hw_unregister_divider); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index bf8c8bb..8885d03 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -407,12 +407,22 @@ struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, spinlock_t *lock); +struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, spinlock_t *lock); struct clk *clk_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock); +struct clk_hw *clk_hw_register_divider_table(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, const struct clk_div_table *table, + spinlock_t *lock); void clk_unregister_divider(struct clk *clk); +void clk_hw_unregister_divider(struct clk_hw *hw); /** * struct clk_mux - multiplexer clock -- cgit v0.10.2 From e270d8cb13763f58107198e879cf396511ba2867 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 6 Feb 2016 23:54:45 -0800 Subject: clk: gate: Add hw based registration APIs Add registration APIs in the clk gate code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index d0d8ec8..4e691e3 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -110,7 +110,7 @@ const struct clk_ops clk_gate_ops = { EXPORT_SYMBOL_GPL(clk_gate_ops); /** - * clk_register_gate - register a gate clock with the clock framework + * clk_hw_register_gate - register a gate clock with the clock framework * @dev: device that is registering this clock * @name: name of this clock * @parent_name: name of this clock's parent @@ -120,14 +120,15 @@ EXPORT_SYMBOL_GPL(clk_gate_ops); * @clk_gate_flags: gate-specific flags for this clock * @lock: shared register lock for this clock */ -struct clk *clk_register_gate(struct device *dev, const char *name, +struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, u8 clk_gate_flags, spinlock_t *lock) { struct clk_gate *gate; - struct clk *clk; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (clk_gate_flags & CLK_GATE_HIWORD_MASK) { if (bit_idx > 15) { @@ -154,12 +155,29 @@ struct clk *clk_register_gate(struct device *dev, const char *name, gate->lock = lock; gate->hw.init = &init; - clk = clk_register(dev, &gate->hw); - - if (IS_ERR(clk)) + hw = &gate->hw; + ret = clk_hw_register(dev, hw); + if (ret) { kfree(gate); + hw = ERR_PTR(ret); + } - return clk; + return hw; +} +EXPORT_SYMBOL_GPL(clk_hw_register_gate); + +struct clk *clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct clk_hw *hw; + + hw = clk_hw_register_gate(dev, name, parent_name, flags, reg, + bit_idx, clk_gate_flags, lock); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } EXPORT_SYMBOL_GPL(clk_register_gate); @@ -178,3 +196,14 @@ void clk_unregister_gate(struct clk *clk) kfree(gate); } EXPORT_SYMBOL_GPL(clk_unregister_gate); + +void clk_hw_unregister_gate(struct clk_hw *hw) +{ + struct clk_gate *gate; + + gate = to_clk_gate(hw); + + clk_hw_unregister(hw); + kfree(gate); +} +EXPORT_SYMBOL_GPL(clk_hw_unregister_gate); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 8885d03..bf12050 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -326,7 +326,12 @@ struct clk *clk_register_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, u8 clk_gate_flags, spinlock_t *lock); +struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); void clk_unregister_gate(struct clk *clk); +void clk_hw_unregister_gate(struct clk_hw *hw); struct clk_div_table { unsigned int val; -- cgit v0.10.2 From 264b31719735eb1fcbed47cecdb20f517e804856 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Feb 2016 00:05:48 -0800 Subject: clk: mux: Add hw based registration APIs Add registration APIs in the clk mux code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 252188f..16a3d57 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -113,16 +113,17 @@ const struct clk_ops clk_mux_ro_ops = { }; EXPORT_SYMBOL_GPL(clk_mux_ro_ops); -struct clk *clk_register_mux_table(struct device *dev, const char *name, +struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u32 mask, u8 clk_mux_flags, u32 *table, spinlock_t *lock) { struct clk_mux *mux; - struct clk *clk; + struct clk_hw *hw; struct clk_init_data init; u8 width = 0; + int ret; if (clk_mux_flags & CLK_MUX_HIWORD_MASK) { width = fls(mask) - ffs(mask) + 1; @@ -157,12 +158,31 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name, mux->table = table; mux->hw.init = &init; - clk = clk_register(dev, &mux->hw); - - if (IS_ERR(clk)) + hw = &mux->hw; + ret = clk_hw_register(dev, hw); + if (ret) { kfree(mux); + hw = ERR_PTR(ret); + } - return clk; + return hw; +} +EXPORT_SYMBOL_GPL(clk_hw_register_mux_table); + +struct clk *clk_register_mux_table(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table, spinlock_t *lock) +{ + struct clk_hw *hw; + + hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents, + flags, reg, shift, mask, clk_mux_flags, + table, lock); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } EXPORT_SYMBOL_GPL(clk_register_mux_table); @@ -180,6 +200,20 @@ struct clk *clk_register_mux(struct device *dev, const char *name, } EXPORT_SYMBOL_GPL(clk_register_mux); +struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_mux_flags, spinlock_t *lock) +{ + u32 mask = BIT(width) - 1; + + return clk_hw_register_mux_table(dev, name, parent_names, num_parents, + flags, reg, shift, mask, clk_mux_flags, + NULL, lock); +} +EXPORT_SYMBOL_GPL(clk_hw_register_mux); + void clk_unregister_mux(struct clk *clk) { struct clk_mux *mux; @@ -195,3 +229,14 @@ void clk_unregister_mux(struct clk *clk) kfree(mux); } EXPORT_SYMBOL_GPL(clk_unregister_mux); + +void clk_hw_unregister_mux(struct clk_hw *hw) +{ + struct clk_mux *mux; + + mux = to_clk_mux(hw); + + clk_hw_unregister(hw); + kfree(mux); +} +EXPORT_SYMBOL_GPL(clk_hw_unregister_mux); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index bf12050..d690d99 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -478,14 +478,25 @@ struct clk *clk_register_mux(struct device *dev, const char *name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock); +struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_mux_flags, spinlock_t *lock); struct clk *clk_register_mux_table(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u32 mask, u8 clk_mux_flags, u32 *table, spinlock_t *lock); +struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table, spinlock_t *lock); void clk_unregister_mux(struct clk *clk); +void clk_hw_unregister_mux(struct clk_hw *hw); void of_fixed_factor_clk_setup(struct device_node *node); -- cgit v0.10.2 From 0759ac8a73dc2c8cc8ac697fbe5dbd8d67348d37 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Feb 2016 00:11:06 -0800 Subject: clk: fixed-factor: Add hw based registration APIs Add registration APIs in the clk fixed-factor code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 053448e..75cd6c7 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -68,13 +68,14 @@ const struct clk_ops clk_fixed_factor_ops = { }; EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); -struct clk *clk_register_fixed_factor(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, +struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div) { struct clk_fixed_factor *fix; struct clk_init_data init; - struct clk *clk; + struct clk_hw *hw; + int ret; fix = kmalloc(sizeof(*fix), GFP_KERNEL); if (!fix) @@ -91,12 +92,28 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, init.parent_names = &parent_name; init.num_parents = 1; - clk = clk_register(dev, &fix->hw); - - if (IS_ERR(clk)) + hw = &fix->hw; + ret = clk_hw_register(dev, hw); + if (ret) { kfree(fix); + hw = ERR_PTR(ret); + } + + return hw; +} +EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor); + +struct clk *clk_register_fixed_factor(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div) +{ + struct clk_hw *hw; - return clk; + hw = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult, + div); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } EXPORT_SYMBOL_GPL(clk_register_fixed_factor); @@ -113,6 +130,17 @@ void clk_unregister_fixed_factor(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_unregister_fixed_factor); +void clk_hw_unregister_fixed_factor(struct clk_hw *hw) +{ + struct clk_fixed_factor *fix; + + fix = to_clk_fixed_factor(hw); + + clk_hw_unregister(hw); + kfree(fix); +} +EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor); + #ifdef CONFIG_OF /** * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index d690d99..79ad1a8 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -525,6 +525,10 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div); void clk_unregister_fixed_factor(struct clk *clk); +struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div); +void clk_hw_unregister_fixed_factor(struct clk_hw *hw); /** * struct clk_fractional_divider - adjustable fractional divider clock -- cgit v0.10.2 From 39b44cff4ad4af6d7abd9dd2acb288b005c26503 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Feb 2016 00:15:09 -0800 Subject: clk: fractional-divider: Add hw based registration APIs Add registration APIs in the clk fractional divider code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 1abcd76..aab9046 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -116,14 +116,15 @@ const struct clk_ops clk_fractional_divider_ops = { }; EXPORT_SYMBOL_GPL(clk_fractional_divider_ops); -struct clk *clk_register_fractional_divider(struct device *dev, +struct clk_hw *clk_hw_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, u8 clk_divider_flags, spinlock_t *lock) { struct clk_fractional_divider *fd; struct clk_init_data init; - struct clk *clk; + struct clk_hw *hw; + int ret; fd = kzalloc(sizeof(*fd), GFP_KERNEL); if (!fd) @@ -146,10 +147,39 @@ struct clk *clk_register_fractional_divider(struct device *dev, fd->lock = lock; fd->hw.init = &init; - clk = clk_register(dev, &fd->hw); - if (IS_ERR(clk)) + hw = &fd->hw; + ret = clk_hw_register(dev, hw); + if (ret) { kfree(fd); + hw = ERR_PTR(ret); + } + + return hw; +} +EXPORT_SYMBOL_GPL(clk_hw_register_fractional_divider); - return clk; +struct clk *clk_register_fractional_divider(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, + u8 clk_divider_flags, spinlock_t *lock) +{ + struct clk_hw *hw; + + hw = clk_hw_register_fractional_divider(dev, name, parent_name, flags, + reg, mshift, mwidth, nshift, nwidth, clk_divider_flags, + lock); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } EXPORT_SYMBOL_GPL(clk_register_fractional_divider); + +void clk_hw_unregister_fractional_divider(struct clk_hw *hw) +{ + struct clk_fractional_divider *fd; + + fd = to_clk_fd(hw); + + clk_hw_unregister(hw); + kfree(fd); +} diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 79ad1a8..bcbaf6c 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -563,6 +563,11 @@ struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, u8 clk_divider_flags, spinlock_t *lock); +struct clk_hw *clk_hw_register_fractional_divider(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, + u8 clk_divider_flags, spinlock_t *lock); +void clk_hw_unregister_fractional_divider(struct clk_hw *hw); /** * struct clk_multiplier - adjustable multiplier clock -- cgit v0.10.2 From 49cb392d36397a296dcd51ec57cf83585a89a94a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Feb 2016 00:20:31 -0800 Subject: clk: composite: Add hw based registration APIs Add registration APIs in the clk composite code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 1f903e1f8..463fadd 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -184,17 +184,18 @@ static void clk_composite_disable(struct clk_hw *hw) gate_ops->disable(gate_hw); } -struct clk *clk_register_composite(struct device *dev, const char *name, +struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, const char * const *parent_names, int num_parents, struct clk_hw *mux_hw, const struct clk_ops *mux_ops, struct clk_hw *rate_hw, const struct clk_ops *rate_ops, struct clk_hw *gate_hw, const struct clk_ops *gate_ops, unsigned long flags) { - struct clk *clk; + struct clk_hw *hw; struct clk_init_data init; struct clk_composite *composite; struct clk_ops *clk_composite_ops; + int ret; composite = kzalloc(sizeof(*composite), GFP_KERNEL); if (!composite) @@ -204,12 +205,13 @@ struct clk *clk_register_composite(struct device *dev, const char *name, init.flags = flags | CLK_IS_BASIC; init.parent_names = parent_names; init.num_parents = num_parents; + hw = &composite->hw; clk_composite_ops = &composite->ops; if (mux_hw && mux_ops) { if (!mux_ops->get_parent) { - clk = ERR_PTR(-EINVAL); + hw = ERR_PTR(-EINVAL); goto err; } @@ -224,7 +226,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name, if (rate_hw && rate_ops) { if (!rate_ops->recalc_rate) { - clk = ERR_PTR(-EINVAL); + hw = ERR_PTR(-EINVAL); goto err; } clk_composite_ops->recalc_rate = clk_composite_recalc_rate; @@ -253,7 +255,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name, if (gate_hw && gate_ops) { if (!gate_ops->is_enabled || !gate_ops->enable || !gate_ops->disable) { - clk = ERR_PTR(-EINVAL); + hw = ERR_PTR(-EINVAL); goto err; } @@ -267,22 +269,41 @@ struct clk *clk_register_composite(struct device *dev, const char *name, init.ops = clk_composite_ops; composite->hw.init = &init; - clk = clk_register(dev, &composite->hw); - if (IS_ERR(clk)) + ret = clk_hw_register(dev, hw); + if (ret) { + hw = ERR_PTR(ret); goto err; + } if (composite->mux_hw) - composite->mux_hw->clk = clk; + composite->mux_hw->clk = hw->clk; if (composite->rate_hw) - composite->rate_hw->clk = clk; + composite->rate_hw->clk = hw->clk; if (composite->gate_hw) - composite->gate_hw->clk = clk; + composite->gate_hw->clk = hw->clk; - return clk; + return hw; err: kfree(composite); - return clk; + return hw; +} + +struct clk *clk_register_composite(struct device *dev, const char *name, + const char * const *parent_names, int num_parents, + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, + unsigned long flags) +{ + struct clk_hw *hw; + + hw = clk_hw_register_composite(dev, name, parent_names, num_parents, + mux_hw, mux_ops, rate_hw, rate_ops, gate_hw, gate_ops, + flags); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index bcbaf6c..456c3ce 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -638,6 +638,13 @@ struct clk *clk_register_composite(struct device *dev, const char *name, struct clk_hw *rate_hw, const struct clk_ops *rate_ops, struct clk_hw *gate_hw, const struct clk_ops *gate_ops, unsigned long flags); +struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, + const char * const *parent_names, int num_parents, + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, + unsigned long flags); +void clk_hw_unregister_composite(struct clk_hw *hw); /*** * struct clk_gpio_gate - gpio gated clock -- cgit v0.10.2 From b120743a64a3ec68b8c5310a6009094329b4a33b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Feb 2016 00:27:55 -0800 Subject: clk: gpio: Add hw based registration APIs Add registration APIs in the clk gpio code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 08f65ac..86b2457 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -94,13 +94,13 @@ const struct clk_ops clk_gpio_mux_ops = { }; EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); -static struct clk *clk_register_gpio(struct device *dev, const char *name, +static struct clk_hw *clk_register_gpio(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low, unsigned long flags, const struct clk_ops *clk_gpio_ops) { struct clk_gpio *clk_gpio; - struct clk *clk; + struct clk_hw *hw; struct clk_init_data init = {}; unsigned long gpio_flags; int err; @@ -141,24 +141,26 @@ static struct clk *clk_register_gpio(struct device *dev, const char *name, clk_gpio->gpiod = gpio_to_desc(gpio); clk_gpio->hw.init = &init; + hw = &clk_gpio->hw; if (dev) - clk = devm_clk_register(dev, &clk_gpio->hw); + err = devm_clk_hw_register(dev, hw); else - clk = clk_register(NULL, &clk_gpio->hw); + err = clk_hw_register(NULL, hw); - if (!IS_ERR(clk)) - return clk; + if (!err) + return hw; if (!dev) { gpiod_put(clk_gpio->gpiod); kfree(clk_gpio); } - return clk; + return ERR_PTR(err); } /** - * clk_register_gpio_gate - register a gpio clock gate with the clock framework + * clk_hw_register_gpio_gate - register a gpio clock gate with the clock + * framework * @dev: device that is registering this clock * @name: name of this clock * @parent_name: name of this clock's parent @@ -166,7 +168,7 @@ static struct clk *clk_register_gpio(struct device *dev, const char *name, * @active_low: true if gpio should be set to 0 to enable clock * @flags: clock flags */ -struct clk *clk_register_gpio_gate(struct device *dev, const char *name, +struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, const char *parent_name, unsigned gpio, bool active_low, unsigned long flags) { @@ -175,10 +177,24 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, (parent_name ? 1 : 0), gpio, active_low, flags, &clk_gpio_gate_ops); } +EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate); + +struct clk *clk_register_gpio_gate(struct device *dev, const char *name, + const char *parent_name, unsigned gpio, bool active_low, + unsigned long flags) +{ + struct clk_hw *hw; + + hw = clk_hw_register_gpio_gate(dev, name, parent_name, gpio, active_low, + flags); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; +} EXPORT_SYMBOL_GPL(clk_register_gpio_gate); /** - * clk_register_gpio_mux - register a gpio clock mux with the clock framework + * clk_hw_register_gpio_mux - register a gpio clock mux with the clock framework * @dev: device that is registering this clock * @name: name of this clock * @parent_names: names of this clock's parents @@ -187,7 +203,7 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_gate); * @active_low: true if gpio should be set to 0 to enable clock * @flags: clock flags */ -struct clk *clk_register_gpio_mux(struct device *dev, const char *name, +struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low, unsigned long flags) { @@ -199,6 +215,20 @@ struct clk *clk_register_gpio_mux(struct device *dev, const char *name, return clk_register_gpio(dev, name, parent_names, num_parents, gpio, active_low, flags, &clk_gpio_mux_ops); } +EXPORT_SYMBOL_GPL(clk_hw_register_gpio_mux); + +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags) +{ + struct clk_hw *hw; + + hw = clk_hw_register_gpio_mux(dev, name, parent_names, num_parents, + gpio, active_low, flags); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; +} EXPORT_SYMBOL_GPL(clk_register_gpio_mux); static int gpio_clk_driver_probe(struct platform_device *pdev) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 456c3ce..6c36c5e 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -667,6 +667,10 @@ extern const struct clk_ops clk_gpio_gate_ops; struct clk *clk_register_gpio_gate(struct device *dev, const char *name, const char *parent_name, unsigned gpio, bool active_low, unsigned long flags); +struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, + const char *parent_name, unsigned gpio, bool active_low, + unsigned long flags); +void clk_hw_unregister_gpio_gate(struct clk_hw *hw); /** * struct clk_gpio_mux - gpio controlled clock multiplexer @@ -682,6 +686,10 @@ extern const struct clk_ops clk_gpio_mux_ops; struct clk *clk_register_gpio_mux(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low, unsigned long flags); +struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags); +void clk_hw_unregister_gpio_mux(struct clk_hw *hw); /** * clk_register - allocate a new clock, register it and return an opaque cookie -- cgit v0.10.2 From 26ef56be9e0944a9b136169eb47140f309ce745b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Feb 2016 00:34:13 -0800 Subject: clk: fixed-rate: Add hw based registration APIs Add registration APIs in the clk fixed-rate code to return struct clk_hw pointers instead of struct clk pointers. This way we hide the struct clk pointer from providers unless they need to use consumer facing APIs. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index cd9dc92..8e4453e 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -45,8 +45,8 @@ const struct clk_ops clk_fixed_rate_ops = { EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); /** - * clk_register_fixed_rate_with_accuracy - register fixed-rate clock with the - * clock framework + * clk_hw_register_fixed_rate_with_accuracy - register fixed-rate clock with + * the clock framework * @dev: device that is registering this clock * @name: name of this clock * @parent_name: name of clock's parent @@ -54,13 +54,14 @@ EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); * @fixed_rate: non-adjustable clock rate * @fixed_accuracy: non-adjustable clock rate */ -struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev, +struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate, unsigned long fixed_accuracy) { struct clk_fixed_rate *fixed; - struct clk *clk; + struct clk_hw *hw; struct clk_init_data init; + int ret; /* allocate fixed-rate clock */ fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); @@ -79,22 +80,49 @@ struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev, fixed->hw.init = &init; /* register the clock */ - clk = clk_register(dev, &fixed->hw); - if (IS_ERR(clk)) + hw = &fixed->hw; + ret = clk_hw_register(dev, hw); + if (ret) { kfree(fixed); + hw = ERR_PTR(ret); + } - return clk; + return hw; +} +EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate_with_accuracy); + +struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + unsigned long fixed_rate, unsigned long fixed_accuracy) +{ + struct clk_hw *hw; + + hw = clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name, + flags, fixed_rate, fixed_accuracy); + if (IS_ERR(hw)) + return ERR_CAST(hw); + return hw->clk; } EXPORT_SYMBOL_GPL(clk_register_fixed_rate_with_accuracy); /** - * clk_register_fixed_rate - register fixed-rate clock with the clock framework + * clk_hw_register_fixed_rate - register fixed-rate clock with the clock + * framework * @dev: device that is registering this clock * @name: name of this clock * @parent_name: name of clock's parent * @flags: framework-specific flags * @fixed_rate: non-adjustable clock rate */ +struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned long fixed_rate) +{ + return clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name, + flags, fixed_rate, 0); +} +EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate); + struct clk *clk_register_fixed_rate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 6c36c5e..c3fc042 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -282,10 +282,17 @@ extern const struct clk_ops clk_fixed_rate_ops; struct clk *clk_register_fixed_rate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate); +struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned long fixed_rate); struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate, unsigned long fixed_accuracy); void clk_unregister_fixed_rate(struct clk *clk); +struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + unsigned long fixed_rate, unsigned long fixed_accuracy); + void of_fixed_clk_setup(struct device_node *np); /** -- cgit v0.10.2 From 660e1551939931657808d47838a3f443c0e83fd0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 11 Mar 2016 16:13:32 +0200 Subject: clk: ti: dra7-atl-clock: Fix of_node reference counting of_find_node_by_name() will call of_node_put() on the node so we need to get it first to avoid warnings. The cfg_node needs to be put after we have finished processing the properties. Signed-off-by: Peter Ujfalusi Tested-by: Nishanth Menon Signed-off-by: Stephen Boyd diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 2e14dfb..c773332 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -265,6 +265,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) /* Get configuration for the ATL instances */ snprintf(prop, sizeof(prop), "atl%u", i); + of_node_get(node); cfg_node = of_find_node_by_name(node, prop); if (cfg_node) { ret = of_property_read_u32(cfg_node, "bws", @@ -278,6 +279,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) atl_write(cinfo, DRA7_ATL_AWSMUX_REG(i), cdesc->aws); } + of_node_put(cfg_node); } cdesc->probed = true; -- cgit v0.10.2 From 3432a2e39742ebbd8b01890a742bd45b219d5d8f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 18 Apr 2016 16:55:34 +0200 Subject: clk: qoriq: add __init attribute Add __init attribute on a function that is only called from other __init functions and that is not inlined, at least with gcc version 4.8.4 on an x86 machine with allyesconfig. Currently, the function is put in the .text.unlikely segment. Declaring it as __init will cause it to be put in the .init.text and to disappear after initialization. The result of objdump -x on the function before the change is as follows: 0000000000000000 l F .text.unlikely 0000000000000071 sysclk_from_fixed.constprop.5 And after the change it is as follows: 0000000000000480 l F .init.text 000000000000006c sysclk_from_fixed.constprop.5 Done with the help of Coccinelle. The semantic patch checks for local static non-init functions that are called from an __init function and are not called from any other function. Signed-off-by: Julia Lawall Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index d247b75..58566a17 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -869,7 +869,8 @@ static void __init core_mux_init(struct device_node *np) } } -static struct clk *sysclk_from_fixed(struct device_node *node, const char *name) +static struct clk __init +*sysclk_from_fixed(struct device_node *node, const char *name) { u32 rate; -- cgit v0.10.2 From 286259ef4b30bff092b223c530c7fa4dc5fd792d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 13 Apr 2016 13:05:02 -0700 Subject: clk: bcm2835: Fix compiler warnings on 64-bit builds Signed-off-by: Eric Anholt Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 4c0f1b5..87616de 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -400,17 +400,17 @@ struct bcm2835_pll_ana_bits { static const struct bcm2835_pll_ana_bits bcm2835_ana_default = { .mask0 = 0, .set0 = 0, - .mask1 = ~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK), + .mask1 = (u32)~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK), .set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT), - .mask3 = ~A2W_PLL_KA_MASK, + .mask3 = (u32)~A2W_PLL_KA_MASK, .set3 = (2 << A2W_PLL_KA_SHIFT), .fb_prediv_mask = BIT(14), }; static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = { - .mask0 = ~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK), + .mask0 = (u32)~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK), .set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT), - .mask1 = ~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK), + .mask1 = (u32)~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK), .set1 = (6 << A2W_PLLH_KP_SHIFT), .mask3 = 0, .set3 = 0, -- cgit v0.10.2 From e708b383f4b94feca2e0d5d06e1cfc13cdfea100 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 13 Apr 2016 13:05:03 -0700 Subject: clk: bcm2835: Fix PLL poweron In poweroff, we set the reset bit and the power down bit, but only managed to unset the reset bit for poweron. This meant that if HDMI did -EPROBE_DEFER after it had grabbed its clocks, we'd power down the PLLH (that had been on at boot time) and never recover. Signed-off-by: Eric Anholt Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Cc: stable@vger.kernel.org Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 87616de..7a79708 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -554,6 +554,10 @@ static int bcm2835_pll_on(struct clk_hw *hw) const struct bcm2835_pll_data *data = pll->data; ktime_t timeout; + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) & + ~A2W_PLL_CTRL_PWRDN); + /* Take the PLL out of reset. */ cprman_write(cprman, data->cm_ctrl_reg, cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST); -- cgit v0.10.2 From 03ae1747869437a8e4d0d4e79d4c88c25c6df39c Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 19 Apr 2016 21:29:27 +0200 Subject: clk: rockchip: fix checkpatch warning in core code We seem to have accumulated a bunch of checkpatch warnings, with mainly overlong lines and two unnecessary allocation error messages. Most were introduced with the recent multi-controller-support but some were quite a bit older. Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index e0dc7e8..bc856f2 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -123,7 +123,8 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; raw_value |= nineties; - writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), mmc_clock->reg); + writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), + mmc_clock->reg); pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n", clk_hw_get_name(hw), degrees, delay_num, diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 277f927..f0a8be1 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -42,7 +42,8 @@ * sometimes without one of those components. */ static struct clk *rockchip_clk_register_branch(const char *name, - const char *const *parent_names, u8 num_parents, void __iomem *base, + const char *const *parent_names, u8 num_parents, + void __iomem *base, int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, u8 div_shift, u8 div_width, u8 div_flags, struct clk_div_table *div_table, int gate_offset, @@ -139,9 +140,11 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb, pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n", __func__, event, ndata->old_rate, ndata->new_rate); if (event == PRE_RATE_CHANGE) { - frac->rate_change_idx = frac->mux_ops->get_parent(&frac_mux->hw); + frac->rate_change_idx = + frac->mux_ops->get_parent(&frac_mux->hw); if (frac->rate_change_idx != frac->mux_frac_idx) { - frac->mux_ops->set_parent(&frac_mux->hw, frac->mux_frac_idx); + frac->mux_ops->set_parent(&frac_mux->hw, + frac->mux_frac_idx); frac->rate_change_remuxed = 1; } } else if (event == POST_RATE_CHANGE) { @@ -152,7 +155,8 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb, * reaches the mux itself. */ if (frac->rate_change_remuxed) { - frac->mux_ops->set_parent(&frac_mux->hw, frac->rate_change_idx); + frac->mux_ops->set_parent(&frac_mux->hw, + frac->rate_change_idx); frac->rate_change_remuxed = 0; } } @@ -326,18 +330,12 @@ struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np, int i; ctx = kzalloc(sizeof(struct rockchip_clk_provider), GFP_KERNEL); - if (!ctx) { - pr_err("%s: Could not allocate clock provider context\n", - __func__); + if (!ctx) return ERR_PTR(-ENOMEM); - } clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); - if (!clk_table) { - pr_err("%s: Could not allocate clock lookup table\n", - __func__); + if (!clk_table) goto err_free; - } for (i = 0; i < nr_clks; ++i) clk_table[i] = ERR_PTR(-ENOENT); @@ -367,7 +365,8 @@ void __init rockchip_clk_of_add_provider(struct device_node *np, struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx) { if (IS_ERR(ctx->grf)) - ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, "rockchip,grf"); + ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, + "rockchip,grf"); return ctx->grf; } @@ -427,7 +426,8 @@ void __init rockchip_clk_register_branches( if (list->div_table) clk = clk_register_divider_table(NULL, list->name, list->parent_names[0], - flags, ctx->reg_base + list->muxdiv_offset, + flags, + ctx->reg_base + list->muxdiv_offset, list->div_shift, list->div_width, list->div_flags, list->div_table, &ctx->lock); @@ -441,7 +441,8 @@ void __init rockchip_clk_register_branches( case branch_fraction_divider: clk = rockchip_clk_register_frac_branch(ctx, list->name, list->parent_names, list->num_parents, - ctx->reg_base, list->muxdiv_offset, list->div_flags, + ctx->reg_base, list->muxdiv_offset, + list->div_flags, list->gate_offset, list->gate_shift, list->gate_flags, flags, list->child, &ctx->lock); @@ -457,7 +458,8 @@ void __init rockchip_clk_register_branches( case branch_composite: clk = rockchip_clk_register_branch(list->name, list->parent_names, list->num_parents, - ctx->reg_base, list->muxdiv_offset, list->mux_shift, + ctx->reg_base, list->muxdiv_offset, + list->mux_shift, list->mux_width, list->mux_flags, list->div_shift, list->div_width, list->div_flags, list->div_table, @@ -517,8 +519,8 @@ void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, struct clk *clk; clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents, - reg_data, rates, nrates, ctx->reg_base, - &ctx->lock); + reg_data, rates, nrates, + ctx->reg_base, &ctx->lock); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s: %ld\n", __func__, name, PTR_ERR(clk)); @@ -560,8 +562,10 @@ static struct notifier_block rockchip_restart_handler = { .priority = 128, }; -void __init rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, - unsigned int reg, void (*cb)(void)) +void __init +rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, + unsigned int reg, + void (*cb)(void)) { int ret; diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 4a355bf..1abb7d0 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -252,7 +252,7 @@ struct rockchip_cpuclk_rate_table { }; /** - * struct rockchip_cpuclk_reg_data - describes register offsets and masks of the cpuclock + * struct rockchip_cpuclk_reg_data - register offsets and masks of the cpuclock * @core_reg: register offset of the core settings register * @div_core_shift: core divider offset used to divide the pll value * @div_core_mask: core divider mask -- cgit v0.10.2 From 0bbd72b4c64fc0803a6efd86ea151184bf553f97 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 18 Apr 2016 12:01:35 +0200 Subject: clk: Add Oxford Semiconductor OXNAS Standard Clocks Add Oxford Semiconductor OXNAS SoC Family Standard Clocks support. Signed-off-by: Neil Armstrong [sboyd@codeaurora.org: Drop NULL/continue check in registration loop] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c455549..2dd371d 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -197,6 +197,12 @@ config COMMON_CLK_PXA ---help--- Support for the Marvell PXA SoC. +config COMMON_CLK_OXNAS + bool "Clock driver for the OXNAS SoC Family" + select MFD_SYSCON + ---help--- + Support for the OXNAS SoC Family clocks. + source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 54964eb..4ef71a1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o +obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o diff --git a/drivers/clk/clk-oxnas.c b/drivers/clk/clk-oxnas.c new file mode 100644 index 0000000..efba7d4 --- /dev/null +++ b/drivers/clk/clk-oxnas.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2010 Broadcom + * Copyright (C) 2012 Stephen Warren + * Copyright (C) 2016 Neil Armstrong + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Standard regmap gate clocks */ +struct clk_oxnas { + struct clk_hw hw; + signed char bit; + struct regmap *regmap; +}; + +/* Regmap offsets */ +#define CLK_STAT_REGOFFSET 0x24 +#define CLK_SET_REGOFFSET 0x2c +#define CLK_CLR_REGOFFSET 0x30 + +static inline struct clk_oxnas *to_clk_oxnas(struct clk_hw *hw) +{ + return container_of(hw, struct clk_oxnas, hw); +} + +static int oxnas_clk_is_enabled(struct clk_hw *hw) +{ + struct clk_oxnas *std = to_clk_oxnas(hw); + int ret; + unsigned int val; + + ret = regmap_read(std->regmap, CLK_STAT_REGOFFSET, &val); + if (ret < 0) + return ret; + + return val & BIT(std->bit); +} + +static int oxnas_clk_enable(struct clk_hw *hw) +{ + struct clk_oxnas *std = to_clk_oxnas(hw); + + regmap_write(std->regmap, CLK_SET_REGOFFSET, BIT(std->bit)); + + return 0; +} + +static void oxnas_clk_disable(struct clk_hw *hw) +{ + struct clk_oxnas *std = to_clk_oxnas(hw); + + regmap_write(std->regmap, CLK_CLR_REGOFFSET, BIT(std->bit)); +} + +static const struct clk_ops oxnas_clk_ops = { + .enable = oxnas_clk_enable, + .disable = oxnas_clk_disable, + .is_enabled = oxnas_clk_is_enabled, +}; + +static const char *const oxnas_clk_parents[] = { + "oscillator", +}; + +static const char *const eth_parents[] = { + "gmacclk", +}; + +#define DECLARE_STD_CLKP(__clk, __parent) \ +static const struct clk_init_data clk_##__clk##_init = { \ + .name = __stringify(__clk), \ + .ops = &oxnas_clk_ops, \ + .parent_names = __parent, \ + .num_parents = ARRAY_SIZE(__parent), \ +} + +#define DECLARE_STD_CLK(__clk) DECLARE_STD_CLKP(__clk, oxnas_clk_parents) + +/* Hardware Bit - Clock association */ +struct clk_oxnas_init_data { + unsigned long bit; + const struct clk_init_data *clk_init; +}; + +/* Clk init data declaration */ +DECLARE_STD_CLK(leon); +DECLARE_STD_CLK(dma_sgdma); +DECLARE_STD_CLK(cipher); +DECLARE_STD_CLK(sata); +DECLARE_STD_CLK(audio); +DECLARE_STD_CLK(usbmph); +DECLARE_STD_CLKP(etha, eth_parents); +DECLARE_STD_CLK(pciea); +DECLARE_STD_CLK(nand); + +/* Table index is clock indice */ +static const struct clk_oxnas_init_data clk_oxnas_init[] = { + [0] = {0, &clk_leon_init}, + [1] = {1, &clk_dma_sgdma_init}, + [2] = {2, &clk_cipher_init}, + /* Skip & Do not touch to DDR clock */ + [3] = {4, &clk_sata_init}, + [4] = {5, &clk_audio_init}, + [5] = {6, &clk_usbmph_init}, + [6] = {7, &clk_etha_init}, + [7] = {8, &clk_pciea_init}, + [8] = {9, &clk_nand_init}, +}; + +struct clk_oxnas_data { + struct clk_oxnas clk_oxnas[ARRAY_SIZE(clk_oxnas_init)]; + struct clk_onecell_data onecell_data[ARRAY_SIZE(clk_oxnas_init)]; + struct clk *clks[ARRAY_SIZE(clk_oxnas_init)]; +}; + +static int oxnas_stdclk_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct clk_oxnas_data *clk_oxnas; + struct regmap *regmap; + int i; + + clk_oxnas = devm_kzalloc(&pdev->dev, sizeof(*clk_oxnas), GFP_KERNEL); + if (!clk_oxnas) + return -ENOMEM; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (!regmap) { + dev_err(&pdev->dev, "failed to have parent regmap\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(clk_oxnas_init); i++) { + struct clk_oxnas *_clk; + + _clk = &clk_oxnas->clk_oxnas[i]; + _clk->bit = clk_oxnas_init[i].bit; + _clk->hw.init = clk_oxnas_init[i].clk_init; + _clk->regmap = regmap; + + clk_oxnas->clks[i] = + devm_clk_register(&pdev->dev, &_clk->hw); + if (WARN_ON(IS_ERR(clk_oxnas->clks[i]))) + return PTR_ERR(clk_oxnas->clks[i]); + } + + clk_oxnas->onecell_data->clks = clk_oxnas->clks; + clk_oxnas->onecell_data->clk_num = ARRAY_SIZE(clk_oxnas_init); + + return of_clk_add_provider(np, of_clk_src_onecell_get, + clk_oxnas->onecell_data); +} + +static int oxnas_stdclk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +static const struct of_device_id oxnas_stdclk_dt_ids[] = { + { .compatible = "oxsemi,ox810se-stdclk" }, + { } +}; +MODULE_DEVICE_TABLE(of, oxnas_stdclk_dt_ids); + +static struct platform_driver oxnas_stdclk_driver = { + .probe = oxnas_stdclk_probe, + .remove = oxnas_stdclk_remove, + .driver = { + .name = "oxnas-stdclk", + .of_match_table = oxnas_stdclk_dt_ids, + }, +}; + +module_platform_driver(oxnas_stdclk_driver); -- cgit v0.10.2 From 624b5ea624f368e8755304bc63a5ee5d0a899dcb Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 18 Apr 2016 12:01:36 +0200 Subject: dt-bindings: Add Oxford Semiconductor OXNAS Standard Clocks bindings Acked-by: Rob Herring Signed-off-by: Neil Armstrong Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt b/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt new file mode 100644 index 0000000..208cca6 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt @@ -0,0 +1,35 @@ +Oxford Semiconductor OXNAS SoC Family Standard Clocks +================================================ + +Please also refer to clock-bindings.txt in this directory for common clock +bindings usage. + +Required properties: +- compatible: Should be "oxsemi,ox810se-stdclk" +- #clock-cells: 1, see below + +Parent node should have the following properties : +- compatible: Should be "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd" + +For OX810SE, the clock indices are : + - 0: LEON + - 1: DMA_SGDMA + - 2: CIPHER + - 3: SATA + - 4: AUDIO + - 5: USBMPH + - 6: ETHA + - 7: PCIA + - 8: NAND + +example: + +sys: sys-ctrl@000000 { + compatible = "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd"; + reg = <0x000000 0x100000>; + + stdclk: stdclk { + compatible = "oxsemi,ox810se-stdclk"; + #clock-cells = <1>; + }; +}; -- cgit v0.10.2 From 92a39d9043ba5ff98adb1c31491f00c7bea5466e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 23 Mar 2016 17:38:24 +0100 Subject: clk: composite: Add unregister function The composite clock didn't have any unregistration function, which forced us to use clk_unregister directly on it. While it was already not great from an API point of view, it also meant that we were leaking the clk_composite structure allocated in clk_register_composite. Add a clk_unregister_composite function to fix this. Signed-off-by: Maxime Ripard Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 1f903e1f8..b0f3b84 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -286,3 +286,18 @@ err: kfree(composite); return clk; } + +void clk_unregister_composite(struct clk *clk) +{ + struct clk_composite *composite; + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + composite = to_clk_composite(hw); + + clk_unregister(clk); + kfree(composite); +} diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index da95258..26a8c9b 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -603,6 +603,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name, struct clk_hw *rate_hw, const struct clk_ops *rate_ops, struct clk_hw *gate_hw, const struct clk_ops *gate_ops, unsigned long flags); +void clk_unregister_composite(struct clk *clk); /*** * struct clk_gpio_gate - gpio gated clock -- cgit v0.10.2 From 8f0767611a0ed719caf975d899d8431834ace2d8 Mon Sep 17 00:00:00 2001 From: Andrea Venturi Date: Mon, 21 Mar 2016 17:10:38 +0100 Subject: clk: sunxi: mod1 clock should modify it's parent add CLK_SET_RATE_PARENT to modify the rate on clk upstream Signed-off-by: Marcus Cooper Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi/clk-a10-mod1.c b/drivers/clk/sunxi/clk-a10-mod1.c index e9d870d..e2819fa 100644 --- a/drivers/clk/sunxi/clk-a10-mod1.c +++ b/drivers/clk/sunxi/clk-a10-mod1.c @@ -62,7 +62,7 @@ static void __init sun4i_mod1_clk_setup(struct device_node *node) clk = clk_register_composite(NULL, clk_name, parents, i, &mux->hw, &clk_mux_ops, NULL, NULL, - &gate->hw, &clk_gate_ops, 0); + &gate->hw, &clk_gate_ops, CLK_SET_RATE_PARENT); if (IS_ERR(clk)) goto err_free_gate; -- cgit v0.10.2 From 5ed400dd96d8222e667ee473c7ebd676f05113f8 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 30 Mar 2016 18:43:29 +0200 Subject: clk: sunxi: Add sun6i/8i display support Add the clock type which is used by the sun6i/8i families for video display. Signed-off-by: Jean-Francois Moine Acked-by: Rob Herring Signed-off-by: Maxime Ripard diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 834436f..9de34a8 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -81,6 +81,7 @@ Required properties: "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80 "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80 "allwinner,sun4i-a10-ve-clk" - for the Video Engine clock + "allwinner,sun6i-a31-display-clk" - for the display clocks Required properties for all clocks: - reg : shall be the control register address for the clock. diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 91de0a0..6ea7cf8 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -1127,3 +1127,41 @@ static void __init sun6i_pll6_clk_setup(struct device_node *node) } CLK_OF_DECLARE(sun6i_pll6, "allwinner,sun6i-a31-pll6-clk", sun6i_pll6_clk_setup); + +/* + * sun6i display + * + * rate = parent_rate / (m + 1); + */ +static void sun6i_display_factors(struct factors_request *req) +{ + u8 m; + + if (req->rate > req->parent_rate) + req->rate = req->parent_rate; + + m = DIV_ROUND_UP(req->parent_rate, req->rate); + + req->rate = req->parent_rate / m; + req->m = m - 1; +} + +static const struct clk_factors_config sun6i_display_config = { + .mshift = 0, + .mwidth = 4, +}; + +static const struct factors_data sun6i_display_data __initconst = { + .enable = 31, + .mux = 24, + .muxmask = BIT(2) | BIT(1) | BIT(0), + .table = &sun6i_display_config, + .getter = sun6i_display_factors, +}; + +static void __init sun6i_display_setup(struct device_node *node) +{ + sunxi_factors_clk_setup(node, &sun6i_display_data); +} +CLK_OF_DECLARE(sun6i_display, "allwinner,sun6i-a31-display-clk", + sun6i_display_setup); -- cgit v0.10.2 From f4b9ef653c047165f096d32816904be5ee337a63 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Mon, 11 Apr 2016 10:23:03 +0530 Subject: clk: sunxi: Use resource_size Use the function resource_size instaed of explicit computation. Problem found using Coccinelle. Signed-off-by: Vaishali Thakkar Acked-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c index a9b1761..0c2dd02 100644 --- a/drivers/clk/sunxi/clk-sun9i-mmc.c +++ b/drivers/clk/sunxi/clk-sun9i-mmc.c @@ -106,7 +106,7 @@ static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); /* one clock/reset pair per word */ - count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH); + count = DIV_ROUND_UP((resource_size(r)), SUN9I_MMC_WIDTH); data->membase = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(data->membase)) return PTR_ERR(data->membase); -- cgit v0.10.2 From 7f2ea3847d47d49929d41573a3b26c80ddebbef5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 23 Mar 2016 17:38:28 +0100 Subject: dt-bindings: clk: sun5i: add DRAM gates compatible The Allwinner SoCs have a gate controller to gate the access to the DRAM clock to the some devices that need to access the DRAM directly (mostly display / image related IPs). Use a simple gates driver to support the one found in the A13 / R8 SoCs. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai Acked-by: Rob Herring Acked-by: Stephen Boyd Signed-off-by: Maxime Ripard diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 9de34a8..1bf588e 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -64,6 +64,7 @@ Required properties: "allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3 "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80 "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10 + "allwinner,sun5i-a13-dram-gates-clk" - for the DRAM gates on A13 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 "allwinner,sun4i-a10-mmc-clk" - for the MMC clock "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80 -- cgit v0.10.2 From fa4d0ca104bfdcda7b7e2bac855b358f302fd310 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 23 Mar 2016 17:38:26 +0100 Subject: clk: sunxi: Add PLL3 clock The A10 SoCs and relatives have a PLL controller to drive the PLL3 and PLL7, clocked from a 3MHz oscillator, that drives the display related clocks (GPU, display engine, TCON, etc.) Add a driver for it. Acked-by: Rob Herring Acked-by: Chen-Yu Tsai Acked-by: Stephen Boyd Signed-off-by: Maxime Ripard diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 1bf588e..005a24c 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -10,6 +10,7 @@ Required properties: "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4 "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23 + "allwinner,sun4i-a10-pll3-clk" - for the video PLL clock on A10 "allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80 "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 3fd7901..e2f7279 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -11,6 +11,7 @@ obj-y += clk-a10-ve.o obj-y += clk-a20-gmac.o obj-y += clk-mod0.o obj-y += clk-simple-gates.o +obj-y += clk-sun4i-pll3.o obj-y += clk-sun8i-bus-gates.o obj-y += clk-sun8i-mbus.o obj-y += clk-sun9i-core.o diff --git a/drivers/clk/sunxi/clk-sun4i-pll3.c b/drivers/clk/sunxi/clk-sun4i-pll3.c new file mode 100644 index 0000000..f66267e --- /dev/null +++ b/drivers/clk/sunxi/clk-sun4i-pll3.c @@ -0,0 +1,98 @@ +/* + * Copyright 2015 Maxime Ripard + * + * Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#define SUN4I_A10_PLL3_GATE_BIT 31 +#define SUN4I_A10_PLL3_DIV_WIDTH 7 +#define SUN4I_A10_PLL3_DIV_SHIFT 0 + +static DEFINE_SPINLOCK(sun4i_a10_pll3_lock); + +static void __init sun4i_a10_pll3_setup(struct device_node *node) +{ + const char *clk_name = node->name, *parent; + struct clk_multiplier *mult; + struct clk_gate *gate; + struct resource res; + void __iomem *reg; + struct clk *clk; + int ret; + + of_property_read_string(node, "clock-output-names", &clk_name); + parent = of_clk_get_parent_name(node, 0); + + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(reg)) { + pr_err("%s: Could not map the clock registers\n", clk_name); + return; + } + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto err_unmap; + + gate->reg = reg; + gate->bit_idx = SUN4I_A10_PLL3_GATE_BIT; + gate->lock = &sun4i_a10_pll3_lock; + + mult = kzalloc(sizeof(*mult), GFP_KERNEL); + if (!mult) + goto err_free_gate; + + mult->reg = reg; + mult->shift = SUN4I_A10_PLL3_DIV_SHIFT; + mult->width = SUN4I_A10_PLL3_DIV_WIDTH; + mult->lock = &sun4i_a10_pll3_lock; + + clk = clk_register_composite(NULL, clk_name, + &parent, 1, + NULL, NULL, + &mult->hw, &clk_multiplier_ops, + &gate->hw, &clk_gate_ops, + 0); + if (IS_ERR(clk)) { + pr_err("%s: Couldn't register the clock\n", clk_name); + goto err_free_mult; + } + + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (ret) { + pr_err("%s: Couldn't register DT provider\n", + clk_name); + goto err_clk_unregister; + } + + return; + +err_clk_unregister: + clk_unregister_composite(clk); +err_free_mult: + kfree(mult); +err_free_gate: + kfree(gate); +err_unmap: + iounmap(reg); + of_address_to_resource(node, 0, &res); + release_mem_region(res.start, resource_size(&res)); +} + +CLK_OF_DECLARE(sun4i_a10_pll3, "allwinner,sun4i-a10-pll3-clk", + sun4i_a10_pll3_setup); -- cgit v0.10.2 From cc510c736b1b278a9925a4a051ecfa72ef8c21fc Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 1 Jul 2015 15:48:37 +0200 Subject: clk: sunxi: Add TCON channel1 clock The TCON is a controller generating the timings to output videos signals, acting like both a CRTC and an encoder. It has two channels depending on the output, each channel being driven by its own clock (and own clock controller). Add a driver for the channel 1 clock. Signed-off-by: Maxime Ripard Acked-by: Rob Herring Acked-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 005a24c..f70f500 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -75,6 +75,7 @@ Required properties: "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 "allwinner,sun7i-a20-out-clk" - for the external output clocks "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 + "allwinner,sun4i-a10-tcon-ch1-clk" - for the TCON channel 1 clock on the A10 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31 diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index e2f7279..2d77407 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -12,6 +12,7 @@ obj-y += clk-a20-gmac.o obj-y += clk-mod0.o obj-y += clk-simple-gates.o obj-y += clk-sun4i-pll3.o +obj-y += clk-sun4i-tcon-ch1.o obj-y += clk-sun8i-bus-gates.o obj-y += clk-sun8i-mbus.o obj-y += clk-sun9i-core.o diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c new file mode 100644 index 0000000..98a4582 --- /dev/null +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c @@ -0,0 +1,300 @@ +/* + * Copyright 2015 Maxime Ripard + * + * Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#define TCON_CH1_SCLK2_PARENTS 4 + +#define TCON_CH1_SCLK2_GATE_BIT BIT(31) +#define TCON_CH1_SCLK2_MUX_MASK 3 +#define TCON_CH1_SCLK2_MUX_SHIFT 24 +#define TCON_CH1_SCLK2_DIV_MASK 0xf +#define TCON_CH1_SCLK2_DIV_SHIFT 0 + +#define TCON_CH1_SCLK1_GATE_BIT BIT(15) +#define TCON_CH1_SCLK1_HALF_BIT BIT(11) + +struct tcon_ch1_clk { + struct clk_hw hw; + spinlock_t lock; + void __iomem *reg; +}; + +#define hw_to_tclk(hw) container_of(hw, struct tcon_ch1_clk, hw) + +static void tcon_ch1_disable(struct clk_hw *hw) +{ + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&tclk->lock, flags); + reg = readl(tclk->reg); + reg &= ~(TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT); + writel(reg, tclk->reg); + spin_unlock_irqrestore(&tclk->lock, flags); +} + +static int tcon_ch1_enable(struct clk_hw *hw) +{ + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&tclk->lock, flags); + reg = readl(tclk->reg); + reg |= TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT; + writel(reg, tclk->reg); + spin_unlock_irqrestore(&tclk->lock, flags); + + return 0; +} + +static int tcon_ch1_is_enabled(struct clk_hw *hw) +{ + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); + u32 reg; + + reg = readl(tclk->reg); + return reg & (TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT); +} + +static u8 tcon_ch1_get_parent(struct clk_hw *hw) +{ + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); + int num_parents = clk_hw_get_num_parents(hw); + u32 reg; + + reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT; + reg &= reg >> TCON_CH1_SCLK2_MUX_MASK; + + if (reg >= num_parents) + return -EINVAL; + + return reg; +} + +static int tcon_ch1_set_parent(struct clk_hw *hw, u8 index) +{ + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&tclk->lock, flags); + reg = readl(tclk->reg); + reg &= ~(TCON_CH1_SCLK2_MUX_MASK << TCON_CH1_SCLK2_MUX_SHIFT); + reg |= index << TCON_CH1_SCLK2_MUX_SHIFT; + writel(reg, tclk->reg); + spin_unlock_irqrestore(&tclk->lock, flags); + + return 0; +}; + +static unsigned long tcon_ch1_calc_divider(unsigned long rate, + unsigned long parent_rate, + u8 *div, + bool *half) +{ + unsigned long best_rate = 0; + u8 best_m = 0, m; + bool is_double; + + for (m = 1; m < 16; m++) { + u8 d; + + for (d = 1; d < 3; d++) { + unsigned long tmp_rate; + + tmp_rate = parent_rate / m / d; + + if (tmp_rate > rate) + continue; + + if (!best_rate || + (rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_m = m; + is_double = d; + } + } + } + + if (div && half) { + *div = best_m; + *half = is_double; + } + + return best_rate; +} + +static int tcon_ch1_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + long best_rate = -EINVAL; + int i; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + unsigned long parent_rate; + unsigned long tmp_rate; + struct clk_hw *parent; + + parent = clk_hw_get_parent_by_index(hw, i); + if (!parent) + continue; + + parent_rate = clk_hw_get_rate(parent); + + tmp_rate = tcon_ch1_calc_divider(req->rate, parent_rate, + NULL, NULL); + + if (best_rate < 0 || + (req->rate - tmp_rate) < (req->rate - best_rate)) { + best_rate = tmp_rate; + req->best_parent_rate = parent_rate; + req->best_parent_hw = parent; + } + } + + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; +} + +static unsigned long tcon_ch1_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); + u32 reg; + + reg = readl(tclk->reg); + + parent_rate /= (reg & TCON_CH1_SCLK2_DIV_MASK) + 1; + + if (reg & TCON_CH1_SCLK1_HALF_BIT) + parent_rate /= 2; + + return parent_rate; +} + +static int tcon_ch1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); + unsigned long flags; + bool half; + u8 div_m; + u32 reg; + + tcon_ch1_calc_divider(rate, parent_rate, &div_m, &half); + + spin_lock_irqsave(&tclk->lock, flags); + reg = readl(tclk->reg); + reg &= ~(TCON_CH1_SCLK2_DIV_MASK | TCON_CH1_SCLK1_HALF_BIT); + reg |= (div_m - 1) & TCON_CH1_SCLK2_DIV_MASK; + + if (half) + reg |= TCON_CH1_SCLK1_HALF_BIT; + + writel(reg, tclk->reg); + spin_unlock_irqrestore(&tclk->lock, flags); + + return 0; +} + +static const struct clk_ops tcon_ch1_ops = { + .disable = tcon_ch1_disable, + .enable = tcon_ch1_enable, + .is_enabled = tcon_ch1_is_enabled, + + .get_parent = tcon_ch1_get_parent, + .set_parent = tcon_ch1_set_parent, + + .determine_rate = tcon_ch1_determine_rate, + .recalc_rate = tcon_ch1_recalc_rate, + .set_rate = tcon_ch1_set_rate, +}; + +static void __init tcon_ch1_setup(struct device_node *node) +{ + const char *parents[TCON_CH1_SCLK2_PARENTS]; + const char *clk_name = node->name; + struct clk_init_data init; + struct tcon_ch1_clk *tclk; + struct resource res; + struct clk *clk; + void __iomem *reg; + int ret; + + of_property_read_string(node, "clock-output-names", &clk_name); + + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(reg)) { + pr_err("%s: Could not map the clock registers\n", clk_name); + return; + } + + ret = of_clk_parent_fill(node, parents, TCON_CH1_SCLK2_PARENTS); + if (ret != TCON_CH1_SCLK2_PARENTS) { + pr_err("%s Could not retrieve the parents\n", clk_name); + goto err_unmap; + } + + tclk = kzalloc(sizeof(*tclk), GFP_KERNEL); + if (!tclk) + goto err_unmap; + + init.name = clk_name; + init.ops = &tcon_ch1_ops; + init.parent_names = parents; + init.num_parents = TCON_CH1_SCLK2_PARENTS; + init.flags = CLK_SET_RATE_PARENT; + + tclk->reg = reg; + tclk->hw.init = &init; + spin_lock_init(&tclk->lock); + + clk = clk_register(NULL, &tclk->hw); + if (IS_ERR(clk)) { + pr_err("%s: Couldn't register the clock\n", clk_name); + goto err_free_data; + } + + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (ret) { + pr_err("%s: Couldn't register our clock provider\n", clk_name); + goto err_unregister_clk; + } + + return; + +err_unregister_clk: + clk_unregister(clk); +err_free_data: + kfree(tclk); +err_unmap: + iounmap(reg); + of_address_to_resource(node, 0, &res); + release_mem_region(res.start, resource_size(&res)); +} + +CLK_OF_DECLARE(tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk", + tcon_ch1_setup); -- cgit v0.10.2 From b8199ff31f86ee94fa1166997259b03022ecb4de Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 24 Apr 2016 23:44:13 +0100 Subject: clk: rockchip: fix of spelling mistake on unsuccessful in pll clock type fix spelling mistake, unsucessful -> unsuccessful Signed-off-by: Colin Ian King Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 128a6b2..8ac73bc 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -236,7 +236,7 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll, /* wait for the pll to lock */ ret = rockchip_pll_wait_lock(pll); if (ret) { - pr_warn("%s: pll update unsucessful, trying to restore old params\n", + pr_warn("%s: pll update unsuccessful, trying to restore old params\n", __func__); rockchip_rk3036_pll_set_params(pll, &cur); } @@ -475,7 +475,7 @@ static int rockchip_rk3066_pll_set_params(struct rockchip_clk_pll *pll, /* wait for the pll to lock */ ret = rockchip_pll_wait_lock(pll); if (ret) { - pr_warn("%s: pll update unsucessful, trying to restore old params\n", + pr_warn("%s: pll update unsuccessful, trying to restore old params\n", __func__); rockchip_rk3066_pll_set_params(pll, &cur); } -- cgit v0.10.2 From ff2bb89335daec6053b5ac778369f7f72b931142 Mon Sep 17 00:00:00 2001 From: Jens Kuske Date: Fri, 18 Mar 2016 09:44:15 +0000 Subject: clk: sunxi: Let divs clocks read the base factor clock name from devicetree Currently, the sunxi clock driver gets the name for the base factor clock of divs clocks from the name field in factors_data. This prevents reusing of the factor clock for clocks with same properties, but different name. This commit makes the divs setup function try to get a name from clock-output-names in the devicetree. It also removes the name field where possible and merges the sun4i PLL5 and PLL6 clocks. [Andre: Make temporary name allocation dynamic.] Signed-off-by: Jens Kuske Signed-off-by: Andre Przywara Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 6ea7cf8..838b22a 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -523,21 +523,12 @@ static const struct factors_data sun4i_pll5_data __initconst = { .enable = 31, .table = &sun4i_pll5_config, .getter = sun4i_get_pll5_factors, - .name = "pll5", -}; - -static const struct factors_data sun4i_pll6_data __initconst = { - .enable = 31, - .table = &sun4i_pll5_config, - .getter = sun4i_get_pll5_factors, - .name = "pll6", }; static const struct factors_data sun6i_a31_pll6_data __initconst = { .enable = 31, .table = &sun6i_a31_pll6_config, .getter = sun6i_a31_get_pll6_factors, - .name = "pll6x2", }; static const struct factors_data sun5i_a13_ahb_data __initconst = { @@ -933,7 +924,7 @@ static const struct divs_data pll5_divs_data __initconst = { }; static const struct divs_data pll6_divs_data __initconst = { - .factors = &sun4i_pll6_data, + .factors = &sun4i_pll5_data, .ndivs = 4, .div = { { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ @@ -975,6 +966,8 @@ static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node, struct clk_gate *gate = NULL; struct clk_fixed_factor *fix_factor; struct clk_divider *divider; + struct factors_data factors = *data->factors; + char *derived_name = NULL; void __iomem *reg; int ndivs = SUNXI_DIVS_MAX_QTY, i = 0; int flags, clkflags; @@ -983,11 +976,37 @@ static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node, if (data->ndivs) ndivs = data->ndivs; + /* Try to find a name for base factor clock */ + for (i = 0; i < ndivs; i++) { + if (data->div[i].self) { + of_property_read_string_index(node, "clock-output-names", + i, &factors.name); + break; + } + } + /* If we don't have a .self clk use the first output-name up to '_' */ + if (factors.name == NULL) { + char *endp; + + of_property_read_string_index(node, "clock-output-names", + 0, &clk_name); + endp = strchr(clk_name, '_'); + if (endp) { + derived_name = kstrndup(clk_name, endp - clk_name, + GFP_KERNEL); + factors.name = derived_name; + } else { + factors.name = clk_name; + } + } + /* Set up factor clock that we will be dividing */ - pclk = sunxi_factors_clk_setup(node, data->factors); + pclk = sunxi_factors_clk_setup(node, &factors); if (!pclk) return NULL; + parent = __clk_get_name(pclk); + kfree(derived_name); reg = of_iomap(node, 0); if (!reg) { -- cgit v0.10.2 From f3d40914d3d52e2f155c4e65bc2ab5f5d1efb0ab Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 20 Apr 2016 19:12:10 +0800 Subject: clk: rockchip: fix the gate bit for i2c4 and i2c8 on rk3399 The gate bits of the i2c4 and i2c8 are incorrect due to the manual error, we need to fix them. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index e8f040b..40b7384 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -1401,11 +1401,11 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { COMPOSITE_NOMUX(SCLK_I2C4_PMU, "clk_i2c4_pmu", "ppll", 0, RK3399_PMU_CLKSEL_CON(3), 0, 7, DFLAGS, - RK3399_PMU_CLKGATE_CON(0), 11, GFLAGS), + RK3399_PMU_CLKGATE_CON(0), 10, GFLAGS), COMPOSITE_NOMUX(SCLK_I2C8_PMU, "clk_i2c8_pmu", "ppll", 0, RK3399_PMU_CLKSEL_CON(2), 8, 7, DFLAGS, - RK3399_PMU_CLKGATE_CON(0), 10, GFLAGS), + RK3399_PMU_CLKGATE_CON(0), 11, GFLAGS), DIV(0, "clk_32k_suspend_pmu", "xin24m", CLK_IGNORE_UNUSED, RK3399_PMU_CLKSEL_CON(4), 0, 10, DFLAGS), -- cgit v0.10.2 From 3f92a05440f92f2734c9b754af39afa3244dfb5b Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 20 Apr 2016 19:06:49 +0800 Subject: clk: rockchip: assign more necessary rk3399 clock ids Assign newly added clock ids. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 40b7384..35cb2d7 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -554,7 +554,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(5), 5, GFLAGS), - MUX(0, "clk_rmii_src", mux_rmii_p, CLK_SET_RATE_PARENT, + MUX(SCLK_RMII_SRC, "clk_rmii_src", mux_rmii_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(19), 4, 1, MFLAGS), GATE(SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(5), 6, GFLAGS), @@ -780,7 +780,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(16), 1, GFLAGS), /* rga */ - COMPOSITE(0, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_RGA_CORE, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(4), 10, GFLAGS), @@ -896,7 +896,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(17), 8, 3, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(6), 2, GFLAGS), - COMPOSITE_NOMUX(0, "clk_pciephy_ref100m", "npll", CLK_IGNORE_UNUSED, + COMPOSITE_NOMUX(SCLK_PCIEPHY_REF100M, "clk_pciephy_ref100m", "npll", CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(18), 11, 5, DFLAGS, RK3399_CLKGATE_CON(12), 6, GFLAGS), MUX(SCLK_PCIEPHY_REF, "clk_pciephy_ref", mux_pll_src_24m_pciephy_p, CLK_SET_RATE_PARENT, @@ -1191,10 +1191,10 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(10), 15, GFLAGS), /* isp */ - COMPOSITE(0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(ACLK_ISP0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(53), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(12), 8, GFLAGS), - COMPOSITE_NOMUX(0, "hclk_isp0", "aclk_isp0", 0, + COMPOSITE_NOMUX(HCLK_ISP0, "hclk_isp0", "aclk_isp0", 0, RK3399_CLKSEL_CON(53), 8, 5, DFLAGS, RK3399_CLKGATE_CON(12), 9, GFLAGS), @@ -1217,7 +1217,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(ACLK_ISP1, "aclk_isp1", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(54), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(12), 10, GFLAGS), - COMPOSITE_NOMUX(0, "hclk_isp1", "aclk_isp1", 0, + COMPOSITE_NOMUX(HCLK_ISP1, "hclk_isp1", "aclk_isp1", 0, RK3399_CLKSEL_CON(54), 8, 5, DFLAGS, RK3399_CLKGATE_CON(12), 11, GFLAGS), -- cgit v0.10.2 From aa2897ceb7dc01b8e081eaf4d2f7e54cbd495834 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 20 Apr 2016 19:06:50 +0800 Subject: clk: rockchip: add some frequencies on the rk3399 PLL table This patch add some necessary frequencies for the RK3399 clock. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 35cb2d7..c64a412 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -92,13 +92,18 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0), RK3036_PLL_RATE( 676000000, 3, 169, 2, 1, 1, 0), RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0), - RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0), + RK3036_PLL_RATE( 594000000, 1, 99, 4, 1, 1, 0), RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0), RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0), RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0), RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0), + RK3036_PLL_RATE( 297000000, 1, 99, 4, 2, 1, 0), RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0), + RK3036_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0), RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0), + RK3036_PLL_RATE( 74250000, 2, 99, 4, 4, 1, 0), + RK3036_PLL_RATE( 54000000, 1, 54, 6, 4, 1, 0), + RK3036_PLL_RATE( 27000000, 1, 27, 6, 4, 1, 0), { /* sentinel */ }, }; @@ -359,6 +364,8 @@ static struct rockchip_cpuclk_rate_table rk3399_cpuclkl_rates[] __initdata = { RK3399_CPUCLKL_RATE( 600000000, 1, 3, 3), RK3399_CPUCLKL_RATE( 408000000, 1, 2, 2), RK3399_CPUCLKL_RATE( 312000000, 1, 1, 1), + RK3399_CPUCLKL_RATE( 216000000, 1, 1, 1), + RK3399_CPUCLKL_RATE( 96000000, 1, 1, 1), }; static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = { @@ -381,6 +388,8 @@ static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = { RK3399_CPUCLKB_RATE( 600000000, 1, 3, 3), RK3399_CPUCLKB_RATE( 408000000, 1, 2, 2), RK3399_CPUCLKB_RATE( 312000000, 1, 1, 1), + RK3399_CPUCLKB_RATE( 216000000, 1, 1, 1), + RK3399_CPUCLKB_RATE( 96000000, 1, 1, 1), }; static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { -- cgit v0.10.2 From 50961e8314babfac525be4d00f3e1f65091251a4 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 20 Apr 2016 19:06:51 +0800 Subject: clk: rockchip: drop unnecessary CLK_IGNORE_UNUSED flags from rk3399 We don't need to many clocks enable after startup, to reduce some power consumption. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index c64a412..7ecb7d6 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -413,50 +413,50 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { MUX(0, "upll", mux_pll_src_24m_usbphy480m_p, 0, RK3399_CLKSEL_CON(14), 15, 1, MFLAGS), - COMPOSITE_NODIV(SCLK_HSICPHY, "clk_hsicphy", mux_pll_src_cpll_gpll_npll_usbphy480m_p, CLK_IGNORE_UNUSED, + COMPOSITE_NODIV(SCLK_HSICPHY, "clk_hsicphy", mux_pll_src_cpll_gpll_npll_usbphy480m_p, 0, RK3399_CLKSEL_CON(19), 0, 2, MFLAGS, RK3399_CLKGATE_CON(6), 4, GFLAGS), - COMPOSITE(ACLK_USB3, "aclk_usb3", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(ACLK_USB3, "aclk_usb3", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(12), 0, GFLAGS), GATE(ACLK_USB3_NOC, "aclk_usb3_noc", "aclk_usb3", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(30), 0, GFLAGS), - GATE(ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_usb3", CLK_IGNORE_UNUSED, + GATE(ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_usb3", 0, RK3399_CLKGATE_CON(30), 1, GFLAGS), - GATE(ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_usb3", CLK_IGNORE_UNUSED, + GATE(ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_usb3", 0, RK3399_CLKGATE_CON(30), 2, GFLAGS), - GATE(ACLK_USB3_RKSOC_AXI_PERF, "aclk_usb3_rksoc_axi_perf", "aclk_usb3", CLK_IGNORE_UNUSED, + GATE(ACLK_USB3_RKSOC_AXI_PERF, "aclk_usb3_rksoc_axi_perf", "aclk_usb3", 0, RK3399_CLKGATE_CON(30), 3, GFLAGS), - GATE(ACLK_USB3_GRF, "aclk_usb3_grf", "aclk_usb3", CLK_IGNORE_UNUSED, + GATE(ACLK_USB3_GRF, "aclk_usb3_grf", "aclk_usb3", 0, RK3399_CLKGATE_CON(30), 4, GFLAGS), - GATE(SCLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", 0, RK3399_CLKGATE_CON(12), 1, GFLAGS), - GATE(SCLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", 0, RK3399_CLKGATE_CON(12), 2, GFLAGS), - COMPOSITE(SCLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", mux_pll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", mux_pll_p, 0, RK3399_CLKSEL_CON(40), 15, 1, MFLAGS, 0, 10, DFLAGS, RK3399_CLKGATE_CON(12), 3, GFLAGS), - COMPOSITE(SCLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", mux_pll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", mux_pll_p, 0, RK3399_CLKSEL_CON(41), 15, 1, MFLAGS, 0, 10, DFLAGS, RK3399_CLKGATE_CON(12), 4, GFLAGS), - COMPOSITE(SCLK_UPHY0_TCPDPHY_REF, "clk_uphy0_tcpdphy_ref", mux_pll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_UPHY0_TCPDPHY_REF, "clk_uphy0_tcpdphy_ref", mux_pll_p, 0, RK3399_CLKSEL_CON(64), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(13), 4, GFLAGS), - COMPOSITE(SCLK_UPHY0_TCPDCORE, "clk_uphy0_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_UPHY0_TCPDCORE, "clk_uphy0_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0, RK3399_CLKSEL_CON(64), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(13), 5, GFLAGS), - COMPOSITE(SCLK_UPHY1_TCPDPHY_REF, "clk_uphy1_tcpdphy_ref", mux_pll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_UPHY1_TCPDPHY_REF, "clk_uphy1_tcpdphy_ref", mux_pll_p, 0, RK3399_CLKSEL_CON(65), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(13), 6, GFLAGS), - COMPOSITE(SCLK_UPHY1_TCPDCORE, "clk_uphy1_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_UPHY1_TCPDCORE, "clk_uphy1_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0, RK3399_CLKSEL_CON(65), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(13), 7, GFLAGS), @@ -540,42 +540,42 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(6), 9, GFLAGS), GATE(0, "gpll_aclk_gmac_src", "gpll", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(6), 8, GFLAGS), - COMPOSITE(0, "aclk_gmac_pre", mux_aclk_gmac_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "aclk_gmac_pre", mux_aclk_gmac_p, 0, RK3399_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(6), 10, GFLAGS), - GATE(ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", 0, RK3399_CLKGATE_CON(32), 0, GFLAGS), GATE(ACLK_GMAC_NOC, "aclk_gmac_noc", "aclk_gmac_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(32), 1, GFLAGS), - GATE(ACLK_PERF_GMAC, "aclk_perf_gmac", "aclk_gmac_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_PERF_GMAC, "aclk_perf_gmac", "aclk_gmac_pre", 0, RK3399_CLKGATE_CON(32), 4, GFLAGS), COMPOSITE_NOMUX(0, "pclk_gmac_pre", "aclk_gmac_pre", 0, RK3399_CLKSEL_CON(19), 8, 3, DFLAGS, RK3399_CLKGATE_CON(6), 11, GFLAGS), - GATE(PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", 0, RK3399_CLKGATE_CON(32), 2, GFLAGS), GATE(PCLK_GMAC_NOC, "pclk_gmac_noc", "pclk_gmac_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(32), 3, GFLAGS), - COMPOSITE(SCLK_MAC, "clk_gmac", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_MAC, "clk_gmac", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(5), 5, GFLAGS), MUX(SCLK_RMII_SRC, "clk_rmii_src", mux_rmii_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(19), 4, 1, MFLAGS), - GATE(SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", CLK_IGNORE_UNUSED, + GATE(SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", 0, RK3399_CLKGATE_CON(5), 6, GFLAGS), - GATE(SCLK_MACREF, "clk_mac_ref", "clk_rmii_src", CLK_IGNORE_UNUSED, + GATE(SCLK_MACREF, "clk_mac_ref", "clk_rmii_src", 0, RK3399_CLKGATE_CON(5), 7, GFLAGS), - GATE(SCLK_MAC_RX, "clk_rmii_rx", "clk_rmii_src", CLK_IGNORE_UNUSED, + GATE(SCLK_MAC_RX, "clk_rmii_rx", "clk_rmii_src", 0, RK3399_CLKGATE_CON(5), 8, GFLAGS), - GATE(SCLK_MAC_TX, "clk_rmii_tx", "clk_rmii_src", CLK_IGNORE_UNUSED, + GATE(SCLK_MAC_TX, "clk_rmii_tx", "clk_rmii_src", 0, RK3399_CLKGATE_CON(5), 9, GFLAGS), /* spdif */ - COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 13, GFLAGS), COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", CLK_SET_RATE_PARENT, @@ -585,11 +585,11 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(SCLK_SPDIF_8CH, "clk_spdif", "clk_spdif_mux", CLK_SET_RATE_PARENT, RK3399_CLKGATE_CON(8), 15, GFLAGS), - COMPOSITE(SCLK_SPDIF_REC_DPTX, "clk_spdif_rec_dptx", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_SPDIF_REC_DPTX, "clk_spdif_rec_dptx", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(32), 15, 1, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(10), 6, GFLAGS), /* i2s */ - COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(28), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 3, GFLAGS), COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", CLK_SET_RATE_PARENT, @@ -599,7 +599,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT, RK3399_CLKGATE_CON(8), 5, GFLAGS), - COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(29), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 6, GFLAGS), COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", CLK_SET_RATE_PARENT, @@ -609,7 +609,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT, RK3399_CLKGATE_CON(8), 8, GFLAGS), - COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(30), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 9, GFLAGS), COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", CLK_SET_RATE_PARENT, @@ -737,21 +737,21 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "hclk_vcodec_pre", "aclk_vcodec_pre", 0, RK3399_CLKSEL_CON(7), 8, 5, DFLAGS, RK3399_CLKGATE_CON(4), 1, GFLAGS), - GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0, RK3399_CLKGATE_CON(17), 2, GFLAGS), GATE(0, "hclk_vcodec_noc", "hclk_vcodec_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(17), 3, GFLAGS), - GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0, RK3399_CLKGATE_CON(17), 0, GFLAGS), GATE(0, "aclk_vcodec_noc", "aclk_vcodec_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(17), 1, GFLAGS), /* vdu */ - COMPOSITE(SCLK_VDU_CORE, "clk_vdu_core", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_VDU_CORE, "clk_vdu_core", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(9), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(4), 4, GFLAGS), - COMPOSITE(SCLK_VDU_CA, "clk_vdu_ca", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_VDU_CA, "clk_vdu_ca", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(9), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(4), 5, GFLAGS), @@ -761,50 +761,50 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "hclk_vdu_pre", "aclk_vdu_pre", 0, RK3399_CLKSEL_CON(8), 8, 5, DFLAGS, RK3399_CLKGATE_CON(4), 3, GFLAGS), - GATE(HCLK_VDU, "hclk_vdu", "hclk_vdu_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_VDU, "hclk_vdu", "hclk_vdu_pre", 0, RK3399_CLKGATE_CON(17), 10, GFLAGS), GATE(HCLK_VDU_NOC, "hclk_vdu_noc", "hclk_vdu_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(17), 11, GFLAGS), - GATE(ACLK_VDU, "aclk_vdu", "aclk_vdu_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_VDU, "aclk_vdu", "aclk_vdu_pre", 0, RK3399_CLKGATE_CON(17), 8, GFLAGS), GATE(ACLK_VDU_NOC, "aclk_vdu_noc", "aclk_vdu_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(17), 9, GFLAGS), /* iep */ - COMPOSITE(0, "aclk_iep_pre", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "aclk_iep_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, RK3399_CLKSEL_CON(10), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(4), 6, GFLAGS), COMPOSITE_NOMUX(0, "hclk_iep_pre", "aclk_iep_pre", 0, RK3399_CLKSEL_CON(10), 8, 5, DFLAGS, RK3399_CLKGATE_CON(4), 7, GFLAGS), - GATE(HCLK_IEP, "hclk_iep", "hclk_iep_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_IEP, "hclk_iep", "hclk_iep_pre", 0, RK3399_CLKGATE_CON(16), 2, GFLAGS), GATE(HCLK_IEP_NOC, "hclk_iep_noc", "hclk_iep_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(16), 3, GFLAGS), - GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0, RK3399_CLKGATE_CON(16), 0, GFLAGS), GATE(ACLK_IEP_NOC, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(16), 1, GFLAGS), /* rga */ - COMPOSITE(SCLK_RGA_CORE, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_RGA_CORE, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, 0, RK3399_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(4), 10, GFLAGS), - COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_npll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, RK3399_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(4), 8, GFLAGS), COMPOSITE_NOMUX(0, "hclk_rga_pre", "aclk_rga_pre", 0, RK3399_CLKSEL_CON(11), 8, 5, DFLAGS, RK3399_CLKGATE_CON(4), 9, GFLAGS), - GATE(HCLK_RGA, "hclk_rga", "hclk_rga_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_RGA, "hclk_rga", "hclk_rga_pre", 0, RK3399_CLKGATE_CON(16), 10, GFLAGS), GATE(HCLK_RGA_NOC, "hclk_rga_noc", "hclk_rga_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(16), 11, GFLAGS), - GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3399_CLKGATE_CON(16), 8, GFLAGS), GATE(ACLK_RGA_NOC, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(16), 9, GFLAGS), @@ -822,13 +822,13 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "aclk_gpu_pre", mux_pll_src_ppll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(13), 5, 3, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(13), 0, GFLAGS), - GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, RK3399_CLKGATE_CON(30), 8, GFLAGS), - GATE(ACLK_PERF_GPU, "aclk_perf_gpu", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_PERF_GPU, "aclk_perf_gpu", "aclk_gpu_pre", 0, RK3399_CLKGATE_CON(30), 10, GFLAGS), - GATE(ACLK_GPU_GRF, "aclk_gpu_grf", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_GPU_GRF, "aclk_gpu_grf", "aclk_gpu_pre", 0, RK3399_CLKGATE_CON(30), 11, GFLAGS), - GATE(SCLK_PVTM_GPU, "aclk_pvtm_gpu", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_PVTM_GPU, "aclk_pvtm_gpu", "xin24m", 0, RK3399_CLKGATE_CON(13), 1, GFLAGS), /* perihp */ @@ -853,15 +853,15 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(0, "aclk_perihp_noc", "aclk_perihp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(20), 12, GFLAGS), - GATE(HCLK_HOST0, "hclk_host0", "hclk_perihp", CLK_IGNORE_UNUSED, + GATE(HCLK_HOST0, "hclk_host0", "hclk_perihp", 0, RK3399_CLKGATE_CON(20), 5, GFLAGS), - GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_perihp", CLK_IGNORE_UNUSED, + GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_perihp", 0, RK3399_CLKGATE_CON(20), 6, GFLAGS), - GATE(HCLK_HOST1, "hclk_host1", "hclk_perihp", CLK_IGNORE_UNUSED, + GATE(HCLK_HOST1, "hclk_host1", "hclk_perihp", 0, RK3399_CLKGATE_CON(20), 7, GFLAGS), - GATE(HCLK_HOST1_ARB, "hclk_host1_arb", "hclk_perihp", CLK_IGNORE_UNUSED, + GATE(HCLK_HOST1_ARB, "hclk_host1_arb", "hclk_perihp", 0, RK3399_CLKGATE_CON(20), 8, GFLAGS), - GATE(HCLK_HSIC, "hclk_hsic", "hclk_perihp", CLK_IGNORE_UNUSED, + GATE(HCLK_HSIC, "hclk_hsic", "hclk_perihp", 0, RK3399_CLKGATE_CON(20), 9, GFLAGS), GATE(0, "hclk_perihp_noc", "hclk_perihp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(20), 13, GFLAGS), @@ -870,27 +870,27 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(PCLK_PERIHP_GRF, "pclk_perihp_grf", "pclk_perihp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(20), 4, GFLAGS), - GATE(PCLK_PCIE, "pclk_pcie", "pclk_perihp", CLK_IGNORE_UNUSED, + GATE(PCLK_PCIE, "pclk_pcie", "pclk_perihp", 0, RK3399_CLKGATE_CON(20), 11, GFLAGS), GATE(0, "pclk_perihp_noc", "pclk_perihp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(20), 14, GFLAGS), - GATE(PCLK_HSICPHY, "pclk_hsicphy", "pclk_perihp", CLK_IGNORE_UNUSED, + GATE(PCLK_HSICPHY, "pclk_hsicphy", "pclk_perihp", 0, RK3399_CLKGATE_CON(31), 8, GFLAGS), /* sdio & sdmmc */ - COMPOSITE(0, "hclk_sd", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "hclk_sd", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(13), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(12), 13, GFLAGS), - GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", CLK_IGNORE_UNUSED, + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0, RK3399_CLKGATE_CON(33), 8, GFLAGS), GATE(0, "hclk_sdmmc_noc", "hclk_sd", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 9, GFLAGS), - COMPOSITE(SCLK_SDIO, "clk_sdio", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_SDIO, "clk_sdio", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0, RK3399_CLKSEL_CON(15), 8, 3, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(6), 0, GFLAGS), - COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0, RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(6), 1, GFLAGS), @@ -901,24 +901,24 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", RK3399_SDIO_CON1, 1), /* pcie */ - COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, 0, RK3399_CLKSEL_CON(17), 8, 3, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(6), 2, GFLAGS), - COMPOSITE_NOMUX(SCLK_PCIEPHY_REF100M, "clk_pciephy_ref100m", "npll", CLK_IGNORE_UNUSED, + COMPOSITE_NOMUX(SCLK_PCIEPHY_REF100M, "clk_pciephy_ref100m", "npll", 0, RK3399_CLKSEL_CON(18), 11, 5, DFLAGS, RK3399_CLKGATE_CON(12), 6, GFLAGS), MUX(SCLK_PCIEPHY_REF, "clk_pciephy_ref", mux_pll_src_24m_pciephy_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(18), 10, 1, MFLAGS), - COMPOSITE(0, "clk_pcie_core_cru", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "clk_pcie_core_cru", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(18), 8, 2, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(6), 3, GFLAGS), MUX(SCLK_PCIE_CORE, "clk_pcie_core", mux_pciecore_cru_phy_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(18), 7, 1, MFLAGS), /* emmc */ - COMPOSITE(SCLK_EMMC, "clk_emmc", mux_pll_src_cpll_gpll_npll_upll_24m_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_EMMC, "clk_emmc", mux_pll_src_cpll_gpll_npll_upll_24m_p, 0, RK3399_CLKSEL_CON(22), 8, 3, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(6), 14, GFLAGS), @@ -962,42 +962,42 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(ACLK_DCF, "aclk_dcf", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 8, GFLAGS), GATE(ACLK_DMAC0_PERILP, "aclk_dmac0_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 5, GFLAGS), GATE(ACLK_DMAC1_PERILP, "aclk_dmac1_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 6, GFLAGS), - GATE(ACLK_PERILP0_NOC, "aclk_perilp0_noc", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 7, GFLAGS), + GATE(ACLK_PERILP0_NOC, "aclk_perilp0_noc", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 7, GFLAGS), /* hclk_perilp0 gates */ GATE(HCLK_ROM, "hclk_rom", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 4, GFLAGS), - GATE(HCLK_M_CRYPTO0, "hclk_m_crypto0", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 5, GFLAGS), - GATE(HCLK_S_CRYPTO0, "hclk_s_crypto0", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 6, GFLAGS), - GATE(HCLK_M_CRYPTO1, "hclk_m_crypto1", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 14, GFLAGS), - GATE(HCLK_S_CRYPTO1, "hclk_s_crypto1", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 15, GFLAGS), + GATE(HCLK_M_CRYPTO0, "hclk_m_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 5, GFLAGS), + GATE(HCLK_S_CRYPTO0, "hclk_s_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 6, GFLAGS), + GATE(HCLK_M_CRYPTO1, "hclk_m_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 14, GFLAGS), + GATE(HCLK_S_CRYPTO1, "hclk_s_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 15, GFLAGS), GATE(HCLK_PERILP0_NOC, "hclk_perilp0_noc", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 8, GFLAGS), /* pclk_perilp0 gates */ GATE(PCLK_DCF, "pclk_dcf", "pclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 9, GFLAGS), /* crypto */ - COMPOSITE(SCLK_CRYPTO0, "clk_crypto0", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_CRYPTO0, "clk_crypto0", mux_pll_src_cpll_gpll_ppll_p, 0, RK3399_CLKSEL_CON(24), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(7), 7, GFLAGS), - COMPOSITE(SCLK_CRYPTO1, "clk_crypto1", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_CRYPTO1, "clk_crypto1", mux_pll_src_cpll_gpll_ppll_p, 0, RK3399_CLKSEL_CON(26), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(7), 8, GFLAGS), /* cm0s_perilp */ - GATE(0, "cpll_fclk_cm0s_src", "cpll", CLK_IGNORE_UNUSED, + GATE(0, "cpll_fclk_cm0s_src", "cpll", 0, RK3399_CLKGATE_CON(7), 6, GFLAGS), - GATE(0, "gpll_fclk_cm0s_src", "gpll", CLK_IGNORE_UNUSED, + GATE(0, "gpll_fclk_cm0s_src", "gpll", 0, RK3399_CLKGATE_CON(7), 5, GFLAGS), - COMPOSITE(FCLK_CM0S, "fclk_cm0s", mux_fclk_cm0s_p, CLK_IGNORE_UNUSED, + COMPOSITE(FCLK_CM0S, "fclk_cm0s", mux_fclk_cm0s_p, 0, RK3399_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(7), 9, GFLAGS), /* fclk_cm0s gates */ - GATE(SCLK_M0_PERILP, "sclk_m0_perilp", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 8, GFLAGS), - GATE(HCLK_M0_PERILP, "hclk_m0_perilp", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 9, GFLAGS), - GATE(DCLK_M0_PERILP, "dclk_m0_perilp", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 10, GFLAGS), - GATE(SCLK_M0_PERILP_DEC, "clk_m0_perilp_dec", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 11, GFLAGS), + GATE(SCLK_M0_PERILP, "sclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 8, GFLAGS), + GATE(HCLK_M0_PERILP, "hclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 9, GFLAGS), + GATE(DCLK_M0_PERILP, "dclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 10, GFLAGS), + GATE(SCLK_M0_PERILP_DEC, "clk_m0_perilp_dec", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 11, GFLAGS), GATE(HCLK_M0_PERILP_NOC, "hclk_m0_perilp_noc", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 11, GFLAGS), /* perilp1 */ @@ -1014,12 +1014,12 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { /* hclk_perilp1 gates */ GATE(0, "hclk_perilp1_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 9, GFLAGS), GATE(0, "hclk_sdio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 12, GFLAGS), - GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 0, GFLAGS), - GATE(HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 1, GFLAGS), - GATE(HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 2, GFLAGS), - GATE(HCLK_SPDIF, "hclk_spdif", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 3, GFLAGS), - GATE(HCLK_SDIO, "hclk_sdio", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 4, GFLAGS), - GATE(PCLK_SPI5, "pclk_spi5", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 5, GFLAGS), + GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 0, GFLAGS), + GATE(HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 1, GFLAGS), + GATE(HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 2, GFLAGS), + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 3, GFLAGS), + GATE(HCLK_SDIO, "hclk_sdio", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 4, GFLAGS), + GATE(PCLK_SPI5, "pclk_spi5", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 5, GFLAGS), GATE(0, "hclk_sdioaudio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 6, GFLAGS), /* pclk_perilp1 gates */ @@ -1051,7 +1051,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(9), 11, GFLAGS), /* tsadc */ - COMPOSITE(SCLK_TSADC, "clk_tsadc", mux_pll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_TSADC, "clk_tsadc", mux_pll_p, 0, RK3399_CLKSEL_CON(27), 15, 1, MFLAGS, 0, 10, DFLAGS, RK3399_CLKGATE_CON(9), 10, GFLAGS), @@ -1079,85 +1079,85 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(ACLK_VIO_NOC, "aclk_vio_noc", "aclk_vio", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(29), 0, GFLAGS), - GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "pclk_vio", CLK_IGNORE_UNUSED, + GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "pclk_vio", 0, RK3399_CLKGATE_CON(29), 1, GFLAGS), - GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "pclk_vio", CLK_IGNORE_UNUSED, + GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "pclk_vio", 0, RK3399_CLKGATE_CON(29), 2, GFLAGS), GATE(PCLK_VIO_GRF, "pclk_vio_grf", "pclk_vio", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(29), 12, GFLAGS), /* hdcp */ - COMPOSITE(ACLK_HDCP, "aclk_hdcp", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(ACLK_HDCP, "aclk_hdcp", mux_pll_src_cpll_gpll_ppll_p, 0, RK3399_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(11), 12, GFLAGS), - COMPOSITE_NOMUX(HCLK_HDCP, "hclk_hdcp", "aclk_hdcp", CLK_IGNORE_UNUSED, + COMPOSITE_NOMUX(HCLK_HDCP, "hclk_hdcp", "aclk_hdcp", 0, RK3399_CLKSEL_CON(43), 5, 5, DFLAGS, RK3399_CLKGATE_CON(11), 3, GFLAGS), - COMPOSITE_NOMUX(PCLK_HDCP, "pclk_hdcp", "aclk_hdcp", CLK_IGNORE_UNUSED, + COMPOSITE_NOMUX(PCLK_HDCP, "pclk_hdcp", "aclk_hdcp", 0, RK3399_CLKSEL_CON(43), 10, 5, DFLAGS, RK3399_CLKGATE_CON(11), 10, GFLAGS), GATE(ACLK_HDCP_NOC, "aclk_hdcp_noc", "aclk_hdcp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(29), 4, GFLAGS), - GATE(ACLK_HDCP22, "aclk_hdcp22", "aclk_hdcp", CLK_IGNORE_UNUSED, + GATE(ACLK_HDCP22, "aclk_hdcp22", "aclk_hdcp", 0, RK3399_CLKGATE_CON(29), 10, GFLAGS), GATE(HCLK_HDCP_NOC, "hclk_hdcp_noc", "hclk_hdcp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(29), 5, GFLAGS), - GATE(HCLK_HDCP22, "hclk_hdcp22", "hclk_hdcp", CLK_IGNORE_UNUSED, + GATE(HCLK_HDCP22, "hclk_hdcp22", "hclk_hdcp", 0, RK3399_CLKGATE_CON(29), 9, GFLAGS), GATE(PCLK_HDCP_NOC, "pclk_hdcp_noc", "pclk_hdcp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(29), 3, GFLAGS), - GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", CLK_IGNORE_UNUSED, + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", 0, RK3399_CLKGATE_CON(29), 6, GFLAGS), - GATE(PCLK_DP_CTRL, "pclk_dp_ctrl", "pclk_hdcp", CLK_IGNORE_UNUSED, + GATE(PCLK_DP_CTRL, "pclk_dp_ctrl", "pclk_hdcp", 0, RK3399_CLKGATE_CON(29), 7, GFLAGS), - GATE(PCLK_HDCP22, "pclk_hdcp22", "pclk_hdcp", CLK_IGNORE_UNUSED, + GATE(PCLK_HDCP22, "pclk_hdcp22", "pclk_hdcp", 0, RK3399_CLKGATE_CON(29), 8, GFLAGS), - GATE(PCLK_GASKET, "pclk_gasket", "pclk_hdcp", CLK_IGNORE_UNUSED, + GATE(PCLK_GASKET, "pclk_gasket", "pclk_hdcp", 0, RK3399_CLKGATE_CON(29), 11, GFLAGS), /* edp */ - COMPOSITE(SCLK_DP_CORE, "clk_dp_core", mux_pll_src_npll_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_DP_CORE, "clk_dp_core", mux_pll_src_npll_cpll_gpll_p, 0, RK3399_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(11), 8, GFLAGS), - COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(11), 11, GFLAGS), GATE(PCLK_EDP_NOC, "pclk_edp_noc", "pclk_edp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(32), 12, GFLAGS), - GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "pclk_edp", CLK_IGNORE_UNUSED, + GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "pclk_edp", 0, RK3399_CLKGATE_CON(32), 13, GFLAGS), /* hdmi */ - GATE(SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", 0, RK3399_CLKGATE_CON(11), 6, GFLAGS), - COMPOSITE(SCLK_HDMI_CEC, "clk_hdmi_cec", mux_pll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_HDMI_CEC, "clk_hdmi_cec", mux_pll_p, 0, RK3399_CLKSEL_CON(45), 15, 1, MFLAGS, 0, 10, DFLAGS, RK3399_CLKGATE_CON(11), 7, GFLAGS), /* vop0 */ - COMPOSITE(ACLK_VOP0_PRE, "aclk_vop0_pre", mux_pll_src_vpll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(ACLK_VOP0_PRE, "aclk_vop0_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(47), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(10), 8, GFLAGS), COMPOSITE_NOMUX(0, "hclk_vop0_pre", "aclk_vop0_pre", 0, RK3399_CLKSEL_CON(47), 8, 5, DFLAGS, RK3399_CLKGATE_CON(10), 9, GFLAGS), - GATE(ACLK_VOP0, "aclk_vop0", "aclk_vop0_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_VOP0, "aclk_vop0", "aclk_vop0_pre", 0, RK3399_CLKGATE_CON(28), 3, GFLAGS), GATE(ACLK_VOP0_NOC, "aclk_vop0_noc", "aclk_vop0_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(28), 1, GFLAGS), - GATE(HCLK_VOP0, "hclk_vop0", "hclk_vop0_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_VOP0, "hclk_vop0", "hclk_vop0_pre", 0, RK3399_CLKGATE_CON(28), 2, GFLAGS), GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(28), 0, GFLAGS), - COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0, RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 12, GFLAGS), @@ -1165,29 +1165,29 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(106), 0, &rk3399_dclk_vop0_fracmux), - COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, 0, RK3399_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(10), 14, GFLAGS), /* vop1 */ - COMPOSITE(ACLK_VOP1_PRE, "aclk_vop1_pre", mux_pll_src_vpll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(ACLK_VOP1_PRE, "aclk_vop1_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(10), 10, GFLAGS), COMPOSITE_NOMUX(0, "hclk_vop1_pre", "aclk_vop1_pre", 0, RK3399_CLKSEL_CON(48), 8, 5, DFLAGS, RK3399_CLKGATE_CON(10), 11, GFLAGS), - GATE(ACLK_VOP1, "aclk_vop1", "aclk_vop1_pre", CLK_IGNORE_UNUSED, + GATE(ACLK_VOP1, "aclk_vop1", "aclk_vop1_pre", 0, RK3399_CLKGATE_CON(28), 7, GFLAGS), GATE(ACLK_VOP1_NOC, "aclk_vop1_noc", "aclk_vop1_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(28), 5, GFLAGS), - GATE(HCLK_VOP1, "hclk_vop1", "hclk_vop1_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_VOP1, "hclk_vop1", "hclk_vop1_pre", 0, RK3399_CLKGATE_CON(28), 6, GFLAGS), GATE(HCLK_VOP1_NOC, "hclk_vop1_noc", "hclk_vop1_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(28), 4, GFLAGS), - COMPOSITE(DCLK_VOP1_DIV, "dclk_vop1_div", mux_pll_src_vpll_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(DCLK_VOP1_DIV, "dclk_vop1_div", mux_pll_src_vpll_cpll_gpll_p, 0, RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 13, GFLAGS), @@ -1200,7 +1200,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(10), 15, GFLAGS), /* isp */ - COMPOSITE(ACLK_ISP0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(ACLK_ISP0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, 0, RK3399_CLKSEL_CON(53), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(12), 8, GFLAGS), COMPOSITE_NOMUX(HCLK_ISP0, "hclk_isp0", "aclk_isp0", 0, @@ -1209,21 +1209,21 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(ACLK_ISP0_NOC, "aclk_isp0_noc", "aclk_isp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(27), 1, GFLAGS), - GATE(ACLK_ISP0_WRAPPER, "aclk_isp0_wrapper", "aclk_isp0", CLK_IGNORE_UNUSED, + GATE(ACLK_ISP0_WRAPPER, "aclk_isp0_wrapper", "aclk_isp0", 0, RK3399_CLKGATE_CON(27), 5, GFLAGS), - GATE(HCLK_ISP1_WRAPPER, "hclk_isp1_wrapper", "aclk_isp0", CLK_IGNORE_UNUSED, + GATE(HCLK_ISP1_WRAPPER, "hclk_isp1_wrapper", "aclk_isp0", 0, RK3399_CLKGATE_CON(27), 7, GFLAGS), GATE(HCLK_ISP0_NOC, "hclk_isp0_noc", "hclk_isp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(27), 0, GFLAGS), - GATE(HCLK_ISP0_WRAPPER, "hclk_isp0_wrapper", "hclk_isp0", CLK_IGNORE_UNUSED, + GATE(HCLK_ISP0_WRAPPER, "hclk_isp0_wrapper", "hclk_isp0", 0, RK3399_CLKGATE_CON(27), 4, GFLAGS), - COMPOSITE(SCLK_ISP0, "clk_isp0", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_ISP0, "clk_isp0", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(11), 4, GFLAGS), - COMPOSITE(ACLK_ISP1, "aclk_isp1", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(ACLK_ISP1, "aclk_isp1", mux_pll_src_cpll_gpll_ppll_p, 0, RK3399_CLKSEL_CON(54), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(12), 10, GFLAGS), COMPOSITE_NOMUX(HCLK_ISP1, "hclk_isp1", "aclk_isp1", 0, @@ -1235,10 +1235,10 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(HCLK_ISP1_NOC, "hclk_isp1_noc", "hclk_isp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(27), 2, GFLAGS), - GATE(ACLK_ISP1_WRAPPER, "aclk_isp1_wrapper", "hclk_isp1", CLK_IGNORE_UNUSED, + GATE(ACLK_ISP1_WRAPPER, "aclk_isp1_wrapper", "hclk_isp1", 0, RK3399_CLKGATE_CON(27), 8, GFLAGS), - COMPOSITE(SCLK_ISP1, "clk_isp1", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_ISP1, "clk_isp1", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(55), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(11), 5, GFLAGS), @@ -1250,11 +1250,11 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { * |GSC20_9|-- pclkin_cifmux -- |G27_6| -- pclkin_isp1_wrapper * pclkin_cif --|-------/ */ - GATE(PCLK_ISP1_WRAPPER, "pclkin_isp1_wrapper", "pclkin_cif", CLK_IGNORE_UNUSED, + GATE(PCLK_ISP1_WRAPPER, "pclkin_isp1_wrapper", "pclkin_cif", 0, RK3399_CLKGATE_CON(27), 6, GFLAGS), /* cif */ - COMPOSITE(0, "clk_cifout_div", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "clk_cifout_div", mux_pll_src_cpll_gpll_npll_p, 0, RK3399_CLKSEL_CON(56), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(10), 7, GFLAGS), MUX(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, CLK_SET_RATE_PARENT, @@ -1285,18 +1285,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(PCLK_GRF, "pclk_grf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 1, GFLAGS), GATE(PCLK_INTR_ARB, "pclk_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 2, GFLAGS), - GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 3, GFLAGS), - GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 4, GFLAGS), - GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 5, GFLAGS), - GATE(PCLK_TIMER0, "pclk_timer0", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 6, GFLAGS), - GATE(PCLK_TIMER1, "pclk_timer1", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 7, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 3, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 4, GFLAGS), + GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 5, GFLAGS), + GATE(PCLK_TIMER0, "pclk_timer0", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 6, GFLAGS), + GATE(PCLK_TIMER1, "pclk_timer1", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 7, GFLAGS), GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS), GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS), - GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(11), 14, GFLAGS), + GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", 0, RK3399_CLKGATE_CON(11), 14, GFLAGS), GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS), - GATE(SCLK_MIPIDPHY_CFG, "clk_mipidphy_cfg", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(11), 15, GFLAGS), + GATE(SCLK_MIPIDPHY_CFG, "clk_mipidphy_cfg", "xin24m", 0, RK3399_CLKGATE_CON(11), 15, GFLAGS), GATE(SCLK_DPHY_TX0_CFG, "clk_dphy_tx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 1, GFLAGS), GATE(SCLK_DPHY_TX1RX1_CFG, "clk_dphy_tx1rx1_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 2, GFLAGS), GATE(SCLK_DPHY_RX0_CFG, "clk_dphy_rx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 3, GFLAGS), @@ -1358,18 +1358,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(10), 5, GFLAGS), /* timer */ - GATE(SCLK_TIMER00, "clk_timer00", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 0, GFLAGS), - GATE(SCLK_TIMER01, "clk_timer01", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 1, GFLAGS), - GATE(SCLK_TIMER02, "clk_timer02", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 2, GFLAGS), - GATE(SCLK_TIMER03, "clk_timer03", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 3, GFLAGS), - GATE(SCLK_TIMER04, "clk_timer04", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 4, GFLAGS), - GATE(SCLK_TIMER05, "clk_timer05", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 5, GFLAGS), - GATE(SCLK_TIMER06, "clk_timer06", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 6, GFLAGS), - GATE(SCLK_TIMER07, "clk_timer07", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 7, GFLAGS), - GATE(SCLK_TIMER08, "clk_timer08", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 8, GFLAGS), - GATE(SCLK_TIMER09, "clk_timer09", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 9, GFLAGS), - GATE(SCLK_TIMER10, "clk_timer10", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 10, GFLAGS), - GATE(SCLK_TIMER11, "clk_timer11", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(26), 11, GFLAGS), + GATE(SCLK_TIMER00, "clk_timer00", "xin24m", 0, RK3399_CLKGATE_CON(26), 0, GFLAGS), + GATE(SCLK_TIMER01, "clk_timer01", "xin24m", 0, RK3399_CLKGATE_CON(26), 1, GFLAGS), + GATE(SCLK_TIMER02, "clk_timer02", "xin24m", 0, RK3399_CLKGATE_CON(26), 2, GFLAGS), + GATE(SCLK_TIMER03, "clk_timer03", "xin24m", 0, RK3399_CLKGATE_CON(26), 3, GFLAGS), + GATE(SCLK_TIMER04, "clk_timer04", "xin24m", 0, RK3399_CLKGATE_CON(26), 4, GFLAGS), + GATE(SCLK_TIMER05, "clk_timer05", "xin24m", 0, RK3399_CLKGATE_CON(26), 5, GFLAGS), + GATE(SCLK_TIMER06, "clk_timer06", "xin24m", 0, RK3399_CLKGATE_CON(26), 6, GFLAGS), + GATE(SCLK_TIMER07, "clk_timer07", "xin24m", 0, RK3399_CLKGATE_CON(26), 7, GFLAGS), + GATE(SCLK_TIMER08, "clk_timer08", "xin24m", 0, RK3399_CLKGATE_CON(26), 8, GFLAGS), + GATE(SCLK_TIMER09, "clk_timer09", "xin24m", 0, RK3399_CLKGATE_CON(26), 9, GFLAGS), + GATE(SCLK_TIMER10, "clk_timer10", "xin24m", 0, RK3399_CLKGATE_CON(26), 10, GFLAGS), + GATE(SCLK_TIMER11, "clk_timer11", "xin24m", 0, RK3399_CLKGATE_CON(26), 11, GFLAGS), /* clk_test */ /* clk_test_pre is controlled by CRU_MISC_CON[3] */ @@ -1383,13 +1383,13 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { * PMU CRU Clock-Architecture */ - GATE(0, "fclk_cm0s_pmu_ppll_src", "ppll", CLK_IGNORE_UNUSED, + GATE(0, "fclk_cm0s_pmu_ppll_src", "ppll", 0, RK3399_PMU_CLKGATE_CON(0), 1, GFLAGS), - COMPOSITE_NOGATE(FCLK_CM0S_SRC_PMU, "fclk_cm0s_src_pmu", mux_fclk_cm0s_pmu_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE_NOGATE(FCLK_CM0S_SRC_PMU, "fclk_cm0s_src_pmu", mux_fclk_cm0s_pmu_ppll_p, 0, RK3399_PMU_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS), - COMPOSITE(SCLK_SPI3_PMU, "clk_spi3_pmu", mux_24m_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_SPI3_PMU, "clk_spi3_pmu", mux_24m_ppll_p, 0, RK3399_PMU_CLKSEL_CON(1), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_PMU_CLKGATE_CON(0), 2, GFLAGS), @@ -1421,7 +1421,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { MUX(0, "clk_testout_2io", mux_clk_testout2_2io_p, CLK_IGNORE_UNUSED, RK3399_PMU_CLKSEL_CON(4), 15, 1, MFLAGS), - COMPOSITE(0, "clk_uart4_div", mux_24m_ppll_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "clk_uart4_div", mux_24m_ppll_p, 0, RK3399_PMU_CLKSEL_CON(5), 10, 1, MFLAGS, 0, 7, DFLAGS, RK3399_PMU_CLKGATE_CON(0), 5, GFLAGS), @@ -1434,32 +1434,32 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { RK3399_PMU_CLKSEL_CON(0), 0, 5, DFLAGS), /* pmu clock gates */ - GATE(SCLK_TIMER12_PMU, "clk_timer0_pmu", "clk_timer_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 3, GFLAGS), - GATE(SCLK_TIMER13_PMU, "clk_timer1_pmu", "clk_timer_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 4, GFLAGS), + GATE(SCLK_TIMER12_PMU, "clk_timer0_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 3, GFLAGS), + GATE(SCLK_TIMER13_PMU, "clk_timer1_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 4, GFLAGS), GATE(SCLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 7, GFLAGS), GATE(PCLK_PMU, "pclk_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 0, GFLAGS), GATE(PCLK_PMUGRF_PMU, "pclk_pmugrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 1, GFLAGS), GATE(PCLK_INTMEM1_PMU, "pclk_intmem1_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 2, GFLAGS), - GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 3, GFLAGS), - GATE(PCLK_GPIO1_PMU, "pclk_gpio1_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 4, GFLAGS), + GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 3, GFLAGS), + GATE(PCLK_GPIO1_PMU, "pclk_gpio1_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 4, GFLAGS), GATE(PCLK_SGRF_PMU, "pclk_sgrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 5, GFLAGS), GATE(PCLK_NOC_PMU, "pclk_noc_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 6, GFLAGS), - GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 7, GFLAGS), - GATE(PCLK_I2C4_PMU, "pclk_i2c4_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 8, GFLAGS), - GATE(PCLK_I2C8_PMU, "pclk_i2c8_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 9, GFLAGS), - GATE(PCLK_RKPWM_PMU, "pclk_rkpwm_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 10, GFLAGS), - GATE(PCLK_SPI3_PMU, "pclk_spi3_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 11, GFLAGS), - GATE(PCLK_TIMER_PMU, "pclk_timer_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 12, GFLAGS), - GATE(PCLK_MAILBOX_PMU, "pclk_mailbox_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 13, GFLAGS), - GATE(PCLK_UART4_PMU, "pclk_uart4_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 14, GFLAGS), - GATE(PCLK_WDT_M0_PMU, "pclk_wdt_m0_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 15, GFLAGS), - - GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS), - GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS), - GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS), - GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS), + GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 7, GFLAGS), + GATE(PCLK_I2C4_PMU, "pclk_i2c4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 8, GFLAGS), + GATE(PCLK_I2C8_PMU, "pclk_i2c8_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 9, GFLAGS), + GATE(PCLK_RKPWM_PMU, "pclk_rkpwm_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 10, GFLAGS), + GATE(PCLK_SPI3_PMU, "pclk_spi3_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 11, GFLAGS), + GATE(PCLK_TIMER_PMU, "pclk_timer_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 12, GFLAGS), + GATE(PCLK_MAILBOX_PMU, "pclk_mailbox_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 13, GFLAGS), + GATE(PCLK_UART4_PMU, "pclk_uart4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 14, GFLAGS), + GATE(PCLK_WDT_M0_PMU, "pclk_wdt_m0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 15, GFLAGS), + + GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS), + GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS), + GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS), + GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS), GATE(HCLK_NOC_PMU, "hclk_noc_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 5, GFLAGS), }; -- cgit v0.10.2 From fd8bc829336a24b770247eb893111bcb8f1ddedb Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Wed, 20 Apr 2016 19:11:32 +0800 Subject: clk: rockchip: fix the rk3399 cifout clock The cifout clock is incorrect due to the manual error, we need to fix it. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 7ecb7d6..5248726 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -158,7 +158,7 @@ PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", PNAME(mux_dclk_vop1_p) = { "dclk_vop1_div", "dclk_vop1_frac" }; -PNAME(mux_clk_cif_p) = { "clk_cifout_div", "xin24m" }; +PNAME(mux_clk_cif_p) = { "clk_cifout_src", "xin24m" }; PNAME(mux_pll_src_24m_usbphy480m_p) = { "xin24m", "clk_usbphy_480m" }; PNAME(mux_pll_src_24m_pciephy_p) = { "xin24m", "clk_pciephy_ref100m" }; @@ -1254,11 +1254,12 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(27), 6, GFLAGS), /* cif */ - COMPOSITE(0, "clk_cifout_div", mux_pll_src_cpll_gpll_npll_p, 0, - RK3399_CLKSEL_CON(56), 6, 2, MFLAGS, 0, 5, DFLAGS, + COMPOSITE_NODIV(0, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(56), 6, 2, MFLAGS, RK3399_CLKGATE_CON(10), 7, GFLAGS), - MUX(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, CLK_SET_RATE_PARENT, - RK3399_CLKSEL_CON(56), 5, 1, MFLAGS), + + COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, 0, + RK3399_CLKSEL_CON(56), 5, 1, MFLAGS, 0, 5, DFLAGS), /* gic */ COMPOSITE(ACLK_GIC_PRE, "aclk_gic_pre", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, -- cgit v0.10.2 From 0187d321a5092fe09687f69ee29ebe8ab75544c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 25 Apr 2016 13:39:19 +0200 Subject: clk: renesas: r8a7795: Add CSI2 clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Niklas Söderlund Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index 6af7f5b..f6a0a9d 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -120,6 +120,7 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014), DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250), DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244), + DEF_DIV6P1("csi0", R8A7795_CLK_CSI0, CLK_PLL1_DIV4, 0x00c), DEF_DIV6_RO("osc", R8A7795_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8), DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32), @@ -190,6 +191,10 @@ static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { DEF_MOD("ehci1", 702, R8A7795_CLK_S3D4), DEF_MOD("ehci0", 703, R8A7795_CLK_S3D4), DEF_MOD("hsusb", 704, R8A7795_CLK_S3D4), + DEF_MOD("csi21", 713, R8A7795_CLK_CSI0), + DEF_MOD("csi20", 714, R8A7795_CLK_CSI0), + DEF_MOD("csi41", 715, R8A7795_CLK_CSI0), + DEF_MOD("csi40", 716, R8A7795_CLK_CSI0), DEF_MOD("du3", 721, R8A7795_CLK_S2D1), DEF_MOD("du2", 722, R8A7795_CLK_S2D1), DEF_MOD("du1", 723, R8A7795_CLK_S2D1), -- cgit v0.10.2 From ccce262de1c5035513d7974ab1550dd757d25bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 25 Apr 2016 13:39:20 +0200 Subject: clk: renesas: r8a7795: Add VIN clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Niklas Söderlund Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index f6a0a9d..ca5519c 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -202,6 +202,14 @@ static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { DEF_MOD("lvds", 727, R8A7795_CLK_S2D1), DEF_MOD("hdmi1", 728, R8A7795_CLK_HDMI), DEF_MOD("hdmi0", 729, R8A7795_CLK_HDMI), + DEF_MOD("vin7", 804, R8A7795_CLK_S2D1), + DEF_MOD("vin6", 805, R8A7795_CLK_S2D1), + DEF_MOD("vin5", 806, R8A7795_CLK_S2D1), + DEF_MOD("vin4", 807, R8A7795_CLK_S2D1), + DEF_MOD("vin3", 808, R8A7795_CLK_S2D1), + DEF_MOD("vin2", 809, R8A7795_CLK_S2D1), + DEF_MOD("vin1", 810, R8A7795_CLK_S2D1), + DEF_MOD("vin0", 811, R8A7795_CLK_S2D1), DEF_MOD("etheravb", 812, R8A7795_CLK_S3D2), DEF_MOD("sata0", 815, R8A7795_CLK_S3D2), DEF_MOD("gpio7", 905, R8A7795_CLK_CP), -- cgit v0.10.2 From 585a60f24bf86671b17ca7420e82b9404ff18502 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 29 Jan 2016 14:49:24 -0800 Subject: clk: imx: return correct frequency for Ethernet PLL The i.MX 7 designs Ethernet PLL provides a 1000MHz reference clock. Store the reference clock in the clk_pllv3 structure according to the PLL type. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index c05c43d..4826b3c 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -44,6 +44,7 @@ struct clk_pllv3 { u32 powerdown; u32 div_mask; u32 div_shift; + unsigned long ref_clock; }; #define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw) @@ -286,7 +287,9 @@ static const struct clk_ops clk_pllv3_av_ops = { static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - return 500000000; + struct clk_pllv3 *pll = to_clk_pllv3(hw); + + return pll->ref_clock; } static const struct clk_ops clk_pllv3_enet_ops = { @@ -326,7 +329,11 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, break; case IMX_PLLV3_ENET_IMX7: pll->powerdown = IMX7_ENET_PLL_POWER; + pll->ref_clock = 1000000000; + ops = &clk_pllv3_enet_ops; + break; case IMX_PLLV3_ENET: + pll->ref_clock = 500000000; ops = &clk_pllv3_enet_ops; break; default: -- cgit v0.10.2 From b3a52d75bc91d2c7299e721c0fb41c33859c2cdf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 14:45:45 +0200 Subject: clk: renesas: mstp: Postpone call to pm_genpd_init() All local setup of the generic_pm_domain structure should have been completed before calling pm_genpd_init(). Signed-off-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Reviewed-by: Ulf Hansson diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 8b597b9..969fbb61 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -316,11 +316,10 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np) return; pd->name = np->name; - pd->flags = GENPD_FLAG_PM_CLK; - pm_genpd_init(pd, &simple_qos_governor, false); pd->attach_dev = cpg_mstp_attach_dev; pd->detach_dev = cpg_mstp_detach_dev; + pm_genpd_init(pd, &simple_qos_governor, false); of_genpd_add_provider_simple(np, pd); } -- cgit v0.10.2 From 20729300cabdad60333e52278bd2dd25e5d85518 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 14:57:29 +0200 Subject: clk: renesas: mstp: Use always-on governor for Clock Domain As a pure Clock Domain does not have the concept of powering the domain itself, the CPG/MSTP driver does not provide power_off() and power_on() callbacks. However, the genpd core may still perform a dummy power down, causing /sys/kernel/debug/pm_genpd/pm_genpd_summary to report the domain's status being "off-0". Use the always-on governor to make sure the domain is never powered down, and always shows up as "on" in pm_genpd_summary. Signed-off-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Reviewed-by: Ulf Hansson diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 969fbb61..5093a25 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -319,7 +319,7 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np) pd->flags = GENPD_FLAG_PM_CLK; pd->attach_dev = cpg_mstp_attach_dev; pd->detach_dev = cpg_mstp_detach_dev; - pm_genpd_init(pd, &simple_qos_governor, false); + pm_genpd_init(pd, &pm_domain_always_on_gov, false); of_genpd_add_provider_simple(np, pd); } -- cgit v0.10.2 From 93662500a1fcc9c8085ac3f056b537d093fd4d20 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 14:46:51 +0200 Subject: clk: renesas: cpg-mssr: Postpone call to pm_genpd_init() All local setup of the generic_pm_domain structure should have been completed before calling pm_genpd_init(). Signed-off-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Reviewed-by: Ulf Hansson diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 1f2dc362..0d59531 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -493,9 +493,9 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev, genpd = &pd->genpd; genpd->name = np->name; genpd->flags = GENPD_FLAG_PM_CLK; - pm_genpd_init(genpd, &simple_qos_governor, false); genpd->attach_dev = cpg_mssr_attach_dev; genpd->detach_dev = cpg_mssr_detach_dev; + pm_genpd_init(genpd, &simple_qos_governor, false); cpg_mssr_clk_domain = pd; of_genpd_add_provider_simple(np, genpd); -- cgit v0.10.2 From d04a75af450782db2937603bb6706bf6fa7c6f37 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 14:59:10 +0200 Subject: clk: renesas: cpg-mssr: Use always-on governor for Clock Domain As a pure Clock Domain does not have the concept of powering the domain itself, the CPG/MSTP driver does not provide power_off() and power_on() callbacks. However, the genpd core may still perform a dummy power down, causing /sys/kernel/debug/pm_genpd/pm_genpd_summary to report the domain's status being "off-0". Use the always-on governor to make sure the domain is never powered down, and always shows up as "on" in pm_genpd_summary. Signed-off-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Reviewed-by: Ulf Hansson diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 0d59531..210cd74 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -495,7 +495,7 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev, genpd->flags = GENPD_FLAG_PM_CLK; genpd->attach_dev = cpg_mssr_attach_dev; genpd->detach_dev = cpg_mssr_detach_dev; - pm_genpd_init(genpd, &simple_qos_governor, false); + pm_genpd_init(genpd, &pm_domain_always_on_gov, false); cpg_mssr_clk_domain = pd; of_genpd_add_provider_simple(np, genpd); -- cgit v0.10.2 From 7e14f22305b09bd57fc2da3bf2fd3bfd53dc285b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 14:38:39 +0200 Subject: clk: tegra: Constify peripheral clock registers The peripheral clock registers are defined in static tables. These tables never need to be modified at runtime, so they can reside in read-only memory. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index d28d6e9..8812782 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -134,7 +134,7 @@ struct clk *tegra_clk_register_periph_gate(const char *name, struct tegra_clk_periph_gate *gate; struct clk *clk; struct clk_init_data init; - struct tegra_clk_periph_regs *pregs; + const struct tegra_clk_periph_regs *pregs; pregs = get_reg_bank(clk_num); if (!pregs) diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index ec5b611..a17ca6d 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -145,7 +145,7 @@ static struct clk *_tegra_clk_register_periph(const char *name, { struct clk *clk; struct clk_init_data init; - struct tegra_clk_periph_regs *bank; + const struct tegra_clk_periph_regs *bank; bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV); if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) { diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index ea2b9cbf..b4e226a 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -877,7 +877,7 @@ static void __init periph_clk_init(void __iomem *clk_base, struct clk **dt_clk; for (i = 0; i < ARRAY_SIZE(periph_clks); i++) { - struct tegra_clk_periph_regs *bank; + const struct tegra_clk_periph_regs *bank; struct tegra_periph_init_data *data; data = periph_clks + i; diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 2a3a4fe..98e65ca 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -84,7 +84,7 @@ static int (*special_reset_assert)(unsigned long); static int (*special_reset_deassert)(unsigned long); static unsigned int num_special_reset; -static struct tegra_clk_periph_regs periph_regs[] = { +static const struct tegra_clk_periph_regs periph_regs[] = { [0] = { .enb_reg = CLK_OUT_ENB_L, .enb_set_reg = CLK_OUT_ENB_SET_L, @@ -182,7 +182,7 @@ static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev, return -EINVAL; } -struct tegra_clk_periph_regs *get_reg_bank(int clkid) +const struct tegra_clk_periph_regs *get_reg_bank(int clkid) { int reg_bank = clkid / 32; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 4dbcfae..3ef530a 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -496,7 +496,7 @@ struct tegra_clk_periph_gate { u8 flags; int clk_num; int *enable_refcnt; - struct tegra_clk_periph_regs *regs; + const struct tegra_clk_periph_regs *regs; }; #define to_clk_periph_gate(_hw) \ @@ -716,7 +716,7 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl, void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max); -struct tegra_clk_periph_regs *get_reg_bank(int clkid); +const struct tegra_clk_periph_regs *get_reg_bank(int clkid); struct clk **tegra_clk_init(void __iomem *clk_base, int num, int periph_banks); struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk); -- cgit v0.10.2 From a9caa8481258576b59b46067dfd8fd6fbd72f3e3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:26:42 +0200 Subject: clk: tegra: Remove trailing blank line Trailing blank lines are undesirable (several tools, such as git, complain about them), so remove it. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c index d64ec7a..91c38f1 100644 --- a/drivers/clk/tegra/clk-tegra-fixed.c +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -107,4 +107,3 @@ void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) *dt_clk = clk; } } - -- cgit v0.10.2 From 07314fc108e195044c074f4b443974b5aaa2d5d7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 8 Apr 2015 16:48:26 +0200 Subject: clk: tegra: Special-case mipi-cal parent on Tegra114 Starting with Tegra124, the mipi-cal clock uses the 72 MHz clock as its source. On Tegra114 this clock's parent was clk_m, so it is the one-off chip. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index b4e226a..463c114 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -803,7 +803,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("hda2hdmi", "clk_m", 128, TEGRA_PERIPH_ON_APB, tegra_clk_hda2hdmi, 0), GATE("bsea", "clk_m", 62, 0, tegra_clk_bsea, 0), GATE("bsev", "clk_m", 63, 0, tegra_clk_bsev, 0), - GATE("mipi-cal", "clk_m", 56, 0, tegra_clk_mipi_cal, 0), + GATE("mipi-cal", "clk72mhz", 56, 0, tegra_clk_mipi_cal, 0), GATE("usbd", "clk_m", 22, 0, tegra_clk_usbd, 0), GATE("usb2", "clk_m", 58, 0, tegra_clk_usb2, 0), GATE("usb3", "clk_m", 59, 0, tegra_clk_usb3, 0), diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index df47ec3..b78054f 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -743,7 +743,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true }, [tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true }, [tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true }, - [tegra_clk_mipi_cal] = { .dt_id = TEGRA114_CLK_MIPI_CAL, .present = true }, [tegra_clk_emc] = { .dt_id = TEGRA114_CLK_EMC, .present = true }, [tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true }, [tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true }, @@ -1237,6 +1236,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base, &emc_lock); clks[TEGRA114_CLK_MC] = clk; + clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base, + CLK_SET_RATE_PARENT, 56, + periph_clk_enb_refcnt); + clks[TEGRA114_CLK_MIPI_CAL] = clk; + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; clk = tegra_clk_register_periph(data->name, -- cgit v0.10.2 From 1ec7032ad517714108cc53a6ee7067276ca21e80 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 14:34:57 +0200 Subject: clk: tegra: Add fixed factor peripheral clock type Some of the peripheral clocks on Tegra are derived from one of the top- level PLLs with a fixed factor. Support these clocks by implementing the ->enable() and ->disable() callbacks using the peripheral clock register banks and the ->recalc_rate() by dividing the parent rate by the fixed factor. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 97984c5..33fd093 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -3,6 +3,7 @@ obj-y += clk-audio-sync.o obj-y += clk-dfll.o obj-y += clk-divider.o obj-y += clk-periph.o +obj-y += clk-periph-fixed.o obj-y += clk-periph-gate.o obj-y += clk-pll.o obj-y += clk-pll-out.o diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c new file mode 100644 index 0000000..c57dfb0 --- /dev/null +++ b/drivers/clk/tegra/clk-periph-fixed.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "clk.h" + +static inline struct tegra_clk_periph_fixed * +to_tegra_clk_periph_fixed(struct clk_hw *hw) +{ + return container_of(hw, struct tegra_clk_periph_fixed, hw); +} + +static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32), value; + + value = readl(fixed->base + fixed->regs->enb_reg); + if (value & mask) { + value = readl(fixed->base + fixed->regs->rst_reg); + if ((value & mask) == 0) + return 1; + } + + return 0; +} + +static int tegra_clk_periph_fixed_enable(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32); + + writel(mask, fixed->base + fixed->regs->enb_set_reg); + + return 0; +} + +static void tegra_clk_periph_fixed_disable(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32); + + writel(mask, fixed->base + fixed->regs->enb_clr_reg); +} + +static unsigned long +tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + unsigned long long rate; + + rate = (unsigned long long)parent_rate * fixed->mul; + do_div(rate, fixed->div); + + return (unsigned long)rate; +} + +static const struct clk_ops tegra_clk_periph_fixed_ops = { + .is_enabled = tegra_clk_periph_fixed_is_enabled, + .enable = tegra_clk_periph_fixed_enable, + .disable = tegra_clk_periph_fixed_disable, + .recalc_rate = tegra_clk_periph_fixed_recalc_rate, +}; + +struct clk *tegra_clk_register_periph_fixed(const char *name, + const char *parent, + unsigned long flags, + void __iomem *base, + unsigned int mul, + unsigned int div, + unsigned int num) +{ + const struct tegra_clk_periph_regs *regs; + struct tegra_clk_periph_fixed *fixed; + struct clk_init_data init; + struct clk *clk; + + regs = get_reg_bank(num); + if (!regs) + return ERR_PTR(-EINVAL); + + fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); + if (!fixed) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = flags; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + init.ops = &tegra_clk_periph_fixed_ops; + + fixed->base = base; + fixed->regs = regs; + fixed->mul = mul; + fixed->div = div; + fixed->num = num; + + fixed->hw.init = &init; + + clk = clk_register(NULL, &fixed->hw); + if (IS_ERR(clk)) + kfree(fixed); + + return clk; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 3ef530a..7264f17 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -516,6 +516,23 @@ struct clk *tegra_clk_register_periph_gate(const char *name, const char *parent_name, u8 gate_flags, void __iomem *clk_base, unsigned long flags, int clk_num, int *enable_refcnt); +struct tegra_clk_periph_fixed { + struct clk_hw hw; + void __iomem *base; + const struct tegra_clk_periph_regs *regs; + unsigned int mul; + unsigned int div; + unsigned int num; +}; + +struct clk *tegra_clk_register_periph_fixed(const char *name, + const char *parent, + unsigned long flags, + void __iomem *base, + unsigned int mul, + unsigned int div, + unsigned int num); + /** * struct clk-periph - peripheral clock * -- cgit v0.10.2 From 3d0f4e5f7a7c9ef2d8504f2b42f9c4d3233ba707 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 14:47:25 +0200 Subject: clk: tegra: Use correct parent for dpaux clock The dpaux clock is derived from pll_p_out0 (pll_p), not clk_m. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 463c114..d758f21 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -821,7 +821,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0), GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), - GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0), + GATE("dpaux", "pll_p", 181, 0, tegra_clk_dpaux, 0), GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0), GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0), -- cgit v0.10.2 From 98c4b3661b5aee0e583d17d6304f6489c0f41155 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:05:33 +0200 Subject: clk: tegra: Add dpaux1 clock This clock is of the same type as dpaux and is added to feed into the second DPAUX block used in conjunction with SOR1. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index 62ea381..fe6c6af 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -71,6 +71,7 @@ enum clk_id { tegra_clk_disp2_8, tegra_clk_dp2, tegra_clk_dpaux, + tegra_clk_dpaux1, tegra_clk_dsialp, tegra_clk_dsia_mux, tegra_clk_dsiblp, diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index d758f21..c716b28 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -822,6 +822,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), GATE("dpaux", "pll_p", 181, 0, tegra_clk_dpaux, 0), + GATE("dpaux1", "pll_p", 207, 0, tegra_clk_dpaux1, 0), GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0), GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0), diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 3d0edee..4f72d1a 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2150,6 +2150,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_clk72Mhz_8] = { .dt_id = TEGRA210_CLK_CLK72MHZ, .present = true }, [tegra_clk_vic03_8] = { .dt_id = TEGRA210_CLK_VIC03, .present = true }, [tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true }, + [tegra_clk_dpaux1] = { .dt_id = TEGRA210_CLK_DPAUX1, .present = true }, [tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true }, [tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true }, [tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true }, -- cgit v0.10.2 From eede7113aabd3f40f8d9c32b1690f2859fcb101a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:10:43 +0200 Subject: clk: tegra: dpaux and dpaux1 are fixed factor clocks The dpaux (on Tegra124 and Tegra210) and dpaux1 (on Tegra210) are fixed factor clocks (1:17) and derived from pll_p_out0 (pll_p). They also have a gate bit in the peripheral clock registers. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index c716b28..29d04c6 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -821,8 +821,6 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0), GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), - GATE("dpaux", "pll_p", 181, 0, tegra_clk_dpaux, 0), - GATE("dpaux1", "pll_p", 207, 0, tegra_clk_dpaux1, 0), GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0), GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0), diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 1627258..f4fbbf1 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1155,6 +1155,10 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk; + clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base, + 1, 17, 181); + clks[TEGRA124_CLK_DPAUX] = clk; + clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC, 30, 0, &pll_d_lock); clks[TEGRA124_CLK_PLL_D_DSI_OUT] = clk; diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 4f72d1a..8133f92 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2462,6 +2462,14 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA210_CLK_XUSB_SS_DIV2] = clk; + clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base, + 1, 17, 181); + clks[TEGRA210_CLK_DPAUX] = clk; + + clk = tegra_clk_register_periph_fixed("dpaux1", "pll_p", 0, clk_base, + 1, 17, 207); + clks[TEGRA210_CLK_DPAUX1] = clk; + /* pll_d_dsi_out */ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC0, 21, 0, &pll_d_lock); -- cgit v0.10.2 From a91bb605ec5f93676e503267c89469d02c5b4cbc Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:13:36 +0200 Subject: clk: tegra: Add sor_safe clock The sor_safe clock is a fixed factor (1:17) clock derived from pll_p. It has a gate bit in the peripheral clock registers. While the SOR is being powered up, sor_safe can be used as the source until the SOR brick can generate its own clock. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index fe6c6af..36c9749 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -307,6 +307,7 @@ enum clk_id { tegra_clk_xusb_ss_div2, tegra_clk_xusb_ssp_src, tegra_clk_sclk_mux, + tegra_clk_sor_safe, tegra_clk_max, }; diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 8133f92..6f66171 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2470,6 +2470,10 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 1, 17, 207); clks[TEGRA210_CLK_DPAUX1] = clk; + clk = tegra_clk_register_periph_fixed("sor_safe", "pll_p", 0, clk_base, + 1, 17, 222); + clks[TEGRA210_CLK_SOR_SAFE] = clk; + /* pll_d_dsi_out */ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC0, 21, 0, &pll_d_lock); -- cgit v0.10.2 From 926655f929063619b13db8b4f2ef8c9a08605492 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Mon, 21 Mar 2016 15:58:52 -0400 Subject: clk: tegra: Fix pllre Tegra210 and add pll_re_out1 Use a new Tegra210 version of the pll_register_pllre function to allow setting the proper settings for the m and n div fields. Additionally define PLL_RE_OUT1 on Tegra210. Signed-off-by: Rhyland Klein [treding@nvidia.com: define PLLRE_OUT1 register offset] Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 6ac3f84..4e194ec 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -2013,6 +2013,52 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, #endif #if defined(CONFIG_ARCH_TEGRA_210_SOC) +struct clk *tegra_clk_register_pllre_tegra210(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock, unsigned long parent_rate) +{ + u32 val; + struct tegra_clk_pll *pll; + struct clk *clk; + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + if (pll_params->adjust_vco) + pll_params->vco_min = pll_params->adjust_vco(pll_params, + parent_rate); + + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + /* program minimum rate by default */ + + val = pll_readl_base(pll); + if (val & PLL_BASE_ENABLE) + WARN_ON(readl_relaxed(clk_base + pll_params->iddq_reg) & + BIT(pll_params->iddq_bit_idx)); + else { + val = 0x4 << divm_shift(pll); + val |= 0x41 << divn_shift(pll); + pll_writel_base(val, pll); + } + + /* disable lock override */ + + val = pll_readl_misc(pll); + val &= ~BIT(29); + pll_writel_misc(val, pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllre_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + static int clk_plle_tegra210_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 6f66171..b855181 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -92,6 +92,7 @@ #define PLLE_AUX 0x48c #define PLLRE_BASE 0x4c4 #define PLLRE_MISC0 0x4c8 +#define PLLRE_OUT1 0x4cc #define PLLDP_BASE 0x590 #define PLLDP_MISC 0x594 @@ -2653,8 +2654,10 @@ static void __init tegra210_pll_init(void __iomem *clk_base, clks[TEGRA210_CLK_PLL_D_OUT0] = clk; /* PLLRE */ - clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, - 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq); + clk = tegra_clk_register_pllre_tegra210("pll_re_vco", "pll_ref", + clk_base, pmc, 0, + &pll_re_vco_params, + &pll_re_lock, pll_ref_freq); clk_register_clkdev(clk, "pll_re_vco", NULL); clks[TEGRA210_CLK_PLL_RE_VCO] = clk; @@ -2664,6 +2667,15 @@ static void __init tegra210_pll_init(void __iomem *clk_base, clk_register_clkdev(clk, "pll_re_out", NULL); clks[TEGRA210_CLK_PLL_RE_OUT] = clk; + clk = tegra_clk_register_divider("pll_re_out1_div", "pll_re_vco", + clk_base + PLLRE_OUT1, 0, + TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div", + clk_base + PLLRE_OUT1, 1, 0, + CLK_SET_RATE_PARENT, 0, NULL); + clks[TEGRA210_CLK_PLL_RE_OUT1] = clk; + /* PLLE */ clk = tegra_clk_register_plle_tegra210("pll_e", "pll_ref", clk_base, 0, &pll_e_params, NULL); diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 7264f17..9421f03 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -386,6 +386,12 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, struct tegra_clk_pll_params *pll_params, spinlock_t *lock, unsigned long parent_rate); +struct clk *tegra_clk_register_pllre_tegra210(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock, unsigned long parent_rate); + struct clk *tegra_clk_register_plle_tegra114(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h index 0a05b0d..bd3530e 100644 --- a/include/dt-bindings/clock/tegra210-car.h +++ b/include/dt-bindings/clock/tegra210-car.h @@ -346,7 +346,7 @@ #define TEGRA210_CLK_PLL_P_OUT_HSIO 316 #define TEGRA210_CLK_PLL_P_OUT_XUSB 317 #define TEGRA210_CLK_XUSB_SSP_SRC 318 -/* 319 */ +#define TEGRA210_CLK_PLL_RE_OUT1 319 /* 320 */ /* 321 */ /* 322 */ -- cgit v0.10.2 From a02cc84a31d3bd46a10546ff7024e7b5a186d339 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 29 Feb 2016 21:46:06 +0100 Subject: clk: tegra: Initialize PLL_C to sane rate on Tegra30 If the bootloader does not touch PLL_C it will stay in its reset state, failing to lock when enabled. This leads to consumers of this clock to fail probing. Fix this by always programming the PLL with a sane rate, which allows it to lock, at startup. Signed-off-by: Lucas Stach Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 0478565..236e2db 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1372,6 +1372,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0 }, + { TEGRA30_CLK_PLL_C, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, { TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0 }, { TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0 }, { TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0 }, -- cgit v0.10.2 From 797097301860c64b63346d068ba4fe4992bd5021 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 29 Feb 2016 21:46:07 +0100 Subject: clk: tegra: Fix PLL_U post divider and initial rate on Tegra30 The post divider value in the frequency table is wrong as it would lead to the PLL producing an output rate of 960 MHz instead of the desired 480 MHz. This wasn't a problem as nothing used the table to actually initialize the PLL rate, but the bootloader configuration was used unaltered. If the bootloader does not set up the PLL it will fail to come when used under Linux. To fix this don't rely on the bootloader, but set the correct rate in the clock driver. Signed-off-by: Lucas Stach Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 236e2db..9396f49 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -339,11 +339,11 @@ static const struct pdiv_map pllu_p[] = { }; static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 1, 12 }, - { 13000000, 480000000, 960, 13, 1, 12 }, - { 16800000, 480000000, 400, 7, 1, 5 }, - { 19200000, 480000000, 200, 4, 1, 3 }, - { 26000000, 480000000, 960, 26, 1, 12 }, + { 12000000, 480000000, 960, 12, 2, 12 }, + { 13000000, 480000000, 960, 13, 2, 12 }, + { 16800000, 480000000, 400, 7, 2, 5 }, + { 19200000, 480000000, 200, 4, 2, 3 }, + { 26000000, 480000000, 960, 26, 2, 12 }, { 0, 0, 0, 0, 0, 0 }, }; @@ -1380,6 +1380,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 }, + { TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 }, /* must be the last entry */ { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 }, }; -- cgit v0.10.2 From 8eaaae9937649f54beac7da582fa6cc6c79ae936 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 14:57:09 +0200 Subject: clk: tegra: dfll: Update kerneldoc The kerneldoc for struct tegra_dfll_soc_data is stale. Update it to match the current structure definition. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index 2e4c077..7e66c07 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -24,15 +24,14 @@ /** * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver - * @opp_dev: struct device * that holds the OPP table for the DFLL + * @dev: struct device * that holds the OPP table for the DFLL * @min_millivolts: minimum voltage (in mV) that the DFLL can operate * @tune0_low: DFLL tuning register 0 (low voltage range) * @tune0_high: DFLL tuning register 0 (high voltage range) * @tune1: DFLL tuning register 1 - * @assert_dvco_reset: fn ptr to place the DVCO in reset - * @deassert_dvco_reset: fn ptr to release the DVCO reset - * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage - * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage + * @init_clock_trimmers: callback to initialize clock trimmers + * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage + * @set_clock_trimmers_low: callback to tune clock trimmers for low voltage */ struct tegra_dfll_soc_data { struct device *dev; @@ -40,6 +39,7 @@ struct tegra_dfll_soc_data { u32 tune0_low; u32 tune0_high; u32 tune1; + void (*init_clock_trimmers)(void); void (*set_clock_trimmers_high)(void); void (*set_clock_trimmers_low)(void); -- cgit v0.10.2 From 27ed2f7e7ca5c38a8ce695e58e6cf270c26f370b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:02:06 +0200 Subject: clk: tegra: dfll: Reference CVB table instead of copying data Instead of copying parts of the CVB table into a separate structure, keep track of the selected CVB table and directly reference data from it. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 19bfa07..f010562 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -55,6 +55,7 @@ #include #include "clk-dfll.h" +#include "cvb.h" /* * DFLL control registers - access via dfll_{readl,writel} @@ -442,8 +443,8 @@ static void dfll_tune_low(struct tegra_dfll *td) { td->tune_range = DFLL_TUNE_LOW; - dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0); - dfll_writel(td, td->soc->tune1, DFLL_TUNE1); + dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune0_low, DFLL_TUNE0); + dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1, DFLL_TUNE1); dfll_wmb(td); if (td->soc->set_clock_trimmers_low) @@ -1449,7 +1450,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) } v_max = dev_pm_opp_get_voltage(opp); - v = td->soc->min_millivolts * 1000; + v = td->soc->cvb->min_millivolts * 1000; lut = find_vdd_map_entry_exact(td, v); if (lut < 0) goto out; @@ -1461,7 +1462,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) break; v_opp = dev_pm_opp_get_voltage(opp); - if (v_opp <= td->soc->min_millivolts * 1000) + if (v_opp <= td->soc->cvb->min_millivolts * 1000) td->dvco_rate_min = dev_pm_opp_get_freq(opp); for (;;) { @@ -1490,7 +1491,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) if (!td->dvco_rate_min) dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n", - td->soc->min_millivolts); + td->soc->cvb->min_millivolts); else ret = 0; diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index 7e66c07..d192982 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -25,20 +25,14 @@ /** * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver * @dev: struct device * that holds the OPP table for the DFLL - * @min_millivolts: minimum voltage (in mV) that the DFLL can operate - * @tune0_low: DFLL tuning register 0 (low voltage range) - * @tune0_high: DFLL tuning register 0 (high voltage range) - * @tune1: DFLL tuning register 1 + * @cvb: CPU frequency table for this SoC * @init_clock_trimmers: callback to initialize clock trimmers * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage * @set_clock_trimmers_low: callback to tune clock trimmers for low voltage */ struct tegra_dfll_soc_data { struct device *dev; - unsigned int min_millivolts; - u32 tune0_low; - u32 tune0_high; - u32 tune1; + const struct cvb_table *cvb; void (*init_clock_trimmers)(void); void (*set_clock_trimmers_high)(void); diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 6125333..6bfa5ca 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -86,7 +86,6 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) { int process_id, speedo_id, speedo_value; struct tegra_dfll_soc_data *soc; - const struct cvb_table *cvb; process_id = tegra_sku_info.cpu_process_id; speedo_id = tegra_sku_info.cpu_speedo_id; @@ -108,21 +107,17 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return -ENODEV; } - cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, - ARRAY_SIZE(tegra124_cpu_cvb_tables), - process_id, speedo_id, speedo_value, - cpu_max_freq_table[speedo_id], - soc->dev); - if (IS_ERR(cvb)) { - dev_err(&pdev->dev, "couldn't build OPP table: %ld\n", - PTR_ERR(cvb)); - return PTR_ERR(cvb); + soc->cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, + ARRAY_SIZE(tegra124_cpu_cvb_tables), + process_id, speedo_id, speedo_value, + cpu_max_freq_table[speedo_id], + soc->dev); + if (IS_ERR(soc->cvb)) { + dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", + PTR_ERR(soc->cvb)); + return PTR_ERR(soc->cvb); } - soc->min_millivolts = cvb->min_millivolts; - soc->tune0_low = cvb->cpu_dfll_data.tune0_low; - soc->tune0_high = cvb->cpu_dfll_data.tune0_high; - soc->tune1 = cvb->cpu_dfll_data.tune1; return tegra_dfll_register(pdev, soc); } -- cgit v0.10.2 From e8f6a68c508b5d1cc4612ada028d87c74ab279d5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:09:56 +0200 Subject: clk: tegra: dfll: Make code more comprehensible Rename some variables and structure fields to make the code more comprehensible. Also change the prototype of internal functions to be more in line with the OPP core functions. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 6bfa5ca..c7ffd4f 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -47,7 +47,7 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { }, .speedo_scale = 100, .voltage_scale = 1000, - .cvb_table = { + .entries = { {204000000UL, {1112619, -29295, 402} }, {306000000UL, {1150460, -30585, 402} }, {408000000UL, {1190122, -31865, 402} }, @@ -107,11 +107,10 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return -ENODEV; } - soc->cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, - ARRAY_SIZE(tegra124_cpu_cvb_tables), - process_id, speedo_id, speedo_value, - cpu_max_freq_table[speedo_id], - soc->dev); + soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables, + ARRAY_SIZE(tegra124_cpu_cvb_tables), + process_id, speedo_id, speedo_value, + cpu_max_freq_table[speedo_id]); if (IS_ERR(soc->cvb)) { dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", PTR_ERR(soc->cvb)); diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c index 69c74ee..7a099b1 100644 --- a/drivers/clk/tegra/cvb.c +++ b/drivers/clk/tegra/cvb.c @@ -61,29 +61,28 @@ static int round_voltage(int mv, const struct rail_alignment *align, int up) return mv; } -static int build_opp_table(const struct cvb_table *d, - int speedo_value, - unsigned long max_freq, - struct device *opp_dev) +static int build_opp_table(struct device *dev, const struct cvb_table *table, + int speedo_value, unsigned long max_freq) { + const struct rail_alignment *align = &table->alignment; int i, ret, dfll_mv, min_mv, max_mv; - const struct cvb_table_freq_entry *table = NULL; - const struct rail_alignment *align = &d->alignment; - min_mv = round_voltage(d->min_millivolts, align, UP); - max_mv = round_voltage(d->max_millivolts, align, DOWN); + min_mv = round_voltage(table->min_millivolts, align, UP); + max_mv = round_voltage(table->max_millivolts, align, DOWN); for (i = 0; i < MAX_DVFS_FREQS; i++) { - table = &d->cvb_table[i]; - if (!table->freq || (table->freq > max_freq)) + const struct cvb_table_freq_entry *entry = &table->entries[i]; + + if (!entry->freq || (entry->freq > max_freq)) break; - dfll_mv = get_cvb_voltage( - speedo_value, d->speedo_scale, &table->coefficients); - dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align); + dfll_mv = get_cvb_voltage(speedo_value, table->speedo_scale, + &entry->coefficients); + dfll_mv = round_cvb_voltage(dfll_mv, table->voltage_scale, + align); dfll_mv = clamp(dfll_mv, min_mv, max_mv); - ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000); + ret = dev_pm_opp_add(dev, entry->freq, dfll_mv * 1000); if (ret) return ret; } @@ -92,7 +91,7 @@ static int build_opp_table(const struct cvb_table *d, } /** - * tegra_cvb_build_opp_table - build OPP table from Tegra CVB tables + * tegra_cvb_add_opp_table - build OPP table from Tegra CVB tables * @cvb_tables: array of CVB tables * @sz: size of the previously mentioned array * @process_id: process id of the HW module @@ -108,25 +107,25 @@ static int build_opp_table(const struct cvb_table *d, * given @opp_dev. Returns a pointer to the struct cvb_table that matched * or an ERR_PTR on failure. */ -const struct cvb_table *tegra_cvb_build_opp_table( - const struct cvb_table *cvb_tables, - size_t sz, int process_id, - int speedo_id, int speedo_value, - unsigned long max_rate, - struct device *opp_dev) +const struct cvb_table * +tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables, + size_t count, int process_id, int speedo_id, + int speedo_value, unsigned long max_freq) { - int i, ret; + size_t i; + int ret; - for (i = 0; i < sz; i++) { - const struct cvb_table *d = &cvb_tables[i]; + for (i = 0; i < count; i++) { + const struct cvb_table *table = &tables[i]; - if (d->speedo_id != -1 && d->speedo_id != speedo_id) + if (table->speedo_id != -1 && table->speedo_id != speedo_id) continue; - if (d->process_id != -1 && d->process_id != process_id) + + if (table->process_id != -1 && table->process_id != process_id) continue; - ret = build_opp_table(d, speedo_value, max_rate, opp_dev); - return ret ? ERR_PTR(ret) : d; + ret = build_opp_table(dev, table, speedo_value, max_freq); + return ret ? ERR_PTR(ret) : table; } return ERR_PTR(-EINVAL); diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h index f62cdc4..e6bf858 100644 --- a/drivers/clk/tegra/cvb.h +++ b/drivers/clk/tegra/cvb.h @@ -53,15 +53,13 @@ struct cvb_table { int speedo_scale; int voltage_scale; - struct cvb_table_freq_entry cvb_table[MAX_DVFS_FREQS]; + struct cvb_table_freq_entry entries[MAX_DVFS_FREQS]; struct cvb_cpu_dfll_data cpu_dfll_data; }; -const struct cvb_table *tegra_cvb_build_opp_table( - const struct cvb_table *cvb_tables, - size_t sz, int process_id, - int speedo_id, int speedo_value, - unsigned long max_rate, - struct device *opp_dev); +const struct cvb_table * +tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables, + size_t count, int process_id, int speedo_id, + int speedo_value, unsigned long max_freq); #endif -- cgit v0.10.2 From f7c42d98621739d416cc4a739b721574fcbe910c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:16:28 +0200 Subject: clk: tegra: dfll: Properly clean up on failure and removal Upon failure to probe the DFLL, the OPP table will not be cleaned up properly. Fix this and while at it make sure the OPP table will also be cleared upon driver removal. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index d192982..ed2ad88 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -25,6 +25,7 @@ /** * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver * @dev: struct device * that holds the OPP table for the DFLL + * @max_freq: maximum frequency supported on this SoC * @cvb: CPU frequency table for this SoC * @init_clock_trimmers: callback to initialize clock trimmers * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage @@ -32,6 +33,7 @@ */ struct tegra_dfll_soc_data { struct device *dev; + unsigned long max_freq; const struct cvb_table *cvb; void (*init_clock_trimmers)(void); diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index c7ffd4f..d052d9f 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -84,7 +84,7 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) { - int process_id, speedo_id, speedo_value; + int process_id, speedo_id, speedo_value, err; struct tegra_dfll_soc_data *soc; process_id = tegra_sku_info.cpu_process_id; @@ -107,18 +107,41 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return -ENODEV; } + soc->max_freq = cpu_max_freq_table[speedo_id]; + soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables, ARRAY_SIZE(tegra124_cpu_cvb_tables), process_id, speedo_id, speedo_value, - cpu_max_freq_table[speedo_id]); + soc->max_freq); if (IS_ERR(soc->cvb)) { dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", PTR_ERR(soc->cvb)); return PTR_ERR(soc->cvb); } + err = tegra_dfll_register(pdev, soc); + if (err < 0) { + tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); + return err; + } + + platform_set_drvdata(pdev, soc); + + return 0; +} + +static int tegra124_dfll_fcpu_remove(struct platform_device *pdev) +{ + struct tegra_dfll_soc_data *soc = platform_get_drvdata(pdev); + int err; + + err = tegra_dfll_unregister(pdev); + if (err < 0) + dev_err(&pdev->dev, "failed to unregister DFLL: %d\n", err); + + tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); - return tegra_dfll_register(pdev, soc); + return 0; } static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { @@ -134,7 +157,7 @@ static const struct dev_pm_ops tegra124_dfll_pm_ops = { static struct platform_driver tegra124_dfll_fcpu_driver = { .probe = tegra124_dfll_fcpu_probe, - .remove = tegra_dfll_unregister, + .remove = tegra124_dfll_fcpu_remove, .driver = { .name = "tegra124-dfll", .of_match_table = tegra124_dfll_fcpu_of_match, diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c index 7a099b1..624115e 100644 --- a/drivers/clk/tegra/cvb.c +++ b/drivers/clk/tegra/cvb.c @@ -130,3 +130,19 @@ tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables, return ERR_PTR(-EINVAL); } + +void tegra_cvb_remove_opp_table(struct device *dev, + const struct cvb_table *table, + unsigned long max_freq) +{ + unsigned int i; + + for (i = 0; i < MAX_DVFS_FREQS; i++) { + const struct cvb_table_freq_entry *entry = &table->entries[i]; + + if (!entry->freq || (entry->freq > max_freq)) + break; + + dev_pm_opp_remove(dev, entry->freq); + } +} diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h index e6bf858..c1f0779 100644 --- a/drivers/clk/tegra/cvb.h +++ b/drivers/clk/tegra/cvb.h @@ -61,5 +61,8 @@ const struct cvb_table * tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables, size_t count, int process_id, int speedo_id, int speedo_value, unsigned long max_freq); +void tegra_cvb_remove_opp_table(struct device *dev, + const struct cvb_table *table, + unsigned long max_freq); #endif -- cgit v0.10.2 From 2690e912644e610854c4c3b23d0a0daec9d030ca Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:17:27 +0200 Subject: clk: tegra: dfll: Reformat CVB frequency table Increase the readability of the CVB frequency table by reformatting it a little. Signed-off-by: Thierry Reding diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index d052d9f..c205809 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -48,31 +48,31 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { .speedo_scale = 100, .voltage_scale = 1000, .entries = { - {204000000UL, {1112619, -29295, 402} }, - {306000000UL, {1150460, -30585, 402} }, - {408000000UL, {1190122, -31865, 402} }, - {510000000UL, {1231606, -33155, 402} }, - {612000000UL, {1274912, -34435, 402} }, - {714000000UL, {1320040, -35725, 402} }, - {816000000UL, {1366990, -37005, 402} }, - {918000000UL, {1415762, -38295, 402} }, - {1020000000UL, {1466355, -39575, 402} }, - {1122000000UL, {1518771, -40865, 402} }, - {1224000000UL, {1573009, -42145, 402} }, - {1326000000UL, {1629068, -43435, 402} }, - {1428000000UL, {1686950, -44715, 402} }, - {1530000000UL, {1746653, -46005, 402} }, - {1632000000UL, {1808179, -47285, 402} }, - {1734000000UL, {1871526, -48575, 402} }, - {1836000000UL, {1936696, -49855, 402} }, - {1938000000UL, {2003687, -51145, 402} }, - {2014500000UL, {2054787, -52095, 402} }, - {2116500000UL, {2124957, -53385, 402} }, - {2218500000UL, {2196950, -54665, 402} }, - {2320500000UL, {2270765, -55955, 402} }, - {2422500000UL, {2346401, -57235, 402} }, - {2524500000UL, {2437299, -58535, 402} }, - {0, { 0, 0, 0} }, + { 204000000UL, { 1112619, -29295, 402 } }, + { 306000000UL, { 1150460, -30585, 402 } }, + { 408000000UL, { 1190122, -31865, 402 } }, + { 510000000UL, { 1231606, -33155, 402 } }, + { 612000000UL, { 1274912, -34435, 402 } }, + { 714000000UL, { 1320040, -35725, 402 } }, + { 816000000UL, { 1366990, -37005, 402 } }, + { 918000000UL, { 1415762, -38295, 402 } }, + { 1020000000UL, { 1466355, -39575, 402 } }, + { 1122000000UL, { 1518771, -40865, 402 } }, + { 1224000000UL, { 1573009, -42145, 402 } }, + { 1326000000UL, { 1629068, -43435, 402 } }, + { 1428000000UL, { 1686950, -44715, 402 } }, + { 1530000000UL, { 1746653, -46005, 402 } }, + { 1632000000UL, { 1808179, -47285, 402 } }, + { 1734000000UL, { 1871526, -48575, 402 } }, + { 1836000000UL, { 1936696, -49855, 402 } }, + { 1938000000UL, { 2003687, -51145, 402 } }, + { 2014500000UL, { 2054787, -52095, 402 } }, + { 2116500000UL, { 2124957, -53385, 402 } }, + { 2218500000UL, { 2196950, -54665, 402 } }, + { 2320500000UL, { 2270765, -55955, 402 } }, + { 2422500000UL, { 2346401, -57235, 402 } }, + { 2524500000UL, { 2437299, -58535, 402 } }, + { 0UL, { 0, 0, 0 } }, }, .cpu_dfll_data = { .tune0_low = 0x005020ff, -- cgit v0.10.2 From c47265ad64fa793657ce7ecf1a8f636c794e9f40 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 1 May 2016 19:56:08 +0900 Subject: clk: fix comment of devm_clk_hw_register() Unlike devm_clk_register(), devm_clk_hw_register() returns integer. So, the statement "Clocks returned from this function ..." sounds odd. Adjust the comment for this new API. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ba1c3647..ce39add 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2719,7 +2719,7 @@ EXPORT_SYMBOL_GPL(devm_clk_register); * @dev: device that is registering this clock * @hw: link to hardware-specific clock data * - * Managed clk_hw_register(). Clocks returned from this function are + * Managed clk_hw_register(). Clocks registered by this function are * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register() * for more information. */ -- cgit v0.10.2 From 92a847e3609a8d00bcbe8bdfacbcbbca03135410 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 28 Apr 2016 14:07:03 -0700 Subject: clk: imx7d: fix ahb clock mux 1 The clock parent of the AHB root clock when using mux option 1 is the SYS PLL 270MHz clock. This is specified in Table 5-11 Clock Root Table of the i.MX 7Dual Applications Processor Reference Manual. While it could be a documentation error, the 270MHz parent is also mentioned in the boot ROM configuration in Table 6-28: The clock is by default at 135MHz due to a POST_PODF value of 1 (=> divider of 2). Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 7912be8..5229968 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -56,7 +56,7 @@ static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_sys_pfd2_135m_clk", "pll_sys_pfd6_clk", "pll_enet_250m_clk", "pll_audio_main_clk", }; -static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_135m_clk", +static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_main_clk", "pll_video_main_clk", }; -- cgit v0.10.2 From 923587aafc2c41ed516d39651d5750ea402cfc06 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 2 May 2016 10:39:05 +0100 Subject: clk/axs10x: Add I2S PLL clock driver The ARC SDP I2S clock can be programmed using a specific PLL. This patch has the goal of adding a clock driver that programs this PLL. At this moment the rate values are hardcoded in a table but in the future it would be ideal to use a function which determines the PLL values given the desired rate. Signed-off-by: Jose Abreu Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/axs10x-i2s-pll-clock.txt b/Documentation/devicetree/bindings/clock/axs10x-i2s-pll-clock.txt new file mode 100644 index 0000000..5ffc8df --- /dev/null +++ b/Documentation/devicetree/bindings/clock/axs10x-i2s-pll-clock.txt @@ -0,0 +1,25 @@ +Binding for the AXS10X I2S PLL clock + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: shall be "snps,axs10x-i2s-pll-clock" +- reg : address and length of the I2S PLL register set. +- clocks: shall be the input parent clock phandle for the PLL. +- #clock-cells: from common clock binding; Should always be set to 0. + +Example: + pll_clock: pll_clock { + compatible = "fixed-clock"; + clock-frequency = <27000000>; + #clock-cells = <0>; + }; + + i2s_clock@100a0 { + compatible = "snps,axs10x-i2s-pll-clock"; + reg = <0x100a0 0x10>; + clocks = <&pll_clock>; + #clock-cells = <0>; + }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 4ef71a1..6d1e3be 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -86,3 +86,4 @@ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_ARCH_ZX) += zte/ obj-$(CONFIG_ARCH_ZYNQ) += zynq/ obj-$(CONFIG_H8300) += h8300/ +obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile new file mode 100644 index 0000000..01996b8 --- /dev/null +++ b/drivers/clk/axs10x/Makefile @@ -0,0 +1 @@ +obj-y += i2s_pll_clock.o diff --git a/drivers/clk/axs10x/i2s_pll_clock.c b/drivers/clk/axs10x/i2s_pll_clock.c new file mode 100644 index 0000000..411310d --- /dev/null +++ b/drivers/clk/axs10x/i2s_pll_clock.c @@ -0,0 +1,228 @@ +/* + * Synopsys AXS10X SDP I2S PLL clock driver + * + * Copyright (C) 2016 Synopsys + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* PLL registers addresses */ +#define PLL_IDIV_REG 0x0 +#define PLL_FBDIV_REG 0x4 +#define PLL_ODIV0_REG 0x8 +#define PLL_ODIV1_REG 0xC + +struct i2s_pll_cfg { + unsigned int rate; + unsigned int idiv; + unsigned int fbdiv; + unsigned int odiv0; + unsigned int odiv1; +}; + +static const struct i2s_pll_cfg i2s_pll_cfg_27m[] = { + /* 27 Mhz */ + { 1024000, 0x104, 0x451, 0x10E38, 0x2000 }, + { 1411200, 0x104, 0x596, 0x10D35, 0x2000 }, + { 1536000, 0x208, 0xA28, 0x10B2C, 0x2000 }, + { 2048000, 0x82, 0x451, 0x10E38, 0x2000 }, + { 2822400, 0x82, 0x596, 0x10D35, 0x2000 }, + { 3072000, 0x104, 0xA28, 0x10B2C, 0x2000 }, + { 2116800, 0x82, 0x3CF, 0x10C30, 0x2000 }, + { 2304000, 0x104, 0x79E, 0x10B2C, 0x2000 }, + { 0, 0, 0, 0, 0 }, +}; + +static const struct i2s_pll_cfg i2s_pll_cfg_28m[] = { + /* 28.224 Mhz */ + { 1024000, 0x82, 0x105, 0x107DF, 0x2000 }, + { 1411200, 0x28A, 0x1, 0x10001, 0x2000 }, + { 1536000, 0xA28, 0x187, 0x10042, 0x2000 }, + { 2048000, 0x41, 0x105, 0x107DF, 0x2000 }, + { 2822400, 0x145, 0x1, 0x10001, 0x2000 }, + { 3072000, 0x514, 0x187, 0x10042, 0x2000 }, + { 2116800, 0x514, 0x42, 0x10001, 0x2000 }, + { 2304000, 0x619, 0x82, 0x10001, 0x2000 }, + { 0, 0, 0, 0, 0 }, +}; + +struct i2s_pll_clk { + void __iomem *base; + struct clk_hw hw; + struct device *dev; +}; + +static inline void i2s_pll_write(struct i2s_pll_clk *clk, unsigned int reg, + unsigned int val) +{ + writel_relaxed(val, clk->base + reg); +} + +static inline unsigned int i2s_pll_read(struct i2s_pll_clk *clk, + unsigned int reg) +{ + return readl_relaxed(clk->base + reg); +} + +static inline struct i2s_pll_clk *to_i2s_pll_clk(struct clk_hw *hw) +{ + return container_of(hw, struct i2s_pll_clk, hw); +} + +static inline unsigned int i2s_pll_get_value(unsigned int val) +{ + return (val & 0x3F) + ((val >> 6) & 0x3F); +} + +static const struct i2s_pll_cfg *i2s_pll_get_cfg(unsigned long prate) +{ + switch (prate) { + case 27000000: + return i2s_pll_cfg_27m; + case 28224000: + return i2s_pll_cfg_28m; + default: + return NULL; + } +} + +static unsigned long i2s_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct i2s_pll_clk *clk = to_i2s_pll_clk(hw); + unsigned int idiv, fbdiv, odiv; + + idiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_IDIV_REG)); + fbdiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_FBDIV_REG)); + odiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_ODIV0_REG)); + + return ((parent_rate / idiv) * fbdiv) / odiv; +} + +static long i2s_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct i2s_pll_clk *clk = to_i2s_pll_clk(hw); + const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(*prate); + int i; + + if (!pll_cfg) { + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate); + return -EINVAL; + } + + for (i = 0; pll_cfg[i].rate != 0; i++) + if (pll_cfg[i].rate == rate) + return rate; + + return -EINVAL; +} + +static int i2s_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct i2s_pll_clk *clk = to_i2s_pll_clk(hw); + const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(parent_rate); + int i; + + if (!pll_cfg) { + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate); + return -EINVAL; + } + + for (i = 0; pll_cfg[i].rate != 0; i++) { + if (pll_cfg[i].rate == rate) { + i2s_pll_write(clk, PLL_IDIV_REG, pll_cfg[i].idiv); + i2s_pll_write(clk, PLL_FBDIV_REG, pll_cfg[i].fbdiv); + i2s_pll_write(clk, PLL_ODIV0_REG, pll_cfg[i].odiv0); + i2s_pll_write(clk, PLL_ODIV1_REG, pll_cfg[i].odiv1); + return 0; + } + } + + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate, + parent_rate); + return -EINVAL; +} + +static const struct clk_ops i2s_pll_ops = { + .recalc_rate = i2s_pll_recalc_rate, + .round_rate = i2s_pll_round_rate, + .set_rate = i2s_pll_set_rate, +}; + +static int i2s_pll_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + const char *clk_name; + const char *parent_name; + struct clk *clk; + struct i2s_pll_clk *pll_clk; + struct clk_init_data init; + struct resource *mem; + + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pll_clk->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(pll_clk->base)) + return PTR_ERR(pll_clk->base); + + clk_name = node->name; + init.name = clk_name; + init.ops = &i2s_pll_ops; + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + pll_clk->hw.init = &init; + pll_clk->dev = dev; + + clk = devm_clk_register(dev, &pll_clk->hw); + if (IS_ERR(clk)) { + dev_err(dev, "failed to register %s clock (%ld)\n", + clk_name, PTR_ERR(clk)); + return PTR_ERR(clk); + } + + return of_clk_add_provider(node, of_clk_src_simple_get, clk); +} + +static int i2s_pll_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static const struct of_device_id i2s_pll_clk_id[] = { + { .compatible = "snps,axs10x-i2s-pll-clock", }, + { }, +}; +MODULE_DEVICE_TABLE(of, i2s_pll_clk_id); + +static struct platform_driver i2s_pll_clk_driver = { + .driver = { + .name = "axs10x-i2s-pll-clock", + .of_match_table = i2s_pll_clk_id, + }, + .probe = i2s_pll_clk_probe, + .remove = i2s_pll_clk_remove, +}; +module_platform_driver(i2s_pll_clk_driver); + +MODULE_AUTHOR("Jose Abreu "); +MODULE_DESCRIPTION("Synopsys AXS10X SDP I2S PLL Clock Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From a444723569b48bc49e3175930eb9777582f48f44 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 6 May 2016 10:55:11 -0700 Subject: clk: nxp: lpc18xx: Initialize clk_init_data::flags to 0 Failure to initialize this flag to 0 by default can result in stack junk filling the clk_init_data structure and weird things happen. Joachim noticed that the critical clk feature started triggering for these clks causing boot failures, when it really shouldn't have happened: BUG: scheduling while atomic: swapper/0/0x00000002 CPU: 0 PID: 0 Comm: swapper Not tainted 4.6.0-rc6-next-20160505-00001-g5c8320450d1c #826 Hardware name: NXP LPC18xx/43xx (Device Tree) [<2800be81>] (unwind_backtrace) from [<2800b22f>] (show_stack+0xb/0xc) [<2800b22f>] (show_stack) from [<2801ea21>] (__schedule_bug+0x2d/0x44) [<2801ea21>] (__schedule_bug) from [<281dc937>] (__schedule+0x3b/0x268) [<281dc937>] (__schedule) from [<281dcbbb>] (schedule+0x57/0x64) [<281dcbbb>] (schedule) from [<281de8ef>] (schedule_timeout+0xfb/0x120) [<281de8ef>] (schedule_timeout) from [<28030fcd>] (msleep+0xf/0x12) [<28030fcd>] (msleep) from [<28165a6d>] (clk_creg_32k_prepare+0x1f/0x24) [<28165a6d>] (clk_creg_32k_prepare) from [<281620d5>] (clk_core_prepare+0x1d/0x36) [<281620d5>] (clk_core_prepare) from [<2816340b>] (clk_register+0x22f/0x318) [<2816340b>] (clk_register) from [<282b06c9>] (lpc18xx_creg_clk_init+0x55/0x84) [<282b06c9>] (lpc18xx_creg_clk_init) from [<282b0149>] (of_clk_init+0xc1/0x12c) [<282b0149>] (of_clk_init) from [<282a665d>] (time_init+0x15/0x20) [<282a665d>] (time_init) from [<282a457d>] (start_kernel+0x169/0x274) [<282a457d>] (start_kernel) from [<28008025>] (0x28008025) bad: scheduling from the idle thread! CPU: 0 PID: 0 Comm: swapper Tainted: G W 4.6.0-rc6-next-20160505-00001-g5c8320450d1c #826 Fix this by initializing the flags member to 0. Acked-by: Joachim Eastwood Signed-off-by: Stephen Boyd diff --git a/drivers/clk/nxp/clk-lpc18xx-creg.c b/drivers/clk/nxp/clk-lpc18xx-creg.c index d44b61a..9e35749 100644 --- a/drivers/clk/nxp/clk-lpc18xx-creg.c +++ b/drivers/clk/nxp/clk-lpc18xx-creg.c @@ -147,6 +147,7 @@ static struct clk *clk_register_creg_clk(struct device *dev, init.name = creg_clk->name; init.parent_names = parent_name; init.num_parents = 1; + init.flags = 0; creg_clk->reg = syscon; creg_clk->hw.init = &init; -- cgit v0.10.2 From 2a0974aa1a0b40a92387ea03dbfeacfbc9ba182c Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Tue, 3 May 2016 15:24:11 -0500 Subject: clk: qcom: msm8916: Fix crypto clock flags This patch adds the CLK_SET_RATE_PARENT flag for the crypto core and ahb blocks. Without this flag, clk_set_rate can fail for certain frequency requests. Signed-off-by: Andy Gross Fixes: 3966fab8b6ab ("clk: qcom: Add MSM8916 Global Clock Controller support") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index 9c29080..5c4e193 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -2346,6 +2346,7 @@ static struct clk_branch gcc_crypto_ahb_clk = { "pcnoc_bfdcd_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2381,6 +2382,7 @@ static struct clk_branch gcc_crypto_clk = { "crypto_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, -- cgit v0.10.2 From 4087a5f2e5e75a6d0231d1318bada1a12972a5fd Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 28 Apr 2016 19:20:33 +0530 Subject: clk: bcm/kona: Do not use sizeof on pointer type When sizeof is applied to a pointer typed expression, it gives the size of the pointer. So, here do not use sizeof on pointer type. Also, silent checkpatch.pl by using kmalloc_array over kmalloc. Note that this has no effect on runtime because 'parent_names' is a pointer to a pointer. Problem found using Coccinelle. Signed-off-by: Vaishali Thakkar Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index deaa7f9..526b0b0 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -577,7 +577,8 @@ static u32 *parent_process(const char *clocks[], * selector is not required, but we allocate space for the * array anyway to keep things simple. */ - parent_names = kmalloc(parent_count * sizeof(parent_names), GFP_KERNEL); + parent_names = kmalloc_array(parent_count, sizeof(*parent_names), + GFP_KERNEL); if (!parent_names) { pr_err("%s: error allocating %u parent names\n", __func__, parent_count); -- cgit v0.10.2 From 25824d52caa8e614b695a7197a8edde19f5b02ad Mon Sep 17 00:00:00 2001 From: Jiancheng Xue Date: Sat, 23 Apr 2016 15:40:28 +0800 Subject: reset: hisilicon: add reset controller driver for hisilicon SOCs In most of hisilicon SOCs, reset controller and clock provider are combined together as a block named CRG (Clock and Reset Generator). This patch mainly implements the reset function. Signed-off-by: Jiancheng Xue Acked-by: Philipp Zabel Signed-off-by: Stephen Boyd diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index e434854..3cd349c 100644 --- a/drivers/clk/hisilicon/Kconfig +++ b/drivers/clk/hisilicon/Kconfig @@ -5,6 +5,13 @@ config COMMON_CLK_HI6220 help Build the Hisilicon Hi6220 clock driver based on the common clock framework. +config RESET_HISI + bool "HiSilicon Reset Controller Driver" + depends on ARCH_HISI || COMPILE_TEST + select RESET_CONTROLLER + help + Build reset controller driver for HiSilicon device chipsets. + config STUB_CLK_HI6220 bool "Hi6220 Stub Clock Driver" depends on COMMON_CLK_HI6220 && MAILBOX diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index 74dba31..c037753 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o +obj-$(CONFIG_RESET_HISI) += reset.o obj-$(CONFIG_STUB_CLK_HI6220) += clk-hi6220-stub.o diff --git a/drivers/clk/hisilicon/reset.c b/drivers/clk/hisilicon/reset.c new file mode 100644 index 0000000..6aa49c2 --- /dev/null +++ b/drivers/clk/hisilicon/reset.c @@ -0,0 +1,134 @@ +/* + * Hisilicon Reset Controller Driver + * + * Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include "reset.h" + +#define HISI_RESET_BIT_MASK 0x1f +#define HISI_RESET_OFFSET_SHIFT 8 +#define HISI_RESET_OFFSET_MASK 0xffff00 + +struct hisi_reset_controller { + spinlock_t lock; + void __iomem *membase; + struct reset_controller_dev rcdev; +}; + + +#define to_hisi_reset_controller(rcdev) \ + container_of(rcdev, struct hisi_reset_controller, rcdev) + +static int hisi_reset_of_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + u32 offset; + u8 bit; + + offset = (reset_spec->args[0] << HISI_RESET_OFFSET_SHIFT) + & HISI_RESET_OFFSET_MASK; + bit = reset_spec->args[1] & HISI_RESET_BIT_MASK; + + return (offset | bit); +} + +static int hisi_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev); + unsigned long flags; + u32 offset, reg; + u8 bit; + + offset = (id & HISI_RESET_OFFSET_MASK) >> HISI_RESET_OFFSET_SHIFT; + bit = id & HISI_RESET_BIT_MASK; + + spin_lock_irqsave(&rstc->lock, flags); + + reg = readl(rstc->membase + offset); + writel(reg | BIT(bit), rstc->membase + offset); + + spin_unlock_irqrestore(&rstc->lock, flags); + + return 0; +} + +static int hisi_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev); + unsigned long flags; + u32 offset, reg; + u8 bit; + + offset = (id & HISI_RESET_OFFSET_MASK) >> HISI_RESET_OFFSET_SHIFT; + bit = id & HISI_RESET_BIT_MASK; + + spin_lock_irqsave(&rstc->lock, flags); + + reg = readl(rstc->membase + offset); + writel(reg & ~BIT(bit), rstc->membase + offset); + + spin_unlock_irqrestore(&rstc->lock, flags); + + return 0; +} + +static const struct reset_control_ops hisi_reset_ops = { + .assert = hisi_reset_assert, + .deassert = hisi_reset_deassert, +}; + +struct hisi_reset_controller *hisi_reset_init(struct device_node *np) +{ + struct hisi_reset_controller *rstc; + + rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); + if (!rstc) + return NULL; + + rstc->membase = of_iomap(np, 0); + if (!rstc->membase) { + kfree(rstc); + return NULL; + } + + spin_lock_init(&rstc->lock); + + rstc->rcdev.owner = THIS_MODULE; + rstc->rcdev.ops = &hisi_reset_ops; + rstc->rcdev.of_node = np; + rstc->rcdev.of_reset_n_cells = 2; + rstc->rcdev.of_xlate = hisi_reset_of_xlate; + reset_controller_register(&rstc->rcdev); + + return rstc; +} +EXPORT_SYMBOL_GPL(hisi_reset_init); + +void hisi_reset_exit(struct hisi_reset_controller *rstc) +{ + reset_controller_unregister(&rstc->rcdev); + iounmap(rstc->membase); + kfree(rstc); +} +EXPORT_SYMBOL_GPL(hisi_reset_exit); diff --git a/drivers/clk/hisilicon/reset.h b/drivers/clk/hisilicon/reset.h new file mode 100644 index 0000000..677d773 --- /dev/null +++ b/drivers/clk/hisilicon/reset.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __HISI_RESET_H +#define __HISI_RESET_H + +struct device_node; +struct hisi_reset_controller; + +#ifdef CONFIG_RESET_CONTROLLER +struct hisi_reset_controller *hisi_reset_init(struct device_node *np); +void hisi_reset_exit(struct hisi_reset_controller *rstc); +#else +static inline hisi_reset_controller *hisi_reset_init(struct device_node *np) +{ + return 0; +} +static inline void hisi_reset_exit(struct hisi_reset_controller *rstc) +{} +#endif + +#endif /* __HISI_RESET_H */ -- cgit v0.10.2 From f6ff57c8abde68c0bb8e0d4539f4204fc5ba45ae Mon Sep 17 00:00:00 2001 From: Jiancheng Xue Date: Sat, 23 Apr 2016 15:40:29 +0800 Subject: clk: hisilicon: export some hisilicon APIs to modules Change some arguments to constant type. Export some hisilicon APIs to modules. Signed-off-by: Jiancheng Xue Signed-off-by: Stephen Boyd diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index 9f8e766..9b15adb 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -37,7 +37,7 @@ static DEFINE_SPINLOCK(hisi_clk_lock); -struct hisi_clock_data __init *hisi_clk_init(struct device_node *np, +struct hisi_clock_data *hisi_clk_init(struct device_node *np, int nr_clks) { struct hisi_clock_data *clk_data; @@ -71,8 +71,9 @@ err_data: err: return NULL; } +EXPORT_SYMBOL_GPL(hisi_clk_init); -void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, +void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -91,8 +92,9 @@ void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, data->clk_data.clks[clks[i].id] = clk; } } +EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate); -void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, +void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, int nums, struct hisi_clock_data *data) { @@ -112,8 +114,9 @@ void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, data->clk_data.clks[clks[i].id] = clk; } } +EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor); -void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, +void hisi_clk_register_mux(const struct hisi_mux_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -141,8 +144,9 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, data->clk_data.clks[clks[i].id] = clk; } } +EXPORT_SYMBOL_GPL(hisi_clk_register_mux); -void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, +void hisi_clk_register_divider(const struct hisi_divider_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -170,8 +174,9 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, data->clk_data.clks[clks[i].id] = clk; } } +EXPORT_SYMBOL_GPL(hisi_clk_register_divider); -void __init hisi_clk_register_gate(struct hisi_gate_clock *clks, +void hisi_clk_register_gate(const struct hisi_gate_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -198,8 +203,9 @@ void __init hisi_clk_register_gate(struct hisi_gate_clock *clks, data->clk_data.clks[clks[i].id] = clk; } } +EXPORT_SYMBOL_GPL(hisi_clk_register_gate); -void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, +void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -226,8 +232,9 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, data->clk_data.clks[clks[i].id] = clk; } } +EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep); -void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks, +void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h index b56fbc1..20d64af 100644 --- a/drivers/clk/hisilicon/clk.h +++ b/drivers/clk/hisilicon/clk.h @@ -111,18 +111,18 @@ struct clk *hi6220_register_clkdiv(struct device *dev, const char *name, u8 shift, u8 width, u32 mask_bit, spinlock_t *lock); struct hisi_clock_data *hisi_clk_init(struct device_node *, int); -void hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *, +void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *, +void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_mux(struct hisi_mux_clock *, int, +void hisi_clk_register_mux(const struct hisi_mux_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_divider(struct hisi_divider_clock *, +void hisi_clk_register_divider(const struct hisi_divider_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_gate(struct hisi_gate_clock *, +void hisi_clk_register_gate(const struct hisi_gate_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_gate_sep(struct hisi_gate_clock *, +void hisi_clk_register_gate_sep(const struct hisi_gate_clock *, int, struct hisi_clock_data *); -void hi6220_clk_register_divider(struct hi6220_divider_clock *, +void hi6220_clk_register_divider(const struct hi6220_divider_clock *, int, struct hisi_clock_data *); #endif /* __HISI_CLK_H */ -- cgit v0.10.2 From 6c9da387c8d5c5254857d2782bd6c314226f4f27 Mon Sep 17 00:00:00 2001 From: Jiancheng Xue Date: Sat, 23 Apr 2016 15:40:30 +0800 Subject: clk: hisilicon: add CRG driver for hi3519 soc The CRG(Clock and Reset Generator) block provides clock and reset signals for other modules in hi3519 soc. Signed-off-by: Jiancheng Xue Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/hi3519-crg.txt b/Documentation/devicetree/bindings/clock/hi3519-crg.txt new file mode 100644 index 0000000..acd1f23 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/hi3519-crg.txt @@ -0,0 +1,46 @@ +* Hisilicon Hi3519 Clock and Reset Generator(CRG) + +The Hi3519 CRG module provides clock and reset signals to various +controllers within the SoC. + +This binding uses the following bindings: + Documentation/devicetree/bindings/clock/clock-bindings.txt + Documentation/devicetree/bindings/reset/reset.txt + +Required Properties: + +- compatible: should be one of the following. + - "hisilicon,hi3519-crg" - controller compatible with Hi3519 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . + +- #reset-cells: should be 2. + +A reset signal can be controlled by writing a bit register in the CRG module. +The reset specifier consists of two cells. The first cell represents the +register offset relative to the base address. The second cell represents the +bit index in the register. + +Example: CRG nodes +CRG: clock-reset-controller@12010000 { + compatible = "hisilicon,hi3519-crg"; + reg = <0x12010000 0x10000>; + #clock-cells = <1>; + #reset-cells = <2>; +}; + +Example: consumer nodes +i2c0: i2c@12110000 { + compatible = "hisilicon,hi3519-i2c"; + reg = <0x12110000 0x1000>; + clocks = <&CRG HI3519_I2C0_RST>; + resets = <&CRG 0xe4 0>; +}; diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index 3cd349c..3f537a0 100644 --- a/drivers/clk/hisilicon/Kconfig +++ b/drivers/clk/hisilicon/Kconfig @@ -1,3 +1,11 @@ +config COMMON_CLK_HI3519 + tristate "Hi3519 Clock Driver" + depends on ARCH_HISI || COMPILE_TEST + select RESET_HISI + default ARCH_HISI + help + Build the clock driver for hi3519. + config COMMON_CLK_HI6220 bool "Hi6220 Clock Driver" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index c037753..e169ec7 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -7,6 +7,7 @@ obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o +obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o obj-$(CONFIG_RESET_HISI) += reset.o obj-$(CONFIG_STUB_CLK_HI6220) += clk-hi6220-stub.o diff --git a/drivers/clk/hisilicon/clk-hi3519.c b/drivers/clk/hisilicon/clk-hi3519.c new file mode 100644 index 0000000..715c730 --- /dev/null +++ b/drivers/clk/hisilicon/clk-hi3519.c @@ -0,0 +1,131 @@ +/* + * Hi3519 Clock Driver + * + * Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include "clk.h" +#include "reset.h" + +#define HI3519_INNER_CLK_OFFSET 64 +#define HI3519_FIXED_24M 65 +#define HI3519_FIXED_50M 66 +#define HI3519_FIXED_75M 67 +#define HI3519_FIXED_125M 68 +#define HI3519_FIXED_150M 69 +#define HI3519_FIXED_200M 70 +#define HI3519_FIXED_250M 71 +#define HI3519_FIXED_300M 72 +#define HI3519_FIXED_400M 73 +#define HI3519_FMC_MUX 74 + +#define HI3519_NR_CLKS 128 + +static const struct hisi_fixed_rate_clock hi3519_fixed_rate_clks[] = { + { HI3519_FIXED_24M, "24m", NULL, 0, 24000000, }, + { HI3519_FIXED_50M, "50m", NULL, 0, 50000000, }, + { HI3519_FIXED_75M, "75m", NULL, 0, 75000000, }, + { HI3519_FIXED_125M, "125m", NULL, 0, 125000000, }, + { HI3519_FIXED_150M, "150m", NULL, 0, 150000000, }, + { HI3519_FIXED_200M, "200m", NULL, 0, 200000000, }, + { HI3519_FIXED_250M, "250m", NULL, 0, 250000000, }, + { HI3519_FIXED_300M, "300m", NULL, 0, 300000000, }, + { HI3519_FIXED_400M, "400m", NULL, 0, 400000000, }, +}; + +static const char *const fmc_mux_p[] = { + "24m", "75m", "125m", "150m", "200m", "250m", "300m", "400m", }; +static u32 fmc_mux_table[] = {0, 1, 2, 3, 4, 5, 6, 7}; + +static const struct hisi_mux_clock hi3519_mux_clks[] = { + { HI3519_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p), + CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, }, +}; + +static const struct hisi_gate_clock hi3519_gate_clks[] = { + { HI3519_FMC_CLK, "clk_fmc", "fmc_mux", + CLK_SET_RATE_PARENT, 0xc0, 1, 0, }, + { HI3519_UART0_CLK, "clk_uart0", "24m", + CLK_SET_RATE_PARENT, 0xe4, 20, 0, }, + { HI3519_UART1_CLK, "clk_uart1", "24m", + CLK_SET_RATE_PARENT, 0xe4, 21, 0, }, + { HI3519_UART2_CLK, "clk_uart2", "24m", + CLK_SET_RATE_PARENT, 0xe4, 22, 0, }, + { HI3519_UART3_CLK, "clk_uart3", "24m", + CLK_SET_RATE_PARENT, 0xe4, 23, 0, }, + { HI3519_UART4_CLK, "clk_uart4", "24m", + CLK_SET_RATE_PARENT, 0xe4, 24, 0, }, + { HI3519_SPI0_CLK, "clk_spi0", "50m", + CLK_SET_RATE_PARENT, 0xe4, 16, 0, }, + { HI3519_SPI1_CLK, "clk_spi1", "50m", + CLK_SET_RATE_PARENT, 0xe4, 17, 0, }, + { HI3519_SPI2_CLK, "clk_spi2", "50m", + CLK_SET_RATE_PARENT, 0xe4, 18, 0, }, +}; + +static int hi3519_clk_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct hisi_clock_data *clk_data; + struct hisi_reset_controller *rstc; + + rstc = hisi_reset_init(np); + if (!rstc) + return -ENOMEM; + + clk_data = hisi_clk_init(np, HI3519_NR_CLKS); + if (!clk_data) { + hisi_reset_exit(rstc); + return -ENODEV; + } + + hisi_clk_register_fixed_rate(hi3519_fixed_rate_clks, + ARRAY_SIZE(hi3519_fixed_rate_clks), + clk_data); + hisi_clk_register_mux(hi3519_mux_clks, ARRAY_SIZE(hi3519_mux_clks), + clk_data); + hisi_clk_register_gate(hi3519_gate_clks, + ARRAY_SIZE(hi3519_gate_clks), clk_data); + + return 0; +} + +static const struct of_device_id hi3519_clk_match_table[] = { + { .compatible = "hisilicon,hi3519-crg" }, + { } +}; +MODULE_DEVICE_TABLE(of, hi3519_clk_match_table); + +static struct platform_driver hi3519_clk_driver = { + .probe = hi3519_clk_probe, + .driver = { + .name = "hi3519-clk", + .of_match_table = hi3519_clk_match_table, + }, +}; + +static int __init hi3519_clk_init(void) +{ + return platform_driver_register(&hi3519_clk_driver); +} +core_initcall(hi3519_clk_init); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon Hi3519 Clock Driver"); diff --git a/include/dt-bindings/clock/hi3519-clock.h b/include/dt-bindings/clock/hi3519-clock.h new file mode 100644 index 0000000..14f4d21 --- /dev/null +++ b/include/dt-bindings/clock/hi3519-clock.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __DTS_HI3519_CLOCK_H +#define __DTS_HI3519_CLOCK_H + +#define HI3519_FMC_CLK 1 +#define HI3519_SPI0_CLK 2 +#define HI3519_SPI1_CLK 3 +#define HI3519_SPI2_CLK 4 +#define HI3519_UART0_CLK 5 +#define HI3519_UART1_CLK 6 +#define HI3519_UART2_CLK 7 +#define HI3519_UART3_CLK 8 +#define HI3519_UART4_CLK 9 +#define HI3519_PWM_CLK 10 +#define HI3519_DMA_CLK 11 +#define HI3519_IR_CLK 12 +#define HI3519_ETH_PHY_CLK 13 +#define HI3519_ETH_MAC_CLK 14 +#define HI3519_ETH_MACIF_CLK 15 +#define HI3519_USB2_BUS_CLK 16 +#define HI3519_USB2_PORT_CLK 17 +#define HI3519_USB3_CLK 18 + +#endif /* __DTS_HI3519_CLOCK_H */ -- cgit v0.10.2 From 89a426b1966588eb215ec08530054016ee10b0cc Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 14 Apr 2016 17:33:31 +0200 Subject: clk: mvebu: new driver for Armada AP806 system controller The Armada AP806 system controller, amongst other things, provides a number of clocks for the platform: the CPU cluster clocks, whose frequencies are found by reading the Sample At Reset register, one fixed clock, and another clock derived from the fixed clock, which is the one used by most peripherals in AP806. The AP806 is one of the two core HW blocks used in the Marvell 7K/8K SoCs. Signed-off-by: Thomas Petazzoni [sboyd@codeaurora.org: Silence some checkpatch noise] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index eaee8f0..bf7ae00 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -29,6 +29,9 @@ config ARMADA_XP_CLK select MVEBU_CLK_COMMON select MVEBU_CLK_CPU +config ARMADA_AP806_SYSCON + bool + config DOVE_CLK bool select MVEBU_CLK_COMMON diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 8866115..f4aa481 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o +obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o obj-$(CONFIG_DOVE_CLK) += dove.o dove-divider.o obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o obj-$(CONFIG_ORION_CLK) += orion.o diff --git a/drivers/clk/mvebu/ap806-system-controller.c b/drivers/clk/mvebu/ap806-system-controller.c new file mode 100644 index 0000000..02023ba --- /dev/null +++ b/drivers/clk/mvebu/ap806-system-controller.c @@ -0,0 +1,168 @@ +/* + * Marvell Armada AP806 System Controller + * + * Copyright (C) 2016 Marvell + * + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) "ap806-system-controller: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define AP806_SAR_REG 0x400 +#define AP806_SAR_CLKFREQ_MODE_MASK 0x1f + +#define AP806_CLK_NUM 4 + +static struct clk *ap806_clks[AP806_CLK_NUM]; + +static struct clk_onecell_data ap806_clk_data = { + .clks = ap806_clks, + .clk_num = AP806_CLK_NUM, +}; + +static int ap806_syscon_clk_probe(struct platform_device *pdev) +{ + unsigned int freq_mode, cpuclk_freq; + const char *name, *fixedclk_name; + struct device_node *np = pdev->dev.of_node; + struct regmap *regmap; + u32 reg; + int ret; + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "cannot get regmap\n"); + return PTR_ERR(regmap); + } + + ret = regmap_read(regmap, AP806_SAR_REG, ®); + if (ret) { + dev_err(&pdev->dev, "cannot read from regmap\n"); + return ret; + } + + freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK; + switch (freq_mode) { + case 0x0 ... 0x5: + cpuclk_freq = 2000; + break; + case 0x6 ... 0xB: + cpuclk_freq = 1800; + break; + case 0xC ... 0x11: + cpuclk_freq = 1600; + break; + case 0x12 ... 0x16: + cpuclk_freq = 1400; + break; + case 0x17 ... 0x19: + cpuclk_freq = 1300; + break; + default: + dev_err(&pdev->dev, "invalid SAR value\n"); + return -EINVAL; + } + + /* Convert to hertz */ + cpuclk_freq *= 1000 * 1000; + + /* CPU clocks depend on the Sample At Reset configuration */ + of_property_read_string_index(np, "clock-output-names", + 0, &name); + ap806_clks[0] = clk_register_fixed_rate(&pdev->dev, name, NULL, + 0, cpuclk_freq); + if (IS_ERR(ap806_clks[0])) { + ret = PTR_ERR(ap806_clks[0]); + goto fail0; + } + + of_property_read_string_index(np, "clock-output-names", + 1, &name); + ap806_clks[1] = clk_register_fixed_rate(&pdev->dev, name, NULL, 0, + cpuclk_freq); + if (IS_ERR(ap806_clks[1])) { + ret = PTR_ERR(ap806_clks[1]); + goto fail1; + } + + /* Fixed clock is always 1200 Mhz */ + of_property_read_string_index(np, "clock-output-names", + 2, &fixedclk_name); + ap806_clks[2] = clk_register_fixed_rate(&pdev->dev, fixedclk_name, NULL, + 0, 1200 * 1000 * 1000); + if (IS_ERR(ap806_clks[2])) { + ret = PTR_ERR(ap806_clks[2]); + goto fail2; + } + + /* MSS Clock is fixed clock divided by 6 */ + of_property_read_string_index(np, "clock-output-names", + 3, &name); + ap806_clks[3] = clk_register_fixed_factor(NULL, name, fixedclk_name, + 0, 1, 6); + if (IS_ERR(ap806_clks[3])) { + ret = PTR_ERR(ap806_clks[3]); + goto fail3; + } + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data); + if (ret) + goto fail_clk_add; + + return 0; + +fail_clk_add: + clk_unregister_fixed_factor(ap806_clks[3]); +fail3: + clk_unregister_fixed_rate(ap806_clks[2]); +fail2: + clk_unregister_fixed_rate(ap806_clks[1]); +fail1: + clk_unregister_fixed_rate(ap806_clks[0]); +fail0: + return ret; +} + +static int ap806_syscon_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + clk_unregister_fixed_factor(ap806_clks[3]); + clk_unregister_fixed_rate(ap806_clks[2]); + clk_unregister_fixed_rate(ap806_clks[1]); + clk_unregister_fixed_rate(ap806_clks[0]); + + return 0; +} + +static const struct of_device_id ap806_syscon_of_match[] = { + { .compatible = "marvell,ap806-system-controller", }, + { } +}; +MODULE_DEVICE_TABLE(of, armada8k_pcie_of_match); + +static struct platform_driver ap806_syscon_driver = { + .probe = ap806_syscon_clk_probe, + .remove = ap806_syscon_clk_remove, + .driver = { + .name = "marvell-ap806-system-controller", + .of_match_table = ap806_syscon_of_match, + }, +}; + +module_platform_driver(ap806_syscon_driver); + +MODULE_DESCRIPTION("Marvell AP806 System Controller driver"); +MODULE_AUTHOR("Thomas Petazzoni "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 6e660e5cd0709f0f8f1e2cf375d204db645b1a51 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 14 Apr 2016 17:33:32 +0200 Subject: dt-bindings: arm: add DT binding for Marvell CP110 system controller This commit adds the DT binding documentation for the Marvell CP110 system controller, which is part of the CP110 HW block, itself used in the Marvell Armada 7K and 8K SoCs. Signed-off-by: Thomas Petazzoni Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller0.txt b/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller0.txt new file mode 100644 index 0000000..30c5469 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller0.txt @@ -0,0 +1,83 @@ +Marvell Armada CP110 System Controller 0 +======================================== + +The CP110 is one of the two core HW blocks of the Marvell Armada 7K/8K +SoCs. It contains two sets of system control registers, System +Controller 0 and System Controller 1. This Device Tree binding allows +to describe the first system controller, which provides registers to +configure various aspects of the SoC. + +The Device Tree node representing this System Controller 0 provides a +number of clocks: + + - a set of core clocks + - a set of gatable clocks + +Those clocks can be referenced by other Device Tree nodes using two +cells: + - The first cell must be 0 or 1. 0 for the core clocks and 1 for the + gatable clocks. + - The second cell identifies the particular core clock or gatable + clocks. + +The following clocks are available: + - Core clocks + - 0 0 APLL + - 0 1 PPv2 core + - 0 2 EIP + - 0 3 Core + - 0 4 NAND core + - Gatable clocks + - 1 0 Audio + - 1 1 Comm Unit + - 1 2 NAND + - 1 3 PPv2 + - 1 4 SDIO + - 1 5 MG Domain + - 1 6 MG Core + - 1 7 XOR1 + - 1 8 XOR0 + - 1 9 GOP DP + - 1 11 PCIe x1 0 + - 1 12 PCIe x1 1 + - 1 13 PCIe x4 + - 1 14 PCIe / XOR + - 1 15 SATA + - 1 16 SATA USB + - 1 17 Main + - 1 18 SD/MMC + - 1 21 Slow IO (SPI, NOR, BootROM, I2C, UART) + - 1 22 USB3H0 + - 1 23 USB3H1 + - 1 24 USB3 Device + - 1 25 EIP150 + - 1 26 EIP197 + +Required properties: + + - compatible: must be: + "marvell,cp110-system-controller0", "syscon"; + - reg: register area of the CP110 system controller 0 + - #clock-cells: must be set to 2 + - core-clock-output-names must be set to: + "cpm-apll", "cpm-ppv2-core", "cpm-eip", "cpm-core", "cpm-nand-core" + - gate-clock-output-names must be set to: + "cpm-audio", "cpm-communit", "cpm-nand", "cpm-ppv2", "cpm-sdio", + "cpm-mg-domain", "cpm-mg-core", "cpm-xor1", "cpm-xor0", "cpm-gop-dp", "none", + "cpm-pcie_x10", "cpm-pcie_x11", "cpm-pcie_x4", "cpm-pcie-xor", "cpm-sata", + "cpm-sata-usb", "cpm-main", "cpm-sd-mmc", "none", "none", "cpm-slow-io", + "cpm-usb3h0", "cpm-usb3h1", "cpm-usb3dev", "cpm-eip150", "cpm-eip197"; + +Example: + + cpm_syscon0: system-controller@440000 { + compatible = "marvell,cp110-system-controller0", "syscon"; + reg = <0x440000 0x1000>; + #clock-cells = <2>; + core-clock-output-names = "cpm-apll", "cpm-ppv2-core", "cpm-eip", "cpm-core", "cpm-nand-core"; + gate-clock-output-names = "cpm-audio", "cpm-communit", "cpm-nand", "cpm-ppv2", "cpm-sdio", + "cpm-mg-domain", "cpm-mg-core", "cpm-xor1", "cpm-xor0", "cpm-gop-dp", "none", + "cpm-pcie_x10", "cpm-pcie_x11", "cpm-pcie_x4", "cpm-pcie-xor", "cpm-sata", + "cpm-sata-usb", "cpm-main", "cpm-sd-mmc", "none", "none", "cpm-slow-io", + "cpm-usb3h0", "cpm-usb3h1", "cpm-usb3dev", "cpm-eip150", "cpm-eip197"; + }; -- cgit v0.10.2 From d3da3eaef7f4d0317d01c08824b65e5aee1315ef Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 14 Apr 2016 17:33:33 +0200 Subject: clk: mvebu: new driver for Armada CP110 system controller The Armada CP110 system controller provides, amongst other things, a number of clocks for the platform: a small number of core clocks, and then a number of gatable clocks, derived from some of the core clocks. Those clocks are configured via registers of the CP110 System Controller. The CP110 is the other core HW block (next to the AP806) used in the Marvel Armada 7K and 8K SoCs. Signed-off-by: Thomas Petazzoni [sboyd@codeaurora.org: Silence some checkpatch noise] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index bf7ae00..3165da7 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -32,6 +32,9 @@ config ARMADA_XP_CLK config ARMADA_AP806_SYSCON bool +config ARMADA_CP110_SYSCON + bool + config DOVE_CLK bool select MVEBU_CLK_COMMON diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index f4aa481..7172ef6 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o +obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o obj-$(CONFIG_DOVE_CLK) += dove.o dove-divider.o obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o obj-$(CONFIG_ORION_CLK) += orion.o diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c new file mode 100644 index 0000000..7fa42d6 --- /dev/null +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -0,0 +1,406 @@ +/* + * Marvell Armada CP110 System Controller + * + * Copyright (C) 2016 Marvell + * + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/* + * CP110 has 5 core clocks: + * + * - APLL (1 Ghz) + * - PPv2 core (1/3 APLL) + * - EIP (1/2 APLL) + * - Core (1/2 EIP) + * + * - NAND clock, which is either: + * - Equal to the core clock + * - 2/5 APLL + * + * CP110 has 32 gatable clocks, for the various peripherals in the + * IP. They have fairly complicated parent/child relationships. + */ + +#define pr_fmt(fmt) "cp110-system-controller: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CP110_PM_CLOCK_GATING_REG 0x220 +#define CP110_NAND_FLASH_CLK_CTRL_REG 0x700 +#define NF_CLOCK_SEL_400_MASK BIT(0) + +enum { + CP110_CLK_TYPE_CORE, + CP110_CLK_TYPE_GATABLE, +}; + +#define CP110_MAX_CORE_CLOCKS 5 +#define CP110_MAX_GATABLE_CLOCKS 32 + +#define CP110_CLK_NUM \ + (CP110_MAX_CORE_CLOCKS + CP110_MAX_GATABLE_CLOCKS) + +#define CP110_CORE_APLL 0 +#define CP110_CORE_PPV2 1 +#define CP110_CORE_EIP 2 +#define CP110_CORE_CORE 3 +#define CP110_CORE_NAND 4 + +/* A number of gatable clocks need special handling */ +#define CP110_GATE_AUDIO 0 +#define CP110_GATE_COMM_UNIT 1 +#define CP110_GATE_NAND 2 +#define CP110_GATE_PPV2 3 +#define CP110_GATE_SDIO 4 +#define CP110_GATE_XOR1 7 +#define CP110_GATE_XOR0 8 +#define CP110_GATE_PCIE_X1_0 11 +#define CP110_GATE_PCIE_X1_1 12 +#define CP110_GATE_PCIE_X4 13 +#define CP110_GATE_PCIE_XOR 14 +#define CP110_GATE_SATA 15 +#define CP110_GATE_SATA_USB 16 +#define CP110_GATE_MAIN 17 +#define CP110_GATE_SDMMC 18 +#define CP110_GATE_SLOW_IO 21 +#define CP110_GATE_USB3H0 22 +#define CP110_GATE_USB3H1 23 +#define CP110_GATE_USB3DEV 24 +#define CP110_GATE_EIP150 25 +#define CP110_GATE_EIP197 26 + +static struct clk *cp110_clks[CP110_CLK_NUM]; + +static struct clk_onecell_data cp110_clk_data = { + .clks = cp110_clks, + .clk_num = CP110_CLK_NUM, +}; + +struct cp110_gate_clk { + struct clk_hw hw; + struct regmap *regmap; + u8 bit_idx; +}; + +#define to_cp110_gate_clk(clk) container_of(clk, struct cp110_gate_clk, hw) + +static int cp110_gate_enable(struct clk_hw *hw) +{ + struct cp110_gate_clk *gate = to_cp110_gate_clk(hw); + + regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG, + BIT(gate->bit_idx), BIT(gate->bit_idx)); + + return 0; +} + +static void cp110_gate_disable(struct clk_hw *hw) +{ + struct cp110_gate_clk *gate = to_cp110_gate_clk(hw); + + regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG, + BIT(gate->bit_idx), 0); +} + +static int cp110_gate_is_enabled(struct clk_hw *hw) +{ + struct cp110_gate_clk *gate = to_cp110_gate_clk(hw); + u32 val; + + regmap_read(gate->regmap, CP110_PM_CLOCK_GATING_REG, &val); + + return val & BIT(gate->bit_idx); +} + +static const struct clk_ops cp110_gate_ops = { + .enable = cp110_gate_enable, + .disable = cp110_gate_disable, + .is_enabled = cp110_gate_is_enabled, +}; + +static struct clk *cp110_register_gate(const char *name, + const char *parent_name, + struct regmap *regmap, u8 bit_idx) +{ + struct cp110_gate_clk *gate; + struct clk *clk; + struct clk_init_data init; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &cp110_gate_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + gate->regmap = regmap; + gate->bit_idx = bit_idx; + gate->hw.init = &init; + + clk = clk_register(NULL, &gate->hw); + if (IS_ERR(clk)) + kfree(gate); + + return clk; +} + +static void cp110_unregister_gate(struct clk *clk) +{ + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + clk_unregister(clk); + kfree(to_cp110_gate_clk(hw)); +} + +static struct clk *cp110_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct clk_onecell_data *clk_data = data; + unsigned int type = clkspec->args[0]; + unsigned int idx = clkspec->args[1]; + + if (type == CP110_CLK_TYPE_CORE) { + if (idx > CP110_MAX_CORE_CLOCKS) + return ERR_PTR(-EINVAL); + return clk_data->clks[idx]; + } else if (type == CP110_CLK_TYPE_GATABLE) { + if (idx > CP110_MAX_GATABLE_CLOCKS) + return ERR_PTR(-EINVAL); + return clk_data->clks[CP110_MAX_CORE_CLOCKS + idx]; + } + + return ERR_PTR(-EINVAL); +} + +static int cp110_syscon_clk_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + struct device_node *np = pdev->dev.of_node; + const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name; + struct clk *clk; + u32 nand_clk_ctrl; + int i, ret; + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = regmap_read(regmap, CP110_NAND_FLASH_CLK_CTRL_REG, + &nand_clk_ctrl); + if (ret) + return ret; + + /* Register the APLL which is the root of the clk tree */ + of_property_read_string_index(np, "core-clock-output-names", + CP110_CORE_APLL, &apll_name); + clk = clk_register_fixed_rate(NULL, apll_name, NULL, 0, + 1000 * 1000 * 1000); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto fail0; + } + + cp110_clks[CP110_CORE_APLL] = clk; + + /* PPv2 is APLL/3 */ + of_property_read_string_index(np, "core-clock-output-names", + CP110_CORE_PPV2, &ppv2_name); + clk = clk_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto fail1; + } + + cp110_clks[CP110_CORE_PPV2] = clk; + + /* EIP clock is APLL/2 */ + of_property_read_string_index(np, "core-clock-output-names", + CP110_CORE_EIP, &eip_name); + clk = clk_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto fail2; + } + + cp110_clks[CP110_CORE_EIP] = clk; + + /* Core clock is EIP/2 */ + of_property_read_string_index(np, "core-clock-output-names", + CP110_CORE_CORE, &core_name); + clk = clk_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto fail3; + } + + cp110_clks[CP110_CORE_CORE] = clk; + + /* NAND can be either APLL/2.5 or core clock */ + of_property_read_string_index(np, "core-clock-output-names", + CP110_CORE_NAND, &nand_name); + if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK) + clk = clk_register_fixed_factor(NULL, nand_name, + apll_name, 0, 2, 5); + else + clk = clk_register_fixed_factor(NULL, nand_name, + core_name, 0, 1, 1); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto fail4; + } + + cp110_clks[CP110_CORE_NAND] = clk; + + for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { + const char *parent, *name; + int ret; + + ret = of_property_read_string_index(np, + "gate-clock-output-names", + i, &name); + /* Reached the end of the list? */ + if (ret < 0) + break; + + if (!strcmp(name, "none")) + continue; + + switch (i) { + case CP110_GATE_AUDIO: + case CP110_GATE_COMM_UNIT: + case CP110_GATE_EIP150: + case CP110_GATE_EIP197: + case CP110_GATE_SLOW_IO: + of_property_read_string_index(np, + "gate-clock-output-names", + CP110_GATE_MAIN, &parent); + break; + case CP110_GATE_NAND: + parent = nand_name; + break; + case CP110_GATE_PPV2: + parent = ppv2_name; + break; + case CP110_GATE_SDIO: + of_property_read_string_index(np, + "gate-clock-output-names", + CP110_GATE_SDMMC, &parent); + break; + case CP110_GATE_XOR1: + case CP110_GATE_XOR0: + case CP110_GATE_PCIE_X1_0: + case CP110_GATE_PCIE_X1_1: + case CP110_GATE_PCIE_X4: + of_property_read_string_index(np, + "gate-clock-output-names", + CP110_GATE_PCIE_XOR, &parent); + break; + case CP110_GATE_SATA: + case CP110_GATE_USB3H0: + case CP110_GATE_USB3H1: + case CP110_GATE_USB3DEV: + of_property_read_string_index(np, + "gate-clock-output-names", + CP110_GATE_SATA_USB, &parent); + break; + default: + parent = core_name; + break; + } + + clk = cp110_register_gate(name, parent, regmap, i); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto fail_gate; + } + + cp110_clks[CP110_MAX_CORE_CLOCKS + i] = clk; + } + + ret = of_clk_add_provider(np, cp110_of_clk_get, &cp110_clk_data); + if (ret) + goto fail_clk_add; + + return 0; + +fail_clk_add: +fail_gate: + for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { + clk = cp110_clks[CP110_MAX_CORE_CLOCKS + i]; + + if (clk) + cp110_unregister_gate(clk); + } + + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]); +fail4: + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); +fail3: + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); +fail2: + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); +fail1: + clk_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); +fail0: + return ret; +} + +static int cp110_syscon_clk_remove(struct platform_device *pdev) +{ + int i; + + of_clk_del_provider(pdev->dev.of_node); + + for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { + struct clk *clk = cp110_clks[CP110_MAX_CORE_CLOCKS + i]; + + if (clk) + cp110_unregister_gate(clk); + } + + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]); + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); + clk_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); + clk_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); + + return 0; +} + +static const struct of_device_id cp110_syscon_of_match[] = { + { .compatible = "marvell,cp110-system-controller0", }, + { } +}; +MODULE_DEVICE_TABLE(of, armada8k_pcie_of_match); + +static struct platform_driver cp110_syscon_driver = { + .probe = cp110_syscon_clk_probe, + .remove = cp110_syscon_clk_remove, + .driver = { + .name = "marvell-cp110-system-controller0", + .of_match_table = cp110_syscon_of_match, + }, +}; + +module_platform_driver(cp110_syscon_driver); + +MODULE_DESCRIPTION("Marvell CP110 System Controller 0 driver"); +MODULE_AUTHOR("Thomas Petazzoni "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 84752e8d8ab6bb72feab96785e9366783b4b9787 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 4 May 2016 16:36:25 -0700 Subject: clk: rockchip: fix the rk3399 sdmmc sample / drv name The rk3399 clock table had a simple typo in it, calling the SDMMC sample and drive clocks by the wrong name. Fix this minor typo. Signed-off-by: Douglas Anderson Tested-by: Brian Norris Acked-by: Brian Norris Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 5248726..291543f 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -894,8 +894,8 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(6), 1, GFLAGS), - MMC(SCLK_SDMMC_DRV, "emmc_drv", "clk_sdmmc", RK3399_SDMMC_CON0, 1), - MMC(SCLK_SDMMC_SAMPLE, "emmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1), + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc", RK3399_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1), MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", RK3399_SDIO_CON0, 1), MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", RK3399_SDIO_CON1, 1), -- cgit v0.10.2 From 6f339dc2719eb01448c70fe3d56287d1eb9bd67e Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 15 Mar 2016 16:40:32 +0100 Subject: clk: rockchip: lookup General Register Files in rockchip_clk_init In the distant past syscons were initialized pretty late and weren't available at the time the clock init ran. As the GRF is mainly needed for PLL lock-status checking, we had this lazy init that tried to grab the syscon on PLL rate changes and denied these changes if it was not available. These days syscons are available very early and recent addition to rockchip clocks, like the PLL clk_init actually also rely on them being available at that time, so there is no need to keep that lazy init around, as it will also result in some more simplifications in other parts of the clock-code. Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index f0a8be1..9f99a42 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -347,6 +347,9 @@ struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np, ctx->grf = ERR_PTR(-EPROBE_DEFER); spin_lock_init(&ctx->lock); + ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, + "rockchip,grf"); + return ctx; err_free: @@ -364,9 +367,6 @@ void __init rockchip_clk_of_add_provider(struct device_node *np, struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx) { - if (IS_ERR(ctx->grf)) - ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, - "rockchip,grf"); return ctx->grf; } -- cgit v0.10.2 From c9c3c6eecc5533d14bb9bc82319257eb8bc52768 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 15 Mar 2016 16:55:41 +0100 Subject: clk: rockchip: simplify GRF handling in pll clocks With the previous commit, the clock drivers now know at init time if the GRF regmap is available. That means if it isn't available then, it also won't become available later and we can therefore switch PLLs, that need the GRF for the lock-status, to read-only mode - similar behaviour as the aborting of rate changes we did before. This saves some conditionals on every rate change and we can also drop the rockchip_clk_get_grf function completely. Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 8ac73bc..76e278d 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -92,15 +92,10 @@ static long rockchip_pll_round_rate(struct clk_hw *hw, */ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) { - struct regmap *grf = rockchip_clk_get_grf(pll->ctx); + struct regmap *grf = pll->ctx->grf; unsigned int val; int delay = 24000000, ret; - if (IS_ERR(grf)) { - pr_err("%s: grf regmap not available\n", __func__); - return PTR_ERR(grf); - } - while (delay > 0) { ret = regmap_read(grf, pll->lock_offset, &val); if (ret) { @@ -253,13 +248,6 @@ static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate, struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate); - struct regmap *grf = rockchip_clk_get_grf(pll->ctx); - - if (IS_ERR(grf)) { - pr_debug("%s: grf regmap not available, aborting rate change\n", - __func__); - return PTR_ERR(grf); - } pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", __func__, __clk_get_name(hw->clk), old_rate, drate, prate); @@ -492,13 +480,6 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); - struct regmap *grf = rockchip_clk_get_grf(pll->ctx); - - if (IS_ERR(grf)) { - pr_debug("%s: grf regmap not available, aborting rate change\n", - __func__); - return PTR_ERR(grf); - } pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", __func__, clk_hw_get_name(hw), old_rate, drate, prate); @@ -565,11 +546,6 @@ static void rockchip_rk3066_pll_init(struct clk_hw *hw) rate->no, cur.no, rate->nf, cur.nf, rate->nb, cur.nb); if (rate->nr != cur.nr || rate->no != cur.no || rate->nf != cur.nf || rate->nb != cur.nb) { - struct regmap *grf = rockchip_clk_get_grf(pll->ctx); - - if (IS_ERR(grf)) - return; - pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", __func__, clk_hw_get_name(hw)); rockchip_rk3066_pll_set_params(pll, rate); @@ -943,13 +919,13 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, switch (pll_type) { case pll_rk3036: - if (!pll->rate_table) + if (!pll->rate_table || IS_ERR(ctx->grf)) init.ops = &rockchip_rk3036_pll_clk_norate_ops; else init.ops = &rockchip_rk3036_pll_clk_ops; break; case pll_rk3066: - if (!pll->rate_table) + if (!pll->rate_table || IS_ERR(ctx->grf)) init.ops = &rockchip_rk3066_pll_clk_norate_ops; else init.ops = &rockchip_rk3066_pll_clk_ops; diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 9f99a42..7ffd134 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -365,11 +365,6 @@ void __init rockchip_clk_of_add_provider(struct device_node *np, pr_err("%s: could not register clk provider\n", __func__); } -struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx) -{ - return ctx->grf; -} - void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, struct clk *clk, unsigned int id) { diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 1abb7d0..2194ffa 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -600,7 +600,6 @@ struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks); void rockchip_clk_of_add_provider(struct device_node *np, struct rockchip_clk_provider *ctx); -struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx); void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, struct clk *clk, unsigned int id); void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, -- cgit v0.10.2 From 7e5385dc722258c862f969ab7e67907156ad0e3f Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 15 Mar 2016 17:34:56 +0100 Subject: clk: rockchip: drop old_rate calculation on pll rate changes Previously when everything happened in the set_rate callbacks itself we needed the old_rate value for the possible rate rollback, so that made it easy to also use it in the debug output. Now with the param-handling being done in separate functions, reading and recalculating the current pll rate only to use it in a debug message that won't get displayed in regular cases anyway is quite a waste. Therefore drop that value from the debug output. In the worst case that previous rate will have been displayed on the rate change before. Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 76e278d..db81e45 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -247,10 +247,9 @@ static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate, { struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; - unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate); - pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", - __func__, __clk_get_name(hw->clk), old_rate, drate, prate); + pr_debug("%s: changing %s to %lu with a parent rate of %lu\n", + __func__, __clk_get_name(hw->clk), drate, prate); /* Get required rate settings from table */ rate = rockchip_get_pll_settings(pll, drate); @@ -479,10 +478,9 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, { struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; - unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); - pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", - __func__, clk_hw_get_name(hw), old_rate, drate, prate); + pr_debug("%s: changing %s to %lu with a parent rate of %lu\n", + __func__, clk_hw_get_name(hw), drate, prate); /* Get required rate settings from table */ rate = rockchip_get_pll_settings(pll, drate); @@ -725,10 +723,9 @@ static int rockchip_rk3399_pll_set_rate(struct clk_hw *hw, unsigned long drate, { struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; - unsigned long old_rate = rockchip_rk3399_pll_recalc_rate(hw, prate); - pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", - __func__, __clk_get_name(hw->clk), old_rate, drate, prate); + pr_debug("%s: changing %s to %lu with a parent rate of %lu\n", + __func__, __clk_get_name(hw->clk), drate, prate); /* Get required rate settings from table */ rate = rockchip_get_pll_settings(pll, drate); -- cgit v0.10.2 From 98b8525abb7f0d9a5ab942a2e044011d7e635490 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 25 Apr 2016 15:22:42 +0200 Subject: clk: sunxi: Add display and TCON0 clocks driver The A10 SoCs and its relatives has a special clock controller to drive the display engines (both frontend and backend), that have a lot in common with the clock to drive the first TCON channel. Add a driver to support both. Signed-off-by: Maxime Ripard Acked-by: Rob Herring [sboyd@codeaurora.org: Silence variable sized array warning] Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index f70f500..8f7619d 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -64,6 +64,7 @@ Required properties: "allwinner,sun8i-a83t-bus-gates-clk" - for the bus gates on A83T "allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3 "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80 + "allwinner,sun4i-a10-display-clk" - for the display clocks on the A10 "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10 "allwinner,sun5i-a13-dram-gates-clk" - for the DRAM gates on A13 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 @@ -75,6 +76,7 @@ Required properties: "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 "allwinner,sun7i-a20-out-clk" - for the external output clocks "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 + "allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10 "allwinner,sun4i-a10-tcon-ch1-clk" - for the TCON channel 1 clock on the A10 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 2d77407..39d2044 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -11,6 +11,7 @@ obj-y += clk-a10-ve.o obj-y += clk-a20-gmac.o obj-y += clk-mod0.o obj-y += clk-simple-gates.o +obj-y += clk-sun4i-display.o obj-y += clk-sun4i-pll3.o obj-y += clk-sun4i-tcon-ch1.o obj-y += clk-sun8i-bus-gates.o diff --git a/drivers/clk/sunxi/clk-sun4i-display.c b/drivers/clk/sunxi/clk-sun4i-display.c new file mode 100644 index 0000000..445a749 --- /dev/null +++ b/drivers/clk/sunxi/clk-sun4i-display.c @@ -0,0 +1,261 @@ +/* + * Copyright 2015 Maxime Ripard + * + * Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +struct sun4i_a10_display_clk_data { + bool has_div; + u8 num_rst; + u8 parents; + + u8 offset_en; + u8 offset_div; + u8 offset_mux; + u8 offset_rst; + + u8 width_div; + u8 width_mux; +}; + +struct reset_data { + void __iomem *reg; + spinlock_t *lock; + struct reset_controller_dev rcdev; + u8 offset; +}; + +static DEFINE_SPINLOCK(sun4i_a10_display_lock); + +static inline struct reset_data *rcdev_to_reset_data(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct reset_data, rcdev); +}; + +static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct reset_data *data = rcdev_to_reset_data(rcdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(data->lock, flags); + + reg = readl(data->reg); + writel(reg & ~BIT(data->offset + id), data->reg); + + spin_unlock_irqrestore(data->lock, flags); + + return 0; +} + +static int sun4i_a10_display_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct reset_data *data = rcdev_to_reset_data(rcdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(data->lock, flags); + + reg = readl(data->reg); + writel(reg | BIT(data->offset + id), data->reg); + + spin_unlock_irqrestore(data->lock, flags); + + return 0; +} + +static int sun4i_a10_display_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct reset_data *data = rcdev_to_reset_data(rcdev); + + return !(readl(data->reg) & BIT(data->offset + id)); +} + +static const struct reset_control_ops sun4i_a10_display_reset_ops = { + .assert = sun4i_a10_display_assert, + .deassert = sun4i_a10_display_deassert, + .status = sun4i_a10_display_status, +}; + +static int sun4i_a10_display_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *spec) +{ + /* We only have a single reset signal */ + return 0; +} + +static void __init sun4i_a10_display_init(struct device_node *node, + const struct sun4i_a10_display_clk_data *data) +{ + const char *parents[4]; + const char *clk_name = node->name; + struct reset_data *reset_data; + struct clk_divider *div = NULL; + struct clk_gate *gate; + struct resource res; + struct clk_mux *mux; + void __iomem *reg; + struct clk *clk; + int ret; + + of_property_read_string(node, "clock-output-names", &clk_name); + + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(reg)) { + pr_err("%s: Could not map the clock registers\n", clk_name); + return; + } + + ret = of_clk_parent_fill(node, parents, data->parents); + if (ret != data->parents) { + pr_err("%s: Could not retrieve the parents\n", clk_name); + goto unmap; + } + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + goto unmap; + + mux->reg = reg; + mux->shift = data->offset_mux; + mux->mask = (1 << data->width_mux) - 1; + mux->lock = &sun4i_a10_display_lock; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto free_mux; + + gate->reg = reg; + gate->bit_idx = data->offset_en; + gate->lock = &sun4i_a10_display_lock; + + if (data->has_div) { + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + goto free_gate; + + div->reg = reg; + div->shift = data->offset_div; + div->width = data->width_div; + div->lock = &sun4i_a10_display_lock; + } + + clk = clk_register_composite(NULL, clk_name, + parents, data->parents, + &mux->hw, &clk_mux_ops, + data->has_div ? &div->hw : NULL, + data->has_div ? &clk_divider_ops : NULL, + &gate->hw, &clk_gate_ops, + 0); + if (IS_ERR(clk)) { + pr_err("%s: Couldn't register the clock\n", clk_name); + goto free_div; + } + + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (ret) { + pr_err("%s: Couldn't register DT provider\n", clk_name); + goto free_clk; + } + + if (!data->num_rst) + return; + + reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); + if (!reset_data) + goto free_of_clk; + + reset_data->reg = reg; + reset_data->offset = data->offset_rst; + reset_data->lock = &sun4i_a10_display_lock; + reset_data->rcdev.nr_resets = data->num_rst; + reset_data->rcdev.ops = &sun4i_a10_display_reset_ops; + reset_data->rcdev.of_node = node; + + if (data->num_rst == 1) { + reset_data->rcdev.of_reset_n_cells = 0; + reset_data->rcdev.of_xlate = &sun4i_a10_display_reset_xlate; + } else { + reset_data->rcdev.of_reset_n_cells = 1; + } + + if (reset_controller_register(&reset_data->rcdev)) { + pr_err("%s: Couldn't register the reset controller\n", + clk_name); + goto free_reset; + } + + return; + +free_reset: + kfree(reset_data); +free_of_clk: + of_clk_del_provider(node); +free_clk: + clk_unregister_composite(clk); +free_div: + kfree(div); +free_gate: + kfree(gate); +free_mux: + kfree(mux); +unmap: + iounmap(reg); + of_address_to_resource(node, 0, &res); + release_mem_region(res.start, resource_size(&res)); +} + +static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initconst = { + .num_rst = 2, + .parents = 4, + .offset_en = 31, + .offset_rst = 29, + .offset_mux = 24, + .width_mux = 2, +}; + +static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node) +{ + sun4i_a10_display_init(node, &sun4i_a10_tcon_ch0_data); +} +CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk", + sun4i_a10_tcon_ch0_setup); + +static const struct sun4i_a10_display_clk_data sun4i_a10_display_data __initconst = { + .has_div = true, + .num_rst = 1, + .parents = 3, + .offset_en = 31, + .offset_rst = 30, + .offset_mux = 24, + .offset_div = 0, + .width_mux = 2, + .width_div = 4, +}; + +static void __init sun4i_a10_display_setup(struct device_node *node) +{ + sun4i_a10_display_init(node, &sun4i_a10_display_data); +} +CLK_OF_DECLARE(sun4i_a10_display, "allwinner,sun4i-a10-display-clk", + sun4i_a10_display_setup); -- cgit v0.10.2 From 4afe2d1a6ed5cba794aeeaa816e7c97a45167b01 Mon Sep 17 00:00:00 2001 From: Harvey Hunt Date: Mon, 9 May 2016 17:29:52 +0100 Subject: clk: ingenic: Allow divider value to be divided The JZ4780's MSC clock divider registers multiply the clock divider by 2. This means that MMC devices run at half their expected speed. Add the ability to divide the clock divider in order to solve this. Signed-off-by: Harvey Hunt Cc: Paul Burton Cc: Ralf Baechle Cc: linux-clk@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Stephen Boyd diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index 7cfb7b2..e8248f9 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -325,6 +325,7 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) div = (div_reg >> clk_info->div.shift) & GENMASK(clk_info->div.bits - 1, 0); div += 1; + div *= clk_info->div.div; rate /= div; } @@ -345,6 +346,14 @@ ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info, div = min_t(unsigned, div, 1 << clk_info->div.bits); div = max_t(unsigned, div, 1); + /* + * If the divider value itself must be divided before being written to + * the divider register, we must ensure we don't have any bits set that + * would be lost as a result of doing so. + */ + div /= clk_info->div.div; + div *= clk_info->div.div; + return div; } @@ -395,7 +404,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate, /* update the divide */ mask = GENMASK(clk_info->div.bits - 1, 0); reg &= ~(mask << clk_info->div.shift); - reg |= (div - 1) << clk_info->div.shift; + reg |= ((div / clk_info->div.div) - 1) << clk_info->div.shift; /* clear the stop bit */ if (clk_info->div.stop_bit != -1) diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h index 99347e2..09700b2 100644 --- a/drivers/clk/ingenic/cgu.h +++ b/drivers/clk/ingenic/cgu.h @@ -76,8 +76,11 @@ struct ingenic_cgu_mux_info { /** * struct ingenic_cgu_div_info - information about a divider * @reg: offset of the divider control register within the CGU - * @shift: number of bits to shift the divide value by (ie. the index of + * @shift: number of bits to left shift the divide value by (ie. the index of * the lowest bit of the divide value within its control register) + * @div: number of bits to divide the divider value by (i.e. if the + * effective divider value is the value written to the register + * multiplied by some constant) * @bits: the size of the divide value in bits * @ce_bit: the index of the change enable bit within reg, or -1 if there * isn't one @@ -87,6 +90,7 @@ struct ingenic_cgu_mux_info { struct ingenic_cgu_div_info { unsigned reg; u8 shift; + u8 div; u8 bits; s8 ce_bit; s8 busy_bit; diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c index 305a26c2..510fe7e 100644 --- a/drivers/clk/ingenic/jz4740-cgu.c +++ b/drivers/clk/ingenic/jz4740-cgu.c @@ -90,51 +90,51 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { [JZ4740_CLK_PLL_HALF] = { "pll half", CGU_CLK_DIV, .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, - .div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 }, }, [JZ4740_CLK_CCLK] = { "cclk", CGU_CLK_DIV, .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, - .div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 }, + .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, }, [JZ4740_CLK_HCLK] = { "hclk", CGU_CLK_DIV, .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, - .div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 }, + .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, }, [JZ4740_CLK_PCLK] = { "pclk", CGU_CLK_DIV, .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, - .div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 }, + .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 }, }, [JZ4740_CLK_MCLK] = { "mclk", CGU_CLK_DIV, .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, - .div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 }, + .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 }, }, [JZ4740_CLK_LCD] = { "lcd", CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, - .div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 }, + .div = { CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1 }, .gate = { CGU_REG_CLKGR, 10 }, }, [JZ4740_CLK_LCD_PCLK] = { "lcd_pclk", CGU_CLK_DIV, .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, - .div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 }, + .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, }, [JZ4740_CLK_I2S] = { "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, .mux = { CGU_REG_CPCCR, 31, 1 }, - .div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 }, + .div = { CGU_REG_I2SCDR, 0, 1, 8, -1, -1, -1 }, .gate = { CGU_REG_CLKGR, 6 }, }, @@ -142,21 +142,21 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 }, .mux = { CGU_REG_SSICDR, 31, 1 }, - .div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 }, + .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, .gate = { CGU_REG_CLKGR, 4 }, }, [JZ4740_CLK_MMC] = { "mmc", CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, - .div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 }, + .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, .gate = { CGU_REG_CLKGR, 7 }, }, [JZ4740_CLK_UHC] = { "uhc", CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, - .div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 }, + .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 }, .gate = { CGU_REG_CLKGR, 14 }, }, @@ -164,7 +164,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { "udc", CGU_CLK_MUX | CGU_CLK_DIV, .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, .mux = { CGU_REG_CPCCR, 29, 1 }, - .div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, .gate = { CGU_REG_SCR, 6 }, }, diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c index 431f962..b35d6d9 100644 --- a/drivers/clk/ingenic/jz4780-cgu.c +++ b/drivers/clk/ingenic/jz4780-cgu.c @@ -296,13 +296,13 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { [JZ4780_CLK_CPU] = { "cpu", CGU_CLK_DIV, .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 }, - .div = { CGU_REG_CLOCKCONTROL, 0, 4, 22, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 0, 1, 4, 22, -1, -1 }, }, [JZ4780_CLK_L2CACHE] = { "l2cache", CGU_CLK_DIV, .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 }, - .div = { CGU_REG_CLOCKCONTROL, 4, 4, -1, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 4, 1, 4, -1, -1, -1 }, }, [JZ4780_CLK_AHB0] = { @@ -310,7 +310,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_EPLL }, .mux = { CGU_REG_CLOCKCONTROL, 26, 2 }, - .div = { CGU_REG_CLOCKCONTROL, 8, 4, 21, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 8, 1, 4, 21, -1, -1 }, }, [JZ4780_CLK_AHB2PMUX] = { @@ -323,20 +323,20 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { [JZ4780_CLK_AHB2] = { "ahb2", CGU_CLK_DIV, .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 }, - .div = { CGU_REG_CLOCKCONTROL, 12, 4, 20, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 12, 1, 4, 20, -1, -1 }, }, [JZ4780_CLK_PCLK] = { "pclk", CGU_CLK_DIV, .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 }, - .div = { CGU_REG_CLOCKCONTROL, 16, 4, 20, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 16, 1, 4, 20, -1, -1 }, }, [JZ4780_CLK_DDR] = { "ddr", CGU_CLK_MUX | CGU_CLK_DIV, .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 }, .mux = { CGU_REG_DDRCDR, 30, 2 }, - .div = { CGU_REG_DDRCDR, 0, 4, 29, 28, 27 }, + .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 }, }, [JZ4780_CLK_VPU] = { @@ -344,7 +344,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_EPLL, -1 }, .mux = { CGU_REG_VPUCDR, 30, 2 }, - .div = { CGU_REG_VPUCDR, 0, 4, 29, 28, 27 }, + .div = { CGU_REG_VPUCDR, 0, 1, 4, 29, 28, 27 }, .gate = { CGU_REG_CLKGR1, 2 }, }, @@ -352,7 +352,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { "i2s_pll", CGU_CLK_MUX | CGU_CLK_DIV, .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_EPLL, -1, -1 }, .mux = { CGU_REG_I2SCDR, 30, 1 }, - .div = { CGU_REG_I2SCDR, 0, 8, 29, 28, 27 }, + .div = { CGU_REG_I2SCDR, 0, 1, 8, 29, 28, 27 }, }, [JZ4780_CLK_I2S] = { @@ -366,7 +366,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_VPLL, -1 }, .mux = { CGU_REG_LP0CDR, 30, 2 }, - .div = { CGU_REG_LP0CDR, 0, 8, 28, 27, 26 }, + .div = { CGU_REG_LP0CDR, 0, 1, 8, 28, 27, 26 }, }, [JZ4780_CLK_LCD1PIXCLK] = { @@ -374,7 +374,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_VPLL, -1 }, .mux = { CGU_REG_LP1CDR, 30, 2 }, - .div = { CGU_REG_LP1CDR, 0, 8, 28, 27, 26 }, + .div = { CGU_REG_LP1CDR, 0, 1, 8, 28, 27, 26 }, }, [JZ4780_CLK_MSCMUX] = { @@ -386,21 +386,21 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { [JZ4780_CLK_MSC0] = { "msc0", CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 }, - .div = { CGU_REG_MSC0CDR, 0, 8, 29, 28, 27 }, + .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 }, .gate = { CGU_REG_CLKGR0, 3 }, }, [JZ4780_CLK_MSC1] = { "msc1", CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 }, - .div = { CGU_REG_MSC1CDR, 0, 8, 29, 28, 27 }, + .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 }, .gate = { CGU_REG_CLKGR0, 11 }, }, [JZ4780_CLK_MSC2] = { "msc2", CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 }, - .div = { CGU_REG_MSC2CDR, 0, 8, 29, 28, 27 }, + .div = { CGU_REG_MSC2CDR, 0, 2, 8, 29, 28, 27 }, .gate = { CGU_REG_CLKGR0, 12 }, }, @@ -409,7 +409,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_EPLL, JZ4780_CLK_OTGPHY }, .mux = { CGU_REG_UHCCDR, 30, 2 }, - .div = { CGU_REG_UHCCDR, 0, 8, 29, 28, 27 }, + .div = { CGU_REG_UHCCDR, 0, 1, 8, 29, 28, 27 }, .gate = { CGU_REG_CLKGR0, 24 }, }, @@ -417,7 +417,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV, .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 }, .mux = { CGU_REG_SSICDR, 30, 1 }, - .div = { CGU_REG_SSICDR, 0, 8, 29, 28, 27 }, + .div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 }, }, [JZ4780_CLK_SSI] = { @@ -430,7 +430,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { "cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV, .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 }, .mux = { CGU_REG_CIMCDR, 31, 1 }, - .div = { CGU_REG_CIMCDR, 0, 8, 30, 29, 28 }, + .div = { CGU_REG_CIMCDR, 0, 1, 8, 30, 29, 28 }, }, [JZ4780_CLK_PCMPLL] = { @@ -438,7 +438,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_EPLL, JZ4780_CLK_VPLL }, .mux = { CGU_REG_PCMCDR, 29, 2 }, - .div = { CGU_REG_PCMCDR, 0, 8, 28, 27, 26 }, + .div = { CGU_REG_PCMCDR, 0, 1, 8, 28, 27, 26 }, }, [JZ4780_CLK_PCM] = { @@ -453,7 +453,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_EPLL }, .mux = { CGU_REG_GPUCDR, 30, 2 }, - .div = { CGU_REG_GPUCDR, 0, 4, 29, 28, 27 }, + .div = { CGU_REG_GPUCDR, 0, 1, 4, 29, 28, 27 }, .gate = { CGU_REG_CLKGR1, 4 }, }, @@ -462,7 +462,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_VPLL, -1 }, .mux = { CGU_REG_HDMICDR, 30, 2 }, - .div = { CGU_REG_HDMICDR, 0, 8, 29, 28, 26 }, + .div = { CGU_REG_HDMICDR, 0, 1, 8, 29, 28, 26 }, .gate = { CGU_REG_CLKGR1, 9 }, }, @@ -471,7 +471,7 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, JZ4780_CLK_EPLL }, .mux = { CGU_REG_BCHCDR, 30, 2 }, - .div = { CGU_REG_BCHCDR, 0, 4, 29, 28, 27 }, + .div = { CGU_REG_BCHCDR, 0, 1, 4, 29, 28, 27 }, .gate = { CGU_REG_CLKGR0, 1 }, }, -- cgit v0.10.2 From 9ffee1c4be7c1981e47e520172638a4b00881880 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 11 May 2016 15:07:32 +0530 Subject: clk: qcom: mmcc-8996: Remove clocks that should be controlled by RPM The branch clocks MMSS_MMAGIC_AXI_CLK and MMAGIC_BIMC_AXI_CLK are controlled by RPM when the APPs processor enable or disable the RPM_MMAXI_CLK. During the boot sequence, someone can enable the RPM_MMAXI_CLK, resulting in register status bits showing that these clocks are enabled, our clock driver may look at the enabled status of these clocks and try to disable them since it thinks they are unused. Don't make the clock driver touch these clocks. Signed-off-by: Archit Taneja Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 6df7ff3..847dd9d 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -1279,21 +1279,6 @@ static struct clk_branch mmss_misc_cxo_clk = { }, }; -static struct clk_branch mmss_mmagic_axi_clk = { - .halt_reg = 0x506c, - .clkr = { - .enable_reg = 0x506c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "mmss_mmagic_axi_clk", - .parent_names = (const char *[]){ "axi_clk_src" }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_branch2_ops, - }, - }, -}; - static struct clk_branch mmss_mmagic_maxi_clk = { .halt_reg = 0x5074, .clkr = { @@ -1579,21 +1564,6 @@ static struct clk_branch smmu_video_axi_clk = { }, }; -static struct clk_branch mmagic_bimc_axi_clk = { - .halt_reg = 0x5294, - .clkr = { - .enable_reg = 0x5294, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "mmagic_bimc_axi_clk", - .parent_names = (const char *[]){ "axi_clk_src" }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_branch2_ops, - }, - }, -}; - static struct clk_branch mmagic_bimc_noc_cfg_ahb_clk = { .halt_reg = 0x5298, .clkr = { @@ -3121,7 +3091,6 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = { [MMSS_MMAGIC_CFG_AHB_CLK] = &mmss_mmagic_cfg_ahb_clk.clkr, [MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr, [MMSS_MISC_CXO_CLK] = &mmss_misc_cxo_clk.clkr, - [MMSS_MMAGIC_AXI_CLK] = &mmss_mmagic_axi_clk.clkr, [MMSS_MMAGIC_MAXI_CLK] = &mmss_mmagic_maxi_clk.clkr, [MMAGIC_CAMSS_AXI_CLK] = &mmagic_camss_axi_clk.clkr, [MMAGIC_CAMSS_NOC_CFG_AHB_CLK] = &mmagic_camss_noc_cfg_ahb_clk.clkr, @@ -3141,7 +3110,6 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = { [MMAGIC_VIDEO_NOC_CFG_AHB_CLK] = &mmagic_video_noc_cfg_ahb_clk.clkr, [SMMU_VIDEO_AHB_CLK] = &smmu_video_ahb_clk.clkr, [SMMU_VIDEO_AXI_CLK] = &smmu_video_axi_clk.clkr, - [MMAGIC_BIMC_AXI_CLK] = &mmagic_bimc_axi_clk.clkr, [MMAGIC_BIMC_NOC_CFG_AHB_CLK] = &mmagic_bimc_noc_cfg_ahb_clk.clkr, [GPU_GX_GFX3D_CLK] = &gpu_gx_gfx3d_clk.clkr, [GPU_GX_RBBMTIMER_CLK] = &gpu_gx_rbbmtimer_clk.clkr, -- cgit v0.10.2 From ef56b79b66faeeb0dc14213d3cc9e0534a960dee Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 13 May 2016 10:00:31 +0200 Subject: clk: fix critical clock locking The critical clock handling in __clk_core_init isn't taking the enable lock before calling clk_core_enable, which in turns triggers the warning in the lockdep_assert_held call in that function when lockep is enabled. Add the calls to clk_enable_lock/unlock to make sure it doesn't happen. Fixes: 32b9b1096186 ("clk: Allow clocks to be marked as CRITICAL") Signed-off-by: Maxime Ripard Reviewed-by: Heiko Stuebner Tested-by: Heiko Stuebner Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ce39add..d584004 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2404,8 +2404,13 @@ static int __clk_core_init(struct clk_core *core) core->ops->init(core->hw); if (core->flags & CLK_IS_CRITICAL) { + unsigned long flags; + clk_core_prepare(core); + + flags = clk_enable_lock(); clk_core_enable(core); + clk_enable_unlock(flags); } kref_init(&core->ref); -- cgit v0.10.2