diff options
Diffstat (limited to 'drivers/clk')
107 files changed, 4039 insertions, 1198 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index eca8e01..16f7d33 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -6,9 +6,6 @@ config CLKDEV_LOOKUP config HAVE_CLK_PREPARE bool -config HAVE_MACH_CLKDEV - bool - config COMMON_CLK bool select HAVE_CLK_PREPARE @@ -99,6 +96,14 @@ config COMMON_CLK_SI570 This driver supports Silicon Labs 570/571/598/599 programmable clock generators. +config COMMON_CLK_CDCE706 + tristate "Clock driver for TI CDCE706 clock synthesizer" + depends on I2C + select REGMAP_I2C + select RATIONAL + ---help--- + This driver supports TI CDCE706 programmable 3-PLL clock synthesizer. + config COMMON_CLK_CDCE925 tristate "Clock driver for TI CDCE925 devices" depends on I2C @@ -190,23 +195,14 @@ config COMMON_CLK_PWM config COMMON_CLK_PXA def_bool COMMON_CLK && ARCH_PXA ---help--- - Sypport for the Marvell PXA SoC. - -config COMMON_CLK_CDCE706 - tristate "Clock driver for TI CDCE706 clock synthesizer" - depends on I2C - select REGMAP_I2C - select RATIONAL - ---help--- - This driver supports TI CDCE706 programmable 3-PLL clock synthesizer. + Support for the Marvell PXA SoC. source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" -source "drivers/clk/qcom/Kconfig" - -endmenu - source "drivers/clk/mvebu/Kconfig" - +source "drivers/clk/qcom/Kconfig" source "drivers/clk/samsung/Kconfig" source "drivers/clk/tegra/Kconfig" +source "drivers/clk/ti/Kconfig" + +endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index b038e36..08c0003 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -43,7 +43,7 @@ obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o -obj-$(CONFIG_ARCH_TANGOX) += clk-tango4.o +obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_ARCH_U300) += clk-u300.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o @@ -70,7 +70,6 @@ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ -obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ obj-$(CONFIG_ARCH_RENESAS) += shmobile/ obj-$(CONFIG_ARCH_SIRF) += sirf/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ @@ -78,7 +77,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ -obj-$(CONFIG_ARCH_OMAP2PLUS) += ti/ +obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_X86) += x86/ diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index abc8094..f82b16a 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -268,13 +268,13 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np, u32 id; const char *name; struct clk *clk; - int num_parents; + unsigned int num_parents; const char *parent_names[GENERATED_SOURCE_MAX]; struct device_node *gcknp; struct clk_range range = CLK_RANGE(0, 0); num_parents = of_clk_get_parent_count(np); - if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX) + if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX) return; of_clk_parent_fill(np, parent_names, num_parents); diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index fd7247d..b85f435 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c @@ -611,12 +611,12 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np, { struct clk *clk; const char *parent_names[2]; - int num_parents; + unsigned int num_parents; unsigned int irq; const char *name = np->name; num_parents = of_clk_get_parent_count(np); - if (num_parents <= 0 || num_parents > 2) + if (num_parents == 0 || num_parents > 2) return; of_clk_parent_fill(np, parent_names, num_parents); diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 620ea32..016fe11 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -221,14 +221,14 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, const struct clk_master_layout *layout) { struct clk *clk; - int num_parents; + unsigned int num_parents; unsigned int irq; const char *parent_names[MASTER_SOURCE_MAX]; const char *name = np->name; struct clk_master_characteristics *characteristics; num_parents = of_clk_get_parent_count(np); - if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) + if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX) return; of_clk_parent_fill(np, parent_names, num_parents); diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 14b270b..b955fb81 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -232,13 +232,13 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, int num; u32 id; struct clk *clk; - int num_parents; + unsigned int num_parents; const char *parent_names[PROG_SOURCE_MAX]; const char *name; struct device_node *progclknp; num_parents = of_clk_get_parent_count(np); - if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX) + if (num_parents == 0 || num_parents > PROG_SOURCE_MAX) return; of_clk_parent_fill(np, parent_names, num_parents); diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index 6f99a53..67b3047 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c @@ -366,11 +366,11 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, { struct clk *clk; const char *parent_names[2]; - int num_parents; + unsigned int num_parents; const char *name = np->name; num_parents = of_clk_get_parent_count(np); - if (num_parents <= 0 || num_parents > 2) + if (num_parents == 0 || num_parents > 2) return; of_clk_parent_fill(np, parent_names, num_parents); @@ -437,7 +437,7 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np, { struct clk *clk; const char *parent_names[2]; - int num_parents; + unsigned int num_parents; const char *name = np->name; num_parents = of_clk_get_parent_count(np); diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c index a7f8501..f525830 100644 --- a/drivers/clk/at91/clk-smd.c +++ b/drivers/clk/at91/clk-smd.c @@ -145,12 +145,12 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, struct at91_pmc *pmc) { struct clk *clk; - int num_parents; + unsigned int num_parents; const char *parent_names[SMD_SOURCE_MAX]; const char *name = np->name; num_parents = of_clk_get_parent_count(np); - if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX) + if (num_parents == 0 || num_parents > SMD_SOURCE_MAX) return; of_clk_parent_fill(np, parent_names, num_parents); diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 8ab8502..be1c7f5 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -373,12 +373,12 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, struct at91_pmc *pmc) { struct clk *clk; - int num_parents; + unsigned int num_parents; const char *parent_names[USB_SOURCE_MAX]; const char *name = np->name; num_parents = of_clk_get_parent_count(np); - if (num_parents <= 0 || num_parents > USB_SOURCE_MAX) + if (num_parents == 0 || num_parents > USB_SOURCE_MAX) return; of_clk_parent_fill(np, parent_names, num_parents); diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 015e687..5747a9d1 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -88,10 +88,23 @@ #define CM_HSMDIV 0x08c #define CM_OTPCTL 0x090 #define CM_OTPDIV 0x094 +#define CM_PCMCTL 0x098 +#define CM_PCMDIV 0x09c #define CM_PWMCTL 0x0a0 #define CM_PWMDIV 0x0a4 +#define CM_SLIMCTL 0x0a8 +#define CM_SLIMDIV 0x0ac #define CM_SMICTL 0x0b0 #define CM_SMIDIV 0x0b4 +/* no definition for 0x0b8 and 0x0bc */ +#define CM_TCNTCTL 0x0c0 +#define CM_TCNTDIV 0x0c4 +#define CM_TECCTL 0x0c8 +#define CM_TECDIV 0x0cc +#define CM_TD0CTL 0x0d0 +#define CM_TD0DIV 0x0d4 +#define CM_TD1CTL 0x0d8 +#define CM_TD1DIV 0x0dc #define CM_TSENSCTL 0x0e0 #define CM_TSENSDIV 0x0e4 #define CM_TIMERCTL 0x0e8 @@ -1060,16 +1073,7 @@ static long bcm2835_pll_divider_round_rate(struct clk_hw *hw, static unsigned long bcm2835_pll_divider_get_rate(struct clk_hw *hw, unsigned long parent_rate) { - 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; - u32 div = cprman_read(cprman, data->a2w_reg); - - div &= (1 << A2W_PLL_DIV_BITS) - 1; - if (div == 0) - div = 256; - - return parent_rate / div; + return clk_divider_ops.recalc_rate(hw, parent_rate); } static void bcm2835_pll_divider_off(struct clk_hw *hw) @@ -1107,13 +1111,15 @@ static int bcm2835_pll_divider_set_rate(struct clk_hw *hw, 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; - u32 cm; - int ret; + u32 cm, div, max_div = 1 << A2W_PLL_DIV_BITS; - ret = clk_divider_ops.set_rate(hw, rate, parent_rate); - if (ret) - return ret; + div = DIV_ROUND_UP_ULL(parent_rate, rate); + + div = min(div, max_div); + if (div == max_div) + div = 0; + cprman_write(cprman, data->a2w_reg, div); cm = cprman_read(cprman, data->cm_reg); cprman_write(cprman, data->cm_reg, cm | data->load_mask); cprman_write(cprman, data->cm_reg, cm & ~data->load_mask); @@ -1428,7 +1434,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, divider->div.reg = cprman->regs + data->a2w_reg; divider->div.shift = A2W_PLL_DIV_SHIFT; divider->div.width = A2W_PLL_DIV_BITS; - divider->div.flags = 0; + divider->div.flags = CLK_DIVIDER_MAX_AT_ZERO; divider->div.lock = &cprman->regs_lock; divider->div.hw.init = &init; divider->div.table = NULL; diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c index 3a228b6..464fdc4 100644 --- a/drivers/clk/bcm/clk-cygnus.c +++ b/drivers/clk/bcm/clk-cygnus.c @@ -268,3 +268,62 @@ static void __init cygnus_asiu_init(struct device_node *node) iproc_asiu_setup(node, asiu_div, asiu_gate, ARRAY_SIZE(asiu_div)); } CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init); + +/* + * AUDIO PLL VCO frequency parameter table + * + * PLL output frequency = ((ndiv_int + ndiv_frac / 2^20) * + * (parent clock rate / pdiv) + * + * On Cygnus, parent is the 25MHz oscillator + */ +static const struct iproc_pll_vco_param audiopll_vco_params[] = { + /* rate (Hz) ndiv_int ndiv_frac pdiv */ + { 1354750204UL, 54, 199238, 1 }, + { 1769470191UL, 70, 816639, 1 }, +}; + +static const struct iproc_pll_ctrl audiopll = { + .flags = IPROC_CLK_PLL_NEEDS_SW_CFG | IPROC_CLK_PLL_HAS_NDIV_FRAC | + IPROC_CLK_PLL_USER_MODE_ON | IPROC_CLK_PLL_RESET_ACTIVE_LOW, + .reset = RESET_VAL(0x5c, 0, 1), + .dig_filter = DF_VAL(0x48, 0, 3, 6, 4, 3, 3), + .sw_ctrl = SW_CTRL_VAL(0x4, 0), + .ndiv_int = REG_VAL(0x8, 0, 10), + .ndiv_frac = REG_VAL(0x8, 10, 20), + .pdiv = REG_VAL(0x44, 0, 4), + .vco_ctrl = VCO_CTRL_VAL(0x0c, 0x10), + .status = REG_VAL(0x54, 0, 1), + .macro_mode = REG_VAL(0x0, 0, 3), +}; + +static const struct iproc_clk_ctrl audiopll_clk[] = { + [BCM_CYGNUS_AUDIOPLL_CH0] = { + .channel = BCM_CYGNUS_AUDIOPLL_CH0, + .flags = IPROC_CLK_AON | + IPROC_CLK_MCLK_DIV_BY_2, + .enable = ENABLE_VAL(0x14, 8, 10, 9), + .mdiv = REG_VAL(0x14, 0, 8), + }, + [BCM_CYGNUS_AUDIOPLL_CH1] = { + .channel = BCM_CYGNUS_AUDIOPLL_CH1, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x18, 8, 10, 9), + .mdiv = REG_VAL(0x18, 0, 8), + }, + [BCM_CYGNUS_AUDIOPLL_CH2] = { + .channel = BCM_CYGNUS_AUDIOPLL_CH2, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x1c, 8, 10, 9), + .mdiv = REG_VAL(0x1c, 0, 8), + }, +}; + +static void __init cygnus_audiopll_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &audiopll, audiopll_vco_params, + ARRAY_SIZE(audiopll_vco_params), audiopll_clk, + ARRAY_SIZE(audiopll_clk)); +} +CLK_OF_DECLARE(cygnus_audiopll, "brcm,cygnus-audiopll", + cygnus_audiopll_clk_init); diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index afd5891..fd492a5d 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -25,6 +25,12 @@ #define PLL_VCO_HIGH_SHIFT 19 #define PLL_VCO_LOW_SHIFT 30 +/* + * PLL MACRO_SELECT modes 0 to 5 choose pre-calculated PLL output frequencies + * from a look-up table. Mode 7 allows user to manipulate PLL clock dividers + */ +#define PLL_USER_MODE 7 + /* number of delay loops waiting for PLL to lock */ #define LOCK_DELAY 100 @@ -215,7 +221,10 @@ static void __pll_put_in_reset(struct iproc_pll *pll) const struct iproc_pll_reset_ctrl *reset = &ctrl->reset; val = readl(pll->control_base + reset->offset); - val &= ~(1 << reset->reset_shift | 1 << reset->p_reset_shift); + if (ctrl->flags & IPROC_CLK_PLL_RESET_ACTIVE_LOW) + val |= BIT(reset->reset_shift) | BIT(reset->p_reset_shift); + else + val &= ~(BIT(reset->reset_shift) | BIT(reset->p_reset_shift)); iproc_pll_write(pll, pll->control_base, reset->offset, val); } @@ -236,7 +245,10 @@ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, iproc_pll_write(pll, pll->control_base, dig_filter->offset, val); val = readl(pll->control_base + reset->offset); - val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift; + if (ctrl->flags & IPROC_CLK_PLL_RESET_ACTIVE_LOW) + val &= ~(BIT(reset->reset_shift) | BIT(reset->p_reset_shift)); + else + val |= BIT(reset->reset_shift) | BIT(reset->p_reset_shift); iproc_pll_write(pll, pll->control_base, reset->offset, val); } @@ -292,6 +304,16 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, /* put PLL in reset */ __pll_put_in_reset(pll); + /* set PLL in user mode before modifying PLL controls */ + if (ctrl->flags & IPROC_CLK_PLL_USER_MODE_ON) { + val = readl(pll->control_base + ctrl->macro_mode.offset); + val &= ~(bit_mask(ctrl->macro_mode.width) << + ctrl->macro_mode.shift); + val |= PLL_USER_MODE << ctrl->macro_mode.shift; + iproc_pll_write(pll, pll->control_base, + ctrl->macro_mode.offset, val); + } + iproc_pll_write(pll, pll->control_base, ctrl->vco_ctrl.u_offset, 0); val = readl(pll->control_base + ctrl->vco_ctrl.l_offset); @@ -505,7 +527,10 @@ static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw, if (mdiv == 0) mdiv = 256; - clk->rate = parent_rate / mdiv; + if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2) + clk->rate = parent_rate / (mdiv * 2); + else + clk->rate = parent_rate / mdiv; return clk->rate; } @@ -543,7 +568,10 @@ static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (rate == 0 || parent_rate == 0) return -EINVAL; - div = DIV_ROUND_UP(parent_rate, rate); + if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2) + div = DIV_ROUND_UP(parent_rate, rate * 2); + else + div = DIV_ROUND_UP(parent_rate, rate); if (div > 256) return -EINVAL; @@ -555,7 +583,10 @@ static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate, val |= div << ctrl->mdiv.shift; } iproc_pll_write(pll, pll->control_base, ctrl->mdiv.offset, val); - clk->rate = parent_rate / div; + if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2) + clk->rate = parent_rate / (div * 2); + else + clk->rate = parent_rate / div; return 0; } diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h index 8988de7..2148b4e 100644 --- a/drivers/clk/bcm/clk-iproc.h +++ b/drivers/clk/bcm/clk-iproc.h @@ -61,6 +61,26 @@ #define IPROC_CLK_PLL_SPLIT_STAT_CTRL BIT(6) /* + * Some PLLs have an additional divide by 2 in master clock calculation; + * MCLK = VCO_freq / (Mdiv * 2). Identify this to let the driver know + * of modified calculations + */ +#define IPROC_CLK_MCLK_DIV_BY_2 BIT(7) + +/* + * Some PLLs provide a look up table for the leaf clock frequencies and + * auto calculates VCO frequency parameters based on the provided leaf + * clock frequencies. They have a user mode that allows the divider + * controls to be determined by the user + */ +#define IPROC_CLK_PLL_USER_MODE_ON BIT(8) + +/* + * Some PLLs have an active low reset + */ +#define IPROC_CLK_PLL_RESET_ACTIVE_LOW BIT(9) + +/* * Parameters for VCO frequency configuration * * VCO frequency = @@ -149,6 +169,7 @@ struct iproc_pll_ctrl { struct iproc_clk_reg_op pdiv; struct iproc_pll_vco_ctrl vco_ctrl; struct iproc_clk_reg_op status; + struct iproc_clk_reg_op macro_mode; }; /* @@ -183,16 +204,16 @@ struct iproc_asiu_div { unsigned int low_width; }; -void __init iproc_armpll_setup(struct device_node *node); -void __init iproc_pll_clk_setup(struct device_node *node, - const struct iproc_pll_ctrl *pll_ctrl, - const struct iproc_pll_vco_param *vco, - unsigned int num_vco_entries, - const struct iproc_clk_ctrl *clk_ctrl, - unsigned int num_clks); -void __init iproc_asiu_setup(struct device_node *node, - const struct iproc_asiu_div *div, - const struct iproc_asiu_gate *gate, - unsigned int num_clks); +void iproc_armpll_setup(struct device_node *node); +void iproc_pll_clk_setup(struct device_node *node, + const struct iproc_pll_ctrl *pll_ctrl, + const struct iproc_pll_vco_param *vco, + unsigned int num_vco_entries, + const struct iproc_clk_ctrl *clk_ctrl, + unsigned int num_clks); +void iproc_asiu_setup(struct device_node *node, + const struct iproc_asiu_div *div, + const struct iproc_asiu_gate *gate, + unsigned int num_clks); #endif /* _CLK_IPROC_H */ diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 3bcd42f..3294db3 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -16,19 +16,8 @@ #include <linux/module.h> #include <linux/err.h> -#define AXI_CLKGEN_V1_REG_UPDATE_ENABLE 0x04 -#define AXI_CLKGEN_V1_REG_CLK_OUT1 0x08 -#define AXI_CLKGEN_V1_REG_CLK_OUT2 0x0c -#define AXI_CLKGEN_V1_REG_CLK_DIV 0x10 -#define AXI_CLKGEN_V1_REG_CLK_FB1 0x14 -#define AXI_CLKGEN_V1_REG_CLK_FB2 0x18 -#define AXI_CLKGEN_V1_REG_LOCK1 0x1c -#define AXI_CLKGEN_V1_REG_LOCK2 0x20 -#define AXI_CLKGEN_V1_REG_LOCK3 0x24 -#define AXI_CLKGEN_V1_REG_FILTER1 0x28 -#define AXI_CLKGEN_V1_REG_FILTER2 0x2c - #define AXI_CLKGEN_V2_REG_RESET 0x40 +#define AXI_CLKGEN_V2_REG_CLKSEL 0x44 #define AXI_CLKGEN_V2_REG_DRP_CNTRL 0x70 #define AXI_CLKGEN_V2_REG_DRP_STATUS 0x74 @@ -51,40 +40,11 @@ #define MMCM_REG_FILTER1 0x4e #define MMCM_REG_FILTER2 0x4f -struct axi_clkgen; - -struct axi_clkgen_mmcm_ops { - void (*enable)(struct axi_clkgen *axi_clkgen, bool enable); - int (*write)(struct axi_clkgen *axi_clkgen, unsigned int reg, - unsigned int val, unsigned int mask); - int (*read)(struct axi_clkgen *axi_clkgen, unsigned int reg, - unsigned int *val); -}; - struct axi_clkgen { void __iomem *base; - const struct axi_clkgen_mmcm_ops *mmcm_ops; struct clk_hw clk_hw; }; -static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen, - bool enable) -{ - axi_clkgen->mmcm_ops->enable(axi_clkgen, enable); -} - -static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen, - unsigned int reg, unsigned int val, unsigned int mask) -{ - return axi_clkgen->mmcm_ops->write(axi_clkgen, reg, val, mask); -} - -static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen, - unsigned int reg, unsigned int *val) -{ - return axi_clkgen->mmcm_ops->read(axi_clkgen, reg, val); -} - static uint32_t axi_clkgen_lookup_filter(unsigned int m) { switch (m) { @@ -207,70 +167,6 @@ static void axi_clkgen_read(struct axi_clkgen *axi_clkgen, *val = readl(axi_clkgen->base + reg); } -static unsigned int axi_clkgen_v1_map_mmcm_reg(unsigned int reg) -{ - switch (reg) { - case MMCM_REG_CLKOUT0_1: - return AXI_CLKGEN_V1_REG_CLK_OUT1; - case MMCM_REG_CLKOUT0_2: - return AXI_CLKGEN_V1_REG_CLK_OUT2; - case MMCM_REG_CLK_FB1: - return AXI_CLKGEN_V1_REG_CLK_FB1; - case MMCM_REG_CLK_FB2: - return AXI_CLKGEN_V1_REG_CLK_FB2; - case MMCM_REG_CLK_DIV: - return AXI_CLKGEN_V1_REG_CLK_DIV; - case MMCM_REG_LOCK1: - return AXI_CLKGEN_V1_REG_LOCK1; - case MMCM_REG_LOCK2: - return AXI_CLKGEN_V1_REG_LOCK2; - case MMCM_REG_LOCK3: - return AXI_CLKGEN_V1_REG_LOCK3; - case MMCM_REG_FILTER1: - return AXI_CLKGEN_V1_REG_FILTER1; - case MMCM_REG_FILTER2: - return AXI_CLKGEN_V1_REG_FILTER2; - default: - return 0; - } -} - -static int axi_clkgen_v1_mmcm_write(struct axi_clkgen *axi_clkgen, - unsigned int reg, unsigned int val, unsigned int mask) -{ - reg = axi_clkgen_v1_map_mmcm_reg(reg); - if (reg == 0) - return -EINVAL; - - axi_clkgen_write(axi_clkgen, reg, val); - - return 0; -} - -static int axi_clkgen_v1_mmcm_read(struct axi_clkgen *axi_clkgen, - unsigned int reg, unsigned int *val) -{ - reg = axi_clkgen_v1_map_mmcm_reg(reg); - if (reg == 0) - return -EINVAL; - - axi_clkgen_read(axi_clkgen, reg, val); - - return 0; -} - -static void axi_clkgen_v1_mmcm_enable(struct axi_clkgen *axi_clkgen, - bool enable) -{ - axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V1_REG_UPDATE_ENABLE, enable); -} - -static const struct axi_clkgen_mmcm_ops axi_clkgen_v1_mmcm_ops = { - .write = axi_clkgen_v1_mmcm_write, - .read = axi_clkgen_v1_mmcm_read, - .enable = axi_clkgen_v1_mmcm_enable, -}; - static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen) { unsigned int timeout = 10000; @@ -286,7 +182,7 @@ static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen) return val & 0xffff; } -static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen, +static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen, unsigned int reg, unsigned int *val) { unsigned int reg_val; @@ -310,7 +206,7 @@ static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen, return 0; } -static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen, +static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen, unsigned int reg, unsigned int val, unsigned int mask) { unsigned int reg_val = 0; @@ -321,7 +217,7 @@ static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen, return ret; if (mask != 0xffff) { - axi_clkgen_v2_mmcm_read(axi_clkgen, reg, ®_val); + axi_clkgen_mmcm_read(axi_clkgen, reg, ®_val); reg_val &= ~mask; } @@ -332,7 +228,7 @@ static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen, return 0; } -static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen, +static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen, bool enable) { unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE; @@ -343,12 +239,6 @@ static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen, axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val); } -static const struct axi_clkgen_mmcm_ops axi_clkgen_v2_mmcm_ops = { - .write = axi_clkgen_v2_mmcm_write, - .read = axi_clkgen_v2_mmcm_read, - .enable = axi_clkgen_v2_mmcm_enable, -}; - static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw) { return container_of(clk_hw, struct axi_clkgen, clk_hw); @@ -438,10 +328,7 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, tmp = (unsigned long long)(parent_rate / d) * m; do_div(tmp, dout); - if (tmp > ULONG_MAX) - return ULONG_MAX; - - return tmp; + return min_t(unsigned long long, tmp, ULONG_MAX); } static int axi_clkgen_enable(struct clk_hw *clk_hw) @@ -460,21 +347,38 @@ static void axi_clkgen_disable(struct clk_hw *clk_hw) axi_clkgen_mmcm_enable(axi_clkgen, false); } +static int axi_clkgen_set_parent(struct clk_hw *clk_hw, u8 index) +{ + struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw); + + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, index); + + return 0; +} + +static u8 axi_clkgen_get_parent(struct clk_hw *clk_hw) +{ + struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw); + unsigned int parent; + + axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, &parent); + + return parent; +} + static const struct clk_ops axi_clkgen_ops = { .recalc_rate = axi_clkgen_recalc_rate, .round_rate = axi_clkgen_round_rate, .set_rate = axi_clkgen_set_rate, .enable = axi_clkgen_enable, .disable = axi_clkgen_disable, + .set_parent = axi_clkgen_set_parent, + .get_parent = axi_clkgen_get_parent, }; static const struct of_device_id axi_clkgen_ids[] = { { - .compatible = "adi,axi-clkgen-1.00.a", - .data = &axi_clkgen_v1_mmcm_ops - }, { .compatible = "adi,axi-clkgen-2.00.a", - .data = &axi_clkgen_v2_mmcm_ops, }, { }, }; @@ -485,10 +389,11 @@ static int axi_clkgen_probe(struct platform_device *pdev) const struct of_device_id *id; struct axi_clkgen *axi_clkgen; struct clk_init_data init; - const char *parent_name; + const char *parent_names[2]; const char *clk_name; struct resource *mem; struct clk *clk; + unsigned int i; if (!pdev->dev.of_node) return -ENODEV; @@ -501,26 +406,29 @@ static int axi_clkgen_probe(struct platform_device *pdev) if (!axi_clkgen) return -ENOMEM; - axi_clkgen->mmcm_ops = id->data; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(axi_clkgen->base)) return PTR_ERR(axi_clkgen->base); - parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0); - if (!parent_name) + init.num_parents = of_clk_get_parent_count(pdev->dev.of_node); + if (init.num_parents < 1 || init.num_parents > 2) return -EINVAL; + for (i = 0; i < init.num_parents; i++) { + parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i); + if (!parent_names[i]) + return -EINVAL; + } + clk_name = pdev->dev.of_node->name; of_property_read_string(pdev->dev.of_node, "clock-output-names", &clk_name); init.name = clk_name; init.ops = &axi_clkgen_ops; - init.flags = CLK_SET_RATE_GATE; - init.parent_names = &parent_name; - init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + init.parent_names = parent_names; axi_clkgen_mmcm_enable(axi_clkgen, false); diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 4735de0..1f903e1f8 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -19,8 +19,6 @@ #include <linux/err.h> #include <linux/slab.h> -#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw) - static u8 clk_composite_get_parent(struct clk_hw *hw) { struct clk_composite *composite = to_clk_composite(hw); diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index ded3ff4..00e035b 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -28,8 +28,6 @@ * parent - fixed parent. No clk_set_parent support */ -#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) - #define div_mask(width) ((1 << (width)) - 1) static unsigned int _get_table_maxdiv(const struct clk_div_table *table, @@ -305,9 +303,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, */ maxdiv = min(ULONG_MAX / rate, maxdiv); - for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) { - if (!_is_valid_div(table, i, flags)) - continue; + for (i = _next_div(table, 0, flags); i <= maxdiv; + i = _next_div(table, i, flags)) { if (rate * i == parent_rate_saved) { /* * It's the most ideal case if the requested rate can be @@ -423,6 +420,12 @@ const struct clk_ops clk_divider_ops = { }; EXPORT_SYMBOL_GPL(clk_divider_ops); +const struct clk_ops clk_divider_ro_ops = { + .recalc_rate = clk_divider_recalc_rate, + .round_rate = clk_divider_round_rate, +}; +EXPORT_SYMBOL_GPL(clk_divider_ro_ops); + static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -446,7 +449,10 @@ static struct clk *_register_divider(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); init.name = name; - init.ops = &clk_divider_ops; + if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) + init.ops = &clk_divider_ro_ops; + else + init.ops = &clk_divider_ops; init.flags = flags | CLK_IS_BASIC; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 83de57a..053448e 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -23,8 +23,6 @@ * parent - fixed parent. No clk_set_parent support */ -#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw) - static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -102,6 +100,19 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, } EXPORT_SYMBOL_GPL(clk_register_fixed_factor); +void clk_unregister_fixed_factor(struct clk *clk) +{ + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + clk_unregister(clk); + kfree(to_clk_fixed_factor(hw)); +} +EXPORT_SYMBOL_GPL(clk_unregister_fixed_factor); + #ifdef CONFIG_OF /** * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index f85ec8d..6858bfc 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -26,8 +26,6 @@ * parent - fixed parent. No clk_set_parent support */ -#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw) - static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -106,6 +104,19 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, } EXPORT_SYMBOL_GPL(clk_register_fixed_rate); +void clk_unregister_fixed_rate(struct clk *clk) +{ + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + clk_unregister(clk); + kfree(to_clk_fixed_rate(hw)); +} +EXPORT_SYMBOL_GPL(clk_unregister_fixed_rate); + #ifdef CONFIG_OF /** * of_fixed_clk_setup() - Setup function for simple fixed rate clock diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 5c4955e..1abcd76 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -16,8 +16,6 @@ #include <linux/slab.h> #include <linux/rational.h> -#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) - static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index de0b322..d0d8ec8 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -26,8 +26,6 @@ * parent - fixed parent. No clk_set_parent support */ -#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) - /* * It works on following logic: * diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 19fed65..08f65ac 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -20,6 +20,8 @@ #include <linux/of_gpio.h> #include <linux/err.h> #include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> /** * DOC: basic gpio gated clock which can be enabled and disabled @@ -31,8 +33,6 @@ * parent - fixed parent. No clk_set_parent support */ -#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) - static int clk_gpio_gate_enable(struct clk_hw *hw) { struct clk_gpio *clk = to_clk_gpio(hw); @@ -201,134 +201,69 @@ struct clk *clk_register_gpio_mux(struct device *dev, const char *name, } EXPORT_SYMBOL_GPL(clk_register_gpio_mux); -#ifdef CONFIG_OF -/** - * clk_register_get() has to be delayed, because -EPROBE_DEFER - * can not be handled properly at of_clk_init() call time. - */ - -struct clk_gpio_delayed_register_data { - const char *gpio_name; - int num_parents; - const char **parent_names; - struct device_node *node; - struct mutex lock; - struct clk *clk; - struct clk *(*clk_register_get)(const char *name, - const char * const *parent_names, u8 num_parents, - unsigned gpio, bool active_low); -}; - -static struct clk *of_clk_gpio_delayed_register_get( - struct of_phandle_args *clkspec, void *_data) +static int gpio_clk_driver_probe(struct platform_device *pdev) { - struct clk_gpio_delayed_register_data *data = _data; - struct clk *clk; + struct device_node *node = pdev->dev.of_node; + const char **parent_names, *gpio_name; + unsigned int num_parents; int gpio; enum of_gpio_flags of_flags; + struct clk *clk; + bool active_low, is_mux; - mutex_lock(&data->lock); + num_parents = of_clk_get_parent_count(node); + if (num_parents) { + parent_names = devm_kcalloc(&pdev->dev, num_parents, + sizeof(char *), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; - if (data->clk) { - mutex_unlock(&data->lock); - return data->clk; + of_clk_parent_fill(node, parent_names, num_parents); + } else { + parent_names = NULL; } - gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0, - &of_flags); + is_mux = of_device_is_compatible(node, "gpio-mux-clock"); + + gpio_name = is_mux ? "select-gpios" : "enable-gpios"; + gpio = of_get_named_gpio_flags(node, gpio_name, 0, &of_flags); if (gpio < 0) { - mutex_unlock(&data->lock); if (gpio == -EPROBE_DEFER) pr_debug("%s: %s: GPIOs not yet available, retry later\n", - data->node->name, __func__); + node->name, __func__); else pr_err("%s: %s: Can't get '%s' DT property\n", - data->node->name, __func__, - data->gpio_name); - return ERR_PTR(gpio); + node->name, __func__, + gpio_name); + return gpio; } - clk = data->clk_register_get(data->node->name, data->parent_names, - data->num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); - if (IS_ERR(clk)) - goto out; - - data->clk = clk; -out: - mutex_unlock(&data->lock); - - return clk; -} - -static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, - const char * const *parent_names, u8 num_parents, - unsigned gpio, bool active_low) -{ - return clk_register_gpio_gate(NULL, name, parent_names ? - parent_names[0] : NULL, gpio, active_low, 0); -} - -static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, - const char * const *parent_names, u8 num_parents, unsigned gpio, - bool active_low) -{ - return clk_register_gpio_mux(NULL, name, parent_names, num_parents, - gpio, active_low, 0); -} - -static void __init of_gpio_clk_setup(struct device_node *node, - const char *gpio_name, - struct clk *(*clk_register_get)(const char *name, - const char * const *parent_names, - u8 num_parents, - unsigned gpio, bool active_low)) -{ - struct clk_gpio_delayed_register_data *data; - const char **parent_names; - int i, num_parents; - - num_parents = of_clk_get_parent_count(node); - if (num_parents < 0) - return; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return; - - if (num_parents) { - parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); - if (!parent_names) { - kfree(data); - return; - } - - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); - } else { - parent_names = NULL; - } + active_low = of_flags & OF_GPIO_ACTIVE_LOW; - data->num_parents = num_parents; - data->parent_names = parent_names; - data->node = node; - data->gpio_name = gpio_name; - data->clk_register_get = clk_register_get; - mutex_init(&data->lock); + if (is_mux) + clk = clk_register_gpio_mux(&pdev->dev, node->name, + parent_names, num_parents, gpio, active_low, 0); + else + clk = clk_register_gpio_gate(&pdev->dev, node->name, + parent_names ? parent_names[0] : NULL, gpio, + active_low, 0); + if (IS_ERR(clk)) + return PTR_ERR(clk); - of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data); + return of_clk_add_provider(node, of_clk_src_simple_get, clk); } -static void __init of_gpio_gate_clk_setup(struct device_node *node) -{ - of_gpio_clk_setup(node, "enable-gpios", - of_clk_gpio_gate_delayed_register_get); -} -CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); +static const struct of_device_id gpio_clk_match_table[] = { + { .compatible = "gpio-mux-clock" }, + { .compatible = "gpio-gate-clock" }, + { } +}; -void __init of_gpio_mux_clk_setup(struct device_node *node) -{ - of_gpio_clk_setup(node, "select-gpios", - of_clk_gpio_mux_delayed_register_get); -} -CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup); -#endif +static struct platform_driver gpio_clk_driver = { + .probe = gpio_clk_driver_probe, + .driver = { + .name = "gpio-clk", + .of_match_table = gpio_clk_match_table, + }, +}; +builtin_platform_driver(gpio_clk_driver); diff --git a/drivers/clk/clk-multiplier.c b/drivers/clk/clk-multiplier.c index fe78065..9e449c7 100644 --- a/drivers/clk/clk-multiplier.c +++ b/drivers/clk/clk-multiplier.c @@ -14,8 +14,6 @@ #include <linux/of.h> #include <linux/slab.h> -#define to_clk_multiplier(_hw) container_of(_hw, struct clk_multiplier, hw) - static unsigned long __get_mult(struct clk_multiplier *mult, unsigned long rate, unsigned long parent_rate) diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 5ed03c8..252188f 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -26,8 +26,6 @@ * parent - parent is adjustable through clk_set_parent */ -#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) - static u8 clk_mux_get_parent(struct clk_hw *hw) { struct clk_mux *mux = to_clk_mux(hw); diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index 8e3039f..9c0b8e6 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c @@ -44,7 +44,7 @@ struct palmas_clock_info { struct clk *clk; struct clk_hw hw; struct palmas *palmas; - struct palmas_clk32k_desc *clk_desc; + const struct palmas_clk32k_desc *clk_desc; int ext_control_pin; }; @@ -125,10 +125,10 @@ static struct clk_ops palmas_clks_ops = { struct palmas_clks_of_match_data { struct clk_init_data init; - struct palmas_clk32k_desc desc; + const struct palmas_clk32k_desc desc; }; -static struct palmas_clks_of_match_data palmas_of_clk32kg = { +static const struct palmas_clks_of_match_data palmas_of_clk32kg = { .init = { .name = "clk32kg", .ops = &palmas_clks_ops, @@ -144,7 +144,7 @@ static struct palmas_clks_of_match_data palmas_of_clk32kg = { }, }; -static struct palmas_clks_of_match_data palmas_of_clk32kgaudio = { +static const struct palmas_clks_of_match_data palmas_of_clk32kgaudio = { .init = { .name = "clk32kgaudio", .ops = &palmas_clks_ops, @@ -240,14 +240,14 @@ static int palmas_clks_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct device_node *node = pdev->dev.of_node; - struct palmas_clks_of_match_data *match_data; - const struct of_device_id *match; + const struct palmas_clks_of_match_data *match_data; struct palmas_clock_info *cinfo; struct clk *clk; int ret; - match = of_match_device(palmas_clks_of_match, &pdev->dev); - match_data = (struct palmas_clks_of_match_data *)match->data; + match_data = of_device_get_match_data(&pdev->dev); + if (!match_data) + return 1; cinfo = devm_kzalloc(&pdev->dev, sizeof(*cinfo), GFP_KERNEL); if (!cinfo) diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index d266299..371150a 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -28,11 +28,6 @@ #include <linux/mfd/samsung/s5m8767.h> #include <linux/mfd/samsung/core.h> -#define s2mps11_name(a) (a->hw.init->name) - -static struct clk **clk_table; -static struct clk_onecell_data clk_data; - enum { S2MPS11_CLK_AP = 0, S2MPS11_CLK_CP, @@ -99,6 +94,7 @@ static struct clk_ops s2mps11_clk_ops = { .recalc_rate = s2mps11_clk_recalc_rate, }; +/* This s2mps11_clks_init tructure is common to s2mps11, s2mps13 and s2mps14 */ static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = { [S2MPS11_CLK_AP] = { .name = "s2mps11_ap", @@ -117,37 +113,6 @@ static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = { }, }; -static struct clk_init_data s2mps13_clks_init[S2MPS11_CLKS_NUM] = { - [S2MPS11_CLK_AP] = { - .name = "s2mps13_ap", - .ops = &s2mps11_clk_ops, - .flags = CLK_IS_ROOT, - }, - [S2MPS11_CLK_CP] = { - .name = "s2mps13_cp", - .ops = &s2mps11_clk_ops, - .flags = CLK_IS_ROOT, - }, - [S2MPS11_CLK_BT] = { - .name = "s2mps13_bt", - .ops = &s2mps11_clk_ops, - .flags = CLK_IS_ROOT, - }, -}; - -static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = { - [S2MPS11_CLK_AP] = { - .name = "s2mps14_ap", - .ops = &s2mps11_clk_ops, - .flags = CLK_IS_ROOT, - }, - [S2MPS11_CLK_BT] = { - .name = "s2mps14_bt", - .ops = &s2mps11_clk_ops, - .flags = CLK_IS_ROOT, - }, -}; - static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev, struct clk_init_data *clks_init) { @@ -164,12 +129,9 @@ static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev, return ERR_PTR(-EINVAL); } - for (i = 0; i < S2MPS11_CLKS_NUM; i++) { - if (!clks_init[i].name) - continue; /* Skip clocks not present in some devices */ + for (i = 0; i < S2MPS11_CLKS_NUM; i++) of_property_read_string_index(clk_np, "clock-output-names", i, &clks_init[i].name); - } return clk_np; } @@ -177,39 +139,38 @@ static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev, static int s2mps11_clk_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct s2mps11_clk *s2mps11_clks, *s2mps11_clk; + struct s2mps11_clk *s2mps11_clks; + struct clk_onecell_data *clk_data; unsigned int s2mps11_reg; - struct clk_init_data *clks_init; int i, ret = 0; + enum sec_device_type hwid = platform_get_device_id(pdev)->driver_data; s2mps11_clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM, - sizeof(*s2mps11_clk), GFP_KERNEL); + sizeof(*s2mps11_clks), GFP_KERNEL); if (!s2mps11_clks) return -ENOMEM; - s2mps11_clk = s2mps11_clks; + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; - clk_table = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM, + clk_data->clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM, sizeof(struct clk *), GFP_KERNEL); - if (!clk_table) + if (!clk_data->clks) return -ENOMEM; - switch(platform_get_device_id(pdev)->driver_data) { + switch (hwid) { case S2MPS11X: s2mps11_reg = S2MPS11_REG_RTC_CTRL; - clks_init = s2mps11_clks_init; break; case S2MPS13X: s2mps11_reg = S2MPS13_REG_RTCCTRL; - clks_init = s2mps13_clks_init; break; case S2MPS14X: s2mps11_reg = S2MPS14_REG_RTCCTRL; - clks_init = s2mps14_clks_init; break; case S5M8767X: s2mps11_reg = S5M8767_REG_CTRL1; - clks_init = s2mps11_clks_init; break; default: dev_err(&pdev->dev, "Invalid device type\n"); @@ -217,46 +178,39 @@ static int s2mps11_clk_probe(struct platform_device *pdev) } /* Store clocks of_node in first element of s2mps11_clks array */ - s2mps11_clks->clk_np = s2mps11_clk_parse_dt(pdev, clks_init); + s2mps11_clks->clk_np = s2mps11_clk_parse_dt(pdev, s2mps11_clks_init); if (IS_ERR(s2mps11_clks->clk_np)) return PTR_ERR(s2mps11_clks->clk_np); - for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) { - if (!clks_init[i].name) + for (i = 0; i < S2MPS11_CLKS_NUM; i++) { + if (i == S2MPS11_CLK_CP && hwid == S2MPS14X) continue; /* Skip clocks not present in some devices */ - s2mps11_clk->iodev = iodev; - s2mps11_clk->hw.init = &clks_init[i]; - s2mps11_clk->mask = 1 << i; - s2mps11_clk->reg = s2mps11_reg; - - s2mps11_clk->clk = devm_clk_register(&pdev->dev, - &s2mps11_clk->hw); - if (IS_ERR(s2mps11_clk->clk)) { + s2mps11_clks[i].iodev = iodev; + s2mps11_clks[i].hw.init = &s2mps11_clks_init[i]; + s2mps11_clks[i].mask = 1 << i; + s2mps11_clks[i].reg = s2mps11_reg; + + s2mps11_clks[i].clk = devm_clk_register(&pdev->dev, + &s2mps11_clks[i].hw); + if (IS_ERR(s2mps11_clks[i].clk)) { dev_err(&pdev->dev, "Fail to register : %s\n", - s2mps11_name(s2mps11_clk)); - ret = PTR_ERR(s2mps11_clk->clk); + s2mps11_clks_init[i].name); + ret = PTR_ERR(s2mps11_clks[i].clk); goto err_reg; } - s2mps11_clk->lookup = clkdev_create(s2mps11_clk->clk, - s2mps11_name(s2mps11_clk), NULL); - if (!s2mps11_clk->lookup) { + s2mps11_clks[i].lookup = clkdev_create(s2mps11_clks[i].clk, + s2mps11_clks_init[i].name, NULL); + if (!s2mps11_clks[i].lookup) { ret = -ENOMEM; goto err_reg; } + clk_data->clks[i] = s2mps11_clks[i].clk; } - for (i = 0; i < S2MPS11_CLKS_NUM; i++) { - /* Skip clocks not present on S2MPS14 */ - if (!clks_init[i].name) - continue; - clk_table[i] = s2mps11_clks[i].clk; - } - - clk_data.clks = clk_table; - clk_data.clk_num = S2MPS11_CLKS_NUM; + clk_data->clk_num = S2MPS11_CLKS_NUM; of_clk_add_provider(s2mps11_clks->clk_np, of_clk_src_onecell_get, - &clk_data); + clk_data); platform_set_drvdata(pdev, s2mps11_clks); diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index cd0f272..89e9ca7 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -299,7 +299,7 @@ static int scpi_clocks_probe(struct platform_device *pdev) /* Add the virtual cpufreq device */ cpufreq_dev = platform_device_register_simple("scpi-cpufreq", -1, NULL, 0); - if (!cpufreq_dev) + if (IS_ERR(cpufreq_dev)) pr_warn("unable to register cpufreq device"); return 0; diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index 37e9288..b0f76a8 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -355,7 +355,7 @@ CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init); #define WM8850_BITS_TO_VAL(m, d1, d2) \ ((((m / 2) - 1) << 16) | ((d1 - 1) << 8) | d2) -static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, +static int vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, u32 *multiplier, u32 *prediv) { unsigned long tclk; @@ -365,7 +365,7 @@ static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, pr_err("%s: requested rate out of range\n", __func__); *multiplier = 0; *prediv = 1; - return; + return -EINVAL; } if (rate <= parent_rate * 31) /* use the prediv to double the resolution */ @@ -379,12 +379,15 @@ static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, if (tclk != rate) pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, tclk); + + return 0; } -static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, +static int wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, u32 *multiplier, u32 *divisor1, u32 *divisor2) { - u32 mul, div1, div2; + u32 mul, div1; + int div2; u32 best_mul, best_div1, best_div2; unsigned long tclk, rate_err, best_err; @@ -403,7 +406,7 @@ static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, *multiplier = mul; *divisor1 = div1; *divisor2 = div2; - return; + return 0; } if (rate_err < best_err) { @@ -414,12 +417,19 @@ static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, } } + if (best_err == (unsigned long)-1) { + pr_warn("%s: impossible rate %lu\n", __func__, rate); + return -EINVAL; + } + /* if we got here, it wasn't an exact match */ pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, rate - best_err); *multiplier = best_mul; *divisor1 = best_div1; *divisor2 = best_div2; + + return 0; } static u32 wm8750_get_filter(u32 parent_rate, u32 divisor1) @@ -449,10 +459,11 @@ static u32 wm8750_get_filter(u32 parent_rate, u32 divisor1) return 0; } -static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate, +static int wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate, u32 *filter, u32 *multiplier, u32 *divisor1, u32 *divisor2) { - u32 mul, div1, div2; + u32 mul; + int div1, div2; u32 best_mul, best_div1, best_div2; unsigned long tclk, rate_err, best_err; @@ -472,7 +483,7 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate, *multiplier = mul; *divisor1 = div1; *divisor2 = div2; - return; + return 0; } if (rate_err < best_err) { @@ -483,6 +494,11 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate, } } + if (best_err == (unsigned long)-1) { + pr_warn("%s: impossible rate %lu\n", __func__, rate); + return -EINVAL; + } + /* if we got here, it wasn't an exact match */ pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, rate - best_err); @@ -491,12 +507,15 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate, *multiplier = best_mul; *divisor1 = best_div1; *divisor2 = best_div2; + + return 0; } -static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate, +static int wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate, u32 *multiplier, u32 *divisor1, u32 *divisor2) { - u32 mul, div1, div2; + u32 mul; + int div1, div2; u32 best_mul, best_div1, best_div2; unsigned long tclk, rate_err, best_err; @@ -516,7 +535,7 @@ static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate, *multiplier = mul; *divisor1 = div1; *divisor2 = div2; - return; + return 0; } if (rate_err < best_err) { @@ -527,6 +546,11 @@ static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate, } } + if (best_err == (unsigned long)-1) { + pr_warn("%s: impossible rate %lu\n", __func__, rate); + return -EINVAL; + } + /* if we got here, it wasn't an exact match */ pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, rate - best_err); @@ -534,6 +558,8 @@ static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate, *multiplier = best_mul; *divisor1 = best_div1; *divisor2 = best_div2; + + return 0; } static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -543,31 +569,39 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, u32 filter, mul, div1, div2; u32 pll_val; unsigned long flags = 0; + int ret; /* sanity check */ switch (pll->type) { case PLL_TYPE_VT8500: - vt8500_find_pll_bits(rate, parent_rate, &mul, &div1); - pll_val = VT8500_BITS_TO_VAL(mul, div1); + ret = vt8500_find_pll_bits(rate, parent_rate, &mul, &div1); + if (!ret) + pll_val = VT8500_BITS_TO_VAL(mul, div1); break; case PLL_TYPE_WM8650: - wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); - pll_val = WM8650_BITS_TO_VAL(mul, div1, div2); + ret = wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); + if (!ret) + pll_val = WM8650_BITS_TO_VAL(mul, div1, div2); break; case PLL_TYPE_WM8750: - wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2); - pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2); + ret = wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2); + if (!ret) + pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2); break; case PLL_TYPE_WM8850: - wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); - pll_val = WM8850_BITS_TO_VAL(mul, div1, div2); + ret = wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); + if (!ret) + pll_val = WM8850_BITS_TO_VAL(mul, div1, div2); break; default: pr_err("%s: invalid pll type\n", __func__); - return 0; + ret = -EINVAL; } + if (ret) + return ret; + spin_lock_irqsave(pll->lock, flags); vt8500_pmc_wait_busy(); @@ -585,28 +619,36 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, struct clk_pll *pll = to_clk_pll(hw); u32 filter, mul, div1, div2; long round_rate; + int ret; switch (pll->type) { case PLL_TYPE_VT8500: - vt8500_find_pll_bits(rate, *prate, &mul, &div1); - round_rate = VT8500_BITS_TO_FREQ(*prate, mul, div1); + ret = vt8500_find_pll_bits(rate, *prate, &mul, &div1); + if (!ret) + round_rate = VT8500_BITS_TO_FREQ(*prate, mul, div1); break; case PLL_TYPE_WM8650: - wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2); - round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2); + ret = wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2); + if (!ret) + round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2); break; case PLL_TYPE_WM8750: - wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2); - round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2); + ret = wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2); + if (!ret) + round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2); break; case PLL_TYPE_WM8850: - wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2); - round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2); + ret = wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2); + if (!ret) + round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2); break; default: - round_rate = 0; + ret = -EINVAL; } + if (ret) + return ret; + return round_rate; } diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index 10224b0..bd7156b 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -29,7 +29,9 @@ #include <linux/of_address.h> /* Register SCU_PCPPLL bit fields */ -#define N_DIV_RD(src) (((src) & 0x000001ff)) +#define N_DIV_RD(src) ((src) & 0x000001ff) +#define SC_N_DIV_RD(src) ((src) & 0x0000007f) +#define SC_OUTDIV2(src) (((src) & 0x00000100) >> 8) /* Register SCU_SOCPLL bit fields */ #define CLKR_RD(src) (((src) & 0x07000000)>>24) @@ -48,7 +50,7 @@ static inline u32 xgene_clk_read(void __iomem *csr) static inline void xgene_clk_write(u32 data, void __iomem *csr) { - return writel_relaxed(data, csr); + writel_relaxed(data, csr); } /* PLL Clock */ @@ -63,6 +65,7 @@ struct xgene_clk_pll { spinlock_t *lock; u32 pll_offset; enum xgene_pll_type type; + int version; }; #define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw) @@ -92,27 +95,37 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw, pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset); - if (pllclk->type == PLL_TYPE_PCP) { - /* - * PLL VCO = Reference clock * NF - * PCP PLL = PLL_VCO / 2 - */ - nout = 2; - fvco = parent_rate * (N_DIV_RD(pll) + 4); + if (pllclk->version <= 1) { + if (pllclk->type == PLL_TYPE_PCP) { + /* + * PLL VCO = Reference clock * NF + * PCP PLL = PLL_VCO / 2 + */ + nout = 2; + fvco = parent_rate * (N_DIV_RD(pll) + 4); + } else { + /* + * Fref = Reference Clock / NREF; + * Fvco = Fref * NFB; + * Fout = Fvco / NOUT; + */ + nref = CLKR_RD(pll) + 1; + nout = CLKOD_RD(pll) + 1; + nfb = CLKF_RD(pll); + fref = parent_rate / nref; + fvco = fref * nfb; + } } else { /* - * Fref = Reference Clock / NREF; - * Fvco = Fref * NFB; - * Fout = Fvco / NOUT; + * fvco = Reference clock * FBDIVC + * PLL freq = fvco / NOUT */ - nref = CLKR_RD(pll) + 1; - nout = CLKOD_RD(pll) + 1; - nfb = CLKF_RD(pll); - fref = parent_rate / nref; - fvco = fref * nfb; + nout = SC_OUTDIV2(pll) ? 2 : 3; + fvco = parent_rate * SC_N_DIV_RD(pll); } - pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw), - fvco / nout, parent_rate); + pr_debug("%s pll recalc rate %ld parent %ld version %d\n", + clk_hw_get_name(hw), fvco / nout, parent_rate, + pllclk->version); return fvco / nout; } @@ -125,7 +138,7 @@ static const struct clk_ops xgene_clk_pll_ops = { static struct clk *xgene_register_clk_pll(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u32 pll_offset, - u32 type, spinlock_t *lock) + u32 type, spinlock_t *lock, int version) { struct xgene_clk_pll *apmclk; struct clk *clk; @@ -144,6 +157,7 @@ static struct clk *xgene_register_clk_pll(struct device *dev, init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; + apmclk->version = version; apmclk->reg = reg; apmclk->lock = lock; apmclk->pll_offset = pll_offset; @@ -160,26 +174,37 @@ static struct clk *xgene_register_clk_pll(struct device *dev, return clk; } +static int xgene_pllclk_version(struct device_node *np) +{ + if (of_device_is_compatible(np, "apm,xgene-socpll-clock")) + return 1; + if (of_device_is_compatible(np, "apm,xgene-pcppll-clock")) + return 1; + return 2; +} + static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type) { - const char *clk_name = np->full_name; - struct clk *clk; - void __iomem *reg; + const char *clk_name = np->full_name; + struct clk *clk; + void __iomem *reg; + int version = xgene_pllclk_version(np); - reg = of_iomap(np, 0); - if (reg == NULL) { - pr_err("Unable to map CSR register for %s\n", np->full_name); - return; - } - 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); - if (!IS_ERR(clk)) { - of_clk_add_provider(np, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, clk_name, NULL); - pr_debug("Add %s clock PLL\n", clk_name); - } + reg = of_iomap(np, 0); + if (reg == NULL) { + pr_err("Unable to map CSR register for %s\n", np->full_name); + return; + } + 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, + version); + if (!IS_ERR(clk)) { + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); + } } static void xgene_socpllclk_init(struct device_node *np) @@ -460,7 +485,7 @@ static void __init xgene_devclk_init(struct device_node *np) rc = of_address_to_resource(np, i, &res); if (rc != 0) { if (i == 0) { - pr_err("no DTS register for %s\n", + pr_err("no DTS register for %s\n", np->full_name); return; } @@ -518,4 +543,8 @@ err: CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init); +CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock", + xgene_socpllclk_init); +CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock", + xgene_pcppllclk_init); CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b4db67a..fb74dc1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -350,13 +350,12 @@ static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core, { if (!core || index >= core->num_parents) return NULL; - else if (!core->parents) - return clk_core_lookup(core->parent_names[index]); - else if (!core->parents[index]) - return core->parents[index] = - clk_core_lookup(core->parent_names[index]); - else - return core->parents[index]; + + if (!core->parents[index]) + core->parents[index] = + clk_core_lookup(core->parent_names[index]); + + return core->parents[index]; } struct clk_hw * @@ -386,7 +385,7 @@ static unsigned long clk_core_get_rate_nolock(struct clk_core *core) ret = core->rate; - if (core->flags & CLK_IS_ROOT) + if (!core->num_parents) goto out; if (!core->parent) @@ -1067,30 +1066,12 @@ static int clk_fetch_parent_index(struct clk_core *core, { int i; - if (!core->parents) { - core->parents = kcalloc(core->num_parents, - sizeof(struct clk *), GFP_KERNEL); - if (!core->parents) - return -ENOMEM; - } - - /* - * find index of new parent clock using cached parent ptrs, - * or if not yet cached, use string name comparison and cache - * them now to avoid future calls to clk_core_lookup. - */ - for (i = 0; i < core->num_parents; i++) { - if (core->parents[i] == parent) - return i; - - if (core->parents[i]) - continue; + if (!parent) + return -EINVAL; - if (!strcmp(core->parent_names[i], parent->name)) { - core->parents[i] = clk_core_lookup(parent->name); + for (i = 0; i < core->num_parents; i++) + if (clk_core_get_parent_by_index(core, i) == parent) return i; - } - } return -EINVAL; } @@ -1677,56 +1658,14 @@ struct clk *clk_get_parent(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_get_parent); -/* - * .get_parent is mandatory for clocks with multiple possible parents. It is - * optional for single-parent clocks. Always call .get_parent if it is - * available and WARN if it is missing for multi-parent clocks. - * - * For single-parent clocks without .get_parent, first check to see if the - * .parents array exists, and if so use it to avoid an expensive tree - * traversal. If .parents does not exist then walk the tree. - */ static struct clk_core *__clk_init_parent(struct clk_core *core) { - struct clk_core *ret = NULL; - u8 index; + u8 index = 0; - /* handle the trivial cases */ + if (core->num_parents > 1 && core->ops->get_parent) + index = core->ops->get_parent(core->hw); - if (!core->num_parents) - goto out; - - if (core->num_parents == 1) { - if (IS_ERR_OR_NULL(core->parent)) - core->parent = clk_core_lookup(core->parent_names[0]); - ret = core->parent; - goto out; - } - - if (!core->ops->get_parent) { - WARN(!core->ops->get_parent, - "%s: multi-parent clocks must implement .get_parent\n", - __func__); - goto out; - } - - /* - * Do our best to cache parent clocks in core->parents. This prevents - * unnecessary and expensive lookups. We don't set core->parent here; - * that is done by the calling function. - */ - - index = core->ops->get_parent(core->hw); - - if (!core->parents) - core->parents = - kcalloc(core->num_parents, sizeof(struct clk *), - GFP_KERNEL); - - ret = clk_core_get_parent_by_index(core, index); - -out: - return ret; + return clk_core_get_parent_by_index(core, index); } static void clk_core_reparent(struct clk_core *core, @@ -1809,13 +1748,13 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) /* try finding the new parent index */ if (parent) { p_index = clk_fetch_parent_index(core, parent); - p_rate = parent->rate; if (p_index < 0) { pr_debug("%s: clk %s can not be parent of clk %s\n", __func__, parent->name, core->name); ret = p_index; goto out; } + p_rate = parent->rate; } /* propagate PRE_RATE_CHANGE notifications */ @@ -1902,6 +1841,10 @@ int clk_set_phase(struct clk *clk, int degrees) clk_prepare_lock(); + /* bail early if nothing to do */ + if (degrees == clk->core->phase) + goto out; + trace_clk_set_phase(clk->core, degrees); if (clk->core->ops->set_phase) @@ -1912,6 +1855,7 @@ int clk_set_phase(struct clk *clk, int degrees) if (!ret) clk->core->phase = degrees; +out: clk_prepare_unlock(); return ret; @@ -2218,7 +2162,7 @@ unlock: * * Dynamically removes a clk and all its child nodes from the * debugfs clk directory if clk->dentry points to debugfs created by - * clk_debug_register in __clk_init. + * clk_debug_register in __clk_core_init. */ static void clk_debug_unregister(struct clk_core *core) { @@ -2303,26 +2247,22 @@ static inline void clk_debug_unregister(struct clk_core *core) #endif /** - * __clk_init - initialize the data structures in a struct clk - * @dev: device initializing this clk, placeholder for now - * @clk: clk being initialized + * __clk_core_init - initialize the data structures in a struct clk_core + * @core: clk_core being initialized * * Initializes the lists in struct clk_core, queries the hardware for the * parent and rate and sets them both. */ -static int __clk_init(struct device *dev, struct clk *clk_user) +static int __clk_core_init(struct clk_core *core) { int i, ret = 0; struct clk_core *orphan; struct hlist_node *tmp2; - struct clk_core *core; unsigned long rate; - if (!clk_user) + if (!core) return -EINVAL; - core = clk_user->core; - clk_prepare_lock(); /* check to see if a clock with this name is already registered */ @@ -2337,22 +2277,29 @@ static int __clk_init(struct device *dev, struct clk *clk_user) if (core->ops->set_rate && !((core->ops->round_rate || core->ops->determine_rate) && core->ops->recalc_rate)) { - pr_warning("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n", - __func__, core->name); + pr_err("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n", + __func__, core->name); ret = -EINVAL; goto out; } if (core->ops->set_parent && !core->ops->get_parent) { - pr_warning("%s: %s must implement .get_parent & .set_parent\n", - __func__, core->name); + pr_err("%s: %s must implement .get_parent & .set_parent\n", + __func__, core->name); + ret = -EINVAL; + goto out; + } + + if (core->num_parents > 1 && !core->ops->get_parent) { + pr_err("%s: %s must implement .get_parent as it has multi parents\n", + __func__, core->name); ret = -EINVAL; goto out; } if (core->ops->set_rate_and_parent && !(core->ops->set_parent && core->ops->set_rate)) { - pr_warn("%s: %s must implement .set_parent & .set_rate\n", + pr_err("%s: %s must implement .set_parent & .set_rate\n", __func__, core->name); ret = -EINVAL; goto out; @@ -2364,37 +2311,12 @@ static int __clk_init(struct device *dev, struct clk *clk_user) "%s: invalid NULL in %s's .parent_names\n", __func__, core->name); - /* - * Allocate an array of struct clk *'s to avoid unnecessary string - * look-ups of clk's possible parents. This can fail for clocks passed - * in to clk_init during early boot; thus any access to core->parents[] - * must always check for a NULL pointer and try to populate it if - * necessary. - * - * If core->parents is not NULL we skip this entire block. This allows - * for clock drivers to statically initialize core->parents. - */ - if (core->num_parents > 1 && !core->parents) { - core->parents = kcalloc(core->num_parents, sizeof(struct clk *), - GFP_KERNEL); - /* - * clk_core_lookup returns NULL for parents that have not been - * clk_init'd; thus any access to clk->parents[] must check - * for a NULL pointer. We can always perform lazy lookups for - * missing parents later on. - */ - if (core->parents) - for (i = 0; i < core->num_parents; i++) - core->parents[i] = - clk_core_lookup(core->parent_names[i]); - } - core->parent = __clk_init_parent(core); /* - * Populate core->parent if parent has already been __clk_init'd. If - * parent has not yet been __clk_init'd then place clk in the orphan - * list. If clk has set the CLK_IS_ROOT flag then place it in the root + * Populate core->parent if parent has already been clk_core_init'd. If + * parent has not yet been clk_core_init'd then place clk in the orphan + * list. If clk doesn't have any parents then place it in the root * clk list. * * Every time a new clk is clk_init'd then we walk the list of orphan @@ -2405,7 +2327,7 @@ static int __clk_init(struct device *dev, struct clk *clk_user) hlist_add_head(&core->child_node, &core->parent->children); core->orphan = core->parent->orphan; - } else if (core->flags & CLK_IS_ROOT) { + } else if (!core->num_parents) { hlist_add_head(&core->child_node, &clk_root_list); core->orphan = false; } else { @@ -2454,24 +2376,15 @@ static int __clk_init(struct device *dev, struct clk *clk_user) core->rate = core->req_rate = rate; /* - * walk the list of orphan clocks and reparent any that are children of - * this clock + * walk the list of orphan clocks and reparent any that newly finds a + * parent. */ hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { - if (orphan->num_parents && orphan->ops->get_parent) { - i = orphan->ops->get_parent(orphan->hw); - if (i >= 0 && i < orphan->num_parents && - !strcmp(core->name, orphan->parent_names[i])) - clk_core_reparent(orphan, core); - continue; - } + struct clk_core *parent = __clk_init_parent(orphan); - for (i = 0; i < orphan->num_parents; i++) - if (!strcmp(core->name, orphan->parent_names[i])) { - clk_core_reparent(orphan, core); - break; - } - } + if (parent) + clk_core_reparent(orphan, parent); + } /* * optional platform-specific magic @@ -2585,21 +2498,31 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) } } + /* avoid unnecessary string look-ups of clk_core's possible parents. */ + core->parents = kcalloc(core->num_parents, sizeof(*core->parents), + GFP_KERNEL); + if (!core->parents) { + ret = -ENOMEM; + goto fail_parents; + }; + INIT_HLIST_HEAD(&core->clks); hw->clk = __clk_create_clk(hw, NULL, NULL); if (IS_ERR(hw->clk)) { ret = PTR_ERR(hw->clk); - goto fail_parent_names_copy; + goto fail_parents; } - ret = __clk_init(dev, hw->clk); + ret = __clk_core_init(core); if (!ret) return hw->clk; __clk_free_clk(hw->clk); hw->clk = NULL; +fail_parents: + kfree(core->parents); fail_parent_names_copy: while (--i >= 0) kfree_const(core->parent_names[i]); @@ -2683,7 +2606,7 @@ void clk_unregister(struct clk *clk) if (clk->core->ops == &clk_nodrv_ops) { pr_err("%s: unregistered clock: %s\n", __func__, clk->core->name); - return; + goto unlock; } /* * Assign empty clock ops for consumers that might still hold @@ -2709,7 +2632,7 @@ void clk_unregister(struct clk *clk) pr_warn("%s: unregistering prepared clock: %s\n", __func__, clk->core->name); kref_put(&clk->core->ref, __clk_release); - +unlock: clk_prepare_unlock(); } EXPORT_SYMBOL_GPL(clk_unregister); @@ -3061,10 +2984,23 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) { return __of_clk_get_from_provider(clkspec, NULL, __func__); } +EXPORT_SYMBOL_GPL(of_clk_get_from_provider); -int of_clk_get_parent_count(struct device_node *np) +/** + * of_clk_get_parent_count() - Count the number of clocks a device node has + * @np: device node to count + * + * Returns: The number of clocks that are possible parents of this node + */ +unsigned int of_clk_get_parent_count(struct device_node *np) { - return of_count_phandle_with_args(np, "clocks", "#clock-cells"); + int count; + + count = of_count_phandle_with_args(np, "clocks", "#clock-cells"); + if (count < 0) + return 0; + + return count; } EXPORT_SYMBOL_GPL(of_clk_get_parent_count); @@ -3214,6 +3150,9 @@ void __init of_clk_init(const struct of_device_id *matches) for_each_matching_node_and_match(np, matches, &match) { struct clock_provider *parent; + if (!of_device_is_available(np)) + continue; + parent = kzalloc(sizeof(*parent), GFP_KERNEL); if (!parent) { list_for_each_entry_safe(clk_provider, next, diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index d71d011..4bf44a2 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -13,7 +13,7 @@ static DEFINE_SPINLOCK(clklock); static void __init h8300_div_clk_setup(struct device_node *node) { - int num_parents; + unsigned int num_parents; struct clk *clk; const char *clk_name = node->name; const char *parent_name; @@ -22,7 +22,7 @@ static void __init h8300_div_clk_setup(struct device_node *node) int offset; num_parents = of_clk_get_parent_count(node); - if (num_parents < 1) { + if (!num_parents) { pr_err("%s: no parent found", clk_name); return; } @@ -34,7 +34,7 @@ static void __init h8300_div_clk_setup(struct device_node *node) } offset = (unsigned long)divcr & 3; offset = (3 - offset) * 8; - divcr = (void *)((unsigned long)divcr & ~3); + divcr = (void __iomem *)((unsigned long)divcr & ~3); parent_name = of_clk_get_parent_name(node, 0); of_property_read_u32(node, "renesas,width", &width); diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index 6cf38dc..c9c2fd5 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -83,7 +83,7 @@ static const struct clk_ops pll_ops = { static void __init h8s2678_pll_clk_setup(struct device_node *node) { - int num_parents; + unsigned int num_parents; struct clk *clk; const char *clk_name = node->name; const char *parent_name; @@ -91,7 +91,7 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node) struct clk_init_data init; num_parents = of_clk_get_parent_count(node); - if (num_parents < 1) { + if (!num_parents) { pr_err("%s: no parent found", clk_name); return; } diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 4bb1bc4..5cc9959 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -38,7 +38,7 @@ struct clk_busy_divider { static inline struct clk_busy_divider *to_clk_busy_divider(struct clk_hw *hw) { - struct clk_divider *div = container_of(hw, struct clk_divider, hw); + struct clk_divider *div = to_clk_divider(hw); return container_of(div, struct clk_busy_divider, div); } @@ -123,7 +123,7 @@ struct clk_busy_mux { static inline struct clk_busy_mux *to_clk_busy_mux(struct clk_hw *hw) { - struct clk_mux *mux = container_of(hw, struct clk_mux, hw); + struct clk_mux *mux = to_clk_mux(hw); return container_of(mux, struct clk_busy_mux, mux); } diff --git a/drivers/clk/imx/clk-fixup-div.c b/drivers/clk/imx/clk-fixup-div.c index 21db020..ce572273 100644 --- a/drivers/clk/imx/clk-fixup-div.c +++ b/drivers/clk/imx/clk-fixup-div.c @@ -15,7 +15,6 @@ #include <linux/slab.h> #include "clk.h" -#define to_clk_div(_hw) container_of(_hw, struct clk_divider, hw) #define div_mask(d) ((1 << (d->width)) - 1) /** @@ -35,7 +34,7 @@ struct clk_fixup_div { static inline struct clk_fixup_div *to_clk_fixup_div(struct clk_hw *hw) { - struct clk_divider *divider = to_clk_div(hw); + struct clk_divider *divider = to_clk_divider(hw); return container_of(divider, struct clk_fixup_div, divider); } @@ -60,7 +59,7 @@ static int clk_fixup_div_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); - struct clk_divider *div = to_clk_div(hw); + struct clk_divider *div = to_clk_divider(hw); unsigned int divider, value; unsigned long flags = 0; u32 val; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index 0d40b35..c9b327e 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -15,8 +15,6 @@ #include <linux/slab.h> #include "clk.h" -#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) - /** * struct clk_fixup_mux - imx integer fixup multiplexer clock * @mux: the parent class diff --git a/drivers/clk/imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c index c12f5f2..3bd9dee 100644 --- a/drivers/clk/imx/clk-gate-exclusive.c +++ b/drivers/clk/imx/clk-gate-exclusive.c @@ -31,7 +31,7 @@ struct clk_gate_exclusive { static int clk_gate_exclusive_enable(struct clk_hw *hw) { - struct clk_gate *gate = container_of(hw, struct clk_gate, hw); + struct clk_gate *gate = to_clk_gate(hw); struct clk_gate_exclusive *exgate = container_of(gate, struct clk_gate_exclusive, gate); u32 val = readl(gate->reg); diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 576bdb7..2a76901 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -25,7 +25,7 @@ static int mtk_cg_bit_is_cleared(struct clk_hw *hw) { - struct mtk_clk_gate *cg = to_clk_gate(hw); + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); u32 val; regmap_read(cg->regmap, cg->sta_ofs, &val); @@ -37,7 +37,7 @@ static int mtk_cg_bit_is_cleared(struct clk_hw *hw) static int mtk_cg_bit_is_set(struct clk_hw *hw) { - struct mtk_clk_gate *cg = to_clk_gate(hw); + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); u32 val; regmap_read(cg->regmap, cg->sta_ofs, &val); @@ -49,14 +49,14 @@ static int mtk_cg_bit_is_set(struct clk_hw *hw) static void mtk_cg_set_bit(struct clk_hw *hw) { - struct mtk_clk_gate *cg = to_clk_gate(hw); + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit)); } static void mtk_cg_clr_bit(struct clk_hw *hw) { - struct mtk_clk_gate *cg = to_clk_gate(hw); + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit)); } diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index 11e25c9..b182160 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -29,7 +29,7 @@ struct mtk_clk_gate { u8 bit; }; -static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw) +static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw) { return container_of(hw, struct mtk_clk_gate, hw); } diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index cf08db6..3528303 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -209,12 +209,14 @@ struct clk * __init mtk_clk_register_composite(const struct mtk_composite *mc, mc->flags); if (IS_ERR(clk)) { - kfree(gate); - kfree(mux); + ret = PTR_ERR(clk); + goto err_out; } return clk; err_out: + kfree(div); + kfree(gate); kfree(mux); return ERR_PTR(ret); diff --git a/drivers/clk/meson/clkc.c b/drivers/clk/meson/clkc.c index c83ae13..d920d41 100644 --- a/drivers/clk/meson/clkc.c +++ b/drivers/clk/meson/clkc.c @@ -198,7 +198,7 @@ meson_clk_register_fixed_rate(const struct clk_conf *clk_conf, } void __init meson_clk_register_clks(const struct clk_conf *clk_confs, - size_t nr_confs, + unsigned int nr_confs, void __iomem *clk_base) { unsigned int i; diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 2769625..eaee8f0 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -11,7 +11,6 @@ config ARMADA_370_CLK bool select MVEBU_CLK_COMMON select MVEBU_CLK_CPU - select MVEBU_CLK_COREDIV config ARMADA_375_CLK bool @@ -29,7 +28,6 @@ config ARMADA_XP_CLK bool select MVEBU_CLK_COMMON select MVEBU_CLK_CPU - select MVEBU_CLK_COREDIV config DOVE_CLK bool diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index 28aac67..daa6ebd 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -199,8 +199,6 @@ struct clk_gating_ctrl { u32 saved_reg; }; -#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) - static struct clk_gating_ctrl *ctrl; static struct clk *clk_gating_get_src( diff --git a/drivers/clk/mvebu/dove-divider.c b/drivers/clk/mvebu/dove-divider.c index d5c5bfa..3e0b52d 100644 --- a/drivers/clk/mvebu/dove-divider.c +++ b/drivers/clk/mvebu/dove-divider.c @@ -247,7 +247,7 @@ static struct clk_onecell_data dove_divider_data = { void __init dove_divider_clk_init(struct device_node *np) { - void *base; + void __iomem *base; base = of_iomap(np, 0); if (WARN_ON(!base)) diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index 99550f2..a2a8d61 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -256,8 +256,6 @@ static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = { 11, 1, 0 }, }; -#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) - static struct clk *clk_muxing_get_src( struct of_phandle_args *clkspec, void *data) { diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c index 049ee27..f75e989 100644 --- a/drivers/clk/mxs/clk-div.c +++ b/drivers/clk/mxs/clk-div.c @@ -33,7 +33,7 @@ struct clk_div { static inline struct clk_div *to_clk_div(struct clk_hw *hw) { - struct clk_divider *divider = container_of(hw, struct clk_divider, hw); + struct clk_divider *divider = to_clk_divider(hw); return container_of(divider, struct clk_div, divider); } diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c index 13aabbb..f7136b9 100644 --- a/drivers/clk/nxp/clk-lpc18xx-ccu.c +++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c @@ -28,8 +28,6 @@ #define CCU_BRANCH_IS_BUS BIT(0) #define CCU_BRANCH_HAVE_DIV2 BIT(1) -#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) - struct lpc18xx_branch_clk_data { const char **name; int num; @@ -222,7 +220,7 @@ static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *bran div->width = 1; div_hw = &div->hw; - div_ops = &clk_divider_ops; + div_ops = &clk_divider_ro_ops; } branch->gate.reg = branch->offset + reg_base; diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index 10dd0fd..48b3a11 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -87,7 +87,7 @@ enum { enum { /* Start from the last defined clock in dt bindings */ - LPC32XX_CLK_ADC_DIV = LPC32XX_CLK_ADC + 1, + LPC32XX_CLK_ADC_DIV = LPC32XX_CLK_HCLK_PLL + 1, LPC32XX_CLK_ADC_RTC, LPC32XX_CLK_TEST1, LPC32XX_CLK_TEST2, @@ -96,7 +96,6 @@ enum { LPC32XX_CLK_OSC, LPC32XX_CLK_SYS, LPC32XX_CLK_PLL397X, - LPC32XX_CLK_HCLK_PLL, LPC32XX_CLK_HCLK_DIV_PERIPH, LPC32XX_CLK_HCLK_DIV, LPC32XX_CLK_HCLK, @@ -1515,7 +1514,7 @@ static void __init lpc32xx_clk_init(struct device_node *np) return; } - for (i = 0; i < LPC32XX_CLK_MAX; i++) { + for (i = 1; i < LPC32XX_CLK_MAX; i++) { clk[i] = lpc32xx_clk_register(i); if (IS_ERR(clk[i])) { pr_err("failed to register %s clock: %ld\n", @@ -1526,9 +1525,6 @@ static void __init lpc32xx_clk_init(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); - /* For 13MHz osc valid output range of PLL is from 156MHz to 266.5MHz */ - clk_set_rate(clk[LPC32XX_CLK_HCLK_PLL], 208000000); - /* Set 48MHz rate of USB PLL clock */ clk_set_rate(clk[LPC32XX_CLK_USB_PLL], 48000000); @@ -1555,7 +1551,7 @@ static void __init lpc32xx_usb_clk_init(struct device_node *np) return; } - for (i = 0; i < LPC32XX_USB_CLK_MAX; i++) { + for (i = 1; i < LPC32XX_USB_CLK_MAX; i++) { usb_clk[i] = lpc32xx_clk_register(i + LPC32XX_CLK_USB_OFFSET); if (IS_ERR(usb_clk[i])) { pr_err("failed to register %s clock: %ld\n", diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index b552ece..95e3b3e 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -28,6 +28,14 @@ config APQ_MMCC_8084 Say Y if you want to support multimedia devices such as display, graphics, video encode/decode, camera, etc. +config IPQ_GCC_4019 + tristate "IPQ4019 Global Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on ipq4019 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2c, USB, SD/eMMC, etc. + config IPQ_GCC_806X tristate "IPQ806x Global Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index dc4280b..2a25f4e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -14,6 +14,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o +obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index bfbb28f..67ce7c1 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -638,7 +638,6 @@ static int clk_rcg_pixel_set_rate(struct clk_hw *hw, unsigned long rate, return ret; src = ns_to_src(&rcg->s, ns); - f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1; for (i = 0; i < num_parents; i++) { if (src == rcg->s.parent_map[i].cfg) { @@ -647,6 +646,9 @@ static int clk_rcg_pixel_set_rate(struct clk_hw *hw, unsigned long rate, } } + /* bypass the pre divider */ + f.pre_div = 1; + /* let us find appropriate m/n values for this */ for (; frac->num; frac++) { request = (rate * frac->den) / frac->num; diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index c112eba..cc8a065 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -185,6 +185,7 @@ int qcom_cc_really_probe(struct platform_device *pdev, struct clk **clks; struct qcom_reset_controller *reset; struct qcom_cc *cc; + struct gdsc_desc *scd; size_t num_clks = desc->num_clks; struct clk_regmap **rclks = desc->clks; @@ -213,7 +214,11 @@ int qcom_cc_really_probe(struct platform_device *pdev, if (ret) return ret; - devm_add_action(dev, qcom_cc_del_clk_provider, pdev->dev.of_node); + ret = devm_add_action_or_reset(dev, qcom_cc_del_clk_provider, + pdev->dev.of_node); + + if (ret) + return ret; reset = &cc->reset; reset->rcdev.of_node = dev->of_node; @@ -227,18 +232,28 @@ int qcom_cc_really_probe(struct platform_device *pdev, if (ret) return ret; - devm_add_action(dev, qcom_cc_reset_unregister, &reset->rcdev); + ret = devm_add_action_or_reset(dev, qcom_cc_reset_unregister, + &reset->rcdev); + + if (ret) + return ret; if (desc->gdscs && desc->num_gdscs) { - ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs, - &reset->rcdev, regmap); + scd = devm_kzalloc(dev, sizeof(*scd), GFP_KERNEL); + if (!scd) + return -ENOMEM; + scd->dev = dev; + scd->scs = desc->gdscs; + scd->num = desc->num_gdscs; + ret = gdsc_register(scd, &reset->rcdev, regmap); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, qcom_cc_gdsc_unregister, + scd); if (ret) return ret; } - devm_add_action(dev, qcom_cc_gdsc_unregister, dev); - - return 0; } EXPORT_SYMBOL_GPL(qcom_cc_really_probe); diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c index cf73e53..070037a 100644 --- a/drivers/clk/qcom/gcc-apq8084.c +++ b/drivers/clk/qcom/gcc-apq8084.c @@ -3587,7 +3587,6 @@ static const struct regmap_config gcc_apq8084_regmap_config = { .val_bits = 32, .max_register = 0x1fc0, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc gcc_apq8084_desc = { diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c new file mode 100644 index 0000000..5428efb --- /dev/null +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -0,0 +1,1354 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 <linux/kernel.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk-provider.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> + +#include <dt-bindings/clock/qcom,gcc-ipq4019.h> + +#include "common.h" +#include "clk-regmap.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" + +enum { + P_XO, + P_FEPLL200, + P_FEPLL500, + P_DDRPLL, + P_FEPLLWCSS2G, + P_FEPLLWCSS5G, + P_FEPLL125DLY, + P_DDRPLLAPSS, +}; + +static struct parent_map gcc_xo_200_500_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 1 }, + { P_FEPLL500, 2 }, +}; + +static const char * const gcc_xo_200_500[] = { + "xo", + "fepll200", + "fepll500", +}; + +static struct parent_map gcc_xo_200_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 1 }, +}; + +static const char * const gcc_xo_200[] = { + "xo", + "fepll200", +}; + +static struct parent_map gcc_xo_200_spi_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 2 }, +}; + +static const char * const gcc_xo_200_spi[] = { + "xo", + "fepll200", +}; + +static struct parent_map gcc_xo_sdcc1_500_map[] = { + { P_XO, 0 }, + { P_DDRPLL, 1 }, + { P_FEPLL500, 2 }, +}; + +static const char * const gcc_xo_sdcc1_500[] = { + "xo", + "ddrpll", + "fepll500", +}; + +static struct parent_map gcc_xo_wcss2g_map[] = { + { P_XO, 0 }, + { P_FEPLLWCSS2G, 1 }, +}; + +static const char * const gcc_xo_wcss2g[] = { + "xo", + "fepllwcss2g", +}; + +static struct parent_map gcc_xo_wcss5g_map[] = { + { P_XO, 0 }, + { P_FEPLLWCSS5G, 1 }, +}; + +static const char * const gcc_xo_wcss5g[] = { + "xo", + "fepllwcss5g", +}; + +static struct parent_map gcc_xo_125_dly_map[] = { + { P_XO, 0 }, + { P_FEPLL125DLY, 1 }, +}; + +static const char * const gcc_xo_125_dly[] = { + "xo", + "fepll125dly", +}; + +static struct parent_map gcc_xo_ddr_500_200_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 3 }, + { P_FEPLL500, 2 }, + { P_DDRPLLAPSS, 1 }, +}; + +static const char * const gcc_xo_ddr_500_200[] = { + "xo", + "fepll200", + "fepll500", + "ddrpllapss", +}; + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } +#define P_XO 0 +#define FE_PLL_200 1 +#define FE_PLL_500 2 +#define DDRC_PLL_666 3 + +#define DDRC_PLL_666_SDCC 1 +#define FE_PLL_125_DLY 1 + +#define FE_PLL_WCSS2G 1 +#define FE_PLL_WCSS5G 1 + +static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(200000000, FE_PLL_200, 1, 0, 0), + { } +}; + +static struct clk_rcg2 audio_clk_src = { + .cmd_rcgr = 0x1b000, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_audio_pwm_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "audio_clk_src", + .parent_names = gcc_xo_200, + .num_parents = 2, + .ops = &clk_rcg2_ops, + + }, +}; + +static struct clk_branch gcc_audio_ahb_clk = { + .halt_reg = 0x1b010, + .clkr = { + .enable_reg = 0x1b010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_audio_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .flags = CLK_SET_RATE_PARENT, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_audio_pwm_clk = { + .halt_reg = 0x1b00C, + .clkr = { + .enable_reg = 0x1b00C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_audio_pwm_clk", + .parent_names = (const char *[]){ + "audio_clk_src", + }, + .flags = CLK_SET_RATE_PARENT, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_2_i2c_apps_clk[] = { + F(19200000, P_XO, 1, 2, 5), + F(24000000, P_XO, 1, 1, 2), + { } +}; + +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x200c, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_i2c_apps_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_i2c_apps_clk_src", + .parent_names = gcc_xo_200, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x2008, + .clkr = { + .enable_reg = 0x2008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup1_i2c_apps_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x3000, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_i2c_apps_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup2_i2c_apps_clk_src", + .parent_names = gcc_xo_200, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x3010, + .clkr = { + .enable_reg = 0x3010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup2_i2c_apps_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_2_spi_apps_clk[] = { + F(960000, P_XO, 12, 1, 4), + F(4800000, P_XO, 1, 1, 10), + F(9600000, P_XO, 1, 1, 5), + F(15000000, P_XO, 1, 1, 3), + F(19200000, P_XO, 1, 2, 5), + F(24000000, P_XO, 1, 1, 2), + F(48000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x2024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_200_spi_map, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_spi_apps_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_spi_apps_clk_src", + .parent_names = gcc_xo_200_spi, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x2004, + .clkr = { + .enable_reg = 0x2004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup1_spi_apps_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x3014, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_spi_apps_clk, + .parent_map = gcc_xo_200_spi_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup2_spi_apps_clk_src", + .parent_names = gcc_xo_200_spi, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x300c, + .clkr = { + .enable_reg = 0x300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup2_spi_apps_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_uart1_2_apps_clk[] = { + F(1843200, FE_PLL_200, 1, 144, 15625), + F(3686400, FE_PLL_200, 1, 288, 15625), + F(7372800, FE_PLL_200, 1, 576, 15625), + F(14745600, FE_PLL_200, 1, 1152, 15625), + F(16000000, FE_PLL_200, 1, 2, 25), + F(24000000, P_XO, 1, 1, 2), + F(32000000, FE_PLL_200, 1, 4, 25), + F(40000000, FE_PLL_200, 1, 1, 5), + F(46400000, FE_PLL_200, 1, 29, 125), + F(48000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x2044, + .mnd_width = 16, + .hid_width = 5, + .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk, + .parent_map = gcc_xo_200_spi_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart1_apps_clk_src", + .parent_names = gcc_xo_200_spi, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x203c, + .clkr = { + .enable_reg = 0x203c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk", + .parent_names = (const char *[]){ + "blsp1_uart1_apps_clk_src", + }, + .flags = CLK_SET_RATE_PARENT, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x3034, + .mnd_width = 16, + .hid_width = 5, + .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk, + .parent_map = gcc_xo_200_spi_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart2_apps_clk_src", + .parent_names = gcc_xo_200_spi, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x302c, + .clkr = { + .enable_reg = 0x302c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk", + .parent_names = (const char *[]){ + "blsp1_uart2_apps_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp_clk[] = { + F(1250000, FE_PLL_200, 1, 16, 0), + F(2500000, FE_PLL_200, 1, 8, 0), + F(5000000, FE_PLL_200, 1, 4, 0), + { } +}; + +static struct clk_rcg2 gp1_clk_src = { + .cmd_rcgr = 0x8004, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_gp_clk, + .parent_map = gcc_xo_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp1_clk_src", + .parent_names = gcc_xo_200, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x8000, + .clkr = { + .enable_reg = 0x8000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_names = (const char *[]){ + "gp1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 gp2_clk_src = { + .cmd_rcgr = 0x9004, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_gp_clk, + .parent_map = gcc_xo_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp2_clk_src", + .parent_names = gcc_xo_200, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x9000, + .clkr = { + .enable_reg = 0x9000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_names = (const char *[]){ + "gp2_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 gp3_clk_src = { + .cmd_rcgr = 0xa004, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_gp_clk, + .parent_map = gcc_xo_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp3_clk_src", + .parent_names = gcc_xo_200, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0xa000, + .clkr = { + .enable_reg = 0xa000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_names = (const char *[]){ + "gp3_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = { + F(144000, P_XO, 1, 3, 240), + F(400000, P_XO, 1, 1, 0), + F(20000000, FE_PLL_500, 1, 1, 25), + F(25000000, FE_PLL_500, 1, 1, 20), + F(50000000, FE_PLL_500, 1, 1, 10), + F(100000000, FE_PLL_500, 1, 1, 5), + F(193000000, DDRC_PLL_666_SDCC, 1, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_apps_clk_src = { + .cmd_rcgr = 0x18004, + .hid_width = 5, + .freq_tbl = ftbl_gcc_sdcc1_apps_clk, + .parent_map = gcc_xo_sdcc1_500_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc1_apps_clk_src", + .parent_names = gcc_xo_sdcc1_500, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_tbl ftbl_gcc_apps_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(200000000, FE_PLL_200, 1, 0, 0), + F(500000000, FE_PLL_500, 1, 0, 0), + F(626000000, DDRC_PLL_666, 1, 0, 0), + { } +}; + +static struct clk_rcg2 apps_clk_src = { + .cmd_rcgr = 0x1900c, + .hid_width = 5, + .freq_tbl = ftbl_gcc_apps_clk, + .parent_map = gcc_xo_ddr_500_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "apps_clk_src", + .parent_names = gcc_xo_ddr_500_200, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_apps_ahb_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(100000000, FE_PLL_200, 2, 0, 0), + { } +}; + +static struct clk_rcg2 apps_ahb_clk_src = { + .cmd_rcgr = 0x19014, + .hid_width = 5, + .parent_map = gcc_xo_200_500_map, + .freq_tbl = ftbl_gcc_apps_ahb_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "apps_ahb_clk_src", + .parent_names = gcc_xo_200_500, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_apss_ahb_clk = { + .halt_reg = 0x19004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_apss_ahb_clk", + .parent_names = (const char *[]){ + "apps_ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x1008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_dcd_xo_clk = { + .halt_reg = 0x2103c, + .clkr = { + .enable_reg = 0x2103c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_dcd_xo_clk", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x1300c, + .clkr = { + .enable_reg = 0x1300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_crypto_ahb_clk = { + .halt_reg = 0x16024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_crypto_axi_clk = { + .halt_reg = 0x16020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_axi_clk", + .parent_names = (const char *[]){ + "fepll125", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_crypto_clk = { + .halt_reg = 0x1601c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_clk", + .parent_names = (const char *[]){ + "fepll125", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ess_clk = { + .halt_reg = 0x12010, + .clkr = { + .enable_reg = 0x12010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ess_clk", + .parent_names = (const char *[]){ + "fephy_125m_dly_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_imem_axi_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "gcc_imem_axi_clk", + .parent_names = (const char *[]){ + "fepll200", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_imem_cfg_ahb_clk = { + .halt_reg = 0xe008, + .clkr = { + .enable_reg = 0xe008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_imem_cfg_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_ahb_clk = { + .halt_reg = 0x1d00c, + .clkr = { + .enable_reg = 0x1d00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_axi_m_clk = { + .halt_reg = 0x1d004, + .clkr = { + .enable_reg = 0x1d004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_axi_m_clk", + .parent_names = (const char *[]){ + "fepll200", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_axi_s_clk = { + .halt_reg = 0x1d008, + .clkr = { + .enable_reg = 0x1d008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_axi_s_clk", + .parent_names = (const char *[]){ + "fepll200", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x13004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "gcc_prng_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_ahb_clk = { + .halt_reg = 0x1c008, + .clkr = { + .enable_reg = 0x1c008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qpic_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_clk = { + .halt_reg = 0x1c004, + .clkr = { + .enable_reg = 0x1c004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qpic_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x18010, + .clkr = { + .enable_reg = 0x18010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x1800c, + .clkr = { + .enable_reg = 0x1800c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_names = (const char *[]){ + "sdcc1_apps_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_tlmm_ahb_clk = { + .halt_reg = 0x5004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tlmm_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb2_master_clk = { + .halt_reg = 0x1e00c, + .clkr = { + .enable_reg = 0x1e00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2_master_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb2_sleep_clk = { + .halt_reg = 0x1e010, + .clkr = { + .enable_reg = 0x1e010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2_sleep_clk", + .parent_names = (const char *[]){ + "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb2_mock_utmi_clk = { + .halt_reg = 0x1e014, + .clkr = { + .enable_reg = 0x1e014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2_mock_utmi_clk", + .parent_names = (const char *[]){ + "usb30_mock_utmi_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = { + F(2000000, FE_PLL_200, 10, 0, 0), + { } +}; + +static struct clk_rcg2 usb30_mock_utmi_clk_src = { + .cmd_rcgr = 0x1e000, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb30_mock_utmi_clk_src", + .parent_names = gcc_xo_200, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_usb3_master_clk = { + .halt_reg = 0x1e028, + .clkr = { + .enable_reg = 0x1e028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_master_clk", + .parent_names = (const char *[]){ + "fepll125", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sleep_clk = { + .halt_reg = 0x1e02C, + .clkr = { + .enable_reg = 0x1e02C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sleep_clk", + .parent_names = (const char *[]){ + "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mock_utmi_clk = { + .halt_reg = 0x1e030, + .clkr = { + .enable_reg = 0x1e030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_mock_utmi_clk", + .parent_names = (const char *[]){ + "usb30_mock_utmi_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_fephy_dly_clk[] = { + F(125000000, FE_PLL_125_DLY, 1, 0, 0), + { } +}; + +static struct clk_rcg2 fephy_125m_dly_clk_src = { + .cmd_rcgr = 0x12000, + .hid_width = 5, + .parent_map = gcc_xo_125_dly_map, + .freq_tbl = ftbl_gcc_fephy_dly_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "fephy_125m_dly_clk_src", + .parent_names = gcc_xo_125_dly, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + + +static const struct freq_tbl ftbl_gcc_wcss2g_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(250000000, FE_PLL_WCSS2G, 1, 0, 0), + { } +}; + +static struct clk_rcg2 wcss2g_clk_src = { + .cmd_rcgr = 0x1f000, + .hid_width = 5, + .freq_tbl = ftbl_gcc_wcss2g_clk, + .parent_map = gcc_xo_wcss2g_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "wcss2g_clk_src", + .parent_names = gcc_xo_wcss2g, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_branch gcc_wcss2g_clk = { + .halt_reg = 0x1f00C, + .clkr = { + .enable_reg = 0x1f00C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss2g_clk", + .parent_names = (const char *[]){ + "wcss2g_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss2g_ref_clk = { + .halt_reg = 0x1f00C, + .clkr = { + .enable_reg = 0x1f00C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss2g_ref_clk", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss2g_rtc_clk = { + .halt_reg = 0x1f010, + .clkr = { + .enable_reg = 0x1f010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss2g_rtc_clk", + .parent_names = (const char *[]){ + "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_wcss5g_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(250000000, FE_PLL_WCSS5G, 1, 0, 0), + { } +}; + +static struct clk_rcg2 wcss5g_clk_src = { + .cmd_rcgr = 0x20000, + .hid_width = 5, + .parent_map = gcc_xo_wcss5g_map, + .freq_tbl = ftbl_gcc_wcss5g_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "wcss5g_clk_src", + .parent_names = gcc_xo_wcss5g, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_wcss5g_clk = { + .halt_reg = 0x2000c, + .clkr = { + .enable_reg = 0x2000c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss5g_clk", + .parent_names = (const char *[]){ + "wcss5g_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss5g_ref_clk = { + .halt_reg = 0x2000c, + .clkr = { + .enable_reg = 0x2000c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss5g_ref_clk", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss5g_rtc_clk = { + .halt_reg = 0x20010, + .clkr = { + .enable_reg = 0x20010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss5g_rtc_clk", + .parent_names = (const char *[]){ + "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap *gcc_ipq4019_clocks[] = { + [AUDIO_CLK_SRC] = &audio_clk_src.clkr, + [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, + [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr, + [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr, + [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr, + [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr, + [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr, + [GCC_USB3_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr, + [GCC_APPS_CLK_SRC] = &apps_clk_src.clkr, + [GCC_APPS_AHB_CLK_SRC] = &apps_ahb_clk_src.clkr, + [GP1_CLK_SRC] = &gp1_clk_src.clkr, + [GP2_CLK_SRC] = &gp2_clk_src.clkr, + [GP3_CLK_SRC] = &gp3_clk_src.clkr, + [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, + [FEPHY_125M_DLY_CLK_SRC] = &fephy_125m_dly_clk_src.clkr, + [WCSS2G_CLK_SRC] = &wcss2g_clk_src.clkr, + [WCSS5G_CLK_SRC] = &wcss5g_clk_src.clkr, + [GCC_APSS_AHB_CLK] = &gcc_apss_ahb_clk.clkr, + [GCC_AUDIO_AHB_CLK] = &gcc_audio_ahb_clk.clkr, + [GCC_AUDIO_PWM_CLK] = &gcc_audio_pwm_clk.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_DCD_XO_CLK] = &gcc_dcd_xo_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CRYPTO_AHB_CLK] = &gcc_crypto_ahb_clk.clkr, + [GCC_CRYPTO_AXI_CLK] = &gcc_crypto_axi_clk.clkr, + [GCC_CRYPTO_CLK] = &gcc_crypto_clk.clkr, + [GCC_ESS_CLK] = &gcc_ess_clk.clkr, + [GCC_IMEM_AXI_CLK] = &gcc_imem_axi_clk.clkr, + [GCC_IMEM_CFG_AHB_CLK] = &gcc_imem_cfg_ahb_clk.clkr, + [GCC_PCIE_AHB_CLK] = &gcc_pcie_ahb_clk.clkr, + [GCC_PCIE_AXI_M_CLK] = &gcc_pcie_axi_m_clk.clkr, + [GCC_PCIE_AXI_S_CLK] = &gcc_pcie_axi_s_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr, + [GCC_QPIC_CLK] = &gcc_qpic_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_TLMM_AHB_CLK] = &gcc_tlmm_ahb_clk.clkr, + [GCC_USB2_MASTER_CLK] = &gcc_usb2_master_clk.clkr, + [GCC_USB2_SLEEP_CLK] = &gcc_usb2_sleep_clk.clkr, + [GCC_USB2_MOCK_UTMI_CLK] = &gcc_usb2_mock_utmi_clk.clkr, + [GCC_USB3_MASTER_CLK] = &gcc_usb3_master_clk.clkr, + [GCC_USB3_SLEEP_CLK] = &gcc_usb3_sleep_clk.clkr, + [GCC_USB3_MOCK_UTMI_CLK] = &gcc_usb3_mock_utmi_clk.clkr, + [GCC_WCSS2G_CLK] = &gcc_wcss2g_clk.clkr, + [GCC_WCSS2G_REF_CLK] = &gcc_wcss2g_ref_clk.clkr, + [GCC_WCSS2G_RTC_CLK] = &gcc_wcss2g_rtc_clk.clkr, + [GCC_WCSS5G_CLK] = &gcc_wcss5g_clk.clkr, + [GCC_WCSS5G_REF_CLK] = &gcc_wcss5g_ref_clk.clkr, + [GCC_WCSS5G_RTC_CLK] = &gcc_wcss5g_rtc_clk.clkr, +}; + +static const struct qcom_reset_map gcc_ipq4019_resets[] = { + [WIFI0_CPU_INIT_RESET] = { 0x1f008, 5 }, + [WIFI0_RADIO_SRIF_RESET] = { 0x1f008, 4 }, + [WIFI0_RADIO_WARM_RESET] = { 0x1f008, 3 }, + [WIFI0_RADIO_COLD_RESET] = { 0x1f008, 2 }, + [WIFI0_CORE_WARM_RESET] = { 0x1f008, 1 }, + [WIFI0_CORE_COLD_RESET] = { 0x1f008, 0 }, + [WIFI1_CPU_INIT_RESET] = { 0x20008, 5 }, + [WIFI1_RADIO_SRIF_RESET] = { 0x20008, 4 }, + [WIFI1_RADIO_WARM_RESET] = { 0x20008, 3 }, + [WIFI1_RADIO_COLD_RESET] = { 0x20008, 2 }, + [WIFI1_CORE_WARM_RESET] = { 0x20008, 1 }, + [WIFI1_CORE_COLD_RESET] = { 0x20008, 0 }, + [USB3_UNIPHY_PHY_ARES] = { 0x1e038, 5 }, + [USB3_HSPHY_POR_ARES] = { 0x1e038, 4 }, + [USB3_HSPHY_S_ARES] = { 0x1e038, 2 }, + [USB2_HSPHY_POR_ARES] = { 0x1e01c, 4 }, + [USB2_HSPHY_S_ARES] = { 0x1e01c, 2 }, + [PCIE_PHY_AHB_ARES] = { 0x1d010, 11 }, + [PCIE_AHB_ARES] = { 0x1d010, 10 }, + [PCIE_PWR_ARES] = { 0x1d010, 9 }, + [PCIE_PIPE_STICKY_ARES] = { 0x1d010, 8 }, + [PCIE_AXI_M_STICKY_ARES] = { 0x1d010, 7 }, + [PCIE_PHY_ARES] = { 0x1d010, 6 }, + [PCIE_PARF_XPU_ARES] = { 0x1d010, 5 }, + [PCIE_AXI_S_XPU_ARES] = { 0x1d010, 4 }, + [PCIE_AXI_M_VMIDMT_ARES] = { 0x1d010, 3 }, + [PCIE_PIPE_ARES] = { 0x1d010, 2 }, + [PCIE_AXI_S_ARES] = { 0x1d010, 1 }, + [PCIE_AXI_M_ARES] = { 0x1d010, 0 }, + [ESS_RESET] = { 0x12008, 0}, + [GCC_BLSP1_BCR] = {0x01000, 0}, + [GCC_BLSP1_QUP1_BCR] = {0x02000, 0}, + [GCC_BLSP1_UART1_BCR] = {0x02038, 0}, + [GCC_BLSP1_QUP2_BCR] = {0x03008, 0}, + [GCC_BLSP1_UART2_BCR] = {0x03028, 0}, + [GCC_BIMC_BCR] = {0x04000, 0}, + [GCC_TLMM_BCR] = {0x05000, 0}, + [GCC_IMEM_BCR] = {0x0E000, 0}, + [GCC_ESS_BCR] = {0x12008, 0}, + [GCC_PRNG_BCR] = {0x13000, 0}, + [GCC_BOOT_ROM_BCR] = {0x13008, 0}, + [GCC_CRYPTO_BCR] = {0x16000, 0}, + [GCC_SDCC1_BCR] = {0x18000, 0}, + [GCC_SEC_CTRL_BCR] = {0x1A000, 0}, + [GCC_AUDIO_BCR] = {0x1B008, 0}, + [GCC_QPIC_BCR] = {0x1C000, 0}, + [GCC_PCIE_BCR] = {0x1D000, 0}, + [GCC_USB2_BCR] = {0x1E008, 0}, + [GCC_USB2_PHY_BCR] = {0x1E018, 0}, + [GCC_USB3_BCR] = {0x1E024, 0}, + [GCC_USB3_PHY_BCR] = {0x1E034, 0}, + [GCC_SYSTEM_NOC_BCR] = {0x21000, 0}, + [GCC_PCNOC_BCR] = {0x2102C, 0}, + [GCC_DCD_BCR] = {0x21038, 0}, + [GCC_SNOC_BUS_TIMEOUT0_BCR] = {0x21064, 0}, + [GCC_SNOC_BUS_TIMEOUT1_BCR] = {0x2106C, 0}, + [GCC_SNOC_BUS_TIMEOUT2_BCR] = {0x21074, 0}, + [GCC_SNOC_BUS_TIMEOUT3_BCR] = {0x2107C, 0}, + [GCC_PCNOC_BUS_TIMEOUT0_BCR] = {0x21084, 0}, + [GCC_PCNOC_BUS_TIMEOUT1_BCR] = {0x2108C, 0}, + [GCC_PCNOC_BUS_TIMEOUT2_BCR] = {0x21094, 0}, + [GCC_PCNOC_BUS_TIMEOUT3_BCR] = {0x2109C, 0}, + [GCC_PCNOC_BUS_TIMEOUT4_BCR] = {0x210A4, 0}, + [GCC_PCNOC_BUS_TIMEOUT5_BCR] = {0x210AC, 0}, + [GCC_PCNOC_BUS_TIMEOUT6_BCR] = {0x210B4, 0}, + [GCC_PCNOC_BUS_TIMEOUT7_BCR] = {0x210BC, 0}, + [GCC_PCNOC_BUS_TIMEOUT8_BCR] = {0x210C4, 0}, + [GCC_PCNOC_BUS_TIMEOUT9_BCR] = {0x210CC, 0}, + [GCC_TCSR_BCR] = {0x22000, 0}, + [GCC_MPM_BCR] = {0x24000, 0}, + [GCC_SPDM_BCR] = {0x25000, 0}, +}; + +static const struct regmap_config gcc_ipq4019_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x2dfff, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_ipq4019_desc = { + .config = &gcc_ipq4019_regmap_config, + .clks = gcc_ipq4019_clocks, + .num_clks = ARRAY_SIZE(gcc_ipq4019_clocks), + .resets = gcc_ipq4019_resets, + .num_resets = ARRAY_SIZE(gcc_ipq4019_resets), +}; + +static const struct of_device_id gcc_ipq4019_match_table[] = { + { .compatible = "qcom,gcc-ipq4019" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table); + +static int gcc_ipq4019_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &gcc_ipq4019_desc); +} + +static struct platform_driver gcc_ipq4019_driver = { + .probe = gcc_ipq4019_probe, + .driver = { + .name = "qcom,gcc-ipq4019", + .owner = THIS_MODULE, + .of_match_table = gcc_ipq4019_match_table, + }, +}; + +static int __init gcc_ipq4019_init(void) +{ + return platform_driver_register(&gcc_ipq4019_driver); +} +core_initcall(gcc_ipq4019_init); + +static void __exit gcc_ipq4019_exit(void) +{ + platform_driver_unregister(&gcc_ipq4019_driver); +} +module_exit(gcc_ipq4019_exit); + +MODULE_ALIAS("platform:gcc-ipq4019"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("QCOM GCC IPQ4019 driver"); diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index b692ae8..dd5402b 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -3005,7 +3005,6 @@ static const struct regmap_config gcc_ipq806x_regmap_config = { .val_bits = 32, .max_register = 0x3e40, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc gcc_ipq806x_desc = { diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index f6a2b14..ad41303 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -2702,7 +2702,6 @@ static const struct regmap_config gcc_msm8660_regmap_config = { .val_bits = 32, .max_register = 0x363c, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc gcc_msm8660_desc = { diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index e3bf09d..9c29080 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -2590,6 +2590,23 @@ static struct clk_branch gcc_mss_cfg_ahb_clk = { }, }; +static struct clk_branch gcc_mss_q6_bimc_axi_clk = { + .halt_reg = 0x49004, + .clkr = { + .enable_reg = 0x49004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_q6_bimc_axi_clk", + .parent_names = (const char *[]){ + "bimc_ddr_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_oxili_ahb_clk = { .halt_reg = 0x59028, .clkr = { @@ -3227,6 +3244,7 @@ static struct clk_regmap *gcc_msm8916_clocks[] = { [GCC_ULTAUDIO_LPAIF_SEC_I2S_CLK] = &gcc_ultaudio_lpaif_sec_i2s_clk.clkr, [GCC_ULTAUDIO_LPAIF_AUX_I2S_CLK] = &gcc_ultaudio_lpaif_aux_i2s_clk.clkr, [GCC_CODEC_DIGCODEC_CLK] = &gcc_codec_digcodec_clk.clkr, + [GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr, }; static struct gdsc *gcc_msm8916_gdscs[] = { @@ -3336,7 +3354,6 @@ static const struct regmap_config gcc_msm8916_regmap_config = { .val_bits = 32, .max_register = 0x80000, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc gcc_msm8916_desc = { diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index f31111e..0a0c1f5 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -2753,7 +2753,7 @@ static struct clk_rcg ce3_src = { }, .freq_tbl = clk_tbl_ce3, .clkr = { - .enable_reg = 0x2c08, + .enable_reg = 0x36c0, .enable_mask = BIT(7), .hw.init = &(struct clk_init_data){ .name = "ce3_src", @@ -2769,7 +2769,7 @@ static struct clk_branch ce3_core_clk = { .halt_reg = 0x2fdc, .halt_bit = 5, .clkr = { - .enable_reg = 0x36c4, + .enable_reg = 0x36cc, .enable_mask = BIT(4), .hw.init = &(struct clk_init_data){ .name = "ce3_core_clk", @@ -3468,7 +3468,6 @@ static const struct regmap_config gcc_msm8960_regmap_config = { .val_bits = 32, .max_register = 0x3660, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct regmap_config gcc_apq8064_regmap_config = { @@ -3477,7 +3476,6 @@ static const struct regmap_config gcc_apq8064_regmap_config = { .val_bits = 32, .max_register = 0x3880, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc gcc_msm8960_desc = { diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index df164d6..335952d 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -2680,7 +2680,6 @@ static const struct regmap_config gcc_msm8974_regmap_config = { .val_bits = 32, .max_register = 0x1fc0, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc gcc_msm8974_desc = { diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 16d7c32..bb8c61f 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -30,6 +30,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "gdsc.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -3059,6 +3060,83 @@ static struct clk_hw *gcc_msm8996_hws[] = { &ufs_ice_core_postdiv_clk_src.hw, }; +static struct gdsc aggre0_noc_gdsc = { + .gdscr = 0x81004, + .gds_hw_ctrl = 0x81028, + .pd = { + .name = "aggre0_noc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_aggre0_noc_gdsc = { + .gdscr = 0x7d024, + .pd = { + .name = "hlos1_vote_aggre0_noc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_lpass_adsp_gdsc = { + .gdscr = 0x7d034, + .pd = { + .name = "hlos1_vote_lpass_adsp", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_lpass_core_gdsc = { + .gdscr = 0x7d038, + .pd = { + .name = "hlos1_vote_lpass_core", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc usb30_gdsc = { + .gdscr = 0xf004, + .pd = { + .name = "usb30", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie0_gdsc = { + .gdscr = 0x6b004, + .pd = { + .name = "pcie0", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie1_gdsc = { + .gdscr = 0x6d004, + .pd = { + .name = "pcie1", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie2_gdsc = { + .gdscr = 0x6e004, + .pd = { + .name = "pcie2", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ufs_gdsc = { + .gdscr = 0x75004, + .pd = { + .name = "ufs", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *gcc_msm8996_clocks[] = { [GPLL0_EARLY] = &gpll0_early.clkr, [GPLL0] = &gpll0.clkr, @@ -3245,6 +3323,18 @@ static struct clk_regmap *gcc_msm8996_clocks[] = { [GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr, }; +static struct gdsc *gcc_msm8996_gdscs[] = { + [AGGRE0_NOC_GDSC] = &aggre0_noc_gdsc, + [HLOS1_VOTE_AGGRE0_NOC_GDSC] = &hlos1_vote_aggre0_noc_gdsc, + [HLOS1_VOTE_LPASS_ADSP_GDSC] = &hlos1_vote_lpass_adsp_gdsc, + [HLOS1_VOTE_LPASS_CORE_GDSC] = &hlos1_vote_lpass_core_gdsc, + [USB30_GDSC] = &usb30_gdsc, + [PCIE0_GDSC] = &pcie0_gdsc, + [PCIE1_GDSC] = &pcie1_gdsc, + [PCIE2_GDSC] = &pcie2_gdsc, + [UFS_GDSC] = &ufs_gdsc, +}; + static const struct qcom_reset_map gcc_msm8996_resets[] = { [GCC_SYSTEM_NOC_BCR] = { 0x4000 }, [GCC_CONFIG_NOC_BCR] = { 0x5000 }, @@ -3363,6 +3453,8 @@ static const struct qcom_cc_desc gcc_msm8996_desc = { .num_clks = ARRAY_SIZE(gcc_msm8996_clocks), .resets = gcc_msm8996_resets, .num_resets = ARRAY_SIZE(gcc_msm8996_resets), + .gdscs = gcc_msm8996_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_msm8996_gdscs), }; static const struct of_device_id gcc_msm8996_match_table[] = { diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index da9fad8..f12d7b2 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/ktime.h> #include <linux/pm_domain.h> #include <linux/regmap.h> #include <linux/reset-controller.h> @@ -42,12 +43,12 @@ #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd) -static int gdsc_is_enabled(struct gdsc *sc) +static int gdsc_is_enabled(struct gdsc *sc, unsigned int reg) { u32 val; int ret; - ret = regmap_read(sc->regmap, sc->gdscr, &val); + ret = regmap_read(sc->regmap, reg, &val); if (ret) return ret; @@ -58,28 +59,46 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en) { int ret; u32 val = en ? 0 : SW_COLLAPSE_MASK; - u32 check = en ? PWR_ON_MASK : 0; - unsigned long timeout; + ktime_t start; + unsigned int status_reg = sc->gdscr; ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val); if (ret) return ret; - timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); - do { - ret = regmap_read(sc->regmap, sc->gdscr, &val); - if (ret) - return ret; + /* If disabling votable gdscs, don't poll on status */ + if ((sc->flags & VOTABLE) && !en) { + /* + * Add a short delay here to ensure that an enable + * right after it was disabled does not put it in an + * unknown state + */ + udelay(TIMEOUT_US); + return 0; + } - if ((val & PWR_ON_MASK) == check) - return 0; - } while (time_before(jiffies, timeout)); + if (sc->gds_hw_ctrl) { + status_reg = sc->gds_hw_ctrl; + /* + * The gds hw controller asserts/de-asserts the status bit soon + * after it receives a power on/off request from a master. + * The controller then takes around 8 xo cycles to start its + * internal state machine and update the status bit. During + * this time, the status bit does not reflect the true status + * of the core. + * Add a delay of 1 us between writing to the SW_COLLAPSE bit + * and polling the status bit. + */ + udelay(1); + } - ret = regmap_read(sc->regmap, sc->gdscr, &val); - if (ret) - return ret; + start = ktime_get(); + do { + if (gdsc_is_enabled(sc, status_reg) == en) + return 0; + } while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US); - if ((val & PWR_ON_MASK) == check) + if (gdsc_is_enabled(sc, status_reg) == en) return 0; return -ETIMEDOUT; @@ -165,6 +184,7 @@ static int gdsc_init(struct gdsc *sc) { u32 mask, val; int on, ret; + unsigned int reg; /* * Disable HW trigger: collapse/restore occur based on registers writes. @@ -185,10 +205,18 @@ static int gdsc_init(struct gdsc *sc) return ret; } - on = gdsc_is_enabled(sc); + reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr; + on = gdsc_is_enabled(sc, reg); if (on < 0) return on; + /* + * Votable GDSCs can be ON due to Vote from other masters. + * If a Votable GDSC is ON, make sure we have a Vote. + */ + if ((sc->flags & VOTABLE) && on) + gdsc_enable(&sc->pd); + if (on || (sc->pwrsts & PWRSTS_RET)) gdsc_force_mem_on(sc); else @@ -201,11 +229,14 @@ static int gdsc_init(struct gdsc *sc) return 0; } -int gdsc_register(struct device *dev, struct gdsc **scs, size_t num, +int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *rcdev, struct regmap *regmap) { int i, ret; struct genpd_onecell_data *data; + struct device *dev = desc->dev; + struct gdsc **scs = desc->scs; + size_t num = desc->num; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -228,10 +259,30 @@ int gdsc_register(struct device *dev, struct gdsc **scs, size_t num, data->domains[i] = &scs[i]->pd; } + /* Add subdomains */ + for (i = 0; i < num; i++) { + if (!scs[i]) + continue; + if (scs[i]->parent) + pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd); + } + return of_genpd_add_provider_onecell(dev->of_node, data); } -void gdsc_unregister(struct device *dev) +void gdsc_unregister(struct gdsc_desc *desc) { + int i; + struct device *dev = desc->dev; + struct gdsc **scs = desc->scs; + size_t num = desc->num; + + /* Remove subdomains */ + for (i = 0; i < num; i++) { + if (!scs[i]) + continue; + if (scs[i]->parent) + pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd); + } of_genpd_del_provider(dev->of_node); } diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 5ded268..3bf497c 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -20,18 +20,12 @@ struct regmap; struct reset_controller_dev; -/* Powerdomain allowable state bitfields */ -#define PWRSTS_OFF BIT(0) -#define PWRSTS_RET BIT(1) -#define PWRSTS_ON BIT(2) -#define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON) -#define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) - /** * struct gdsc - Globally Distributed Switch Controller * @pd: generic power domain * @regmap: regmap for MMIO accesses * @gdscr: gsdc control register + * @gds_hw_ctrl: gds_hw_ctrl register * @cxcs: offsets of branch registers to toggle mem/periph bits in * @cxc_count: number of @cxcs * @pwrsts: Possible powerdomain power states @@ -41,28 +35,44 @@ struct reset_controller_dev; */ struct gdsc { struct generic_pm_domain pd; + struct generic_pm_domain *parent; struct regmap *regmap; unsigned int gdscr; + unsigned int gds_hw_ctrl; unsigned int *cxcs; unsigned int cxc_count; const u8 pwrsts; +/* Powerdomain allowable state bitfields */ +#define PWRSTS_OFF BIT(0) +#define PWRSTS_RET BIT(1) +#define PWRSTS_ON BIT(2) +#define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON) +#define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) + const u8 flags; +#define VOTABLE BIT(0) struct reset_controller_dev *rcdev; unsigned int *resets; unsigned int reset_count; }; +struct gdsc_desc { + struct device *dev; + struct gdsc **scs; + size_t num; +}; + #ifdef CONFIG_QCOM_GDSC -int gdsc_register(struct device *, struct gdsc **, size_t n, - struct reset_controller_dev *, struct regmap *); -void gdsc_unregister(struct device *); +int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *, + struct regmap *); +void gdsc_unregister(struct gdsc_desc *desc); #else -static inline int gdsc_register(struct device *d, struct gdsc **g, size_t n, +static inline int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *rcdev, struct regmap *r) { return -ENOSYS; } -static inline void gdsc_unregister(struct device *d) {}; +static inline void gdsc_unregister(struct gdsc_desc *desc) {}; #endif /* CONFIG_QCOM_GDSC */ #endif /* __QCOM_GDSC_H__ */ diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c index 62e79fa..db3998e 100644 --- a/drivers/clk/qcom/lcc-ipq806x.c +++ b/drivers/clk/qcom/lcc-ipq806x.c @@ -419,7 +419,6 @@ static const struct regmap_config lcc_ipq806x_regmap_config = { .val_bits = 32, .max_register = 0xfc, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc lcc_ipq806x_desc = { diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c index bf95bb0..4fcf9d1 100644 --- a/drivers/clk/qcom/lcc-msm8960.c +++ b/drivers/clk/qcom/lcc-msm8960.c @@ -524,7 +524,6 @@ static const struct regmap_config lcc_msm8960_regmap_config = { .val_bits = 32, .max_register = 0xfc, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc lcc_msm8960_desc = { diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 1e703fd..30777f9 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -3368,7 +3368,6 @@ static const struct regmap_config mmcc_apq8084_regmap_config = { .val_bits = 32, .max_register = 0x5104, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc mmcc_apq8084_desc = { diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index d73a048..00e3619 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -3029,7 +3029,6 @@ static const struct regmap_config mmcc_msm8960_regmap_config = { .val_bits = 32, .max_register = 0x334, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct regmap_config mmcc_apq8064_regmap_config = { @@ -3038,7 +3037,6 @@ static const struct regmap_config mmcc_apq8064_regmap_config = { .val_bits = 32, .max_register = 0x350, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc mmcc_msm8960_desc = { diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index bbe28ed..715e7cd 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -2400,6 +2400,7 @@ static struct gdsc oxilicx_gdsc = { .pd = { .name = "oxilicx", }, + .parent = &oxili_gdsc.pd, .pwrsts = PWRSTS_OFF_ON, }; @@ -2594,7 +2595,6 @@ static const struct regmap_config mmcc_msm8974_regmap_config = { .val_bits = 32, .max_register = 0x5104, .fast_io = true, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; static const struct qcom_cc_desc mmcc_msm8974_desc = { @@ -2616,7 +2616,6 @@ MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table); static int mmcc_msm8974_probe(struct platform_device *pdev) { struct regmap *regmap; - int ret; regmap = qcom_cc_map(pdev, &mmcc_msm8974_desc); if (IS_ERR(regmap)) @@ -2625,22 +2624,11 @@ static int mmcc_msm8974_probe(struct platform_device *pdev) clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); - ret = qcom_cc_really_probe(pdev, &mmcc_msm8974_desc, regmap); - if (ret) - return ret; - - return pm_genpd_add_subdomain(&oxili_gdsc.pd, &oxilicx_gdsc.pd); -} - -static int mmcc_msm8974_remove(struct platform_device *pdev) -{ - pm_genpd_remove_subdomain(&oxili_gdsc.pd, &oxilicx_gdsc.pd); - return 0; + return qcom_cc_really_probe(pdev, &mmcc_msm8974_desc, regmap); } static struct platform_driver mmcc_msm8974_driver = { .probe = mmcc_msm8974_probe, - .remove = mmcc_msm8974_remove, .driver = { .name = "mmcc-msm8974", .of_match_table = mmcc_msm8974_match_table, diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 064f3ea..6df7ff3 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -32,6 +32,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "gdsc.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -2917,6 +2918,144 @@ static struct clk_hw *mmcc_msm8996_hws[] = { &gpll0_div.hw, }; +static struct gdsc mmagic_video_gdsc = { + .gdscr = 0x119c, + .gds_hw_ctrl = 0x120c, + .pd = { + .name = "mmagic_video", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc mmagic_mdss_gdsc = { + .gdscr = 0x247c, + .gds_hw_ctrl = 0x2480, + .pd = { + .name = "mmagic_mdss", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc mmagic_camss_gdsc = { + .gdscr = 0x3c4c, + .gds_hw_ctrl = 0x3c50, + .pd = { + .name = "mmagic_camss", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc venus_gdsc = { + .gdscr = 0x1024, + .cxcs = (unsigned int []){ 0x1028, 0x1034, 0x1038 }, + .cxc_count = 3, + .pd = { + .name = "venus", + }, + .parent = &mmagic_video_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc venus_core0_gdsc = { + .gdscr = 0x1040, + .cxcs = (unsigned int []){ 0x1048 }, + .cxc_count = 1, + .pd = { + .name = "venus_core0", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc venus_core1_gdsc = { + .gdscr = 0x1044, + .cxcs = (unsigned int []){ 0x104c }, + .cxc_count = 1, + .pd = { + .name = "venus_core1", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc camss_gdsc = { + .gdscr = 0x34a0, + .cxcs = (unsigned int []){ 0x36bc, 0x36c4 }, + .cxc_count = 2, + .pd = { + .name = "camss", + }, + .parent = &mmagic_camss_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc vfe0_gdsc = { + .gdscr = 0x3664, + .cxcs = (unsigned int []){ 0x36a8 }, + .cxc_count = 1, + .pd = { + .name = "vfe0", + }, + .parent = &camss_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc vfe1_gdsc = { + .gdscr = 0x3674, + .cxcs = (unsigned int []){ 0x36ac }, + .cxc_count = 1, + .pd = { + .name = "vfe0", + }, + .parent = &camss_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc jpeg_gdsc = { + .gdscr = 0x35a4, + .cxcs = (unsigned int []){ 0x35a8, 0x35b0, 0x35c0, 0x35b8 }, + .cxc_count = 4, + .pd = { + .name = "jpeg", + }, + .parent = &camss_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc cpp_gdsc = { + .gdscr = 0x36d4, + .cxcs = (unsigned int []){ 0x36b0 }, + .cxc_count = 1, + .pd = { + .name = "cpp", + }, + .parent = &camss_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc fd_gdsc = { + .gdscr = 0x3b64, + .cxcs = (unsigned int []){ 0x3b68, 0x3b6c }, + .cxc_count = 2, + .pd = { + .name = "fd", + }, + .parent = &camss_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc mdss_gdsc = { + .gdscr = 0x2304, + .cxcs = (unsigned int []){ 0x2310, 0x231c }, + .cxc_count = 2, + .pd = { + .name = "mdss", + }, + .parent = &mmagic_mdss_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *mmcc_msm8996_clocks[] = { [MMPLL0_EARLY] = &mmpll0_early.clkr, [MMPLL0_PLL] = &mmpll0.clkr, @@ -3093,6 +3232,22 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = { [FD_AHB_CLK] = &fd_ahb_clk.clkr, }; +static struct gdsc *mmcc_msm8996_gdscs[] = { + [MMAGIC_VIDEO_GDSC] = &mmagic_video_gdsc, + [MMAGIC_MDSS_GDSC] = &mmagic_mdss_gdsc, + [MMAGIC_CAMSS_GDSC] = &mmagic_camss_gdsc, + [VENUS_GDSC] = &venus_gdsc, + [VENUS_CORE0_GDSC] = &venus_core0_gdsc, + [VENUS_CORE1_GDSC] = &venus_core1_gdsc, + [CAMSS_GDSC] = &camss_gdsc, + [VFE0_GDSC] = &vfe0_gdsc, + [VFE1_GDSC] = &vfe1_gdsc, + [JPEG_GDSC] = &jpeg_gdsc, + [CPP_GDSC] = &cpp_gdsc, + [FD_GDSC] = &fd_gdsc, + [MDSS_GDSC] = &mdss_gdsc, +}; + static const struct qcom_reset_map mmcc_msm8996_resets[] = { [MMAGICAHB_BCR] = { 0x5020 }, [MMAGIC_CFG_BCR] = { 0x5050 }, @@ -3170,6 +3325,8 @@ static const struct qcom_cc_desc mmcc_msm8996_desc = { .num_clks = ARRAY_SIZE(mmcc_msm8996_clocks), .resets = mmcc_msm8996_resets, .num_resets = ARRAY_SIZE(mmcc_msm8996_resets), + .gdscs = mmcc_msm8996_gdscs, + .num_gdscs = ARRAY_SIZE(mmcc_msm8996_gdscs), }; static const struct of_device_id mmcc_msm8996_match_table[] = { diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c index ebce980..0703c8f 100644 --- a/drivers/clk/rockchip/clk-rk3036.c +++ b/drivers/clk/rockchip/clk-rk3036.c @@ -133,7 +133,7 @@ PNAME(mux_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" }; PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" }; PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; -PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" }; +PNAME(mux_mac_p) = { "mac_pll_src", "rmii_clkin" }; PNAME(mux_dclk_p) = { "dclk_lcdc", "dclk_cru" }; static struct rockchip_pll_clock rk3036_pll_clks[] __initdata = { @@ -177,6 +177,8 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { GATE(0, "gpll_armclk", "gpll", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(0), 6, GFLAGS), + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + /* * Clock-Architecture Diagram 2 */ @@ -187,6 +189,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { RK2928_CLKGATE_CON(0), 8, GFLAGS), COMPOSITE_NOGATE(0, "ddrphy2x", mux_ddrphy_p, CLK_IGNORE_UNUSED, RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + FACTOR(0, "ddrphy", "ddrphy2x", 0, 1, 2), COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, @@ -224,16 +227,16 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { RK2928_CLKGATE_CON(2), 2, GFLAGS), COMPOSITE_NODIV(SCLK_TIMER0, "sclk_timer0", mux_timer_p, CLK_IGNORE_UNUSED, - RK2928_CLKSEL_CON(2), 4, 1, DFLAGS, + RK2928_CLKSEL_CON(2), 4, 1, MFLAGS, RK2928_CLKGATE_CON(1), 0, GFLAGS), COMPOSITE_NODIV(SCLK_TIMER1, "sclk_timer1", mux_timer_p, CLK_IGNORE_UNUSED, - RK2928_CLKSEL_CON(2), 5, 1, DFLAGS, + RK2928_CLKSEL_CON(2), 5, 1, MFLAGS, RK2928_CLKGATE_CON(1), 1, GFLAGS), COMPOSITE_NODIV(SCLK_TIMER2, "sclk_timer2", mux_timer_p, CLK_IGNORE_UNUSED, - RK2928_CLKSEL_CON(2), 6, 1, DFLAGS, + RK2928_CLKSEL_CON(2), 6, 1, MFLAGS, RK2928_CLKGATE_CON(2), 4, GFLAGS), COMPOSITE_NODIV(SCLK_TIMER3, "sclk_timer3", mux_timer_p, CLK_IGNORE_UNUSED, - RK2928_CLKSEL_CON(2), 7, 1, DFLAGS, + RK2928_CLKSEL_CON(2), 7, 1, MFLAGS, RK2928_CLKGATE_CON(2), 5, GFLAGS), MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0, @@ -242,11 +245,11 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 8, GFLAGS), COMPOSITE_NOMUX(0, "uart1_src", "uart_pll_clk", 0, - RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, - RK2928_CLKGATE_CON(1), 8, GFLAGS), + RK2928_CLKSEL_CON(14), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(1), 10, GFLAGS), COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0, - RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, - RK2928_CLKGATE_CON(1), 8, GFLAGS), + RK2928_CLKSEL_CON(15), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(1), 12, GFLAGS), COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(17), 0, RK2928_CLKGATE_CON(1), 9, GFLAGS, @@ -263,6 +266,8 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0, RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, RK2928_CLKGATE_CON(3), 11, GFLAGS), + FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4, + RK2928_CLKGATE_CON(3), 12, GFLAGS), COMPOSITE(0, "aclk_hvec", mux_pll_src_3plls_p, 0, RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS, @@ -279,13 +284,13 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { RK2928_CLKGATE_CON(3), 2, GFLAGS), COMPOSITE_NODIV(0, "sclk_sdmmc_src", mux_mmc_src_p, 0, - RK2928_CLKSEL_CON(12), 8, 2, DFLAGS, + RK2928_CLKSEL_CON(12), 8, 2, MFLAGS, RK2928_CLKGATE_CON(2), 11, GFLAGS), DIV(SCLK_SDMMC, "sclk_sdmmc", "sclk_sdmmc_src", 0, RK2928_CLKSEL_CON(11), 0, 7, DFLAGS), COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0, - RK2928_CLKSEL_CON(12), 10, 2, DFLAGS, + RK2928_CLKSEL_CON(12), 10, 2, MFLAGS, RK2928_CLKGATE_CON(2), 13, GFLAGS), DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0, RK2928_CLKSEL_CON(11), 8, 7, DFLAGS), @@ -344,13 +349,14 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { RK2928_CLKGATE_CON(10), 5, GFLAGS), COMPOSITE_NOGATE(0, "mac_pll_src", mux_pll_src_3plls_p, 0, - RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 4, 5, DFLAGS), + RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 9, 5, DFLAGS), MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(21), 3, 1, MFLAGS), COMPOSITE_NOMUX(SCLK_MAC, "mac_clk", "mac_clk_ref", 0, - RK2928_CLKSEL_CON(21), 9, 5, DFLAGS, + RK2928_CLKSEL_CON(21), 4, 5, DFLAGS, RK2928_CLKGATE_CON(2), 6, GFLAGS), + FACTOR(0, "sclk_macref_out", "hclk_peri_src", 0, 1, 2), MUX(SCLK_HDMI, "dclk_hdmi", mux_dclk_p, 0, RK2928_CLKSEL_CON(31), 0, 1, MFLAGS), @@ -376,11 +382,9 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { GATE(ACLK_VIO, "aclk_vio", "aclk_disp1_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(6), 13, GFLAGS), GATE(ACLK_LCDC, "aclk_lcdc", "aclk_disp1_pre", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), - GATE(HCLK_VIO_BUS, "hclk_vio_bus", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(6), 12, GFLAGS), + GATE(HCLK_VIO_BUS, "hclk_vio_bus", "hclk_disp_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(6), 12, GFLAGS), GATE(HCLK_LCDC, "hclk_lcdc", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS), - /* hclk_video gates */ - GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(3), 12, GFLAGS), /* xin24m gates */ GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK2928_CLKGATE_CON(10), 0, GFLAGS), @@ -444,34 +448,11 @@ static void __init rk3036_clk_init(struct device_node *np) rockchip_clk_init(np, reg_base, CLK_NR_CLKS); - /* xin12m is created by an cru-internal divider */ - clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock xin12m: %ld\n", - __func__, PTR_ERR(clk)); - 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)); - clk = clk_register_fixed_factor(NULL, "ddrphy", "ddrphy2x", 0, 1, 2); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock ddrphy: %ld\n", - __func__, PTR_ERR(clk)); - - clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre", - "aclk_vcodec", 0, 1, 4); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n", - __func__, PTR_ERR(clk)); - - clk = clk_register_fixed_factor(NULL, "sclk_macref_out", - "hclk_peri_src", 0, 1, 2); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock sclk_macref_out: %ld\n", - __func__, PTR_ERR(clk)); - rockchip_clk_register_plls(rk3036_pll_clks, ARRAY_SIZE(rk3036_pll_clks), RK3036_GRF_SOC_STATUS0); diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 7f7444cb..40bab39 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -339,13 +339,15 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { INVERTER(0, "pclk_cif0", "pclkin_cif0", RK2928_CLKSEL_CON(30), 8, IFLAGS), + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + /* * the 480m are generated inside the usb block from these clocks, * but they are also a source for the hsicphy clock. */ - GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", CLK_IGNORE_UNUSED, + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin24m", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(1), 5, GFLAGS), - GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", CLK_IGNORE_UNUSED, + GATE(SCLK_OTGPHY1, "sclk_otgphy1", "xin24m", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(1), 6, GFLAGS), COMPOSITE(0, "mac_src", mux_mac_p, 0, @@ -605,7 +607,7 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { GATE(SCLK_TIMER2, "timer2", "xin24m", 0, RK2928_CLKGATE_CON(3), 2, GFLAGS), - COMPOSITE_NOMUX(0, "sclk_tsadc", "xin24m", 0, + COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin24m", 0, RK2928_CLKSEL_CON(34), 0, 16, DFLAGS, RK2928_CLKGATE_CON(2), 15, GFLAGS), @@ -662,11 +664,11 @@ static struct clk_div_table div_rk3188_aclk_core_t[] = { { /* sentinel */ }, }; -PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1", +PNAME(mux_hsicphy_p) = { "sclk_otgphy0_480m", "sclk_otgphy1_480m", "gpll", "cpll" }; static struct rockchip_clk_branch rk3188_i2s0_fracmux __initdata = - MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, + MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(3), 8, 2, MFLAGS); static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { @@ -722,7 +724,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0, RK2928_CLKSEL_CON(3), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 9, GFLAGS), - COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0, + COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(7), 0, RK2928_CLKGATE_CON(0), 10, GFLAGS, &rk3188_i2s0_fracmux), @@ -748,12 +750,12 @@ static const char *const rk3188_critical_clocks[] __initconst = { "hclk_peri", "pclk_cpu", "pclk_peri", + "hclk_cpubus" }; static void __init rk3188_common_clk_init(struct device_node *np) { void __iomem *reg_base; - struct clk *clk; reg_base = of_iomap(np, 0); if (!reg_base) { @@ -763,17 +765,6 @@ static void __init rk3188_common_clk_init(struct device_node *np) rockchip_clk_init(np, reg_base, CLK_NR_CLKS); - /* xin12m is created by an cru-internal divider */ - clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock xin12m: %ld\n", - __func__, PTR_ERR(clk)); - - 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_branches(common_clk_branches, ARRAY_SIZE(common_clk_branches)); diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index 981a502..c515915 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -187,7 +187,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { RK2928_CLKGATE_CON(7), 1, GFLAGS), GATE(0, "ddrc", "ddrphy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 5, GFLAGS), - GATE(0, "ddrphy", "ddrphy_pre", CLK_IGNORE_UNUSED, + FACTOR_GATE(0, "ddrphy", "ddrphy4x", CLK_IGNORE_UNUSED, 1, 4, RK2928_CLKGATE_CON(7), 0, GFLAGS), /* PD_CORE */ @@ -240,13 +240,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { COMPOSITE(0, "aclk_vpu_pre", mux_pll_src_4plls_p, 0, RK2928_CLKSEL_CON(32), 5, 2, MFLAGS, 0, 5, DFLAGS, RK2928_CLKGATE_CON(3), 11, GFLAGS), - GATE(0, "hclk_vpu_src", "aclk_vpu_pre", 0, + FACTOR_GATE(0, "hclk_vpu_pre", "aclk_vpu_pre", 0, 1, 4, RK2928_CLKGATE_CON(4), 4, GFLAGS), COMPOSITE(0, "aclk_rkvdec_pre", mux_pll_src_4plls_p, 0, RK2928_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS, RK2928_CLKGATE_CON(3), 2, GFLAGS), - GATE(0, "hclk_rkvdec_src", "aclk_rkvdec_pre", 0, + FACTOR_GATE(0, "hclk_rkvdec_pre", "aclk_rkvdec_pre", 0, 1, 4, RK2928_CLKGATE_CON(4), 5, GFLAGS), COMPOSITE(0, "sclk_vdec_cabac", mux_pll_src_4plls_p, 0, @@ -371,6 +371,8 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { MUX(0, "dclk_vop", mux_dclk_vop_p, 0, RK2928_CLKSEL_CON(27), 1, 1, MFLAGS), + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + COMPOSITE(0, "i2s0_src", mux_pll_src_2plls_p, 0, RK2928_CLKSEL_CON(9), 15, 1, MFLAGS, 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 3, GFLAGS), @@ -605,13 +607,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { /* PD_MMC */ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), - MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 0), MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3228_SDIO_CON0, 1), - MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 1), + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 0), MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3228_EMMC_CON0, 1), - MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 0), }; static const char *const rk3228_critical_clocks[] __initconst = { @@ -624,7 +626,6 @@ static const char *const rk3228_critical_clocks[] __initconst = { static void __init rk3228_clk_init(struct device_node *np) { void __iomem *reg_base; - struct clk *clk; reg_base = of_iomap(np, 0); if (!reg_base) { @@ -634,29 +635,6 @@ static void __init rk3228_clk_init(struct device_node *np) rockchip_clk_init(np, reg_base, CLK_NR_CLKS); - /* xin12m is created by an cru-internal divider */ - clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock xin12m: %ld\n", - __func__, PTR_ERR(clk)); - - clk = clk_register_fixed_factor(NULL, "ddrphy_pre", "ddrphy4x", 0, 1, 4); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock ddrphy_pre: %ld\n", - __func__, PTR_ERR(clk)); - - clk = clk_register_fixed_factor(NULL, "hclk_vpu_pre", - "hclk_vpu_src", 0, 1, 4); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock hclk_vpu_pre: %ld\n", - __func__, PTR_ERR(clk)); - - clk = clk_register_fixed_factor(NULL, "hclk_rkvdec_pre", - "hclk_rkvdec_src", 0, 1, 4); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock hclk_rkvdec_pre: %ld\n", - __func__, PTR_ERR(clk)); - rockchip_clk_register_plls(rk3228_pll_clks, ARRAY_SIZE(rk3228_pll_clks), RK3228_GRF_SOC_STATUS0); diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 984fc18..3cb7216 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -195,8 +195,8 @@ PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" }; PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" }; -PNAME(mux_usbphy480m_p) = { "sclk_otgphy1", "sclk_otgphy2", - "sclk_otgphy0" }; +PNAME(mux_usbphy480m_p) = { "sclk_otgphy1_480m", "sclk_otgphy2_480m", + "sclk_otgphy0_480m" }; PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy480m_src" }; PNAME(mux_hsicphy12m_p) = { "hsicphy12m_xin12m", "hsicphy12m_usbphy" }; @@ -333,6 +333,8 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 7, GFLAGS), + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS, RK3288_CLKGATE_CON(4), 1, GFLAGS), @@ -399,12 +401,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { */ GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vdpu", 0, RK3288_CLKGATE_CON(9), 0, GFLAGS), - /* - * We introduce a virtul node of hclk_vodec_pre_v to split one clock - * struct with a gate and a fix divider into two node in software. - */ - GATE(0, "hclk_vcodec_pre_v", "aclk_vdpu", 0, + + FACTOR_GATE(0, "hclk_vcodec_pre", "aclk_vdpu", 0, 1, 4, RK3288_CLKGATE_CON(3), 10, GFLAGS), + GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0, RK3288_CLKGATE_CON(9), 1, GFLAGS), @@ -537,11 +537,11 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { RK3288_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3288_CLKGATE_CON(4), 10, GFLAGS), - GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", CLK_IGNORE_UNUSED, + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin24m", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 4, GFLAGS), - GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", CLK_IGNORE_UNUSED, + GATE(SCLK_OTGPHY1, "sclk_otgphy1", "xin24m", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 5, GFLAGS), - GATE(SCLK_OTGPHY2, "sclk_otgphy2", "usb480m", CLK_IGNORE_UNUSED, + GATE(SCLK_OTGPHY2, "sclk_otgphy2", "xin24m", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 6, GFLAGS), GATE(SCLK_OTG_ADP, "sclk_otg_adp", "xin32k", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 7, GFLAGS), @@ -888,24 +888,6 @@ static void __init rk3288_clk_init(struct device_node *np) rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS); - /* xin12m is created by an cru-internal divider */ - clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock xin12m: %ld\n", - __func__, PTR_ERR(clk)); - - - 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)); - - clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre", - "hclk_vcodec_pre_v", 0, 1, 4); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n", - __func__, PTR_ERR(clk)); - /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1); if (IS_ERR(clk)) diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c index be0ede5..c2b0421 100644 --- a/drivers/clk/rockchip/clk-rk3368.c +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -121,7 +121,7 @@ PNAME(mux_i2s_2ch_p) = { "i2s_2ch_src", "i2s_2ch_frac", "dummy", "xin12m" }; PNAME(mux_spdif_8ch_p) = { "spdif_8ch_pre", "spdif_8ch_frac", "ext_i2s", "xin12m" }; -PNAME(mux_edp_24m_p) = { "dummy", "xin24m" }; +PNAME(mux_edp_24m_p) = { "xin24m", "dummy" }; PNAME(mux_vip_out_p) = { "vip_src", "xin24m" }; PNAME(mux_usbphy480m_p) = { "usbotg_out", "xin24m" }; PNAME(mux_hsic_usbphy480m_p) = { "usbotg_out", "dummy" }; @@ -165,7 +165,7 @@ 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_shift = 15, + .mux_core_shift = 7, }; static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = { @@ -218,29 +218,29 @@ static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = { } static struct rockchip_cpuclk_rate_table rk3368_cpuclkb_rates[] __initdata = { - RK3368_CPUCLKB_RATE(1512000000, 2, 6, 6), - RK3368_CPUCLKB_RATE(1488000000, 2, 5, 5), - RK3368_CPUCLKB_RATE(1416000000, 2, 5, 5), - RK3368_CPUCLKB_RATE(1200000000, 2, 4, 4), - RK3368_CPUCLKB_RATE(1008000000, 2, 4, 4), - RK3368_CPUCLKB_RATE( 816000000, 2, 3, 3), - RK3368_CPUCLKB_RATE( 696000000, 2, 3, 3), - RK3368_CPUCLKB_RATE( 600000000, 2, 2, 2), - RK3368_CPUCLKB_RATE( 408000000, 2, 2, 2), - RK3368_CPUCLKB_RATE( 312000000, 2, 2, 2), + RK3368_CPUCLKB_RATE(1512000000, 1, 5, 5), + RK3368_CPUCLKB_RATE(1488000000, 1, 4, 4), + RK3368_CPUCLKB_RATE(1416000000, 1, 4, 4), + RK3368_CPUCLKB_RATE(1200000000, 1, 3, 3), + RK3368_CPUCLKB_RATE(1008000000, 1, 3, 3), + RK3368_CPUCLKB_RATE( 816000000, 1, 2, 2), + RK3368_CPUCLKB_RATE( 696000000, 1, 2, 2), + RK3368_CPUCLKB_RATE( 600000000, 1, 1, 1), + RK3368_CPUCLKB_RATE( 408000000, 1, 1, 1), + RK3368_CPUCLKB_RATE( 312000000, 1, 1, 1), }; static struct rockchip_cpuclk_rate_table rk3368_cpuclkl_rates[] __initdata = { - RK3368_CPUCLKL_RATE(1512000000, 2, 7, 7), - RK3368_CPUCLKL_RATE(1488000000, 2, 6, 6), - RK3368_CPUCLKL_RATE(1416000000, 2, 6, 6), - RK3368_CPUCLKL_RATE(1200000000, 2, 5, 5), - RK3368_CPUCLKL_RATE(1008000000, 2, 5, 5), - RK3368_CPUCLKL_RATE( 816000000, 2, 4, 4), - RK3368_CPUCLKL_RATE( 696000000, 2, 3, 3), - RK3368_CPUCLKL_RATE( 600000000, 2, 3, 3), - RK3368_CPUCLKL_RATE( 408000000, 2, 2, 2), - RK3368_CPUCLKL_RATE( 312000000, 2, 2, 2), + RK3368_CPUCLKL_RATE(1512000000, 1, 6, 6), + RK3368_CPUCLKL_RATE(1488000000, 1, 5, 5), + RK3368_CPUCLKL_RATE(1416000000, 1, 5, 5), + RK3368_CPUCLKL_RATE(1200000000, 1, 4, 4), + RK3368_CPUCLKL_RATE(1008000000, 1, 4, 4), + RK3368_CPUCLKL_RATE( 816000000, 1, 3, 3), + RK3368_CPUCLKL_RATE( 696000000, 1, 2, 2), + RK3368_CPUCLKL_RATE( 600000000, 1, 2, 2), + RK3368_CPUCLKL_RATE( 408000000, 1, 1, 1), + RK3368_CPUCLKL_RATE( 312000000, 1, 1, 1), }; static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { @@ -248,6 +248,8 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { * Clock-Architecture Diagram 2 */ + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + MUX(SCLK_USBPHY480M, "usbphy_480m", mux_usbphy480m_p, CLK_SET_RATE_PARENT, RK3368_CLKSEL_CON(13), 8, 1, MFLAGS), @@ -299,7 +301,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { COMPOSITE_NOGATE_DIVTBL(0, "ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED, RK3368_CLKSEL_CON(13), 4, 1, MFLAGS, 0, 2, DFLAGS, div_ddrphy_t), - GATE(0, "sclk_ddr", "ddrphy_div4", CLK_IGNORE_UNUSED, + FACTOR_GATE(0, "sclk_ddr", "ddrphy_src", CLK_IGNORE_UNUSED, 1, 4, RK3368_CLKGATE_CON(6), 14, GFLAGS), GATE(0, "sclk_ddr4x", "ddrphy_src", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(6), 15, GFLAGS), @@ -353,7 +355,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_src", CLK_SET_RATE_PARENT, RK3368_CLKSEL_CON(32), 0, RK3368_CLKGATE_CON(6), 5, GFLAGS), - COMPOSITE_NODIV(SCLK_SPDIF_8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0, + COMPOSITE_NODIV(SCLK_SPDIF_8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, CLK_SET_RATE_PARENT, RK3368_CLKSEL_CON(31), 8, 2, MFLAGS, RK3368_CLKGATE_CON(6), 6, GFLAGS), COMPOSITE(0, "i2s_2ch_src", mux_pll_src_cpll_gpll_p, 0, @@ -362,7 +364,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { COMPOSITE_FRAC(0, "i2s_2ch_frac", "i2s_2ch_src", CLK_SET_RATE_PARENT, RK3368_CLKSEL_CON(54), 0, RK3368_CLKGATE_CON(5), 14, GFLAGS), - COMPOSITE_NODIV(SCLK_I2S_2CH, "sclk_i2s_2ch", mux_i2s_2ch_p, 0, + COMPOSITE_NODIV(SCLK_I2S_2CH, "sclk_i2s_2ch", mux_i2s_2ch_p, CLK_SET_RATE_PARENT, RK3368_CLKSEL_CON(53), 8, 2, MFLAGS, RK3368_CLKGATE_CON(5), 15, GFLAGS), @@ -384,18 +386,18 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { * Clock-Architecture Diagram 3 */ - COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_usb_p, 0, + COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_npll_usb_p, 0, RK3368_CLKSEL_CON(15), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3368_CLKGATE_CON(4), 6, GFLAGS), - COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb_p, 0, + COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_npll_usb_p, 0, RK3368_CLKSEL_CON(15), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3368_CLKGATE_CON(4), 7, GFLAGS), /* - * We introduce a virtual node of hclk_vodec_pre_v to split one clock - * struct with a gate and a fix divider into two node in software. + * We use aclk_vdpu by default ---GRF_SOC_CON0[7] setting in system, + * so we ignore the mux and make clocks nodes as following, */ - GATE(0, "hclk_video_pre_v", "aclk_vdpu", 0, + FACTOR_GATE(0, "hclk_video_pre", "aclk_vdpu", 0, 1, 4, RK3368_CLKGATE_CON(4), 8, GFLAGS), COMPOSITE(0, "sclk_hevc_cabac_src", mux_pll_src_cpll_gpll_npll_usb_p, 0, @@ -442,7 +444,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { GATE(SCLK_HDMI_HDCP, "sclk_hdmi_hdcp", "xin24m", 0, RK3368_CLKGATE_CON(4), 13, GFLAGS), GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0, - RK3368_CLKGATE_CON(5), 12, GFLAGS), + RK3368_CLKGATE_CON(4), 12, GFLAGS), COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0, RK3368_CLKSEL_CON(21), 15, 1, MFLAGS, @@ -780,13 +782,13 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 0, GFLAGS), /* pclk_pd_alive gates */ - GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 8, GFLAGS), - GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 7, GFLAGS), - GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 12, GFLAGS), - GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 11, GFLAGS), - GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 3, GFLAGS), - GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 2, GFLAGS), - GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 1, GFLAGS), + GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 13, GFLAGS), + GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 12, GFLAGS), + GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(22), 9, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(22), 8, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 3, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 2, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 1, GFLAGS), /* * pclk_vio gates @@ -796,12 +798,12 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { GATE(0, "pclk_dphytx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS), /* pclk_pd_pmu gates */ - GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 0, GFLAGS), - GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS), - GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 3, GFLAGS), - GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS), - GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 1, GFLAGS), - GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS), + GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 5, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(23), 4, GFLAGS), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 3, GFLAGS), + GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 2, GFLAGS), + GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 1, GFLAGS), + GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 0, GFLAGS), /* timer gates */ GATE(0, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS), @@ -842,24 +844,6 @@ static void __init rk3368_clk_init(struct device_node *np) rockchip_clk_init(np, reg_base, CLK_NR_CLKS); - /* xin12m is created by a cru-internal divider */ - clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock xin12m: %ld\n", - __func__, PTR_ERR(clk)); - - /* ddrphy_div4 is created by a cru-internal divider */ - clk = clk_register_fixed_factor(NULL, "ddrphy_div4", "ddrphy_src", 0, 1, 4); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock xin12m: %ld\n", - __func__, PTR_ERR(clk)); - - clk = clk_register_fixed_factor(NULL, "hclk_video_pre", - "hclk_video_pre_v", 0, 1, 4); - if (IS_ERR(clk)) - pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n", - __func__, PTR_ERR(clk)); - /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1); if (IS_ERR(clk)) diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index d9a0b5d..ec06350 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -70,7 +70,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, if (gate_offset >= 0) { gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) - return ERR_PTR(-ENOMEM); + goto err_gate; gate->flags = gate_flags; gate->reg = base + gate_offset; @@ -82,7 +82,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, if (div_width > 0) { div = kzalloc(sizeof(*div), GFP_KERNEL); if (!div) - return ERR_PTR(-ENOMEM); + goto err_div; div->flags = div_flags; div->reg = base + muxdiv_offset; @@ -90,7 +90,9 @@ static struct clk *rockchip_clk_register_branch(const char *name, div->width = div_width; div->lock = lock; div->table = div_table; - div_ops = &clk_divider_ops; + div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) + ? &clk_divider_ro_ops + : &clk_divider_ops; } clk = clk_register_composite(NULL, name, parent_names, num_parents, @@ -100,6 +102,11 @@ static struct clk *rockchip_clk_register_branch(const char *name, flags); return clk; +err_div: + kfree(gate); +err_gate: + kfree(mux); + return ERR_PTR(-ENOMEM); } struct rockchip_clk_frac { @@ -260,6 +267,53 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name, return clk; } +static struct clk *rockchip_clk_register_factor_branch(const char *name, + const char *const *parent_names, u8 num_parents, + void __iomem *base, unsigned int mult, unsigned int div, + int gate_offset, u8 gate_shift, u8 gate_flags, + unsigned long flags, spinlock_t *lock) +{ + struct clk *clk; + struct clk_gate *gate = NULL; + struct clk_fixed_factor *fix = NULL; + + /* without gate, register a simple factor clock */ + if (gate_offset == 0) { + return clk_register_fixed_factor(NULL, name, + parent_names[0], flags, mult, + div); + } + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->flags = gate_flags; + gate->reg = base + gate_offset; + gate->bit_idx = gate_shift; + gate->lock = lock; + + fix = kzalloc(sizeof(*fix), GFP_KERNEL); + if (!fix) { + kfree(gate); + return ERR_PTR(-ENOMEM); + } + + fix->mult = mult; + fix->div = div; + + clk = clk_register_composite(NULL, name, parent_names, num_parents, + NULL, NULL, + &fix->hw, &clk_fixed_factor_ops, + &gate->hw, &clk_gate_ops, flags); + if (IS_ERR(clk)) { + kfree(fix); + kfree(gate); + } + + return clk; +} + static DEFINE_SPINLOCK(clk_lock); static struct clk **clk_table; static void __iomem *reg_base; @@ -395,6 +449,14 @@ void __init rockchip_clk_register_branches( reg_base + list->muxdiv_offset, list->div_shift, list->div_flags, &clk_lock); break; + case branch_factor: + clk = rockchip_clk_register_factor_branch( + list->name, list->parent_names, + list->num_parents, reg_base, + list->div_shift, list->div_width, + list->gate_offset, list->gate_shift, + list->gate_flags, flags, &clk_lock); + break; } /* none of the cases above matched */ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index ff8bd23..39c198b 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -254,6 +254,7 @@ enum rockchip_clk_branch_type { branch_gate, branch_mmc, branch_inverter, + branch_factor, }; struct rockchip_clk_branch { @@ -508,6 +509,33 @@ struct rockchip_clk_branch { .div_flags = if, \ } +#define FACTOR(_id, cname, pname, f, fm, fd) \ + { \ + .id = _id, \ + .branch_type = branch_factor, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .div_shift = fm, \ + .div_width = fd, \ + } + +#define FACTOR_GATE(_id, cname, pname, f, fm, fd, go, gb, gf) \ + { \ + .id = _id, \ + .branch_type = branch_factor, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .div_shift = fm, \ + .div_width = fd, \ + .gate_offset = go, \ + .gate_shift = gb, \ + .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); diff --git a/drivers/clk/samsung/Kconfig b/drivers/clk/samsung/Kconfig index 84196ec..20c5fe9 100644 --- a/drivers/clk/samsung/Kconfig +++ b/drivers/clk/samsung/Kconfig @@ -1,9 +1,17 @@ +# Recent Exynos platforms should just select COMMON_CLK_SAMSUNG: config COMMON_CLK_SAMSUNG - bool - select COMMON_CLK + bool "Samsung Exynos clock controller support" if COMPILE_TEST + # Clocks on ARM64 SoCs (e.g. Exynos5433, Exynos7) are chosen by + # EXYNOS_ARM64_COMMON_CLK to avoid building them on ARMv7: + select EXYNOS_ARM64_COMMON_CLK if ARM64 && ARCH_EXYNOS + +config EXYNOS_ARM64_COMMON_CLK + bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG +# For S3C24XX platforms, select following symbols: config S3C2410_COMMON_CLK - bool + bool "Samsung S3C2410 clock controller support" if COMPILE_TEST select COMMON_CLK_SAMSUNG help Build the s3c2410 clock driver based on the common clock framework. @@ -17,10 +25,9 @@ config S3C2410_COMMON_DCLK framework. config S3C2412_COMMON_CLK - bool + bool "Samsung S3C2412 clock controller support" if COMPILE_TEST select COMMON_CLK_SAMSUNG config S3C2443_COMMON_CLK - bool + bool "Samsung S3C2443 clock controller support" if COMPILE_TEST select COMMON_CLK_SAMSUNG - diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 5f6833e..fc367d4 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -10,11 +10,11 @@ obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o -obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos5433.o +obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o -obj-$(CONFIG_ARCH_EXYNOS7) += clk-exynos7.o +obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index cee062c..707a814 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -142,17 +142,6 @@ static unsigned long top_clk_regs[] __initdata = { MUX_ENABLE_TOP_FSYS1, MUX_ENABLE_TOP_PERIC0, MUX_ENABLE_TOP_PERIC1, - MUX_STAT_TOP0, - MUX_STAT_TOP1, - MUX_STAT_TOP2, - MUX_STAT_TOP3, - MUX_STAT_TOP4, - MUX_STAT_TOP_MSCL, - MUX_STAT_TOP_CAM1, - MUX_STAT_TOP_FSYS0, - MUX_STAT_TOP_FSYS1, - MUX_STAT_TOP_PERIC0, - MUX_STAT_TOP_PERIC1, DIV_TOP0, DIV_TOP1, DIV_TOP2, @@ -170,22 +159,6 @@ static unsigned long top_clk_regs[] __initdata = { DIV_TOP_PERIC3, DIV_TOP_PERIC4, DIV_TOP_PLL_FREQ_DET, - DIV_STAT_TOP0, - DIV_STAT_TOP1, - DIV_STAT_TOP2, - DIV_STAT_TOP3, - DIV_STAT_TOP4, - DIV_STAT_TOP_MSCL, - DIV_STAT_TOP_CAM10, - DIV_STAT_TOP_CAM11, - DIV_STAT_TOP_FSYS0, - DIV_STAT_TOP_FSYS1, - DIV_STAT_TOP_FSYS2, - DIV_STAT_TOP_PERIC0, - DIV_STAT_TOP_PERIC1, - DIV_STAT_TOP_PERIC2, - DIV_STAT_TOP_PERIC3, - DIV_STAT_TOP_PLL_FREQ_DET, ENABLE_ACLK_TOP, ENABLE_SCLK_TOP, ENABLE_SCLK_TOP_MSCL, @@ -490,9 +463,9 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_SCLK_ISP_SENSOR1_A, "div_sclk_isp_sensor1_a", "mout_sclk_isp_sensor1", DIV_TOP_CAM11, 8, 4), DIV(CLK_DIV_SCLK_ISP_SENSOR0_B, "div_sclk_isp_sensor0_b", - "div_sclk_isp_sensor0_a", DIV_TOP_CAM11, 12, 4), + "div_sclk_isp_sensor0_a", DIV_TOP_CAM11, 4, 4), DIV(CLK_DIV_SCLK_ISP_SENSOR0_A, "div_sclk_isp_sensor0_a", - "mout_sclk_isp_sensor0", DIV_TOP_CAM11, 8, 4), + "mout_sclk_isp_sensor0", DIV_TOP_CAM11, 0, 4), /* DIV_TOP_FSYS0 */ DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", @@ -999,26 +972,12 @@ static unsigned long mif_clk_regs[] __initdata = { MUX_ENABLE_MIF5, MUX_ENABLE_MIF6, MUX_ENABLE_MIF7, - MUX_STAT_MIF0, - MUX_STAT_MIF1, - MUX_STAT_MIF2, - MUX_STAT_MIF3, - MUX_STAT_MIF4, - MUX_STAT_MIF5, - MUX_STAT_MIF6, - MUX_STAT_MIF7, DIV_MIF1, DIV_MIF2, DIV_MIF3, DIV_MIF4, DIV_MIF5, DIV_MIF_PLL_FREQ_DET, - DIV_STAT_MIF1, - DIV_STAT_MIF2, - DIV_STAT_MIF3, - DIV_STAT_MIF4, - DIV_STAT_MIF5, - DIV_STAT_MIF_PLL_FREQ_DET, ENABLE_ACLK_MIF0, ENABLE_ACLK_MIF1, ENABLE_ACLK_MIF2, @@ -1565,7 +1524,6 @@ CLK_OF_DECLARE(exynos5433_cmu_mif, "samsung,exynos5433-cmu-mif", static unsigned long peric_clk_regs[] __initdata = { DIV_PERIC, - DIV_STAT_PERIC, ENABLE_ACLK_PERIC, ENABLE_PCLK_PERIC0, ENABLE_PCLK_PERIC1, @@ -2012,11 +1970,6 @@ static unsigned long fsys_clk_regs[] __initdata = { MUX_ENABLE_FSYS2, MUX_ENABLE_FSYS3, MUX_ENABLE_FSYS4, - MUX_STAT_FSYS0, - MUX_STAT_FSYS1, - MUX_STAT_FSYS2, - MUX_STAT_FSYS3, - MUX_STAT_FSYS4, MUX_IGNORE_FSYS2, MUX_IGNORE_FSYS3, ENABLE_ACLK_FSYS0, @@ -2362,9 +2315,7 @@ CLK_OF_DECLARE(exynos5433_cmu_fsys, "samsung,exynos5433-cmu-fsys", static unsigned long g2d_clk_regs[] __initdata = { MUX_SEL_G2D0, MUX_SEL_ENABLE_G2D0, - MUX_SEL_STAT_G2D0, DIV_G2D, - DIV_STAT_G2D, DIV_ENABLE_ACLK_G2D, DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D, DIV_ENABLE_PCLK_G2D, @@ -2520,16 +2471,9 @@ static unsigned long disp_clk_regs[] __initdata = { MUX_ENABLE_DISP2, MUX_ENABLE_DISP3, MUX_ENABLE_DISP4, - MUX_STAT_DISP0, - MUX_STAT_DISP1, - MUX_STAT_DISP2, - MUX_STAT_DISP3, - MUX_STAT_DISP4, MUX_IGNORE_DISP2, DIV_DISP, DIV_DISP_PLL_FREQ_DET, - DIV_STAT_DISP, - DIV_STAT_DISP_PLL_FREQ_DET, ENABLE_ACLK_DISP0, ENABLE_ACLK_DISP1, ENABLE_PCLK_DISP, @@ -2614,8 +2558,10 @@ static struct samsung_fixed_rate_clock disp_fixed_clks[] __initdata = { FRATE(0, "phyclk_mipidphy0_rxclkesc0_phy", NULL, CLK_IS_ROOT, 100000000), /* PHY clocks from HDMI_PHY */ - FRATE(0, "phyclk_hdmiphy_tmds_clko_phy", NULL, CLK_IS_ROOT, 300000000), - FRATE(0, "phyclk_hdmiphy_pixel_clko_phy", NULL, CLK_IS_ROOT, 166000000), + FRATE(CLK_PHYCLK_HDMIPHY_TMDS_CLKO_PHY, "phyclk_hdmiphy_tmds_clko_phy", + NULL, CLK_IS_ROOT, 300000000), + FRATE(CLK_PHYCLK_HDMIPHY_PIXEL_CLKO_PHY, "phyclk_hdmiphy_pixel_clko_phy", + NULL, CLK_IS_ROOT, 166000000), }; static struct samsung_mux_clock disp_mux_clks[] __initdata = { @@ -2820,6 +2766,8 @@ static struct samsung_gate_clock disp_gate_clks[] __initdata = { ENABLE_PCLK_DISP, 2, 0, 0), GATE(CLK_PCLK_DECON_TV, "pclk_decon_tv", "div_pclk_disp", ENABLE_PCLK_DISP, 1, 0, 0), + GATE(CLK_PCLK_DECON, "pclk_decon", "div_pclk_disp", + ENABLE_PCLK_DISP, 0, 0, 0), /* ENABLE_SCLK_DISP */ GATE(CLK_PHYCLK_MIPIDPHY1_BITCLKDIV8, "phyclk_mipidphy1_bitclkdiv8", @@ -2919,11 +2867,8 @@ static unsigned long aud_clk_regs[] __initdata = { MUX_SEL_AUD1, MUX_ENABLE_AUD0, MUX_ENABLE_AUD1, - MUX_STAT_AUD0, DIV_AUD0, DIV_AUD1, - DIV_STAT_AUD0, - DIV_STAT_AUD1, ENABLE_ACLK_AUD, ENABLE_PCLK_AUD, ENABLE_SCLK_AUD0, @@ -3087,7 +3032,6 @@ PNAME(mout_aclk_bus2_400_p) = { "oscclk", "aclk_bus2_400", }; #define CMU_BUS_COMMON_CLK_REGS \ DIV_BUS, \ - DIV_STAT_BUS, \ ENABLE_ACLK_BUS, \ ENABLE_PCLK_BUS, \ ENABLE_IP_BUS0, \ @@ -3100,7 +3044,6 @@ static unsigned long bus01_clk_regs[] __initdata = { static unsigned long bus2_clk_regs[] __initdata = { MUX_SEL_BUS2, MUX_ENABLE_BUS2, - MUX_STAT_BUS2, CMU_BUS_COMMON_CLK_REGS, }; @@ -3259,11 +3202,8 @@ static unsigned long g3d_clk_regs[] __initdata = { G3D_PLL_FREQ_DET, MUX_SEL_G3D, MUX_ENABLE_G3D, - MUX_STAT_G3D, DIV_G3D, DIV_G3D_PLL_FREQ_DET, - DIV_STAT_G3D, - DIV_STAT_G3D_PLL_FREQ_DET, ENABLE_ACLK_G3D, ENABLE_PCLK_G3D, ENABLE_SCLK_G3D, @@ -3379,7 +3319,6 @@ CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d", static unsigned long gscl_clk_regs[] __initdata = { MUX_SEL_GSCL, MUX_ENABLE_GSCL, - MUX_STAT_GSCL, ENABLE_ACLK_GSCL, ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0, ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1, @@ -3472,11 +3411,11 @@ static struct samsung_gate_clock gscl_gate_clks[] __initdata = { /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1 */ GATE(CLK_PCLK_SMMU_GSCL1, "pclk_smmu_gscl1", "mout_aclk_gscl_111_user", - ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1, 0, 0, 0), /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2 */ GATE(CLK_PCLK_SMMU_GSCL2, "pclk_smmu_gscl2", "mout_aclk_gscl_111_user", - ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2, 0, 0, 0), }; static struct samsung_cmu_info gscl_cmu_info __initdata = { @@ -3543,15 +3482,9 @@ static unsigned long apollo_clk_regs[] __initdata = { MUX_ENABLE_APOLLO0, MUX_ENABLE_APOLLO1, MUX_ENABLE_APOLLO2, - MUX_STAT_APOLLO0, - MUX_STAT_APOLLO1, - MUX_STAT_APOLLO2, DIV_APOLLO0, DIV_APOLLO1, DIV_APOLLO_PLL_FREQ_DET, - DIV_STAT_APOLLO0, - DIV_STAT_APOLLO1, - DIV_STAT_APOLLO_PLL_FREQ_DET, ENABLE_ACLK_APOLLO, ENABLE_PCLK_APOLLO, ENABLE_SCLK_APOLLO, @@ -3735,15 +3668,9 @@ static unsigned long atlas_clk_regs[] __initdata = { MUX_ENABLE_ATLAS0, MUX_ENABLE_ATLAS1, MUX_ENABLE_ATLAS2, - MUX_STAT_ATLAS0, - MUX_STAT_ATLAS1, - MUX_STAT_ATLAS2, DIV_ATLAS0, DIV_ATLAS1, DIV_ATLAS_PLL_FREQ_DET, - DIV_STAT_ATLAS0, - DIV_STAT_ATLAS1, - DIV_STAT_ATLAS_PLL_FREQ_DET, ENABLE_ACLK_ATLAS, ENABLE_PCLK_ATLAS, ENABLE_SCLK_ATLAS, @@ -3937,10 +3864,7 @@ static unsigned long mscl_clk_regs[] __initdata = { MUX_SEL_MSCL1, MUX_ENABLE_MSCL0, MUX_ENABLE_MSCL1, - MUX_STAT_MSCL0, - MUX_STAT_MSCL1, DIV_MSCL, - DIV_STAT_MSCL, ENABLE_ACLK_MSCL, ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0, ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1, @@ -4097,9 +4021,7 @@ CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl", static unsigned long mfc_clk_regs[] __initdata = { MUX_SEL_MFC, MUX_ENABLE_MFC, - MUX_STAT_MFC, DIV_MFC, - DIV_STAT_MFC, ENABLE_ACLK_MFC, ENABLE_ACLK_MFC_SECURE_SMMU_MFC, ENABLE_PCLK_MFC, @@ -4207,9 +4129,7 @@ CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc", static unsigned long hevc_clk_regs[] __initdata = { MUX_SEL_HEVC, MUX_ENABLE_HEVC, - MUX_STAT_HEVC, DIV_HEVC, - DIV_STAT_HEVC, ENABLE_ACLK_HEVC, ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC, ENABLE_PCLK_HEVC, @@ -4321,9 +4241,7 @@ CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc", static unsigned long isp_clk_regs[] __initdata = { MUX_SEL_ISP, MUX_ENABLE_ISP, - MUX_STAT_ISP, DIV_ISP, - DIV_STAT_ISP, ENABLE_ACLK_ISP0, ENABLE_ACLK_ISP1, ENABLE_ACLK_ISP2, @@ -4603,20 +4521,11 @@ static unsigned long cam0_clk_regs[] __initdata = { MUX_ENABLE_CAM02, MUX_ENABLE_CAM03, MUX_ENABLE_CAM04, - MUX_STAT_CAM00, - MUX_STAT_CAM01, - MUX_STAT_CAM02, - MUX_STAT_CAM03, - MUX_STAT_CAM04, MUX_IGNORE_CAM01, DIV_CAM00, DIV_CAM01, DIV_CAM02, DIV_CAM03, - DIV_STAT_CAM00, - DIV_STAT_CAM01, - DIV_STAT_CAM02, - DIV_STAT_CAM03, ENABLE_ACLK_CAM00, ENABLE_ACLK_CAM01, ENABLE_ACLK_CAM02, @@ -4749,21 +4658,21 @@ static struct samsung_mux_clock cam0_mux_clks[] __initdata = { MUX(CLK_MOUT_SCLK_LITE_FREECNT_C, "mout_sclk_lite_freecnt_c", mout_sclk_lite_freecnt_c_p, MUX_SEL_CAM04, 24, 1), MUX(CLK_MOUT_SCLK_LITE_FREECNT_B, "mout_sclk_lite_freecnt_b", - mout_sclk_lite_freecnt_b_p, MUX_SEL_CAM04, 24, 1), + mout_sclk_lite_freecnt_b_p, MUX_SEL_CAM04, 20, 1), MUX(CLK_MOUT_SCLK_LITE_FREECNT_A, "mout_sclk_lite_freecnt_a", - mout_sclk_lite_freecnt_a_p, MUX_SEL_CAM04, 24, 1), + mout_sclk_lite_freecnt_a_p, MUX_SEL_CAM04, 16, 1), MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_B, "mout_sclk_pixelasync_lite_c_b", - mout_sclk_pixelasync_lite_c_b_p, MUX_SEL_CAM04, 24, 1), + mout_sclk_pixelasync_lite_c_b_p, MUX_SEL_CAM04, 12, 1), MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_A, "mout_sclk_pixelasync_lite_c_a", - mout_sclk_pixelasync_lite_c_a_p, MUX_SEL_CAM04, 24, 1), + mout_sclk_pixelasync_lite_c_a_p, MUX_SEL_CAM04, 8, 1), MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_B, "mout_sclk_pixelasync_lite_c_init_b", mout_sclk_pixelasync_lite_c_init_b_p, - MUX_SEL_CAM04, 24, 1), + MUX_SEL_CAM04, 4, 1), MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_A, "mout_sclk_pixelasync_lite_c_init_a", mout_sclk_pixelasync_lite_c_init_a_p, - MUX_SEL_CAM04, 24, 1), + MUX_SEL_CAM04, 0, 1), }; static struct samsung_div_clock cam0_div_clks[] __initdata = { @@ -5074,14 +4983,9 @@ static unsigned long cam1_clk_regs[] __initdata = { MUX_ENABLE_CAM10, MUX_ENABLE_CAM11, MUX_ENABLE_CAM12, - MUX_STAT_CAM10, - MUX_STAT_CAM11, - MUX_STAT_CAM12, MUX_IGNORE_CAM11, DIV_CAM10, DIV_CAM11, - DIV_STAT_CAM10, - DIV_STAT_CAM11, ENABLE_ACLK_CAM10, ENABLE_ACLK_CAM11, ENABLE_ACLK_CAM12, @@ -5134,9 +5038,9 @@ static struct samsung_mux_clock cam1_mux_clks[] __initdata = { MUX(CLK_MOUT_ACLK_CAM1_333_USER, "mout_aclk_cam1_333_user", mout_aclk_cam1_333_user_p, MUX_SEL_CAM10, 8, 1), MUX(CLK_MOUT_ACLK_CAM1_400_USER, "mout_aclk_cam1_400_user", - mout_aclk_cam1_400_user_p, MUX_SEL_CAM01, 4, 1), + mout_aclk_cam1_400_user_p, MUX_SEL_CAM10, 4, 1), MUX(CLK_MOUT_ACLK_CAM1_552_USER, "mout_aclk_cam1_552_user", - mout_aclk_cam1_552_user_p, MUX_SEL_CAM01, 0, 1), + mout_aclk_cam1_552_user_p, MUX_SEL_CAM10, 0, 1), /* MUX_SEL_CAM11 */ MUX(CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2B_USER, @@ -5161,7 +5065,7 @@ static struct samsung_mux_clock cam1_mux_clks[] __initdata = { static struct samsung_div_clock cam1_div_clks[] __initdata = { /* DIV_CAM10 */ - DIV(CLK_DIV_SCLK_ISP_WPWM, "div_sclk_isp_wpwm", + DIV(CLK_DIV_SCLK_ISP_MPWM, "div_sclk_isp_mpwm", "div_pclk_cam1_83", DIV_CAM10, 16, 2), DIV(CLK_DIV_PCLK_CAM1_83, "div_pclk_cam1_83", "mout_aclk_cam1_333_user", DIV_CAM10, 12, 2), @@ -5355,7 +5259,7 @@ static struct samsung_gate_clock cam1_gate_clks[] __initdata = { ENABLE_PCLK_CAM1, 5, CLK_IGNORE_UNUSED, 0), GATE(CLK_PCLK_ISP_I2C0, "pclk_isp_i2c0", "div_pclk_cam1_83", ENABLE_PCLK_CAM1, 4, CLK_IGNORE_UNUSED, 0), - GATE(CLK_PCLK_ISP_MPWM, "pclk_isp_wpwm", "div_pclk_cam1_83", + GATE(CLK_PCLK_ISP_MPWM, "pclk_isp_mpwm", "div_pclk_cam1_83", ENABLE_PCLK_CAM1, 3, CLK_IGNORE_UNUSED, 0), GATE(CLK_PCLK_FD, "pclk_fd", "div_pclk_fd", ENABLE_PCLK_CAM1, 3, CLK_IGNORE_UNUSED, 0), @@ -5388,7 +5292,7 @@ static struct samsung_gate_clock cam1_gate_clks[] __initdata = { ENABLE_SCLK_CAM1, 5, 0, 0), GATE(CLK_SCLK_ISP_SPI0, "sclk_isp_spi0", "mout_sclk_isp_spi0_user", ENABLE_SCLK_CAM1, 4, 0, 0), - GATE(CLK_SCLK_ISP_MPWM, "sclk_isp_wpwm", "div_sclk_isp_wpwm", + GATE(CLK_SCLK_ISP_MPWM, "sclk_isp_mpwm", "div_sclk_isp_mpwm", ENABLE_SCLK_CAM1, 3, 0, 0), GATE(CLK_PCLK_DBG_ISP, "sclk_dbg_isp", "div_pclk_dbg_cam1", ENABLE_SCLK_CAM1, 2, 0, 0), diff --git a/drivers/clk/shmobile/r8a7795-cpg-mssr.c b/drivers/clk/shmobile/r8a7795-cpg-mssr.c index 13e9947..1f4b21a 100644 --- a/drivers/clk/shmobile/r8a7795-cpg-mssr.c +++ b/drivers/clk/shmobile/r8a7795-cpg-mssr.c @@ -20,6 +20,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/of.h> +#include <linux/slab.h> #include <dt-bindings/clock/r8a7795-cpg-mssr.h> @@ -61,6 +62,7 @@ enum r8a7795_clk_types { CLK_TYPE_GEN3_PLL2, CLK_TYPE_GEN3_PLL3, CLK_TYPE_GEN3_PLL4, + CLK_TYPE_GEN3_SD, }; static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { @@ -99,6 +101,12 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { DEF_FIXED("s3d1", R8A7795_CLK_S3D1, CLK_S3, 1, 1), DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1), DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1), + + DEF_SD("sd0", R8A7795_CLK_SD0, CLK_PLL1_DIV2, 0x0074), + DEF_SD("sd1", R8A7795_CLK_SD1, CLK_PLL1_DIV2, 0x0078), + DEF_SD("sd2", R8A7795_CLK_SD2, CLK_PLL1_DIV2, 0x0268), + DEF_SD("sd3", R8A7795_CLK_SD3, CLK_PLL1_DIV2, 0x026c), + DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1), DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1), @@ -120,8 +128,17 @@ static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S3D1), DEF_MOD("scif2", 310, R8A7795_CLK_S3D4), + DEF_MOD("sdif3", 311, R8A7795_CLK_SD3), + DEF_MOD("sdif2", 312, R8A7795_CLK_SD2), + DEF_MOD("sdif1", 313, R8A7795_CLK_SD1), + DEF_MOD("sdif0", 314, R8A7795_CLK_SD0), DEF_MOD("pcie1", 318, R8A7795_CLK_S3D1), DEF_MOD("pcie0", 319, R8A7795_CLK_S3D1), + DEF_MOD("usb3-if1", 327, R8A7795_CLK_S3D1), + DEF_MOD("usb3-if0", 328, R8A7795_CLK_S3D1), + DEF_MOD("usb-dmac0", 330, R8A7795_CLK_S3D1), + DEF_MOD("usb-dmac1", 331, R8A7795_CLK_S3D1), + DEF_MOD("intc-ex", 407, R8A7795_CLK_CP), DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1), DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4), DEF_MOD("audmac1", 501, R8A7795_CLK_S3D4), @@ -198,6 +215,221 @@ static const unsigned int r8a7795_crit_mod_clks[] __initconst = { MOD_CLK_ID(408), /* INTC-AP (GIC) */ }; +/* ----------------------------------------------------------------------------- + * SDn Clock + * + */ +#define CPG_SD_STP_HCK BIT(9) +#define CPG_SD_STP_CK BIT(8) + +#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK) +#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0) + +#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \ +{ \ + .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \ + ((stp_ck) ? CPG_SD_STP_CK : 0) | \ + ((sd_srcfc) << 2) | \ + ((sd_fc) << 0), \ + .div = (sd_div), \ +} + +struct sd_div_table { + u32 val; + unsigned int div; +}; + +struct sd_clock { + struct clk_hw hw; + void __iomem *reg; + const struct sd_div_table *div_table; + unsigned int div_num; + unsigned int div_min; + unsigned int div_max; +}; + +/* SDn divider + * sd_srcfc sd_fc div + * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc + *------------------------------------------------------------------- + * 0 0 0 (1) 1 (4) 4 + * 0 0 1 (2) 1 (4) 8 + * 1 0 2 (4) 1 (4) 16 + * 1 0 3 (8) 1 (4) 32 + * 1 0 4 (16) 1 (4) 64 + * 0 0 0 (1) 0 (2) 2 + * 0 0 1 (2) 0 (2) 4 + * 1 0 2 (4) 0 (2) 8 + * 1 0 3 (8) 0 (2) 16 + * 1 0 4 (16) 0 (2) 32 + */ +static const struct sd_div_table cpg_sd_div_table[] = { +/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */ + CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4), + CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8), + CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16), + CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32), + CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64), + CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2), + CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4), + CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8), + CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16), + CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32), +}; + +#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw) + +static int cpg_sd_clock_enable(struct clk_hw *hw) +{ + struct sd_clock *clock = to_sd_clock(hw); + u32 val, sd_fc; + unsigned int i; + + val = clk_readl(clock->reg); + + sd_fc = val & CPG_SD_FC_MASK; + for (i = 0; i < clock->div_num; i++) + if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK)) + break; + + if (i >= clock->div_num) + return -EINVAL; + + val &= ~(CPG_SD_STP_MASK); + val |= clock->div_table[i].val & CPG_SD_STP_MASK; + + clk_writel(val, clock->reg); + + return 0; +} + +static void cpg_sd_clock_disable(struct clk_hw *hw) +{ + struct sd_clock *clock = to_sd_clock(hw); + + clk_writel(clk_readl(clock->reg) | CPG_SD_STP_MASK, clock->reg); +} + +static int cpg_sd_clock_is_enabled(struct clk_hw *hw) +{ + struct sd_clock *clock = to_sd_clock(hw); + + return !(clk_readl(clock->reg) & CPG_SD_STP_MASK); +} + +static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sd_clock *clock = to_sd_clock(hw); + unsigned long rate = parent_rate; + u32 val, sd_fc; + unsigned int i; + + val = clk_readl(clock->reg); + + sd_fc = val & CPG_SD_FC_MASK; + for (i = 0; i < clock->div_num; i++) + if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK)) + break; + + if (i >= clock->div_num) + return -EINVAL; + + return DIV_ROUND_CLOSEST(rate, clock->div_table[i].div); +} + +static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock, + unsigned long rate, + unsigned long parent_rate) +{ + unsigned int div; + + if (!rate) + rate = 1; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + + return clamp_t(unsigned int, div, clock->div_min, clock->div_max); +} + +static long cpg_sd_clock_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct sd_clock *clock = to_sd_clock(hw); + unsigned int div = cpg_sd_clock_calc_div(clock, rate, *parent_rate); + + return DIV_ROUND_CLOSEST(*parent_rate, div); +} + +static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sd_clock *clock = to_sd_clock(hw); + unsigned int div = cpg_sd_clock_calc_div(clock, rate, parent_rate); + u32 val; + unsigned int i; + + for (i = 0; i < clock->div_num; i++) + if (div == clock->div_table[i].div) + break; + + if (i >= clock->div_num) + return -EINVAL; + + val = clk_readl(clock->reg); + val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK); + val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK); + clk_writel(val, clock->reg); + + return 0; +} + +static const struct clk_ops cpg_sd_clock_ops = { + .enable = cpg_sd_clock_enable, + .disable = cpg_sd_clock_disable, + .is_enabled = cpg_sd_clock_is_enabled, + .recalc_rate = cpg_sd_clock_recalc_rate, + .round_rate = cpg_sd_clock_round_rate, + .set_rate = cpg_sd_clock_set_rate, +}; + +static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, + void __iomem *base, + const char *parent_name) +{ + struct clk_init_data init; + struct sd_clock *clock; + struct clk *clk; + unsigned int i; + + clock = kzalloc(sizeof(*clock), GFP_KERNEL); + if (!clock) + return ERR_PTR(-ENOMEM); + + init.name = core->name; + init.ops = &cpg_sd_clock_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + + clock->reg = base + core->offset; + clock->hw.init = &init; + clock->div_table = cpg_sd_div_table; + clock->div_num = ARRAY_SIZE(cpg_sd_div_table); + + clock->div_max = clock->div_table[0].div; + clock->div_min = clock->div_max; + for (i = 1; i < clock->div_num; i++) { + clock->div_max = max(clock->div_max, clock->div_table[i].div); + clock->div_min = min(clock->div_min, clock->div_table[i].div); + } + + clk = clk_register(NULL, &clock->hw); + if (IS_ERR(clk)) + kfree(clock); + + return clk; +} #define CPG_PLL0CR 0x00d8 #define CPG_PLL2CR 0x002c @@ -323,6 +555,9 @@ struct clk * __init r8a7795_cpg_clk_register(struct device *dev, mult = (((value >> 24) & 0x7f) + 1) * 2; break; + case CLK_TYPE_GEN3_SD: + return cpg_sd_clk_register(core, base, __clk_get_name(parent)); + default: return ERR_PTR(-EINVAL); } diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.c b/drivers/clk/shmobile/renesas-cpg-mssr.c index 9a4d888..58e24b3 100644 --- a/drivers/clk/shmobile/renesas-cpg-mssr.c +++ b/drivers/clk/shmobile/renesas-cpg-mssr.c @@ -348,6 +348,7 @@ static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod, #else dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n", mod->name); + kfree(clock); return; #endif } @@ -568,7 +569,11 @@ static int __init cpg_mssr_probe(struct platform_device *pdev) if (error) return error; - devm_add_action(dev, cpg_mssr_del_clk_provider, np); + error = devm_add_action_or_reset(dev, + cpg_mssr_del_clk_provider, + np); + if (error) + return error; error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks, info->num_core_pm_clks); diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.h b/drivers/clk/shmobile/renesas-cpg-mssr.h index e09f03c..952b695 100644 --- a/drivers/clk/shmobile/renesas-cpg-mssr.h +++ b/drivers/clk/shmobile/renesas-cpg-mssr.h @@ -53,6 +53,8 @@ enum clk_types { DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult) #define DEF_DIV6P1(_name, _id, _parent, _offset) \ DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset) +#define DEF_SD(_name, _id, _parent, _offset) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset) /* diff --git a/drivers/clk/socfpga/clk-gate-a10.c b/drivers/clk/socfpga/clk-gate-a10.c index 1cebf25..c2d5727 100644 --- a/drivers/clk/socfpga/clk-gate-a10.c +++ b/drivers/clk/socfpga/clk-gate-a10.c @@ -115,7 +115,6 @@ static void __init __socfpga_gate_init(struct device_node *node, const char *parent_name[SOCFPGA_MAX_PARENTS]; struct clk_init_data init; int rc; - int i = 0; socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL); if (WARN_ON(!socfpga_clk)) @@ -167,12 +166,9 @@ static void __init __socfpga_gate_init(struct device_node *node, init.name = clk_name; init.ops = ops; init.flags = 0; - while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] = - of_clk_get_parent_name(node, i)) != NULL) - i++; + init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS); init.parent_names = parent_name; - init.num_parents = i; socfpga_clk->hw.hw.init = &init; clk = clk_register(NULL, &socfpga_clk->hw.hw); diff --git a/drivers/clk/socfpga/clk-periph-a10.c b/drivers/clk/socfpga/clk-periph-a10.c index 1f397cb..70993f1 100644 --- a/drivers/clk/socfpga/clk-periph-a10.c +++ b/drivers/clk/socfpga/clk-periph-a10.c @@ -74,7 +74,7 @@ static __init void __socfpga_periph_init(struct device_node *node, struct clk *clk; struct socfpga_periph_clk *periph_clk; const char *clk_name = node->name; - const char *parent_name; + const char *parent_name[SOCFPGA_MAX_PARENTS]; struct clk_init_data init; int rc; u32 fixed_div; @@ -109,9 +109,8 @@ static __init void __socfpga_periph_init(struct device_node *node, init.ops = ops; init.flags = 0; - parent_name = of_clk_get_parent_name(node, 0); - init.num_parents = 1; - init.parent_names = &parent_name; + init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS); + init.parent_names = parent_name; periph_clk->hw.hw.init = &init; diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index 402d630..35fabe1 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -74,7 +74,7 @@ static struct clk_ops clk_pll_ops = { .get_parent = clk_pll_get_parent, }; -static struct __init clk * __socfpga_pll_init(struct device_node *node, +static struct clk * __init __socfpga_pll_init(struct device_node *node, const struct clk_ops *ops) { u32 reg; diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 24d9959..627267c 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -244,10 +244,10 @@ static const char ** __init flexgen_get_parents(struct device_node *np, int *num_parents) { const char **parents; - int nparents; + unsigned int nparents; nparents = of_clk_get_parent_count(np); - if (WARN_ON(nparents <= 0)) + if (WARN_ON(!nparents)) return NULL; parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL); diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index ccb324d..dec4eaa 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -574,12 +574,16 @@ static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate, struct stm_fs params; long hwrate = 0; unsigned long flags = 0; + int ret; if (!rate || !parent_rate) return -EINVAL; - if (!clk_fs660c32_vco_get_params(parent_rate, rate, ¶ms)) - clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &hwrate); + ret = clk_fs660c32_vco_get_params(parent_rate, rate, ¶ms); + if (ret) + return ret; + + clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &hwrate); pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n", __func__, clk_hw_get_name(hw), diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index 5dc5ce2..b1e10ff 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -26,10 +26,10 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np, int *num_parents) { const char **parents; - int nparents; + unsigned int nparents; nparents = of_clk_get_parent_count(np); - if (WARN_ON(nparents <= 0)) + if (WARN_ON(!nparents)) return ERR_PTR(-EINVAL); parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL); @@ -822,11 +822,10 @@ err: if (!clk_data->clks[i]) continue; - composite = container_of(__clk_get_hw(clk_data->clks[i]), - struct clk_composite, hw); - kfree(container_of(composite->gate_hw, struct clk_gate, hw)); - kfree(container_of(composite->rate_hw, struct clk_divider, hw)); - kfree(container_of(composite->mux_hw, struct clk_mux, hw)); + composite = to_clk_composite(__clk_get_hw(clk_data->clks[i])); + kfree(to_clk_gate(composite->gate_hw)); + kfree(to_clk_divider(composite->rate_hw)); + kfree(to_clk_mux(composite->mux_hw)); } kfree(clk_data->clks); diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index e1fe8f3..74e7544 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -450,8 +450,10 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra, struct emc_timing *timing = tegra->timings + (i++); err = load_one_timing_from_dt(tegra, timing, child); - if (err) + if (err) { + of_node_put(child); return err; + } timing->ram_code = ram_code; } @@ -499,9 +501,9 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, * fuses until the apbmisc driver is loaded. */ err = load_timings_from_dt(tegra, node, node_ram_code); + of_node_put(node); if (err) return ERR_PTR(err); - of_node_put(node); break; } diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index 19ce073..62ea381 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -11,6 +11,7 @@ enum clk_id { tegra_clk_afi, tegra_clk_amx, tegra_clk_amx1, + tegra_clk_apb2ape, tegra_clk_apbdma, tegra_clk_apbif, tegra_clk_ape, diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index a534bfa..6ac3f84 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -86,15 +86,21 @@ #define PLLE_SS_DISABLE (PLLE_SS_CNTL_BYPASS_SS | PLLE_SS_CNTL_INTERP_RESET |\ PLLE_SS_CNTL_SSC_BYP) #define PLLE_SS_MAX_MASK 0x1ff -#define PLLE_SS_MAX_VAL 0x25 +#define PLLE_SS_MAX_VAL_TEGRA114 0x25 +#define PLLE_SS_MAX_VAL_TEGRA210 0x21 #define PLLE_SS_INC_MASK (0xff << 16) #define PLLE_SS_INC_VAL (0x1 << 16) #define PLLE_SS_INCINTRV_MASK (0x3f << 24) -#define PLLE_SS_INCINTRV_VAL (0x20 << 24) +#define PLLE_SS_INCINTRV_VAL_TEGRA114 (0x20 << 24) +#define PLLE_SS_INCINTRV_VAL_TEGRA210 (0x23 << 24) #define PLLE_SS_COEFFICIENTS_MASK \ (PLLE_SS_MAX_MASK | PLLE_SS_INC_MASK | PLLE_SS_INCINTRV_MASK) -#define PLLE_SS_COEFFICIENTS_VAL \ - (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL) +#define PLLE_SS_COEFFICIENTS_VAL_TEGRA114 \ + (PLLE_SS_MAX_VAL_TEGRA114 | PLLE_SS_INC_VAL |\ + PLLE_SS_INCINTRV_VAL_TEGRA114) +#define PLLE_SS_COEFFICIENTS_VAL_TEGRA210 \ + (PLLE_SS_MAX_VAL_TEGRA210 | PLLE_SS_INC_VAL |\ + PLLE_SS_INCINTRV_VAL_TEGRA210) #define PLLE_AUX_PLLP_SEL BIT(2) #define PLLE_AUX_USE_LOCKDET BIT(3) @@ -880,7 +886,7 @@ static int clk_plle_training(struct tegra_clk_pll *pll) static int clk_plle_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); - unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); + unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); struct tegra_clk_pll_freq_table sel; u32 val; int err; @@ -1378,7 +1384,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) u32 val; int ret; unsigned long flags = 0; - unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); + unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) return -EINVAL; @@ -1401,7 +1407,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) val |= PLLE_MISC_IDDQ_SW_CTRL; val &= ~PLLE_MISC_IDDQ_SW_VALUE; val |= PLLE_MISC_PLLE_PTS; - val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK; + val &= ~(PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK); pll_writel_misc(val, pll); udelay(5); @@ -1428,7 +1434,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) val = pll_readl(PLLE_SS_CTRL, pll); val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT); val &= ~PLLE_SS_COEFFICIENTS_MASK; - val |= PLLE_SS_COEFFICIENTS_VAL; + val |= PLLE_SS_COEFFICIENTS_VAL_TEGRA114; pll_writel(val, PLLE_SS_CTRL, pll); val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS); pll_writel(val, PLLE_SS_CTRL, pll); @@ -2012,9 +2018,9 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw) struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table sel; u32 val; - int ret; + int ret = 0; unsigned long flags = 0; - unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); + unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) return -EINVAL; @@ -2022,22 +2028,20 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw) if (pll->lock) spin_lock_irqsave(pll->lock, flags); + val = pll_readl(pll->params->aux_reg, pll); + if (val & PLLE_AUX_SEQ_ENABLE) + goto out; + val = pll_readl_base(pll); val &= ~BIT(30); /* Disable lock override */ pll_writel_base(val, pll); - val = pll_readl(pll->params->aux_reg, pll); - val |= PLLE_AUX_ENABLE_SWCTL; - val &= ~PLLE_AUX_SEQ_ENABLE; - pll_writel(val, pll->params->aux_reg, pll); - udelay(1); - val = pll_readl_misc(pll); val |= PLLE_MISC_LOCK_ENABLE; val |= PLLE_MISC_IDDQ_SW_CTRL; val &= ~PLLE_MISC_IDDQ_SW_VALUE; val |= PLLE_MISC_PLLE_PTS; - val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK; + val &= ~(PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK); pll_writel_misc(val, pll); udelay(5); @@ -2067,7 +2071,7 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw) val = pll_readl(PLLE_SS_CTRL, pll); val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT); val &= ~PLLE_SS_COEFFICIENTS_MASK; - val |= PLLE_SS_COEFFICIENTS_VAL; + val |= PLLE_SS_COEFFICIENTS_VAL_TEGRA210; pll_writel(val, PLLE_SS_CTRL, pll); val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS); pll_writel(val, PLLE_SS_CTRL, pll); @@ -2104,15 +2108,25 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw) if (pll->lock) spin_lock_irqsave(pll->lock, flags); + /* If PLLE HW sequencer is enabled, SW should not disable PLLE */ + val = pll_readl(pll->params->aux_reg, pll); + if (val & PLLE_AUX_SEQ_ENABLE) + goto out; + val = pll_readl_base(pll); val &= ~PLLE_BASE_ENABLE; pll_writel_base(val, pll); + val = pll_readl(pll->params->aux_reg, pll); + val |= PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL; + pll_writel(val, pll->params->aux_reg, pll); + val = pll_readl_misc(pll); val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE; pll_writel_misc(val, pll); udelay(1); +out: if (pll->lock) spin_unlock_irqrestore(pll->lock, flags); } diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 6ad381a..ea2b9cbf 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -773,7 +773,7 @@ static struct tegra_periph_init_data periph_clks[] = { XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src), XUSB("xusb_dev_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src_8), MUX8("dbgapb", mux_pllp_clkm_2, CLK_SOURCE_DBGAPB, 185, TEGRA_PERIPH_NO_RESET, tegra_clk_dbgapb), - MUX8("msenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc), + MUX8("nvenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc), MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec), MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg), MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape), @@ -782,7 +782,7 @@ static struct tegra_periph_init_data periph_clks[] = { NODIV("sor1", mux_clkm_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 15, MASK(1), 183, 0, tegra_clk_sor1, &sor1_lock), MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy), MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi), - MUX("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, TEGRA_PERIPH_ON_APB, tegra_clk_vi_i2c), + I2C("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, tegra_clk_vi_i2c), MUX("mipibif", mux_pllp_clkm, CLK_SOURCE_MIPIBIF, 173, TEGRA_PERIPH_ON_APB, tegra_clk_mipibif), MUX("uartape", mux_pllp_pllc_clkm, CLK_SOURCE_UARTAPE, 212, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_uartape), MUX8("tsecb", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_TSECB, 206, 0, tegra_clk_tsecb), @@ -829,6 +829,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("xusb_gate", "osc", 143, 0, tegra_clk_xusb_gate, 0), GATE("pll_p_out_cpu", "pll_p", 223, 0, tegra_clk_pll_p_out_cpu, 0), GATE("pll_p_out_adsp", "pll_p", 187, 0, tegra_clk_pll_p_out_adsp, 0), + GATE("apb2ape", "clk_m", 107, 0, tegra_clk_apb2ape, 0), }; static struct tegra_periph_init_data div_clks[] = { diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index 4559a20..474de0f 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -67,7 +67,7 @@ static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", "pll_p", "pll_p_out4", "unused", "unused", "pll_x", "pll_x_out0" }; -const struct tegra_super_gen_info tegra_super_gen_info_gen4 = { +static const struct tegra_super_gen_info tegra_super_gen_info_gen4 = { .gen = gen4, .sclk_parents = sclk_parents, .cclk_g_parents = cclk_g_parents, @@ -93,7 +93,7 @@ static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unu "unused", "unused", "unused", "unused", "dfllCPU_out" }; -const struct tegra_super_gen_info tegra_super_gen_info_gen5 = { +static const struct tegra_super_gen_info tegra_super_gen_info_gen5 = { .gen = gen5, .sclk_parents = sclk_parents_gen5, .cclk_g_parents = cclk_g_parents_gen5, @@ -171,7 +171,7 @@ static void __init tegra_sclk_init(void __iomem *clk_base, *dt_clk = clk; } -void __init tegra_super_clk_init(void __iomem *clk_base, +static void __init tegra_super_clk_init(void __iomem *clk_base, void __iomem *pmc_base, struct tegra_clk *tegra_clks, struct tegra_clk_pll_params *params, diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 58514c4..637041f 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -59,8 +59,8 @@ #define PLLC3_MISC3 0x50c #define PLLM_BASE 0x90 -#define PLLM_MISC0 0x9c #define PLLM_MISC1 0x98 +#define PLLM_MISC2 0x9c #define PLLP_BASE 0xa0 #define PLLP_MISC0 0xac #define PLLP_MISC1 0x680 @@ -99,7 +99,7 @@ #define PLLC4_MISC0 0x5a8 #define PLLC4_OUT 0x5e4 #define PLLMB_BASE 0x5e8 -#define PLLMB_MISC0 0x5ec +#define PLLMB_MISC1 0x5ec #define PLLA1_BASE 0x6a4 #define PLLA1_MISC0 0x6a8 #define PLLA1_MISC1 0x6ac @@ -243,7 +243,8 @@ static unsigned long tegra210_input_freq[] = { }; static const char *mux_pllmcp_clkm[] = { - "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3", + "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_mb", "pll_mb", + "pll_p", }; #define mux_pllmcp_clkm_idx NULL @@ -367,12 +368,12 @@ static const char *mux_pllmcp_clkm[] = { /* PLLMB */ #define PLLMB_BASE_LOCK (1 << 27) -#define PLLMB_MISC0_LOCK_OVERRIDE (1 << 18) -#define PLLMB_MISC0_IDDQ (1 << 17) -#define PLLMB_MISC0_LOCK_ENABLE (1 << 16) +#define PLLMB_MISC1_LOCK_OVERRIDE (1 << 18) +#define PLLMB_MISC1_IDDQ (1 << 17) +#define PLLMB_MISC1_LOCK_ENABLE (1 << 16) -#define PLLMB_MISC0_DEFAULT_VALUE 0x00030000 -#define PLLMB_MISC0_WRITE_MASK 0x0007ffff +#define PLLMB_MISC1_DEFAULT_VALUE 0x00030000 +#define PLLMB_MISC1_WRITE_MASK 0x0007ffff /* PLLP */ #define PLLP_BASE_OVERRIDE (1 << 28) @@ -457,7 +458,8 @@ static void pllcx_check_defaults(struct tegra_clk_pll_params *params) PLLCX_MISC3_WRITE_MASK); } -void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx) +static void tegra210_pllcx_set_defaults(const char *name, + struct tegra_clk_pll *pllcx) { pllcx->params->defaults_set = true; @@ -482,22 +484,22 @@ void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx) udelay(1); } -void _pllc_set_defaults(struct tegra_clk_pll *pllcx) +static void _pllc_set_defaults(struct tegra_clk_pll *pllcx) { tegra210_pllcx_set_defaults("PLL_C", pllcx); } -void _pllc2_set_defaults(struct tegra_clk_pll *pllcx) +static void _pllc2_set_defaults(struct tegra_clk_pll *pllcx) { tegra210_pllcx_set_defaults("PLL_C2", pllcx); } -void _pllc3_set_defaults(struct tegra_clk_pll *pllcx) +static void _pllc3_set_defaults(struct tegra_clk_pll *pllcx) { tegra210_pllcx_set_defaults("PLL_C3", pllcx); } -void _plla1_set_defaults(struct tegra_clk_pll *pllcx) +static void _plla1_set_defaults(struct tegra_clk_pll *pllcx) { tegra210_pllcx_set_defaults("PLL_A1", pllcx); } @@ -507,7 +509,7 @@ void _plla1_set_defaults(struct tegra_clk_pll *pllcx) * PLL with dynamic ramp and fractional SDM. Dynamic ramp is not used. * Fractional SDM is allowed to provide exact audio rates. */ -void tegra210_plla_set_defaults(struct tegra_clk_pll *plla) +static void tegra210_plla_set_defaults(struct tegra_clk_pll *plla) { u32 mask; u32 val = readl_relaxed(clk_base + plla->params->base_reg); @@ -559,7 +561,7 @@ void tegra210_plla_set_defaults(struct tegra_clk_pll *plla) * PLLD * PLL with fractional SDM. */ -void tegra210_plld_set_defaults(struct tegra_clk_pll *plld) +static void tegra210_plld_set_defaults(struct tegra_clk_pll *plld) { u32 val; u32 mask = 0xffff; @@ -698,7 +700,7 @@ static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss, udelay(1); } -void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2) +static void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2) { plldss_defaults("PLL_D2", plld2, PLLD2_MISC0_DEFAULT_VALUE, PLLD2_MISC1_CFG_DEFAULT_VALUE, @@ -706,7 +708,7 @@ void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2) PLLD2_MISC3_CTRL2_DEFAULT_VALUE); } -void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp) +static void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp) { plldss_defaults("PLL_DP", plldp, PLLDP_MISC0_DEFAULT_VALUE, PLLDP_MISC1_CFG_DEFAULT_VALUE, @@ -719,7 +721,7 @@ void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp) * Base and misc0 layout is the same as PLLD2/PLLDP, but no SDM/SSC support. * VCO is exposed to the clock tree via fixed 1/3 and 1/5 dividers. */ -void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4) +static void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4) { plldss_defaults("PLL_C4", pllc4, PLLC4_MISC0_DEFAULT_VALUE, 0, 0, 0); } @@ -728,7 +730,7 @@ void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4) * PLLRE * VCO is exposed to the clock tree directly along with post-divider output */ -void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre) +static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre) { u32 mask; u32 val = readl_relaxed(clk_base + pllre->params->base_reg); @@ -780,13 +782,13 @@ static void pllx_get_dyn_steps(struct clk_hw *hw, u32 *step_a, u32 *step_b) { unsigned long input_rate; - if (!IS_ERR_OR_NULL(hw->clk)) { + /* cf rate */ + if (!IS_ERR_OR_NULL(hw->clk)) input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); - /* cf rate */ - input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate); - } else { + else input_rate = 38400000; - } + + input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate); switch (input_rate) { case 12000000: @@ -841,7 +843,7 @@ static void pllx_check_defaults(struct tegra_clk_pll *pll) PLLX_MISC5_WRITE_MASK); } -void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx) +static void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx) { u32 val; u32 step_a, step_b; @@ -901,7 +903,7 @@ void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx) } /* PLLMB */ -void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb) +static void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb) { u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg); @@ -914,15 +916,15 @@ void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb) * PLL is ON: check if defaults already set, then set those * that can be updated in flight. */ - val = PLLMB_MISC0_DEFAULT_VALUE & (~PLLMB_MISC0_IDDQ); - mask = PLLMB_MISC0_LOCK_ENABLE | PLLMB_MISC0_LOCK_OVERRIDE; + val = PLLMB_MISC1_DEFAULT_VALUE & (~PLLMB_MISC1_IDDQ); + mask = PLLMB_MISC1_LOCK_ENABLE | PLLMB_MISC1_LOCK_OVERRIDE; _pll_misc_chk_default(clk_base, pllmb->params, 0, val, - ~mask & PLLMB_MISC0_WRITE_MASK); + ~mask & PLLMB_MISC1_WRITE_MASK); /* Enable lock detect */ val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]); val &= ~mask; - val |= PLLMB_MISC0_DEFAULT_VALUE & mask; + val |= PLLMB_MISC1_DEFAULT_VALUE & mask; writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]); udelay(1); @@ -930,7 +932,7 @@ void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb) } /* set IDDQ, enable lock detect */ - writel_relaxed(PLLMB_MISC0_DEFAULT_VALUE, + writel_relaxed(PLLMB_MISC1_DEFAULT_VALUE, clk_base + pllmb->params->ext_misc_reg[0]); udelay(1); } @@ -960,7 +962,7 @@ static void pllp_check_defaults(struct tegra_clk_pll *pll, bool enabled) ~mask & PLLP_MISC1_WRITE_MASK); } -void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp) +static void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp) { u32 mask; u32 val = readl_relaxed(clk_base + pllp->params->base_reg); @@ -1022,7 +1024,7 @@ static void pllu_check_defaults(struct tegra_clk_pll *pll, bool hw_control) ~mask & PLLU_MISC1_WRITE_MASK); } -void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu) +static void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu) { u32 val = readl_relaxed(clk_base + pllu->params->base_reg); @@ -1212,8 +1214,9 @@ static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg) cfg->m *= PLL_SDM_COEFF; } -unsigned long tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params, - unsigned long parent_rate) +static unsigned long +tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params, + unsigned long parent_rate) { unsigned long vco_min = params->vco_min; @@ -1386,7 +1389,7 @@ static struct tegra_clk_pll_params pll_c_params = { .mdiv_default = 3, .div_nmp = &pllc_nmp, .freq_table = pll_cx_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .set_defaults = _pllc_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1425,7 +1428,7 @@ static struct tegra_clk_pll_params pll_c2_params = { .ext_misc_reg[2] = PLLC2_MISC2, .ext_misc_reg[3] = PLLC2_MISC3, .freq_table = pll_cx_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .set_defaults = _pllc2_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1455,7 +1458,7 @@ static struct tegra_clk_pll_params pll_c3_params = { .ext_misc_reg[2] = PLLC3_MISC2, .ext_misc_reg[3] = PLLC3_MISC3, .freq_table = pll_cx_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .set_defaults = _pllc3_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1505,7 +1508,6 @@ static struct tegra_clk_pll_params pll_c4_vco_params = { .base_reg = PLLC4_BASE, .misc_reg = PLLC4_MISC0, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, .lock_delay = 300, .max_p = PLL_QLIN_PDIV_MAX, .ext_misc_reg[0] = PLLC4_MISC0, @@ -1517,8 +1519,7 @@ static struct tegra_clk_pll_params pll_c4_vco_params = { .div_nmp = &pllss_nmp, .freq_table = pll_c4_vco_freq_table, .set_defaults = tegra210_pllc4_set_defaults, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | - TEGRA_PLL_VCO_OUT, + .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1559,15 +1560,15 @@ static struct tegra_clk_pll_params pll_m_params = { .vco_min = 800000000, .vco_max = 1866000000, .base_reg = PLLM_BASE, - .misc_reg = PLLM_MISC1, + .misc_reg = PLLM_MISC2, .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLM_MISC_LOCK_ENABLE, .lock_delay = 300, - .iddq_reg = PLLM_MISC0, + .iddq_reg = PLLM_MISC2, .iddq_bit_idx = PLLM_IDDQ_BIT, .max_p = PLL_QLIN_PDIV_MAX, - .ext_misc_reg[0] = PLLM_MISC0, - .ext_misc_reg[0] = PLLM_MISC1, + .ext_misc_reg[0] = PLLM_MISC2, + .ext_misc_reg[1] = PLLM_MISC1, .round_p_to_pdiv = pll_qlin_p_to_pdiv, .pdiv_tohw = pll_qlin_pdiv_to_hw, .div_nmp = &pllm_nmp, @@ -1586,19 +1587,18 @@ static struct tegra_clk_pll_params pll_mb_params = { .vco_min = 800000000, .vco_max = 1866000000, .base_reg = PLLMB_BASE, - .misc_reg = PLLMB_MISC0, + .misc_reg = PLLMB_MISC1, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLMB_MISC_LOCK_ENABLE, .lock_delay = 300, - .iddq_reg = PLLMB_MISC0, + .iddq_reg = PLLMB_MISC1, .iddq_bit_idx = PLLMB_IDDQ_BIT, .max_p = PLL_QLIN_PDIV_MAX, - .ext_misc_reg[0] = PLLMB_MISC0, + .ext_misc_reg[0] = PLLMB_MISC1, .round_p_to_pdiv = pll_qlin_p_to_pdiv, .pdiv_tohw = pll_qlin_pdiv_to_hw, .div_nmp = &pllm_nmp, .freq_table = pll_m_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .set_defaults = tegra210_pllmb_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1671,7 +1671,6 @@ static struct tegra_clk_pll_params pll_re_vco_params = { .base_reg = PLLRE_BASE, .misc_reg = PLLRE_MISC0, .lock_mask = PLLRE_MISC_LOCK, - .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE, .lock_delay = 300, .max_p = PLL_QLIN_PDIV_MAX, .ext_misc_reg[0] = PLLRE_MISC0, @@ -1681,8 +1680,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = { .pdiv_tohw = pll_qlin_pdiv_to_hw, .div_nmp = &pllre_nmp, .freq_table = pll_re_vco_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC | - TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT, + .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC | TEGRA_PLL_VCO_OUT, .set_defaults = tegra210_pllre_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1712,7 +1710,6 @@ static struct tegra_clk_pll_params pll_p_params = { .base_reg = PLLP_BASE, .misc_reg = PLLP_MISC0, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLP_MISC_LOCK_ENABLE, .lock_delay = 300, .iddq_reg = PLLP_MISC0, .iddq_bit_idx = PLLXP_IDDQ_BIT, @@ -1721,8 +1718,7 @@ static struct tegra_clk_pll_params pll_p_params = { .div_nmp = &pllp_nmp, .freq_table = pll_p_freq_table, .fixed_rate = 408000000, - .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK | - TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT, + .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT, .set_defaults = tegra210_pllp_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1750,7 +1746,7 @@ static struct tegra_clk_pll_params pll_a1_params = { .ext_misc_reg[2] = PLLA1_MISC2, .ext_misc_reg[3] = PLLA1_MISC3, .freq_table = pll_cx_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .set_defaults = _plla1_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -1787,7 +1783,6 @@ static struct tegra_clk_pll_params pll_a_params = { .base_reg = PLLA_BASE, .misc_reg = PLLA_MISC0, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLA_MISC_LOCK_ENABLE, .lock_delay = 300, .round_p_to_pdiv = pll_qlin_p_to_pdiv, .pdiv_tohw = pll_qlin_pdiv_to_hw, @@ -1802,8 +1797,7 @@ static struct tegra_clk_pll_params pll_a_params = { .ext_misc_reg[1] = PLLA_MISC1, .ext_misc_reg[2] = PLLA_MISC2, .freq_table = pll_a_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW | - TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW, .set_defaults = tegra210_plla_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, .set_gain = tegra210_clk_pll_set_gain, @@ -1836,7 +1830,6 @@ static struct tegra_clk_pll_params pll_d_params = { .base_reg = PLLD_BASE, .misc_reg = PLLD_MISC0, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLD_MISC_LOCK_ENABLE, .lock_delay = 1000, .iddq_reg = PLLD_MISC0, .iddq_bit_idx = PLLD_IDDQ_BIT, @@ -1850,7 +1843,7 @@ static struct tegra_clk_pll_params pll_d_params = { .ext_misc_reg[0] = PLLD_MISC0, .ext_misc_reg[1] = PLLD_MISC1, .freq_table = pll_d_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .mdiv_default = 1, .set_defaults = tegra210_plld_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, @@ -1876,7 +1869,6 @@ static struct tegra_clk_pll_params pll_d2_params = { .base_reg = PLLD2_BASE, .misc_reg = PLLD2_MISC0, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, .lock_delay = 300, .iddq_reg = PLLD2_BASE, .iddq_bit_idx = PLLSS_IDDQ_BIT, @@ -1897,7 +1889,7 @@ static struct tegra_clk_pll_params pll_d2_params = { .mdiv_default = 1, .freq_table = tegra210_pll_d2_freq_table, .set_defaults = tegra210_plld2_set_defaults, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .calc_rate = tegra210_pll_fixed_mdiv_cfg, .set_gain = tegra210_clk_pll_set_gain, .adjust_vco = tegra210_clk_adjust_vco_min, @@ -1920,7 +1912,6 @@ static struct tegra_clk_pll_params pll_dp_params = { .base_reg = PLLDP_BASE, .misc_reg = PLLDP_MISC, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, .lock_delay = 300, .iddq_reg = PLLDP_BASE, .iddq_bit_idx = PLLSS_IDDQ_BIT, @@ -1941,7 +1932,7 @@ static struct tegra_clk_pll_params pll_dp_params = { .mdiv_default = 1, .freq_table = pll_dp_freq_table, .set_defaults = tegra210_plldp_set_defaults, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, .calc_rate = tegra210_pll_fixed_mdiv_cfg, .set_gain = tegra210_clk_pll_set_gain, .adjust_vco = tegra210_clk_adjust_vco_min, @@ -1973,7 +1964,6 @@ static struct tegra_clk_pll_params pll_u_vco_params = { .base_reg = PLLU_BASE, .misc_reg = PLLU_MISC0, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLLU_MISC_LOCK_ENABLE, .lock_delay = 1000, .iddq_reg = PLLU_MISC0, .iddq_bit_idx = PLLU_IDDQ_BIT, @@ -1983,8 +1973,7 @@ static struct tegra_clk_pll_params pll_u_vco_params = { .pdiv_tohw = pll_qlin_pdiv_to_hw, .div_nmp = &pllu_nmp, .freq_table = pll_u_freq_table, - .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | - TEGRA_PLL_VCO_OUT, + .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT, .set_defaults = tegra210_pllu_set_defaults, .calc_rate = tegra210_pll_fixed_mdiv_cfg, }; @@ -2218,6 +2207,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_pll_c4_out1] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT1, .present = true }, [tegra_clk_pll_c4_out2] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT2, .present = true }, [tegra_clk_pll_c4_out3] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT3, .present = true }, + [tegra_clk_apb2ape] = { .dt_id = TEGRA210_CLK_APB2APE, .present = true }, }; static struct tegra_devclk devclks[] __initdata = { @@ -2519,7 +2509,7 @@ static void __init tegra210_pll_init(void __iomem *clk_base, /* PLLU_VCO */ val = readl(clk_base + pll_u_vco_params.base_reg); - val &= ~BIT(24); /* disable PLLU_OVERRIDE */ + val &= ~PLLU_BASE_OVERRIDE; /* disable PLLU_OVERRIDE */ writel(val, clk_base + pll_u_vco_params.base_reg); clk = tegra_clk_register_pllre("pll_u_vco", "pll_ref", clk_base, pmc, @@ -2738,8 +2728,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 }, { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 }, - { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 }, - { TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 }, { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 }, { TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 }, diff --git a/drivers/clk/ti/Kconfig b/drivers/clk/ti/Kconfig new file mode 100644 index 0000000..2713417 --- /dev/null +++ b/drivers/clk/ti/Kconfig @@ -0,0 +1,6 @@ +config COMMON_CLK_TI_ADPLL + tristate "Clock driver for dm814x ADPLL" + depends on ARCH_OMAP2PLUS || COMPILE_TEST + default y if SOC_TI81XX + ---help--- + ADPLL clock driver for the dm814x SoC using common clock framework. diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index d4ac960..0deac98 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -1,3 +1,5 @@ +ifeq ($(CONFIG_ARCH_OMAP2PLUS), y) + obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ fixed-factor.o mux.o apll.o \ @@ -18,3 +20,7 @@ obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o ifdef CONFIG_ATAGS obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o endif + +endif # CONFIG_ARCH_OMAP2PLUS + +obj-$(CONFIG_COMMON_CLK_TI_ADPLL) += adpll.o diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c new file mode 100644 index 0000000..255cafb --- /dev/null +++ b/drivers/clk/ti/adpll.c @@ -0,0 +1,983 @@ +/* + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/string.h> + +#define ADPLL_PLLSS_MMR_LOCK_OFFSET 0x00 /* Managed by MPPULL */ +#define ADPLL_PLLSS_MMR_LOCK_ENABLED 0x1f125B64 +#define ADPLL_PLLSS_MMR_UNLOCK_MAGIC 0x1eda4c3d + +#define ADPLL_PWRCTRL_OFFSET 0x00 +#define ADPLL_PWRCTRL_PONIN 5 +#define ADPLL_PWRCTRL_PGOODIN 4 +#define ADPLL_PWRCTRL_RET 3 +#define ADPLL_PWRCTRL_ISORET 2 +#define ADPLL_PWRCTRL_ISOSCAN 1 +#define ADPLL_PWRCTRL_OFFMODE 0 + +#define ADPLL_CLKCTRL_OFFSET 0x04 +#define ADPLL_CLKCTRL_CLKDCOLDOEN 29 +#define ADPLL_CLKCTRL_IDLE 23 +#define ADPLL_CLKCTRL_CLKOUTEN 20 +#define ADPLL_CLKINPHIFSEL_ADPLL_S 19 /* REVISIT: which bit? */ +#define ADPLL_CLKCTRL_CLKOUTLDOEN_ADPLL_LJ 19 +#define ADPLL_CLKCTRL_ULOWCLKEN 18 +#define ADPLL_CLKCTRL_CLKDCOLDOPWDNZ 17 +#define ADPLL_CLKCTRL_M2PWDNZ 16 +#define ADPLL_CLKCTRL_M3PWDNZ_ADPLL_S 15 +#define ADPLL_CLKCTRL_LOWCURRSTDBY_ADPLL_S 13 +#define ADPLL_CLKCTRL_LPMODE_ADPLL_S 12 +#define ADPLL_CLKCTRL_REGM4XEN_ADPLL_S 10 +#define ADPLL_CLKCTRL_SELFREQDCO_ADPLL_LJ 10 +#define ADPLL_CLKCTRL_TINITZ 0 + +#define ADPLL_TENABLE_OFFSET 0x08 +#define ADPLL_TENABLEDIV_OFFSET 0x8c + +#define ADPLL_M2NDIV_OFFSET 0x10 +#define ADPLL_M2NDIV_M2 16 +#define ADPLL_M2NDIV_M2_ADPLL_S_WIDTH 5 +#define ADPLL_M2NDIV_M2_ADPLL_LJ_WIDTH 7 + +#define ADPLL_MN2DIV_OFFSET 0x14 +#define ADPLL_MN2DIV_N2 16 + +#define ADPLL_FRACDIV_OFFSET 0x18 +#define ADPLL_FRACDIV_REGSD 24 +#define ADPLL_FRACDIV_FRACTIONALM 0 +#define ADPLL_FRACDIV_FRACTIONALM_MASK 0x3ffff + +#define ADPLL_BWCTRL_OFFSET 0x1c +#define ADPLL_BWCTRL_BWCONTROL 1 +#define ADPLL_BWCTRL_BW_INCR_DECRZ 0 + +#define ADPLL_RESERVED_OFFSET 0x20 + +#define ADPLL_STATUS_OFFSET 0x24 +#define ADPLL_STATUS_PONOUT 31 +#define ADPLL_STATUS_PGOODOUT 30 +#define ADPLL_STATUS_LDOPWDN 29 +#define ADPLL_STATUS_RECAL_BSTATUS3 28 +#define ADPLL_STATUS_RECAL_OPPIN 27 +#define ADPLL_STATUS_PHASELOCK 10 +#define ADPLL_STATUS_FREQLOCK 9 +#define ADPLL_STATUS_BYPASSACK 8 +#define ADPLL_STATUS_LOSSREF 6 +#define ADPLL_STATUS_CLKOUTENACK 5 +#define ADPLL_STATUS_LOCK2 4 +#define ADPLL_STATUS_M2CHANGEACK 3 +#define ADPLL_STATUS_HIGHJITTER 1 +#define ADPLL_STATUS_BYPASS 0 +#define ADPLL_STATUS_PREPARED_MASK (BIT(ADPLL_STATUS_PHASELOCK) | \ + BIT(ADPLL_STATUS_FREQLOCK)) + +#define ADPLL_M3DIV_OFFSET 0x28 /* Only on MPUPLL */ +#define ADPLL_M3DIV_M3 0 +#define ADPLL_M3DIV_M3_WIDTH 5 +#define ADPLL_M3DIV_M3_MASK 0x1f + +#define ADPLL_RAMPCTRL_OFFSET 0x2c /* Only on MPUPLL */ +#define ADPLL_RAMPCTRL_CLKRAMPLEVEL 19 +#define ADPLL_RAMPCTRL_CLKRAMPRATE 16 +#define ADPLL_RAMPCTRL_RELOCK_RAMP_EN 0 + +#define MAX_ADPLL_INPUTS 3 +#define MAX_ADPLL_OUTPUTS 4 +#define ADPLL_MAX_RETRIES 5 + +#define to_dco(_hw) container_of(_hw, struct ti_adpll_dco_data, hw) +#define to_adpll(_hw) container_of(_hw, struct ti_adpll_data, dco) +#define to_clkout(_hw) container_of(_hw, struct ti_adpll_clkout_data, hw) + +enum ti_adpll_clocks { + TI_ADPLL_DCO, + TI_ADPLL_DCO_GATE, + TI_ADPLL_N2, + TI_ADPLL_M2, + TI_ADPLL_M2_GATE, + TI_ADPLL_BYPASS, + TI_ADPLL_HIF, + TI_ADPLL_DIV2, + TI_ADPLL_CLKOUT, + TI_ADPLL_CLKOUT2, + TI_ADPLL_M3, +}; + +#define TI_ADPLL_NR_CLOCKS (TI_ADPLL_M3 + 1) + +enum ti_adpll_inputs { + TI_ADPLL_CLKINP, + TI_ADPLL_CLKINPULOW, + TI_ADPLL_CLKINPHIF, +}; + +enum ti_adpll_s_outputs { + TI_ADPLL_S_DCOCLKLDO, + TI_ADPLL_S_CLKOUT, + TI_ADPLL_S_CLKOUTX2, + TI_ADPLL_S_CLKOUTHIF, +}; + +enum ti_adpll_lj_outputs { + TI_ADPLL_LJ_CLKDCOLDO, + TI_ADPLL_LJ_CLKOUT, + TI_ADPLL_LJ_CLKOUTLDO, +}; + +struct ti_adpll_platform_data { + const bool is_type_s; + const int nr_max_inputs; + const int nr_max_outputs; + const int output_index; +}; + +struct ti_adpll_clock { + struct clk *clk; + struct clk_lookup *cl; + void (*unregister)(struct clk *clk); +}; + +struct ti_adpll_dco_data { + struct clk_hw hw; +}; + +struct ti_adpll_clkout_data { + struct ti_adpll_data *adpll; + struct clk_gate gate; + struct clk_hw hw; +}; + +struct ti_adpll_data { + struct device *dev; + const struct ti_adpll_platform_data *c; + struct device_node *np; + unsigned long pa; + void __iomem *iobase; + void __iomem *regs; + spinlock_t lock; /* For ADPLL shared register access */ + const char *parent_names[MAX_ADPLL_INPUTS]; + struct clk *parent_clocks[MAX_ADPLL_INPUTS]; + struct ti_adpll_clock *clocks; + struct clk_onecell_data outputs; + struct ti_adpll_dco_data dco; +}; + +static const char *ti_adpll_clk_get_name(struct ti_adpll_data *d, + int output_index, + const char *postfix) +{ + const char *name; + int err; + + if (output_index >= 0) { + err = of_property_read_string_index(d->np, + "clock-output-names", + output_index, + &name); + if (err) + return NULL; + } else { + const char *base_name = "adpll"; + char *buf; + + buf = devm_kzalloc(d->dev, 8 + 1 + strlen(base_name) + 1 + + strlen(postfix), GFP_KERNEL); + if (!buf) + return NULL; + sprintf(buf, "%08lx.%s.%s", d->pa, base_name, postfix); + name = buf; + } + + return name; +} + +#define ADPLL_MAX_CON_ID 16 /* See MAX_CON_ID */ + +static int ti_adpll_setup_clock(struct ti_adpll_data *d, struct clk *clock, + int index, int output_index, const char *name, + void (*unregister)(struct clk *clk)) +{ + struct clk_lookup *cl; + const char *postfix = NULL; + char con_id[ADPLL_MAX_CON_ID]; + + d->clocks[index].clk = clock; + d->clocks[index].unregister = unregister; + + /* Separate con_id in format "pll040dcoclkldo" to fit MAX_CON_ID */ + postfix = strrchr(name, '.'); + if (strlen(postfix) > 1) { + if (strlen(postfix) > ADPLL_MAX_CON_ID) + dev_warn(d->dev, "clock %s con_id lookup may fail\n", + name); + snprintf(con_id, 16, "pll%03lx%s", d->pa & 0xfff, postfix + 1); + cl = clkdev_create(clock, con_id, NULL); + if (!cl) + return -ENOMEM; + d->clocks[index].cl = cl; + } else { + dev_warn(d->dev, "no con_id for clock %s\n", name); + } + + if (output_index < 0) + return 0; + + d->outputs.clks[output_index] = clock; + d->outputs.clk_num++; + + return 0; +} + +static int ti_adpll_init_divider(struct ti_adpll_data *d, + enum ti_adpll_clocks index, + int output_index, char *name, + struct clk *parent_clock, + void __iomem *reg, + u8 shift, u8 width, + u8 clk_divider_flags) +{ + const char *child_name; + const char *parent_name; + struct clk *clock; + + child_name = ti_adpll_clk_get_name(d, output_index, name); + if (!child_name) + return -EINVAL; + + parent_name = __clk_get_name(parent_clock); + clock = clk_register_divider(d->dev, child_name, parent_name, 0, + reg, shift, width, clk_divider_flags, + &d->lock); + if (IS_ERR(clock)) { + dev_err(d->dev, "failed to register divider %s: %li\n", + name, PTR_ERR(clock)); + return PTR_ERR(clock); + } + + return ti_adpll_setup_clock(d, clock, index, output_index, child_name, + clk_unregister_divider); +} + +static int ti_adpll_init_mux(struct ti_adpll_data *d, + enum ti_adpll_clocks index, + char *name, struct clk *clk0, + struct clk *clk1, + void __iomem *reg, + u8 shift) +{ + const char *child_name; + const char *parents[2]; + struct clk *clock; + + child_name = ti_adpll_clk_get_name(d, -ENODEV, name); + if (!child_name) + return -ENOMEM; + parents[0] = __clk_get_name(clk0); + parents[1] = __clk_get_name(clk1); + clock = clk_register_mux(d->dev, child_name, parents, 2, 0, + reg, shift, 1, 0, &d->lock); + if (IS_ERR(clock)) { + dev_err(d->dev, "failed to register mux %s: %li\n", + name, PTR_ERR(clock)); + return PTR_ERR(clock); + } + + return ti_adpll_setup_clock(d, clock, index, -ENODEV, child_name, + clk_unregister_mux); +} + +static int ti_adpll_init_gate(struct ti_adpll_data *d, + enum ti_adpll_clocks index, + int output_index, char *name, + struct clk *parent_clock, + void __iomem *reg, + u8 bit_idx, + u8 clk_gate_flags) +{ + const char *child_name; + const char *parent_name; + struct clk *clock; + + child_name = ti_adpll_clk_get_name(d, output_index, name); + if (!child_name) + return -EINVAL; + + parent_name = __clk_get_name(parent_clock); + clock = clk_register_gate(d->dev, child_name, parent_name, 0, + reg, bit_idx, clk_gate_flags, + &d->lock); + if (IS_ERR(clock)) { + dev_err(d->dev, "failed to register gate %s: %li\n", + name, PTR_ERR(clock)); + return PTR_ERR(clock); + } + + return ti_adpll_setup_clock(d, clock, index, output_index, child_name, + clk_unregister_gate); +} + +static int ti_adpll_init_fixed_factor(struct ti_adpll_data *d, + enum ti_adpll_clocks index, + char *name, + struct clk *parent_clock, + unsigned int mult, + unsigned int div) +{ + const char *child_name; + const char *parent_name; + struct clk *clock; + + child_name = ti_adpll_clk_get_name(d, -ENODEV, name); + if (!child_name) + return -ENOMEM; + + parent_name = __clk_get_name(parent_clock); + clock = clk_register_fixed_factor(d->dev, child_name, parent_name, + 0, mult, div); + if (IS_ERR(clock)) + return PTR_ERR(clock); + + return ti_adpll_setup_clock(d, clock, index, -ENODEV, child_name, + clk_unregister); +} + +static void ti_adpll_set_idle_bypass(struct ti_adpll_data *d) +{ + unsigned long flags; + u32 v; + + spin_lock_irqsave(&d->lock, flags); + v = readl_relaxed(d->regs + ADPLL_CLKCTRL_OFFSET); + v |= BIT(ADPLL_CLKCTRL_IDLE); + writel_relaxed(v, d->regs + ADPLL_CLKCTRL_OFFSET); + spin_unlock_irqrestore(&d->lock, flags); +} + +static void ti_adpll_clear_idle_bypass(struct ti_adpll_data *d) +{ + unsigned long flags; + u32 v; + + spin_lock_irqsave(&d->lock, flags); + v = readl_relaxed(d->regs + ADPLL_CLKCTRL_OFFSET); + v &= ~BIT(ADPLL_CLKCTRL_IDLE); + writel_relaxed(v, d->regs + ADPLL_CLKCTRL_OFFSET); + spin_unlock_irqrestore(&d->lock, flags); +} + +static bool ti_adpll_clock_is_bypass(struct ti_adpll_data *d) +{ + u32 v; + + v = readl_relaxed(d->regs + ADPLL_STATUS_OFFSET); + + return v & BIT(ADPLL_STATUS_BYPASS); +} + +/* + * Locked and bypass are not actually mutually exclusive: if you only care + * about the DCO clock and not CLKOUT you can clear M2PWDNZ before enabling + * the PLL, resulting in status (FREQLOCK | PHASELOCK | BYPASS) after lock. + */ +static bool ti_adpll_is_locked(struct ti_adpll_data *d) +{ + u32 v = readl_relaxed(d->regs + ADPLL_STATUS_OFFSET); + + return (v & ADPLL_STATUS_PREPARED_MASK) == ADPLL_STATUS_PREPARED_MASK; +} + +static int ti_adpll_wait_lock(struct ti_adpll_data *d) +{ + int retries = ADPLL_MAX_RETRIES; + + do { + if (ti_adpll_is_locked(d)) + return 0; + usleep_range(200, 300); + } while (retries--); + + dev_err(d->dev, "pll failed to lock\n"); + return -ETIMEDOUT; +} + +static int ti_adpll_prepare(struct clk_hw *hw) +{ + struct ti_adpll_dco_data *dco = to_dco(hw); + struct ti_adpll_data *d = to_adpll(dco); + + ti_adpll_clear_idle_bypass(d); + ti_adpll_wait_lock(d); + + return 0; +} + +static void ti_adpll_unprepare(struct clk_hw *hw) +{ + struct ti_adpll_dco_data *dco = to_dco(hw); + struct ti_adpll_data *d = to_adpll(dco); + + ti_adpll_set_idle_bypass(d); +} + +static int ti_adpll_is_prepared(struct clk_hw *hw) +{ + struct ti_adpll_dco_data *dco = to_dco(hw); + struct ti_adpll_data *d = to_adpll(dco); + + return ti_adpll_is_locked(d); +} + +/* + * Note that the DCO clock is never subject to bypass: if the PLL is off, + * dcoclk is low. + */ +static unsigned long ti_adpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ti_adpll_dco_data *dco = to_dco(hw); + struct ti_adpll_data *d = to_adpll(dco); + u32 frac_m, divider, v; + u64 rate; + unsigned long flags; + + if (ti_adpll_clock_is_bypass(d)) + return 0; + + spin_lock_irqsave(&d->lock, flags); + frac_m = readl_relaxed(d->regs + ADPLL_FRACDIV_OFFSET); + frac_m &= ADPLL_FRACDIV_FRACTIONALM_MASK; + rate = (u64)readw_relaxed(d->regs + ADPLL_MN2DIV_OFFSET) << 18; + rate += frac_m; + rate *= parent_rate; + divider = (readw_relaxed(d->regs + ADPLL_M2NDIV_OFFSET) + 1) << 18; + spin_unlock_irqrestore(&d->lock, flags); + + do_div(rate, divider); + + if (d->c->is_type_s) { + v = readl_relaxed(d->regs + ADPLL_CLKCTRL_OFFSET); + if (v & BIT(ADPLL_CLKCTRL_REGM4XEN_ADPLL_S)) + rate *= 4; + rate *= 2; + } + + return rate; +} + +/* PLL parent is always clkinp, bypass only affects the children */ +static u8 ti_adpll_get_parent(struct clk_hw *hw) +{ + return 0; +} + +static struct clk_ops ti_adpll_ops = { + .prepare = ti_adpll_prepare, + .unprepare = ti_adpll_unprepare, + .is_prepared = ti_adpll_is_prepared, + .recalc_rate = ti_adpll_recalc_rate, + .get_parent = ti_adpll_get_parent, +}; + +static int ti_adpll_init_dco(struct ti_adpll_data *d) +{ + struct clk_init_data init; + struct clk *clock; + const char *postfix; + int width, err; + + d->outputs.clks = devm_kzalloc(d->dev, sizeof(struct clk *) * + MAX_ADPLL_OUTPUTS, + GFP_KERNEL); + if (!d->outputs.clks) + return -ENOMEM; + + if (d->c->output_index < 0) + postfix = "dco"; + else + postfix = NULL; + + init.name = ti_adpll_clk_get_name(d, d->c->output_index, postfix); + if (!init.name) + return -EINVAL; + + init.parent_names = d->parent_names; + init.num_parents = d->c->nr_max_inputs; + init.ops = &ti_adpll_ops; + init.flags = CLK_GET_RATE_NOCACHE; + d->dco.hw.init = &init; + + if (d->c->is_type_s) + width = 5; + else + width = 4; + + /* Internal input clock divider N2 */ + err = ti_adpll_init_divider(d, TI_ADPLL_N2, -ENODEV, "n2", + d->parent_clocks[TI_ADPLL_CLKINP], + d->regs + ADPLL_MN2DIV_OFFSET, + ADPLL_MN2DIV_N2, width, 0); + if (err) + return err; + + clock = devm_clk_register(d->dev, &d->dco.hw); + if (IS_ERR(clock)) + return PTR_ERR(clock); + + return ti_adpll_setup_clock(d, clock, TI_ADPLL_DCO, d->c->output_index, + init.name, NULL); +} + +static int ti_adpll_clkout_enable(struct clk_hw *hw) +{ + struct ti_adpll_clkout_data *co = to_clkout(hw); + struct clk_hw *gate_hw = &co->gate.hw; + + __clk_hw_set_clk(gate_hw, hw); + + return clk_gate_ops.enable(gate_hw); +} + +static void ti_adpll_clkout_disable(struct clk_hw *hw) +{ + struct ti_adpll_clkout_data *co = to_clkout(hw); + struct clk_hw *gate_hw = &co->gate.hw; + + __clk_hw_set_clk(gate_hw, hw); + clk_gate_ops.disable(gate_hw); +} + +static int ti_adpll_clkout_is_enabled(struct clk_hw *hw) +{ + struct ti_adpll_clkout_data *co = to_clkout(hw); + struct clk_hw *gate_hw = &co->gate.hw; + + __clk_hw_set_clk(gate_hw, hw); + + return clk_gate_ops.is_enabled(gate_hw); +} + +/* Setting PLL bypass puts clkout and clkoutx2 into bypass */ +static u8 ti_adpll_clkout_get_parent(struct clk_hw *hw) +{ + struct ti_adpll_clkout_data *co = to_clkout(hw); + struct ti_adpll_data *d = co->adpll; + + return ti_adpll_clock_is_bypass(d); +} + +static int ti_adpll_init_clkout(struct ti_adpll_data *d, + enum ti_adpll_clocks index, + int output_index, int gate_bit, + char *name, struct clk *clk0, + struct clk *clk1) +{ + struct ti_adpll_clkout_data *co; + struct clk_init_data init; + struct clk_ops *ops; + const char *parent_names[2]; + const char *child_name; + struct clk *clock; + int err; + + co = devm_kzalloc(d->dev, sizeof(*co), GFP_KERNEL); + if (!co) + return -ENOMEM; + co->adpll = d; + + err = of_property_read_string_index(d->np, + "clock-output-names", + output_index, + &child_name); + if (err) + return err; + + ops = devm_kzalloc(d->dev, sizeof(*ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + + init.name = child_name; + init.ops = ops; + init.flags = CLK_IS_BASIC; + co->hw.init = &init; + parent_names[0] = __clk_get_name(clk0); + parent_names[1] = __clk_get_name(clk1); + init.parent_names = parent_names; + init.num_parents = 2; + + ops->get_parent = ti_adpll_clkout_get_parent; + ops->determine_rate = __clk_mux_determine_rate; + if (gate_bit) { + co->gate.lock = &d->lock; + co->gate.reg = d->regs + ADPLL_CLKCTRL_OFFSET; + co->gate.bit_idx = gate_bit; + ops->enable = ti_adpll_clkout_enable; + ops->disable = ti_adpll_clkout_disable; + ops->is_enabled = ti_adpll_clkout_is_enabled; + } + + clock = devm_clk_register(d->dev, &co->hw); + if (IS_ERR(clock)) { + dev_err(d->dev, "failed to register output %s: %li\n", + name, PTR_ERR(clock)); + return PTR_ERR(clock); + } + + return ti_adpll_setup_clock(d, clock, index, output_index, child_name, + NULL); +} + +static int ti_adpll_init_children_adpll_s(struct ti_adpll_data *d) +{ + int err; + + if (!d->c->is_type_s) + return 0; + + /* Internal mux, sources from divider N2 or clkinpulow */ + err = ti_adpll_init_mux(d, TI_ADPLL_BYPASS, "bypass", + d->clocks[TI_ADPLL_N2].clk, + d->parent_clocks[TI_ADPLL_CLKINPULOW], + d->regs + ADPLL_CLKCTRL_OFFSET, + ADPLL_CLKCTRL_ULOWCLKEN); + if (err) + return err; + + /* Internal divider M2, sources DCO */ + err = ti_adpll_init_divider(d, TI_ADPLL_M2, -ENODEV, "m2", + d->clocks[TI_ADPLL_DCO].clk, + d->regs + ADPLL_M2NDIV_OFFSET, + ADPLL_M2NDIV_M2, + ADPLL_M2NDIV_M2_ADPLL_S_WIDTH, + CLK_DIVIDER_ONE_BASED); + if (err) + return err; + + /* Internal fixed divider, after M2 before clkout */ + err = ti_adpll_init_fixed_factor(d, TI_ADPLL_DIV2, "div2", + d->clocks[TI_ADPLL_M2].clk, + 1, 2); + if (err) + return err; + + /* Output clkout with a mux and gate, sources from div2 or bypass */ + err = ti_adpll_init_clkout(d, TI_ADPLL_CLKOUT, TI_ADPLL_S_CLKOUT, + ADPLL_CLKCTRL_CLKOUTEN, "clkout", + d->clocks[TI_ADPLL_DIV2].clk, + d->clocks[TI_ADPLL_BYPASS].clk); + if (err) + return err; + + /* Output clkoutx2 with a mux and gate, sources from M2 or bypass */ + err = ti_adpll_init_clkout(d, TI_ADPLL_CLKOUT2, TI_ADPLL_S_CLKOUTX2, 0, + "clkout2", d->clocks[TI_ADPLL_M2].clk, + d->clocks[TI_ADPLL_BYPASS].clk); + if (err) + return err; + + /* Internal mux, sources from DCO and clkinphif */ + if (d->parent_clocks[TI_ADPLL_CLKINPHIF]) { + err = ti_adpll_init_mux(d, TI_ADPLL_HIF, "hif", + d->clocks[TI_ADPLL_DCO].clk, + d->parent_clocks[TI_ADPLL_CLKINPHIF], + d->regs + ADPLL_CLKCTRL_OFFSET, + ADPLL_CLKINPHIFSEL_ADPLL_S); + if (err) + return err; + } + + /* Output clkouthif with a divider M3, sources from hif */ + err = ti_adpll_init_divider(d, TI_ADPLL_M3, TI_ADPLL_S_CLKOUTHIF, "m3", + d->clocks[TI_ADPLL_HIF].clk, + d->regs + ADPLL_M3DIV_OFFSET, + ADPLL_M3DIV_M3, + ADPLL_M3DIV_M3_WIDTH, + CLK_DIVIDER_ONE_BASED); + if (err) + return err; + + /* Output clock dcoclkldo is the DCO */ + + return 0; +} + +static int ti_adpll_init_children_adpll_lj(struct ti_adpll_data *d) +{ + int err; + + if (d->c->is_type_s) + return 0; + + /* Output clkdcoldo, gated output of DCO */ + err = ti_adpll_init_gate(d, TI_ADPLL_DCO_GATE, TI_ADPLL_LJ_CLKDCOLDO, + "clkdcoldo", d->clocks[TI_ADPLL_DCO].clk, + d->regs + ADPLL_CLKCTRL_OFFSET, + ADPLL_CLKCTRL_CLKDCOLDOEN, 0); + if (err) + return err; + + /* Internal divider M2, sources from DCO */ + err = ti_adpll_init_divider(d, TI_ADPLL_M2, -ENODEV, + "m2", d->clocks[TI_ADPLL_DCO].clk, + d->regs + ADPLL_M2NDIV_OFFSET, + ADPLL_M2NDIV_M2, + ADPLL_M2NDIV_M2_ADPLL_LJ_WIDTH, + CLK_DIVIDER_ONE_BASED); + if (err) + return err; + + /* Output clkoutldo, gated output of M2 */ + err = ti_adpll_init_gate(d, TI_ADPLL_M2_GATE, TI_ADPLL_LJ_CLKOUTLDO, + "clkoutldo", d->clocks[TI_ADPLL_M2].clk, + d->regs + ADPLL_CLKCTRL_OFFSET, + ADPLL_CLKCTRL_CLKOUTLDOEN_ADPLL_LJ, + 0); + if (err) + return err; + + /* Internal mux, sources from divider N2 or clkinpulow */ + err = ti_adpll_init_mux(d, TI_ADPLL_BYPASS, "bypass", + d->clocks[TI_ADPLL_N2].clk, + d->parent_clocks[TI_ADPLL_CLKINPULOW], + d->regs + ADPLL_CLKCTRL_OFFSET, + ADPLL_CLKCTRL_ULOWCLKEN); + if (err) + return err; + + /* Output clkout, sources M2 or bypass */ + err = ti_adpll_init_clkout(d, TI_ADPLL_CLKOUT, TI_ADPLL_S_CLKOUT, + ADPLL_CLKCTRL_CLKOUTEN, "clkout", + d->clocks[TI_ADPLL_M2].clk, + d->clocks[TI_ADPLL_BYPASS].clk); + if (err) + return err; + + return 0; +} + +static void ti_adpll_free_resources(struct ti_adpll_data *d) +{ + int i; + + for (i = TI_ADPLL_M3; i >= 0; i--) { + struct ti_adpll_clock *ac = &d->clocks[i]; + + if (!ac || IS_ERR_OR_NULL(ac->clk)) + continue; + if (ac->cl) + clkdev_drop(ac->cl); + if (ac->unregister) + ac->unregister(ac->clk); + } +} + +/* MPU PLL manages the lock register for all PLLs */ +static void ti_adpll_unlock_all(void __iomem *reg) +{ + u32 v; + + v = readl_relaxed(reg); + if (v == ADPLL_PLLSS_MMR_LOCK_ENABLED) + writel_relaxed(ADPLL_PLLSS_MMR_UNLOCK_MAGIC, reg); +} + +static int ti_adpll_init_registers(struct ti_adpll_data *d) +{ + int register_offset = 0; + + if (d->c->is_type_s) { + register_offset = 8; + ti_adpll_unlock_all(d->iobase + ADPLL_PLLSS_MMR_LOCK_OFFSET); + } + + d->regs = d->iobase + register_offset + ADPLL_PWRCTRL_OFFSET; + + return 0; +} + +static int ti_adpll_init_inputs(struct ti_adpll_data *d) +{ + const char *error = "need at least %i inputs"; + struct clk *clock; + int nr_inputs; + + nr_inputs = of_clk_get_parent_count(d->np); + if (nr_inputs < d->c->nr_max_inputs) { + dev_err(d->dev, error, nr_inputs); + return -EINVAL; + } + of_clk_parent_fill(d->np, d->parent_names, nr_inputs); + + clock = devm_clk_get(d->dev, d->parent_names[0]); + if (IS_ERR(clock)) { + dev_err(d->dev, "could not get clkinp\n"); + return PTR_ERR(clock); + } + d->parent_clocks[TI_ADPLL_CLKINP] = clock; + + clock = devm_clk_get(d->dev, d->parent_names[1]); + if (IS_ERR(clock)) { + dev_err(d->dev, "could not get clkinpulow clock\n"); + return PTR_ERR(clock); + } + d->parent_clocks[TI_ADPLL_CLKINPULOW] = clock; + + if (d->c->is_type_s) { + clock = devm_clk_get(d->dev, d->parent_names[2]); + if (IS_ERR(clock)) { + dev_err(d->dev, "could not get clkinphif clock\n"); + return PTR_ERR(clock); + } + d->parent_clocks[TI_ADPLL_CLKINPHIF] = clock; + } + + return 0; +} + +static const struct ti_adpll_platform_data ti_adpll_type_s = { + .is_type_s = true, + .nr_max_inputs = MAX_ADPLL_INPUTS, + .nr_max_outputs = MAX_ADPLL_OUTPUTS, + .output_index = TI_ADPLL_S_DCOCLKLDO, +}; + +static const struct ti_adpll_platform_data ti_adpll_type_lj = { + .is_type_s = false, + .nr_max_inputs = MAX_ADPLL_INPUTS - 1, + .nr_max_outputs = MAX_ADPLL_OUTPUTS - 1, + .output_index = -EINVAL, +}; + +static const struct of_device_id ti_adpll_match[] = { + { .compatible = "ti,dm814-adpll-s-clock", &ti_adpll_type_s }, + { .compatible = "ti,dm814-adpll-lj-clock", &ti_adpll_type_lj }, + {}, +}; +MODULE_DEVICE_TABLE(of, ti_adpll_match); + +static int ti_adpll_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + const struct of_device_id *match; + const struct ti_adpll_platform_data *pdata; + struct ti_adpll_data *d; + struct resource *res; + int err; + + match = of_match_device(ti_adpll_match, dev); + if (match) + pdata = match->data; + else + return -ENODEV; + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + d->dev = dev; + d->np = node; + d->c = pdata; + dev_set_drvdata(d->dev, d); + spin_lock_init(&d->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + d->pa = res->start; + + d->iobase = devm_ioremap_resource(dev, res); + if (IS_ERR(d->iobase)) { + dev_err(dev, "could not get IO base: %li\n", + PTR_ERR(d->iobase)); + return PTR_ERR(d->iobase); + } + + err = ti_adpll_init_registers(d); + if (err) + return err; + + err = ti_adpll_init_inputs(d); + if (err) + return err; + + d->clocks = devm_kzalloc(d->dev, sizeof(struct ti_adpll_clock) * + TI_ADPLL_NR_CLOCKS, + GFP_KERNEL); + if (!d->clocks) + return -ENOMEM; + + err = ti_adpll_init_dco(d); + if (err) { + dev_err(dev, "could not register dco: %i\n", err); + goto free; + } + + err = ti_adpll_init_children_adpll_s(d); + if (err) + goto free; + err = ti_adpll_init_children_adpll_lj(d); + if (err) + goto free; + + err = of_clk_add_provider(d->np, of_clk_src_onecell_get, &d->outputs); + if (err) + goto free; + + return 0; + +free: + WARN_ON(1); + ti_adpll_free_resources(d); + + return err; +} + +static int ti_adpll_remove(struct platform_device *pdev) +{ + struct ti_adpll_data *d = dev_get_drvdata(&pdev->dev); + + ti_adpll_free_resources(d); + + return 0; +} + +static struct platform_driver ti_adpll_driver = { + .driver = { + .name = "ti-adpll", + .of_match_table = ti_adpll_match, + }, + .probe = ti_adpll_probe, + .remove = ti_adpll_remove, +}; + +static int __init ti_adpll_init(void) +{ + return platform_driver_register(&ti_adpll_driver); +} +core_initcall(ti_adpll_init); + +static void __exit ti_adpll_exit(void) +{ + platform_driver_unregister(&ti_adpll_driver); +} +module_exit(ti_adpll_exit); + +MODULE_DESCRIPTION("Clock driver for dm814x ADPLL"); +MODULE_ALIAS("platform:dm814-adpll-clock"); +MODULE_AUTHOR("Tony LIndgren <tony@atomide.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index b336a8c..6411e13 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -140,11 +140,21 @@ static void __init omap_clk_register_apll(struct clk_hw *hw, struct dpll_data *ad = clk_hw->dpll_data; struct clk *clk; - ad->clk_ref = of_clk_get(node, 0); - ad->clk_bypass = of_clk_get(node, 1); + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_debug("clk-ref for %s not ready, retry\n", + node->name); + if (!ti_clk_retry_init(node, hw, omap_clk_register_apll)) + return; + + goto cleanup; + } - if (IS_ERR(ad->clk_ref) || IS_ERR(ad->clk_bypass)) { - pr_debug("clk-ref or clk-bypass for %s not ready, retry\n", + ad->clk_ref = __clk_get_hw(clk); + + clk = of_clk_get(node, 1); + if (IS_ERR(clk)) { + pr_debug("clk-bypass for %s not ready, retry\n", node->name); if (!ti_clk_retry_init(node, hw, omap_clk_register_apll)) return; @@ -152,6 +162,8 @@ static void __init omap_clk_register_apll(struct clk_hw *hw, goto cleanup; } + ad->clk_bypass = __clk_get_hw(clk); + clk = clk_register(NULL, &clk_hw->hw); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); diff --git a/drivers/clk/ti/clk-814x.c b/drivers/clk/ti/clk-814x.c index 9e85fcc..52c6efc 100644 --- a/drivers/clk/ti/clk-814x.c +++ b/drivers/clk/ti/clk-814x.c @@ -5,8 +5,10 @@ */ #include <linux/kernel.h> +#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clk/ti.h> +#include <linux/of_platform.h> #include "clock.h" @@ -27,11 +29,62 @@ static struct ti_dt_clk dm814_clks[] = { { .node_name = NULL }, }; +static bool timer_clocks_initialized; + +static int __init dm814x_adpll_early_init(void) +{ + struct device_node *np; + + if (!timer_clocks_initialized) + return -ENODEV; + + np = of_find_node_by_name(NULL, "pllss"); + if (!np) { + pr_err("Could not find node for plls\n"); + return -ENODEV; + } + + of_platform_populate(np, NULL, NULL, NULL); + + return 0; +} +core_initcall(dm814x_adpll_early_init); + +static const char * const init_clocks[] = { + "pll040clkout", /* MPU 481c5040.adpll.clkout */ + "pll290clkout", /* DDR 481c5290.adpll.clkout */ +}; + +static int __init dm814x_adpll_enable_init_clocks(void) +{ + int i, err; + + if (!timer_clocks_initialized) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(init_clocks); i++) { + struct clk *clock; + + clock = clk_get(NULL, init_clocks[i]); + if (WARN(IS_ERR(clock), "could not find init clock %s\n", + init_clocks[i])) + continue; + err = clk_prepare_enable(clock); + if (WARN(err, "could not enable init clock %s\n", + init_clocks[i])) + continue; + } + + return 0; +} +postcore_initcall(dm814x_adpll_enable_init_clocks); + int __init dm814x_dt_clk_init(void) { ti_dt_clocks_register(dm814_clks); omap2_clk_disable_autoidle_all(); omap2_clk_enable_init_clocks(NULL, 0); + timer_clocks_initialized = true; return 0; } diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c index b5cc6f6..032c658 100644 --- a/drivers/clk/ti/clkt_dpll.c +++ b/drivers/clk/ti/clkt_dpll.c @@ -254,7 +254,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) v >>= __ffs(dd->enable_mask); if (_omap2_dpll_is_in_bypass(v)) - return clk_get_rate(dd->clk_bypass); + return clk_hw_get_rate(dd->clk_bypass); v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg); dpll_mult = v & dd->mult_mask; @@ -262,7 +262,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) dpll_div = v & dd->div1_mask; dpll_div >>= __ffs(dd->div1_mask); - dpll_clk = (u64)clk_get_rate(dd->clk_ref) * dpll_mult; + dpll_clk = (u64)clk_hw_get_rate(dd->clk_ref) * dpll_mult; do_div(dpll_clk, dpll_div + 1); return dpll_clk; @@ -301,7 +301,7 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, dd = clk->dpll_data; - ref_rate = clk_get_rate(dd->clk_ref); + 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", clk_name, target_rate); diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index b9bc3b8..6cf9dd1 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -109,7 +109,7 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) struct clk_hw *clk_hw; const char *clkdm_name = node->name; int i; - int num_clks; + unsigned int num_clks; num_clks = of_clk_get_parent_count(node); diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index dbef218..1cf70f4 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -28,8 +28,6 @@ #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ -#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) - static unsigned long ti_composite_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -236,14 +234,14 @@ cleanup: static void __init of_ti_composite_clk_setup(struct device_node *node) { - int num_clks; + unsigned int num_clks; int i; struct clk_hw_omap_comp *cclk; /* Number of component clocks to be put inside this clock */ num_clks = of_clk_get_parent_count(node); - if (num_clks < 1) { + if (!num_clks) { pr_err("composite clk %s must have component(s)\n", node->name); return; } @@ -273,13 +271,13 @@ CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock", int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type) { - int num_parents; + unsigned int num_parents; const char **parent_names; struct component_clk *clk; num_parents = of_clk_get_parent_count(node); - if (num_parents < 1) { + if (!num_parents) { pr_err("component-clock %s must have parent(s)\n", node->name); return -EINVAL; } diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index df25583..b4e5de1 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -26,8 +26,6 @@ #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ -#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) - #define div_mask(d) ((1 << ((d)->width)) - 1) static unsigned int _get_table_maxdiv(const struct clk_div_table *table) diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 5519b38..3bc9959 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -147,11 +147,22 @@ static void __init _register_dpll(struct clk_hw *hw, struct dpll_data *dd = clk_hw->dpll_data; struct clk *clk; - dd->clk_ref = of_clk_get(node, 0); - dd->clk_bypass = of_clk_get(node, 1); + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_debug("clk-ref missing for %s, retry later\n", + node->name); + if (!ti_clk_retry_init(node, hw, _register_dpll)) + return; - if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) { - pr_debug("clk-ref or clk-bypass missing for %s, retry later\n", + goto cleanup; + } + + dd->clk_ref = __clk_get_hw(clk); + + clk = of_clk_get(node, 1); + + if (IS_ERR(clk)) { + pr_debug("clk-bypass missing for %s, retry later\n", node->name); if (!ti_clk_retry_init(node, hw, _register_dpll)) return; @@ -159,6 +170,8 @@ static void __init _register_dpll(struct clk_hw *hw, goto cleanup; } + dd->clk_bypass = __clk_get_hw(clk); + /* register the clock */ clk = clk_register(NULL, &clk_hw->hw); @@ -251,8 +264,8 @@ struct clk *ti_clk_register_dpll(struct ti_clk *setup) dd->recal_en_bit = dpll->recal_en_bit; dd->recal_st_bit = dpll->recal_st_bit; - dd->clk_ref = clk_ref; - dd->clk_bypass = clk_bypass; + dd->clk_ref = __clk_get_hw(clk_ref); + dd->clk_bypass = __clk_get_hw(clk_bypass); if (dpll->flags & CLKF_CORE) ops = &omap3_dpll_core_ck_ops; @@ -361,7 +374,7 @@ static void __init of_ti_dpll_setup(struct device_node *node, init->ops = ops; init->num_parents = of_clk_get_parent_count(node); - if (init->num_parents < 1) { + if (!init->num_parents) { pr_err("%s must have parent(s)\n", node->name); goto cleanup; } diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c index 1c30038..88f2ce8 100644 --- a/drivers/clk/ti/dpll3xxx.c +++ b/drivers/clk/ti/dpll3xxx.c @@ -98,7 +98,7 @@ static u16 _omap3_dpll_compute_freqsel(struct clk_hw_omap *clk, u8 n) unsigned long fint; u16 f = 0; - fint = clk_get_rate(clk->dpll_data->clk_ref) / n; + fint = clk_hw_get_rate(clk->dpll_data->clk_ref) / n; pr_debug("clock: fint is %lu\n", fint); @@ -460,11 +460,11 @@ int omap3_noncore_dpll_enable(struct clk_hw *hw) parent = clk_hw_get_parent(hw); - if (clk_hw_get_rate(hw) == clk_get_rate(dd->clk_bypass)) { - WARN_ON(parent != __clk_get_hw(dd->clk_bypass)); + if (clk_hw_get_rate(hw) == clk_hw_get_rate(dd->clk_bypass)) { + WARN_ON(parent != dd->clk_bypass); r = _omap3_noncore_dpll_bypass(clk); } else { - WARN_ON(parent != __clk_get_hw(dd->clk_ref)); + WARN_ON(parent != dd->clk_ref); r = _omap3_noncore_dpll_lock(clk); } @@ -512,13 +512,13 @@ int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, if (!dd) return -EINVAL; - if (clk_get_rate(dd->clk_bypass) == req->rate && + if (clk_hw_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - req->best_parent_hw = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = dd->clk_bypass; } else { req->rate = omap2_dpll_round_rate(hw, req->rate, &req->best_parent_rate); - req->best_parent_hw = __clk_get_hw(dd->clk_ref); + req->best_parent_hw = dd->clk_ref; } req->best_parent_rate = req->rate; @@ -576,7 +576,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, if (!dd) return -EINVAL; - if (clk_hw_get_parent(hw) != __clk_get_hw(dd->clk_ref)) + if (clk_hw_get_parent(hw) != dd->clk_ref) return -EINVAL; if (dd->last_rounded_rate == 0) diff --git a/drivers/clk/ti/dpll44xx.c b/drivers/clk/ti/dpll44xx.c index 660d743..82c05b5 100644 --- a/drivers/clk/ti/dpll44xx.c +++ b/drivers/clk/ti/dpll44xx.c @@ -94,7 +94,7 @@ static void omap4_dpll_lpmode_recalc(struct dpll_data *dd) { long fint, fout; - fint = clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1); + fint = clk_hw_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1); fout = fint * dd->last_rounded_m; if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX)) @@ -212,13 +212,13 @@ int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, if (!dd) return -EINVAL; - if (clk_get_rate(dd->clk_bypass) == req->rate && + if (clk_hw_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - req->best_parent_hw = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = dd->clk_bypass; } else { req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate, &req->best_parent_rate); - req->best_parent_hw = __clk_get_hw(dd->clk_ref); + req->best_parent_hw = dd->clk_ref; } req->best_parent_rate = req->rate; diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index 5429d35..bc05f27 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -24,8 +24,6 @@ #include "clock.h" -#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) - #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index dab9ba8..44777ab 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -26,8 +26,6 @@ #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ -#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) - static u8 ti_clk_mux_get_parent(struct clk_hw *hw) { struct clk_mux *mux = to_clk_mux(hw); @@ -180,7 +178,7 @@ static void of_mux_clk_setup(struct device_node *node) { struct clk *clk; void __iomem *reg; - int num_parents; + unsigned int num_parents; const char **parent_names; u8 clk_mux_flags = 0; u32 mask = 0; @@ -263,7 +261,7 @@ struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup) static void __init of_ti_composite_mux_clk_setup(struct device_node *node) { struct clk_mux *mux; - int num_parents; + unsigned int num_parents; u32 val; mux = kzalloc(sizeof(*mux), GFP_KERNEL); diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index e62f8cb..3bca438 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -78,6 +78,9 @@ static int vco_set(struct clk_icst *icst, struct icst_vco vco) ret = regmap_read(icst->map, icst->vcoreg_off, &val); if (ret) return ret; + + /* Mask the 18 bits used by the VCO */ + val &= ~0x7ffff; val |= vco.v | (vco.r << 9) | (vco.s << 16); /* This magic unlocks the VCO so it can be controlled */ diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index e78755e..1fe1e8d 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -92,6 +92,7 @@ static void __init clk_sp810_of_setup(struct device_node *node) int num = ARRAY_SIZE(parent_names); char name[12]; struct clk_init_data init; + static int instance; int i; bool deprecated; @@ -117,7 +118,7 @@ static void __init clk_sp810_of_setup(struct device_node *node) deprecated = !of_find_property(node, "assigned-clock-parents", NULL); for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) { - snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); + snprintf(name, sizeof(name), "sp810_%d_%d", instance, i); sp810->timerclken[i].sp810 = sp810; sp810->timerclken[i].channel = i; @@ -138,5 +139,6 @@ static void __init clk_sp810_of_setup(struct device_node *node) } of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810); + instance++; } CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup); |