From 1e9bc9d6369ba73885e4786b48f954f05348c3cb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 15 Oct 2015 15:48:24 -0400 Subject: ARM: cygnus: fix link failures when CONFIG_COMMON_CLK_IPROC is disabled When CONFIG_CYGNUS is set but CONFIG_COMMON_CLK_IPROC is disabled, the following link failures are caused: drivers/built-in.o: In function `cygnus_armpll_init': :(.init.text+0x1d290): undefined reference to `iproc_armpll_setup' drivers/built-in.o: In function `cygnus_genpll_clk_init': :(.init.text+0x1d2c4): undefined reference to `iproc_pll_clk_setup' drivers/built-in.o: In function `cygnus_lcpll0_clk_init': :(.init.text+0x1d304): undefined reference to `iproc_pll_clk_setup' drivers/built-in.o: In function `cygnus_mipipll_clk_init': :(.init.text+0x1d344): undefined reference to `iproc_pll_clk_setup' drivers/built-in.o: In function `cygnus_asiu_init': :(.init.text+0x1d370): undefined reference to `iproc_asiu_setup' It is fixed it by always selecting COMMON_CLK_IPROC from ARCH_BCM_IPROC, and making COMMON_CLK_IPROC a silent option (thus preventing it from being erroneously disabled by a user). Signed-off-by: Arnd Bergmann Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd --- drivers/clk/bcm/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig index 88febf53b276..46ee475a1d76 100644 --- a/drivers/clk/bcm/Kconfig +++ b/drivers/clk/bcm/Kconfig @@ -9,10 +9,8 @@ config CLK_BCM_KONA in the BCM281xx and BCM21664 families. config COMMON_CLK_IPROC - bool "Broadcom iProc clock support" - depends on ARCH_BCM_IPROC + bool depends on COMMON_CLK - default ARCH_BCM_IPROC help Enable common clock framework support for Broadcom SoCs based on the iProc architecture -- cgit v1.2.3-59-g8ed1b From 2dfc8a27ecfb3a54cc60376e0e7c4872934008f1 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 15 Oct 2015 15:48:25 -0400 Subject: clk: cygnus: Convert all macros to all caps The macros that are being used to initialize the values of the clk structures should be all caps. Find and replace all of them with their relevant counterparts. Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-cygnus.c | 146 +++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 73 deletions(-) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c index 316c60337661..aac82c671eeb 100644 --- a/drivers/clk/bcm/clk-cygnus.c +++ b/drivers/clk/bcm/clk-cygnus.c @@ -23,28 +23,28 @@ #include #include "clk-iproc.h" -#define reg_val(o, s, w) { .offset = o, .shift = s, .width = w, } +#define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, } -#define aon_val(o, pw, ps, is) { .offset = o, .pwr_width = pw, \ +#define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \ .pwr_shift = ps, .iso_shift = is } -#define sw_ctrl_val(o, s) { .offset = o, .shift = s, } +#define SW_CTRL_VAL(o, s) { .offset = o, .shift = s, } -#define asiu_div_val(o, es, hs, hw, ls, lw) \ +#define ASIU_DIV_VAL(o, es, hs, hw, ls, lw) \ { .offset = o, .en_shift = es, .high_shift = hs, \ .high_width = hw, .low_shift = ls, .low_width = lw } -#define reset_val(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \ +#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \ .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \ .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ .ka_width = kaw } -#define vco_ctrl_val(uo, lo) { .u_offset = uo, .l_offset = lo } +#define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo } -#define enable_val(o, es, hs, bs) { .offset = o, .enable_shift = es, \ +#define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \ .hold_shift = hs, .bypass_shift = bs } -#define asiu_gate_val(o, es) { .offset = o, .en_shift = es } +#define ASIU_GATE_VAL(o, es) { .offset = o, .en_shift = es } static void __init cygnus_armpll_init(struct device_node *node) { @@ -55,52 +55,52 @@ CLK_OF_DECLARE(cygnus_armpll, "brcm,cygnus-armpll", cygnus_armpll_init); static const struct iproc_pll_ctrl genpll = { .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_PLL_NEEDS_SW_CFG, - .aon = aon_val(0x0, 2, 1, 0), - .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 3), - .sw_ctrl = sw_ctrl_val(0x10, 31), - .ndiv_int = reg_val(0x10, 20, 10), - .ndiv_frac = reg_val(0x10, 0, 20), - .pdiv = reg_val(0x14, 0, 4), - .vco_ctrl = vco_ctrl_val(0x18, 0x1c), - .status = reg_val(0x28, 12, 1), + .aon = AON_VAL(0x0, 2, 1, 0), + .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3), + .sw_ctrl = SW_CTRL_VAL(0x10, 31), + .ndiv_int = REG_VAL(0x10, 20, 10), + .ndiv_frac = REG_VAL(0x10, 0, 20), + .pdiv = REG_VAL(0x14, 0, 4), + .vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c), + .status = REG_VAL(0x28, 12, 1), }; static const struct iproc_clk_ctrl genpll_clk[] = { [BCM_CYGNUS_GENPLL_AXI21_CLK] = { .channel = BCM_CYGNUS_GENPLL_AXI21_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x4, 6, 0, 12), - .mdiv = reg_val(0x20, 0, 8), + .enable = ENABLE_VAL(0x4, 6, 0, 12), + .mdiv = REG_VAL(0x20, 0, 8), }, [BCM_CYGNUS_GENPLL_250MHZ_CLK] = { .channel = BCM_CYGNUS_GENPLL_250MHZ_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x4, 7, 1, 13), - .mdiv = reg_val(0x20, 10, 8), + .enable = ENABLE_VAL(0x4, 7, 1, 13), + .mdiv = REG_VAL(0x20, 10, 8), }, [BCM_CYGNUS_GENPLL_IHOST_SYS_CLK] = { .channel = BCM_CYGNUS_GENPLL_IHOST_SYS_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x4, 8, 2, 14), - .mdiv = reg_val(0x20, 20, 8), + .enable = ENABLE_VAL(0x4, 8, 2, 14), + .mdiv = REG_VAL(0x20, 20, 8), }, [BCM_CYGNUS_GENPLL_ENET_SW_CLK] = { .channel = BCM_CYGNUS_GENPLL_ENET_SW_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x4, 9, 3, 15), - .mdiv = reg_val(0x24, 0, 8), + .enable = ENABLE_VAL(0x4, 9, 3, 15), + .mdiv = REG_VAL(0x24, 0, 8), }, [BCM_CYGNUS_GENPLL_AUDIO_125_CLK] = { .channel = BCM_CYGNUS_GENPLL_AUDIO_125_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x4, 10, 4, 16), - .mdiv = reg_val(0x24, 10, 8), + .enable = ENABLE_VAL(0x4, 10, 4, 16), + .mdiv = REG_VAL(0x24, 10, 8), }, [BCM_CYGNUS_GENPLL_CAN_CLK] = { .channel = BCM_CYGNUS_GENPLL_CAN_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x4, 11, 5, 17), - .mdiv = reg_val(0x24, 20, 8), + .enable = ENABLE_VAL(0x4, 11, 5, 17), + .mdiv = REG_VAL(0x24, 20, 8), }, }; @@ -113,51 +113,51 @@ CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll", cygnus_genpll_clk_init); static const struct iproc_pll_ctrl lcpll0 = { .flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG, - .aon = aon_val(0x0, 2, 5, 4), - .reset = reset_val(0x0, 31, 30, 27, 3, 23, 4, 19, 4), - .sw_ctrl = sw_ctrl_val(0x4, 31), - .ndiv_int = reg_val(0x4, 16, 10), - .pdiv = reg_val(0x4, 26, 4), - .vco_ctrl = vco_ctrl_val(0x10, 0x14), - .status = reg_val(0x18, 12, 1), + .aon = AON_VAL(0x0, 2, 5, 4), + .reset = RESET_VAL(0x0, 31, 30, 27, 3, 23, 4, 19, 4), + .sw_ctrl = SW_CTRL_VAL(0x4, 31), + .ndiv_int = REG_VAL(0x4, 16, 10), + .pdiv = REG_VAL(0x4, 26, 4), + .vco_ctrl = VCO_CTRL_VAL(0x10, 0x14), + .status = REG_VAL(0x18, 12, 1), }; static const struct iproc_clk_ctrl lcpll0_clk[] = { [BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK] = { .channel = BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x0, 7, 1, 13), - .mdiv = reg_val(0x8, 0, 8), + .enable = ENABLE_VAL(0x0, 7, 1, 13), + .mdiv = REG_VAL(0x8, 0, 8), }, [BCM_CYGNUS_LCPLL0_DDR_PHY_CLK] = { .channel = BCM_CYGNUS_LCPLL0_DDR_PHY_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x0, 8, 2, 14), - .mdiv = reg_val(0x8, 10, 8), + .enable = ENABLE_VAL(0x0, 8, 2, 14), + .mdiv = REG_VAL(0x8, 10, 8), }, [BCM_CYGNUS_LCPLL0_SDIO_CLK] = { .channel = BCM_CYGNUS_LCPLL0_SDIO_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x0, 9, 3, 15), - .mdiv = reg_val(0x8, 20, 8), + .enable = ENABLE_VAL(0x0, 9, 3, 15), + .mdiv = REG_VAL(0x8, 20, 8), }, [BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK] = { .channel = BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x0, 10, 4, 16), - .mdiv = reg_val(0xc, 0, 8), + .enable = ENABLE_VAL(0x0, 10, 4, 16), + .mdiv = REG_VAL(0xc, 0, 8), }, [BCM_CYGNUS_LCPLL0_SMART_CARD_CLK] = { .channel = BCM_CYGNUS_LCPLL0_SMART_CARD_CLK, .flags = IPROC_CLK_AON, - .enable = enable_val(0x0, 11, 5, 17), - .mdiv = reg_val(0xc, 10, 8), + .enable = ENABLE_VAL(0x0, 11, 5, 17), + .mdiv = REG_VAL(0xc, 10, 8), }, [BCM_CYGNUS_LCPLL0_CH5_UNUSED] = { .channel = BCM_CYGNUS_LCPLL0_CH5_UNUSED, .flags = IPROC_CLK_AON, - .enable = enable_val(0x0, 12, 6, 18), - .mdiv = reg_val(0xc, 20, 8), + .enable = ENABLE_VAL(0x0, 12, 6, 18), + .mdiv = REG_VAL(0xc, 20, 8), }, }; @@ -189,52 +189,52 @@ static const struct iproc_pll_vco_param mipipll_vco_params[] = { static const struct iproc_pll_ctrl mipipll = { .flags = IPROC_CLK_PLL_ASIU | IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_NEEDS_READ_BACK, - .aon = aon_val(0x0, 4, 17, 16), - .asiu = asiu_gate_val(0x0, 3), - .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 4), - .ndiv_int = reg_val(0x10, 20, 10), - .ndiv_frac = reg_val(0x10, 0, 20), - .pdiv = reg_val(0x14, 0, 4), - .vco_ctrl = vco_ctrl_val(0x18, 0x1c), - .status = reg_val(0x28, 12, 1), + .aon = AON_VAL(0x0, 4, 17, 16), + .asiu = ASIU_GATE_VAL(0x0, 3), + .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 4), + .ndiv_int = REG_VAL(0x10, 20, 10), + .ndiv_frac = REG_VAL(0x10, 0, 20), + .pdiv = REG_VAL(0x14, 0, 4), + .vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c), + .status = REG_VAL(0x28, 12, 1), }; static const struct iproc_clk_ctrl mipipll_clk[] = { [BCM_CYGNUS_MIPIPLL_CH0_UNUSED] = { .channel = BCM_CYGNUS_MIPIPLL_CH0_UNUSED, .flags = IPROC_CLK_NEEDS_READ_BACK, - .enable = enable_val(0x4, 12, 6, 18), - .mdiv = reg_val(0x20, 0, 8), + .enable = ENABLE_VAL(0x4, 12, 6, 18), + .mdiv = REG_VAL(0x20, 0, 8), }, [BCM_CYGNUS_MIPIPLL_CH1_LCD] = { .channel = BCM_CYGNUS_MIPIPLL_CH1_LCD, .flags = IPROC_CLK_NEEDS_READ_BACK, - .enable = enable_val(0x4, 13, 7, 19), - .mdiv = reg_val(0x20, 10, 8), + .enable = ENABLE_VAL(0x4, 13, 7, 19), + .mdiv = REG_VAL(0x20, 10, 8), }, [BCM_CYGNUS_MIPIPLL_CH2_V3D] = { .channel = BCM_CYGNUS_MIPIPLL_CH2_V3D, .flags = IPROC_CLK_NEEDS_READ_BACK, - .enable = enable_val(0x4, 14, 8, 20), - .mdiv = reg_val(0x20, 20, 8), + .enable = ENABLE_VAL(0x4, 14, 8, 20), + .mdiv = REG_VAL(0x20, 20, 8), }, [BCM_CYGNUS_MIPIPLL_CH3_UNUSED] = { .channel = BCM_CYGNUS_MIPIPLL_CH3_UNUSED, .flags = IPROC_CLK_NEEDS_READ_BACK, - .enable = enable_val(0x4, 15, 9, 21), - .mdiv = reg_val(0x24, 0, 8), + .enable = ENABLE_VAL(0x4, 15, 9, 21), + .mdiv = REG_VAL(0x24, 0, 8), }, [BCM_CYGNUS_MIPIPLL_CH4_UNUSED] = { .channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED, .flags = IPROC_CLK_NEEDS_READ_BACK, - .enable = enable_val(0x4, 16, 10, 22), - .mdiv = reg_val(0x24, 10, 8), + .enable = ENABLE_VAL(0x4, 16, 10, 22), + .mdiv = REG_VAL(0x24, 10, 8), }, [BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = { .channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED, .flags = IPROC_CLK_NEEDS_READ_BACK, - .enable = enable_val(0x4, 17, 11, 23), - .mdiv = reg_val(0x24, 20, 8), + .enable = ENABLE_VAL(0x4, 17, 11, 23), + .mdiv = REG_VAL(0x24, 20, 8), }, }; @@ -247,15 +247,15 @@ static void __init cygnus_mipipll_clk_init(struct device_node *node) CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll", cygnus_mipipll_clk_init); static const struct iproc_asiu_div asiu_div[] = { - [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_div_val(0x0, 31, 16, 10, 0, 10), - [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_div_val(0x4, 31, 16, 10, 0, 10), - [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_div_val(0x8, 31, 16, 10, 0, 10), + [BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_DIV_VAL(0x0, 31, 16, 10, 0, 10), + [BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_DIV_VAL(0x4, 31, 16, 10, 0, 10), + [BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_DIV_VAL(0x8, 31, 16, 10, 0, 10), }; static const struct iproc_asiu_gate asiu_gate[] = { - [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_gate_val(0x0, 7), - [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_gate_val(0x0, 9), - [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_gate_val(IPROC_CLK_INVALID_OFFSET, 0), + [BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_GATE_VAL(0x0, 7), + [BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_GATE_VAL(0x0, 9), + [BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_GATE_VAL(IPROC_CLK_INVALID_OFFSET, 0), }; static void __init cygnus_asiu_init(struct device_node *node) -- cgit v1.2.3-59-g8ed1b From 01b6722fdf65a91d588338e5a1964d57fa2dd590 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 15 Oct 2015 15:48:26 -0400 Subject: clk: iproc: Add PWRCTRL support Some iProc SoC clocks use a different way to control clock power, via the PWRDWN bit in the PLL control register. Since the PLL control register is used to access the PWRDWN bit, there is no need for the pwr_base when this is being used. A new flag, IPROC_CLK_EMBED_PWRCTRL, has been added to identify this usage. We can use the AON interface to write the values to enable/disable PWRDOWN. Signed-off-by: Jon Mason [sboyd@codeaurora.org: Remove useless parentheses] Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-iproc-pll.c | 55 ++++++++++++++++++++++++++++------------- drivers/clk/bcm/clk-iproc.h | 6 +++++ 2 files changed, 44 insertions(+), 17 deletions(-) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 2dda4e8295a9..e27acb9c655c 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -148,14 +148,25 @@ static void __pll_disable(struct iproc_pll *pll) writel(val, pll->asiu_base + ctrl->asiu.offset); } - /* latch input value so core power can be shut down */ - val = readl(pll->pwr_base + ctrl->aon.offset); - val |= (1 << ctrl->aon.iso_shift); - writel(val, pll->pwr_base + ctrl->aon.offset); - - /* power down the core */ - val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift); - writel(val, pll->pwr_base + ctrl->aon.offset); + if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) { + val = readl(pll->pll_base + ctrl->aon.offset); + val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift; + writel(val, pll->pll_base + ctrl->aon.offset); + + if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) + readl(pll->pll_base + ctrl->aon.offset); + } + + if (pll->pwr_base) { + /* latch input value so core power can be shut down */ + val = readl(pll->pwr_base + ctrl->aon.offset); + val |= 1 << ctrl->aon.iso_shift; + writel(val, pll->pwr_base + ctrl->aon.offset); + + /* power down the core */ + val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift); + writel(val, pll->pwr_base + ctrl->aon.offset); + } } static int __pll_enable(struct iproc_pll *pll) @@ -163,11 +174,22 @@ static int __pll_enable(struct iproc_pll *pll) const struct iproc_pll_ctrl *ctrl = pll->ctrl; u32 val; - /* power up the PLL and make sure it's not latched */ - val = readl(pll->pwr_base + ctrl->aon.offset); - val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift; - val &= ~(1 << ctrl->aon.iso_shift); - writel(val, pll->pwr_base + ctrl->aon.offset); + if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) { + val = readl(pll->pll_base + ctrl->aon.offset); + val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift); + writel(val, pll->pll_base + ctrl->aon.offset); + + if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) + readl(pll->pll_base + ctrl->aon.offset); + } + + if (pll->pwr_base) { + /* power up the PLL and make sure it's not latched */ + val = readl(pll->pwr_base + ctrl->aon.offset); + val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift; + val &= ~(1 << ctrl->aon.iso_shift); + writel(val, pll->pwr_base + ctrl->aon.offset); + } /* certain PLLs also need to be ungated from the ASIU top level */ if (ctrl->flags & IPROC_CLK_PLL_ASIU) { @@ -610,9 +632,8 @@ void __init iproc_pll_clk_setup(struct device_node *node, if (WARN_ON(!pll->pll_base)) goto err_pll_iomap; + /* Some SoCs do not require the pwr_base, thus failing is not fatal */ pll->pwr_base = of_iomap(node, 1); - if (WARN_ON(!pll->pwr_base)) - goto err_pwr_iomap; /* some PLLs require gating control at the top ASIU level */ if (pll_ctrl->flags & IPROC_CLK_PLL_ASIU) { @@ -695,9 +716,9 @@ err_pll_register: iounmap(pll->asiu_base); err_asiu_iomap: - iounmap(pll->pwr_base); + if (pll->pwr_base) + iounmap(pll->pwr_base); -err_pwr_iomap: iounmap(pll->pll_base); err_pll_iomap: diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h index d834b7abd5c6..ff7bfad48c13 100644 --- a/drivers/clk/bcm/clk-iproc.h +++ b/drivers/clk/bcm/clk-iproc.h @@ -48,6 +48,12 @@ */ #define IPROC_CLK_PLL_NEEDS_SW_CFG BIT(4) +/* + * Some PLLs use a different way to control clock power, via the PWRDWN bit in + * the PLL control register + */ +#define IPROC_CLK_EMBED_PWRCTRL BIT(5) + /* * Parameters for VCO frequency configuration * -- cgit v1.2.3-59-g8ed1b From 5f024b0685f753325f1b8cacbe37ffe5921b13d1 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 15 Oct 2015 15:48:27 -0400 Subject: clk: nsp: add clock support for Broadcom Northstar Plus SoC The Broadcom Northstar Plus SoC is architected under the iProc architecture. It has the following PLLs: ARMPLL, GENPLL, LCPLL0, all derived from an onboard crystal. Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd --- drivers/clk/bcm/Makefile | 2 + drivers/clk/bcm/clk-nsp.c | 135 ++++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/bcm-nsp.h | 51 ++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 drivers/clk/bcm/clk-nsp.c create mode 100644 include/dt-bindings/clock/bcm-nsp.h (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index 8a7a477862c7..e258b280a622 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -4,3 +4,5 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o +obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o +obj-$(CONFIG_ARCH_BCM_5301X) += clk-nsp.o diff --git a/drivers/clk/bcm/clk-nsp.c b/drivers/clk/bcm/clk-nsp.c new file mode 100644 index 000000000000..bc8ebdcdfeca --- /dev/null +++ b/drivers/clk/bcm/clk-nsp.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2015 Broadcom Corporation + * + * 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 +#include +#include +#include +#include +#include + +#include +#include "clk-iproc.h" + +#define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, } + +#define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \ + .pwr_shift = ps, .iso_shift = is } + +#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \ + .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \ + .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ + .ka_width = kaw } + +#define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \ + .hold_shift = hs, .bypass_shift = bs } + +static void __init nsp_armpll_init(struct device_node *node) +{ + iproc_armpll_setup(node); +} +CLK_OF_DECLARE(nsp_armpll, "brcm,nsp-armpll", nsp_armpll_init); + +static const struct iproc_pll_ctrl genpll = { + .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL, + .aon = AON_VAL(0x0, 1, 12, 0), + .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3), + .ndiv_int = REG_VAL(0x14, 20, 10), + .ndiv_frac = REG_VAL(0x14, 0, 20), + .pdiv = REG_VAL(0x18, 24, 3), + .status = REG_VAL(0x20, 12, 1), +}; + +static const struct iproc_clk_ctrl genpll_clk[] = { + [BCM_NSP_GENPLL_PHY_CLK] = { + .channel = BCM_NSP_GENPLL_PHY_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x4, 12, 6, 18), + .mdiv = REG_VAL(0x18, 16, 8), + }, + [BCM_NSP_GENPLL_ENET_SW_CLK] = { + .channel = BCM_NSP_GENPLL_ENET_SW_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x4, 13, 7, 19), + .mdiv = REG_VAL(0x18, 8, 8), + }, + [BCM_NSP_GENPLL_USB_PHY_REF_CLK] = { + .channel = BCM_NSP_GENPLL_USB_PHY_REF_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x4, 14, 8, 20), + .mdiv = REG_VAL(0x18, 0, 8), + }, + [BCM_NSP_GENPLL_IPROCFAST_CLK] = { + .channel = BCM_NSP_GENPLL_IPROCFAST_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x4, 15, 9, 21), + .mdiv = REG_VAL(0x1c, 16, 8), + }, + [BCM_NSP_GENPLL_SATA1_CLK] = { + .channel = BCM_NSP_GENPLL_SATA1_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x4, 16, 10, 22), + .mdiv = REG_VAL(0x1c, 8, 8), + }, + [BCM_NSP_GENPLL_SATA2_CLK] = { + .channel = BCM_NSP_GENPLL_SATA2_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x4, 17, 11, 23), + .mdiv = REG_VAL(0x1c, 0, 8), + }, +}; + +static void __init nsp_genpll_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &genpll, NULL, 0, genpll_clk, + ARRAY_SIZE(genpll_clk)); +} +CLK_OF_DECLARE(nsp_genpll_clk, "brcm,nsp-genpll", nsp_genpll_clk_init); + +static const struct iproc_pll_ctrl lcpll0 = { + .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL, + .aon = AON_VAL(0x0, 1, 24, 0), + .reset = RESET_VAL(0x0, 23, 22, 16, 3, 12, 4, 19, 4), + .ndiv_int = REG_VAL(0x4, 20, 8), + .ndiv_frac = REG_VAL(0x4, 0, 20), + .pdiv = REG_VAL(0x4, 28, 3), + .status = REG_VAL(0x10, 12, 1), +}; + +static const struct iproc_clk_ctrl lcpll0_clk[] = { + [BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK] = { + .channel = BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 6, 3, 9), + .mdiv = REG_VAL(0x8, 24, 8), + }, + [BCM_NSP_LCPLL0_SDIO_CLK] = { + .channel = BCM_NSP_LCPLL0_SDIO_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 7, 4, 10), + .mdiv = REG_VAL(0x8, 16, 8), + }, + [BCM_NSP_LCPLL0_DDR_PHY_CLK] = { + .channel = BCM_NSP_LCPLL0_DDR_PHY_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 8, 5, 11), + .mdiv = REG_VAL(0x8, 8, 8), + }, +}; + +static void __init nsp_lcpll0_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk, + ARRAY_SIZE(lcpll0_clk)); +} +CLK_OF_DECLARE(nsp_lcpll0_clk, "brcm,nsp-lcpll0", nsp_lcpll0_clk_init); diff --git a/include/dt-bindings/clock/bcm-nsp.h b/include/dt-bindings/clock/bcm-nsp.h new file mode 100644 index 000000000000..ad5827cde782 --- /dev/null +++ b/include/dt-bindings/clock/bcm-nsp.h @@ -0,0 +1,51 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2015 Broadcom Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Broadcom Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CLOCK_BCM_NSP_H +#define _CLOCK_BCM_NSP_H + +/* GENPLL clock channel ID */ +#define BCM_NSP_GENPLL 0 +#define BCM_NSP_GENPLL_PHY_CLK 1 +#define BCM_NSP_GENPLL_ENET_SW_CLK 2 +#define BCM_NSP_GENPLL_USB_PHY_REF_CLK 3 +#define BCM_NSP_GENPLL_IPROCFAST_CLK 4 +#define BCM_NSP_GENPLL_SATA1_CLK 5 +#define BCM_NSP_GENPLL_SATA2_CLK 6 + +/* LCPLL0 clock channel ID */ +#define BCM_NSP_LCPLL0 0 +#define BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK 1 +#define BCM_NSP_LCPLL0_SDIO_CLK 2 +#define BCM_NSP_LCPLL0_DDR_PHY_CLK 3 + +#endif /* _CLOCK_BCM_NSP_H */ -- cgit v1.2.3-59-g8ed1b From 7968d24107f5a50a11792f8a7f011877e7470dfa Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 15 Oct 2015 15:48:28 -0400 Subject: clk: iproc: Add PLL base write function All writes to the PLL base address must be flushed if the IPROC_CLK_NEEDS_READ_BACK flag is set. If we add a function to make the necessary write and reads, we can make sure that any future code which makes PLL base writes will do the correct thing. Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-iproc-pll.c | 80 +++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 47 deletions(-) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index e27acb9c655c..bfa28ba1394e 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -137,6 +137,18 @@ static int pll_wait_for_lock(struct iproc_pll *pll) return -EIO; } +static void iproc_pll_write(const struct iproc_pll *pll, void __iomem *base, + const u32 offset, u32 val) +{ + const struct iproc_pll_ctrl *ctrl = pll->ctrl; + + writel(val, base + offset); + + if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK && + base == pll->pll_base)) + val = readl(base + offset); +} + static void __pll_disable(struct iproc_pll *pll) { const struct iproc_pll_ctrl *ctrl = pll->ctrl; @@ -145,27 +157,24 @@ static void __pll_disable(struct iproc_pll *pll) if (ctrl->flags & IPROC_CLK_PLL_ASIU) { val = readl(pll->asiu_base + ctrl->asiu.offset); val &= ~(1 << ctrl->asiu.en_shift); - writel(val, pll->asiu_base + ctrl->asiu.offset); + iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val); } if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) { val = readl(pll->pll_base + ctrl->aon.offset); val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift; - writel(val, pll->pll_base + ctrl->aon.offset); - - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->aon.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val); } if (pll->pwr_base) { /* latch input value so core power can be shut down */ val = readl(pll->pwr_base + ctrl->aon.offset); val |= 1 << ctrl->aon.iso_shift; - writel(val, pll->pwr_base + ctrl->aon.offset); + iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val); /* power down the core */ val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift); - writel(val, pll->pwr_base + ctrl->aon.offset); + iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val); } } @@ -177,10 +186,7 @@ static int __pll_enable(struct iproc_pll *pll) if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) { val = readl(pll->pll_base + ctrl->aon.offset); val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift); - writel(val, pll->pll_base + ctrl->aon.offset); - - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->aon.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val); } if (pll->pwr_base) { @@ -188,14 +194,14 @@ static int __pll_enable(struct iproc_pll *pll) val = readl(pll->pwr_base + ctrl->aon.offset); val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift; val &= ~(1 << ctrl->aon.iso_shift); - writel(val, pll->pwr_base + ctrl->aon.offset); + iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val); } /* certain PLLs also need to be ungated from the ASIU top level */ if (ctrl->flags & IPROC_CLK_PLL_ASIU) { val = readl(pll->asiu_base + ctrl->asiu.offset); val |= (1 << ctrl->asiu.en_shift); - writel(val, pll->asiu_base + ctrl->asiu.offset); + iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val); } return 0; @@ -209,9 +215,7 @@ static void __pll_put_in_reset(struct iproc_pll *pll) val = readl(pll->pll_base + reset->offset); val &= ~(1 << reset->reset_shift | 1 << reset->p_reset_shift); - writel(val, pll->pll_base + reset->offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + reset->offset); + iproc_pll_write(pll, pll->pll_base, reset->offset, val); } static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, @@ -228,9 +232,7 @@ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, val |= ki << reset->ki_shift | kp << reset->kp_shift | ka << reset->ka_shift; val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift; - writel(val, pll->pll_base + reset->offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + reset->offset); + iproc_pll_write(pll, pll->pll_base, reset->offset, val); } static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, @@ -285,9 +287,8 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, /* put PLL in reset */ __pll_put_in_reset(pll); - writel(0, pll->pll_base + ctrl->vco_ctrl.u_offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->vco_ctrl.u_offset); + iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.u_offset, 0); + val = readl(pll->pll_base + ctrl->vco_ctrl.l_offset); if (rate >= VCO_LOW && rate < VCO_MID) @@ -298,17 +299,13 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, else val |= (1 << PLL_VCO_HIGH_SHIFT); - writel(val, pll->pll_base + ctrl->vco_ctrl.l_offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->vco_ctrl.l_offset); + iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.l_offset, val); /* program integer part of NDIV */ val = readl(pll->pll_base + ctrl->ndiv_int.offset); val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift); val |= vco->ndiv_int << ctrl->ndiv_int.shift; - writel(val, pll->pll_base + ctrl->ndiv_int.offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->ndiv_int.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_int.offset, val); /* program fractional part of NDIV */ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { @@ -316,18 +313,15 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, val &= ~(bit_mask(ctrl->ndiv_frac.width) << ctrl->ndiv_frac.shift); val |= vco->ndiv_frac << ctrl->ndiv_frac.shift; - writel(val, pll->pll_base + ctrl->ndiv_frac.offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->ndiv_frac.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_frac.offset, + val); } /* program PDIV */ val = readl(pll->pll_base + ctrl->pdiv.offset); val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift); val |= vco->pdiv << ctrl->pdiv.shift; - writel(val, pll->pll_base + ctrl->pdiv.offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->pdiv.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->pdiv.offset, val); __pll_bring_out_reset(pll, kp, ka, ki); @@ -467,14 +461,12 @@ static int iproc_clk_enable(struct clk_hw *hw) /* channel enable is active low */ val = readl(pll->pll_base + ctrl->enable.offset); val &= ~(1 << ctrl->enable.enable_shift); - writel(val, pll->pll_base + ctrl->enable.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val); /* also make sure channel is not held */ val = readl(pll->pll_base + ctrl->enable.offset); val &= ~(1 << ctrl->enable.hold_shift); - writel(val, pll->pll_base + ctrl->enable.offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->enable.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val); return 0; } @@ -491,9 +483,7 @@ static void iproc_clk_disable(struct clk_hw *hw) val = readl(pll->pll_base + ctrl->enable.offset); val |= 1 << ctrl->enable.enable_shift; - writel(val, pll->pll_base + ctrl->enable.offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->enable.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val); } static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw, @@ -562,9 +552,7 @@ static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate, val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift); val |= div << ctrl->mdiv.shift; } - writel(val, pll->pll_base + ctrl->mdiv.offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->mdiv.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->mdiv.offset, val); clk->rate = parent_rate / div; return 0; @@ -591,9 +579,7 @@ static void iproc_pll_sw_cfg(struct iproc_pll *pll) val = readl(pll->pll_base + ctrl->sw_ctrl.offset); val |= BIT(ctrl->sw_ctrl.shift); - writel(val, pll->pll_base + ctrl->sw_ctrl.offset); - if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK)) - readl(pll->pll_base + ctrl->sw_ctrl.offset); + iproc_pll_write(pll, pll->pll_base, ctrl->sw_ctrl.offset, val); } } -- cgit v1.2.3-59-g8ed1b From f713c6bf32092a259d6baf2be24f9c3dbf2462c3 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 15 Oct 2015 15:48:29 -0400 Subject: clk: iproc: Split off dig_filter The PLL loop filter/gain can be located in a separate register on some SoCs. Split these off into a separate variable, so that an offset can be added if necessary. Also, make the necessary modifications to the Cygnus and NSP drivers for this change. Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-cygnus.c | 17 +++++++++++------ drivers/clk/bcm/clk-iproc-pll.c | 14 +++++++++----- drivers/clk/bcm/clk-iproc.h | 10 +++++++++- drivers/clk/bcm/clk-nsp.c | 14 +++++++++----- 4 files changed, 38 insertions(+), 17 deletions(-) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c index aac82c671eeb..3a228b6d4fee 100644 --- a/drivers/clk/bcm/clk-cygnus.c +++ b/drivers/clk/bcm/clk-cygnus.c @@ -34,9 +34,11 @@ { .offset = o, .en_shift = es, .high_shift = hs, \ .high_width = hw, .low_shift = ls, .low_width = lw } -#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \ - .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \ - .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ +#define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \ + .p_reset_shift = prs } + +#define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, .ki_shift = kis,\ + .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ .ka_width = kaw } #define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo } @@ -56,7 +58,8 @@ static const struct iproc_pll_ctrl genpll = { .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_PLL_NEEDS_SW_CFG, .aon = AON_VAL(0x0, 2, 1, 0), - .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3), + .reset = RESET_VAL(0x0, 11, 10), + .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3), .sw_ctrl = SW_CTRL_VAL(0x10, 31), .ndiv_int = REG_VAL(0x10, 20, 10), .ndiv_frac = REG_VAL(0x10, 0, 20), @@ -114,7 +117,8 @@ CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll", cygnus_genpll_clk_init); static const struct iproc_pll_ctrl lcpll0 = { .flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG, .aon = AON_VAL(0x0, 2, 5, 4), - .reset = RESET_VAL(0x0, 31, 30, 27, 3, 23, 4, 19, 4), + .reset = RESET_VAL(0x0, 31, 30), + .dig_filter = DF_VAL(0x0, 27, 3, 23, 4, 19, 4), .sw_ctrl = SW_CTRL_VAL(0x4, 31), .ndiv_int = REG_VAL(0x4, 16, 10), .pdiv = REG_VAL(0x4, 26, 4), @@ -191,7 +195,8 @@ static const struct iproc_pll_ctrl mipipll = { IPROC_CLK_NEEDS_READ_BACK, .aon = AON_VAL(0x0, 4, 17, 16), .asiu = ASIU_GATE_VAL(0x0, 3), - .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 4), + .reset = RESET_VAL(0x0, 11, 10), + .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 4), .ndiv_int = REG_VAL(0x10, 20, 10), .ndiv_frac = REG_VAL(0x10, 0, 20), .pdiv = REG_VAL(0x14, 0, 4), diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index bfa28ba1394e..2be93955262e 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -224,13 +224,17 @@ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, u32 val; const struct iproc_pll_ctrl *ctrl = pll->ctrl; const struct iproc_pll_reset_ctrl *reset = &ctrl->reset; + const struct iproc_pll_dig_filter_ctrl *dig_filter = &ctrl->dig_filter; + + val = readl(pll->pll_base + dig_filter->offset); + val &= ~(bit_mask(dig_filter->ki_width) << dig_filter->ki_shift | + bit_mask(dig_filter->kp_width) << dig_filter->kp_shift | + bit_mask(dig_filter->ka_width) << dig_filter->ka_shift); + val |= ki << dig_filter->ki_shift | kp << dig_filter->kp_shift | + ka << dig_filter->ka_shift; + iproc_pll_write(pll, pll->pll_base, dig_filter->offset, val); val = readl(pll->pll_base + reset->offset); - val &= ~(bit_mask(reset->ki_width) << reset->ki_shift | - bit_mask(reset->kp_width) << reset->kp_shift | - bit_mask(reset->ka_width) << reset->ka_shift); - val |= ki << reset->ki_shift | kp << reset->kp_shift | - ka << reset->ka_shift; val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift; iproc_pll_write(pll, pll->pll_base, reset->offset, val); } diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h index ff7bfad48c13..b71c19737efd 100644 --- a/drivers/clk/bcm/clk-iproc.h +++ b/drivers/clk/bcm/clk-iproc.h @@ -94,12 +94,19 @@ struct iproc_pll_aon_pwr_ctrl { }; /* - * Control of the PLL reset, with Ki, Kp, and Ka parameters + * Control of the PLL reset */ struct iproc_pll_reset_ctrl { unsigned int offset; unsigned int reset_shift; unsigned int p_reset_shift; +}; + +/* + * Control of the Ki, Kp, and Ka parameters + */ +struct iproc_pll_dig_filter_ctrl { + unsigned int offset; unsigned int ki_shift; unsigned int ki_width; unsigned int kp_shift; @@ -129,6 +136,7 @@ struct iproc_pll_ctrl { struct iproc_pll_aon_pwr_ctrl aon; struct iproc_asiu_gate asiu; struct iproc_pll_reset_ctrl reset; + struct iproc_pll_dig_filter_ctrl dig_filter; struct iproc_pll_sw_ctrl sw_ctrl; struct iproc_clk_reg_op ndiv_int; struct iproc_clk_reg_op ndiv_frac; diff --git a/drivers/clk/bcm/clk-nsp.c b/drivers/clk/bcm/clk-nsp.c index bc8ebdcdfeca..cf66f640a47d 100644 --- a/drivers/clk/bcm/clk-nsp.c +++ b/drivers/clk/bcm/clk-nsp.c @@ -26,9 +26,11 @@ #define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \ .pwr_shift = ps, .iso_shift = is } -#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \ - .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \ - .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ +#define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \ + .p_reset_shift = prs } + +#define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, .ki_shift = kis,\ + .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ .ka_width = kaw } #define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \ @@ -43,7 +45,8 @@ CLK_OF_DECLARE(nsp_armpll, "brcm,nsp-armpll", nsp_armpll_init); static const struct iproc_pll_ctrl genpll = { .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL, .aon = AON_VAL(0x0, 1, 12, 0), - .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3), + .reset = RESET_VAL(0x0, 11, 10), + .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3), .ndiv_int = REG_VAL(0x14, 20, 10), .ndiv_frac = REG_VAL(0x14, 0, 20), .pdiv = REG_VAL(0x18, 24, 3), @@ -99,7 +102,8 @@ CLK_OF_DECLARE(nsp_genpll_clk, "brcm,nsp-genpll", nsp_genpll_clk_init); static const struct iproc_pll_ctrl lcpll0 = { .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL, .aon = AON_VAL(0x0, 1, 24, 0), - .reset = RESET_VAL(0x0, 23, 22, 16, 3, 12, 4, 19, 4), + .reset = RESET_VAL(0x0, 23, 22), + .dig_filter = DF_VAL(0x0, 16, 3, 12, 4, 19, 4), .ndiv_int = REG_VAL(0x4, 20, 8), .ndiv_frac = REG_VAL(0x4, 0, 20), .pdiv = REG_VAL(0x4, 28, 3), -- cgit v1.2.3-59-g8ed1b From 40c8bec3f2591856e21124270be51a0a2b77c82d Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 15 Oct 2015 15:48:30 -0400 Subject: clk: iproc: Separate status and control variables Some PLLs have separate registers for Status and Control. The means the pll_base needs to be split into 2 new variables, so that those PLLs can specify device tree registers for those independently. Also, add a new driver flag to identify this presence of the split, and let the driver know that additional registers need to be used. Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-iproc-pll.c | 96 ++++++++++++++++++++++++----------------- drivers/clk/bcm/clk-iproc.h | 6 +++ 2 files changed, 62 insertions(+), 40 deletions(-) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 2be93955262e..7f7da79f4adc 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -74,7 +74,8 @@ struct iproc_clk { }; struct iproc_pll { - void __iomem *pll_base; + void __iomem *status_base; + void __iomem *control_base; void __iomem *pwr_base; void __iomem *asiu_base; @@ -127,7 +128,7 @@ static int pll_wait_for_lock(struct iproc_pll *pll) const struct iproc_pll_ctrl *ctrl = pll->ctrl; for (i = 0; i < LOCK_DELAY; i++) { - u32 val = readl(pll->pll_base + ctrl->status.offset); + u32 val = readl(pll->status_base + ctrl->status.offset); if (val & (1 << ctrl->status.shift)) return 0; @@ -145,7 +146,7 @@ static void iproc_pll_write(const struct iproc_pll *pll, void __iomem *base, writel(val, base + offset); if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK && - base == pll->pll_base)) + (base == pll->status_base || base == pll->control_base))) val = readl(base + offset); } @@ -161,9 +162,9 @@ static void __pll_disable(struct iproc_pll *pll) } if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) { - val = readl(pll->pll_base + ctrl->aon.offset); + val = readl(pll->control_base + ctrl->aon.offset); val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift; - iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val); } if (pll->pwr_base) { @@ -184,9 +185,9 @@ static int __pll_enable(struct iproc_pll *pll) u32 val; if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) { - val = readl(pll->pll_base + ctrl->aon.offset); + val = readl(pll->control_base + ctrl->aon.offset); val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift); - iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val); } if (pll->pwr_base) { @@ -213,9 +214,9 @@ static void __pll_put_in_reset(struct iproc_pll *pll) const struct iproc_pll_ctrl *ctrl = pll->ctrl; const struct iproc_pll_reset_ctrl *reset = &ctrl->reset; - val = readl(pll->pll_base + reset->offset); + val = readl(pll->control_base + reset->offset); val &= ~(1 << reset->reset_shift | 1 << reset->p_reset_shift); - iproc_pll_write(pll, pll->pll_base, reset->offset, val); + iproc_pll_write(pll, pll->control_base, reset->offset, val); } static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, @@ -226,17 +227,17 @@ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, const struct iproc_pll_reset_ctrl *reset = &ctrl->reset; const struct iproc_pll_dig_filter_ctrl *dig_filter = &ctrl->dig_filter; - val = readl(pll->pll_base + dig_filter->offset); + val = readl(pll->control_base + dig_filter->offset); val &= ~(bit_mask(dig_filter->ki_width) << dig_filter->ki_shift | bit_mask(dig_filter->kp_width) << dig_filter->kp_shift | bit_mask(dig_filter->ka_width) << dig_filter->ka_shift); val |= ki << dig_filter->ki_shift | kp << dig_filter->kp_shift | ka << dig_filter->ka_shift; - iproc_pll_write(pll, pll->pll_base, dig_filter->offset, val); + iproc_pll_write(pll, pll->control_base, dig_filter->offset, val); - val = readl(pll->pll_base + reset->offset); + val = readl(pll->control_base + reset->offset); val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift; - iproc_pll_write(pll, pll->pll_base, reset->offset, val); + iproc_pll_write(pll, pll->control_base, reset->offset, val); } static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, @@ -291,9 +292,9 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, /* put PLL in reset */ __pll_put_in_reset(pll); - iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.u_offset, 0); + iproc_pll_write(pll, pll->control_base, ctrl->vco_ctrl.u_offset, 0); - val = readl(pll->pll_base + ctrl->vco_ctrl.l_offset); + val = readl(pll->control_base + ctrl->vco_ctrl.l_offset); if (rate >= VCO_LOW && rate < VCO_MID) val |= (1 << PLL_VCO_LOW_SHIFT); @@ -303,29 +304,29 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, else val |= (1 << PLL_VCO_HIGH_SHIFT); - iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.l_offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->vco_ctrl.l_offset, val); /* program integer part of NDIV */ - val = readl(pll->pll_base + ctrl->ndiv_int.offset); + val = readl(pll->control_base + ctrl->ndiv_int.offset); val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift); val |= vco->ndiv_int << ctrl->ndiv_int.shift; - iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_int.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->ndiv_int.offset, val); /* program fractional part of NDIV */ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { - val = readl(pll->pll_base + ctrl->ndiv_frac.offset); + val = readl(pll->control_base + ctrl->ndiv_frac.offset); val &= ~(bit_mask(ctrl->ndiv_frac.width) << ctrl->ndiv_frac.shift); val |= vco->ndiv_frac << ctrl->ndiv_frac.shift; - iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_frac.offset, + iproc_pll_write(pll, pll->control_base, ctrl->ndiv_frac.offset, val); } /* program PDIV */ - val = readl(pll->pll_base + ctrl->pdiv.offset); + val = readl(pll->control_base + ctrl->pdiv.offset); val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift); val |= vco->pdiv << ctrl->pdiv.shift; - iproc_pll_write(pll, pll->pll_base, ctrl->pdiv.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->pdiv.offset, val); __pll_bring_out_reset(pll, kp, ka, ki); @@ -372,7 +373,7 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, return 0; /* PLL needs to be locked */ - val = readl(pll->pll_base + ctrl->status.offset); + val = readl(pll->status_base + ctrl->status.offset); if ((val & (1 << ctrl->status.shift)) == 0) { clk->rate = 0; return 0; @@ -383,13 +384,13 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, * * ((ndiv_int + ndiv_frac / 2^20) * (parent clock rate / pdiv) */ - val = readl(pll->pll_base + ctrl->ndiv_int.offset); + val = readl(pll->control_base + ctrl->ndiv_int.offset); ndiv_int = (val >> ctrl->ndiv_int.shift) & bit_mask(ctrl->ndiv_int.width); ndiv = (u64)ndiv_int << ctrl->ndiv_int.shift; if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { - val = readl(pll->pll_base + ctrl->ndiv_frac.offset); + val = readl(pll->control_base + ctrl->ndiv_frac.offset); ndiv_frac = (val >> ctrl->ndiv_frac.shift) & bit_mask(ctrl->ndiv_frac.width); @@ -398,7 +399,7 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, ndiv_frac; } - val = readl(pll->pll_base + ctrl->pdiv.offset); + val = readl(pll->control_base + ctrl->pdiv.offset); pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width); clk->rate = (ndiv * parent_rate) >> ctrl->ndiv_int.shift; @@ -463,14 +464,14 @@ static int iproc_clk_enable(struct clk_hw *hw) u32 val; /* channel enable is active low */ - val = readl(pll->pll_base + ctrl->enable.offset); + val = readl(pll->control_base + ctrl->enable.offset); val &= ~(1 << ctrl->enable.enable_shift); - iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val); /* also make sure channel is not held */ - val = readl(pll->pll_base + ctrl->enable.offset); + val = readl(pll->control_base + ctrl->enable.offset); val &= ~(1 << ctrl->enable.hold_shift); - iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val); return 0; } @@ -485,9 +486,9 @@ static void iproc_clk_disable(struct clk_hw *hw) if (ctrl->flags & IPROC_CLK_AON) return; - val = readl(pll->pll_base + ctrl->enable.offset); + val = readl(pll->control_base + ctrl->enable.offset); val |= 1 << ctrl->enable.enable_shift; - iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val); } static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw, @@ -502,7 +503,7 @@ static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw, if (parent_rate == 0) return 0; - val = readl(pll->pll_base + ctrl->mdiv.offset); + val = readl(pll->control_base + ctrl->mdiv.offset); mdiv = (val >> ctrl->mdiv.shift) & bit_mask(ctrl->mdiv.width); if (mdiv == 0) mdiv = 256; @@ -549,14 +550,14 @@ static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (div > 256) return -EINVAL; - val = readl(pll->pll_base + ctrl->mdiv.offset); + val = readl(pll->control_base + ctrl->mdiv.offset); if (div == 256) { val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift); } else { val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift); val |= div << ctrl->mdiv.shift; } - iproc_pll_write(pll, pll->pll_base, ctrl->mdiv.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->mdiv.offset, val); clk->rate = parent_rate / div; return 0; @@ -581,9 +582,10 @@ static void iproc_pll_sw_cfg(struct iproc_pll *pll) if (ctrl->flags & IPROC_CLK_PLL_NEEDS_SW_CFG) { u32 val; - val = readl(pll->pll_base + ctrl->sw_ctrl.offset); + val = readl(pll->control_base + ctrl->sw_ctrl.offset); val |= BIT(ctrl->sw_ctrl.shift); - iproc_pll_write(pll, pll->pll_base, ctrl->sw_ctrl.offset, val); + iproc_pll_write(pll, pll->control_base, ctrl->sw_ctrl.offset, + val); } } @@ -618,8 +620,8 @@ void __init iproc_pll_clk_setup(struct device_node *node, if (WARN_ON(!pll->clks)) goto err_clks; - pll->pll_base = of_iomap(node, 0); - if (WARN_ON(!pll->pll_base)) + pll->control_base = of_iomap(node, 0); + if (WARN_ON(!pll->control_base)) goto err_pll_iomap; /* Some SoCs do not require the pwr_base, thus failing is not fatal */ @@ -632,6 +634,16 @@ void __init iproc_pll_clk_setup(struct device_node *node, goto err_asiu_iomap; } + if (pll_ctrl->flags & IPROC_CLK_PLL_SPLIT_STAT_CTRL) { + /* Some SoCs have a split status/control. If this does not + * exist, assume they are unified. + */ + pll->status_base = of_iomap(node, 2); + if (!pll->status_base) + goto err_status_iomap; + } else + pll->status_base = pll->control_base; + /* initialize and register the PLL itself */ pll->ctrl = pll_ctrl; @@ -702,6 +714,10 @@ err_clk_register: clk_unregister(pll->clk_data.clks[i]); err_pll_register: + if (pll->status_base != pll->control_base) + iounmap(pll->status_base); + +err_status_iomap: if (pll->asiu_base) iounmap(pll->asiu_base); @@ -709,7 +725,7 @@ err_asiu_iomap: if (pll->pwr_base) iounmap(pll->pwr_base); - iounmap(pll->pll_base); + iounmap(pll->control_base); err_pll_iomap: kfree(pll->clks); diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h index b71c19737efd..8988de70a98c 100644 --- a/drivers/clk/bcm/clk-iproc.h +++ b/drivers/clk/bcm/clk-iproc.h @@ -54,6 +54,12 @@ */ #define IPROC_CLK_EMBED_PWRCTRL BIT(5) +/* + * Some PLLs have separate registers for Status and Control. Identify this to + * let the driver know if additional registers need to be used + */ +#define IPROC_CLK_PLL_SPLIT_STAT_CTRL BIT(6) + /* * Parameters for VCO frequency configuration * -- cgit v1.2.3-59-g8ed1b From f7225a832dde995325b486b41728dfbe4634311c Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 15 Oct 2015 15:48:31 -0400 Subject: clk: ns2: add clock support for Broadcom Northstar 2 SoC The Broadcom Northstar 2 SoC is architected under the iProc architecture. It has the following PLLs: GENPLL SCR, GENPLL SW, LCPLL DDR, LCPLL Ports, all derived from an onboard crystal. Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd --- drivers/clk/Makefile | 2 +- drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-ns2.c | 288 ++++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/bcm-ns2.h | 72 +++++++++ 4 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/bcm/clk-ns2.c create mode 100644 include/dt-bindings/clock/bcm-ns2.h (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d08b3e5985be..6124bd31e557 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -47,7 +47,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ -obj-$(CONFIG_ARCH_BCM) += bcm/ +obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ obj-$(CONFIG_ARCH_MXC) += imx/ diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index e258b280a622..2d1cbc5aac41 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o +obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o obj-$(CONFIG_ARCH_BCM_5301X) += clk-nsp.o diff --git a/drivers/clk/bcm/clk-ns2.c b/drivers/clk/bcm/clk-ns2.c new file mode 100644 index 000000000000..a564e9248814 --- /dev/null +++ b/drivers/clk/bcm/clk-ns2.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2015 Broadcom Corporation + * + * 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 +#include +#include +#include +#include +#include + +#include +#include "clk-iproc.h" + +#define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, } + +#define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \ + .pwr_shift = ps, .iso_shift = is } + +#define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \ + .p_reset_shift = prs } + +#define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, .ki_shift = kis,\ + .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ + .ka_width = kaw } + +#define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo } + +#define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \ + .hold_shift = hs, .bypass_shift = bs } + +static const struct iproc_pll_ctrl genpll_scr = { + .flags = IPROC_CLK_AON | IPROC_CLK_PLL_SPLIT_STAT_CTRL, + .aon = AON_VAL(0x0, 1, 15, 12), + .reset = RESET_VAL(0x4, 2, 1), + .dig_filter = DF_VAL(0x0, 9, 3, 5, 4, 2, 3), + .ndiv_int = REG_VAL(0x8, 4, 10), + .pdiv = REG_VAL(0x8, 0, 4), + .vco_ctrl = VCO_CTRL_VAL(0x10, 0xc), + .status = REG_VAL(0x0, 27, 1), +}; + + +static const struct iproc_clk_ctrl genpll_scr_clk[] = { + /* bypass_shift, the last value passed into ENABLE_VAL(), is not defined + * in NS2. However, it doesn't appear to be used anywhere, so setting + * it to 0. + */ + [BCM_NS2_GENPLL_SCR_SCR_CLK] = { + .channel = BCM_NS2_GENPLL_SCR_SCR_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 18, 12, 0), + .mdiv = REG_VAL(0x18, 0, 8), + }, + [BCM_NS2_GENPLL_SCR_FS_CLK] = { + .channel = BCM_NS2_GENPLL_SCR_FS_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 19, 13, 0), + .mdiv = REG_VAL(0x18, 8, 8), + }, + [BCM_NS2_GENPLL_SCR_AUDIO_CLK] = { + .channel = BCM_NS2_GENPLL_SCR_AUDIO_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 20, 14, 0), + .mdiv = REG_VAL(0x14, 0, 8), + }, + [BCM_NS2_GENPLL_SCR_CH3_UNUSED] = { + .channel = BCM_NS2_GENPLL_SCR_CH3_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 21, 15, 0), + .mdiv = REG_VAL(0x14, 8, 8), + }, + [BCM_NS2_GENPLL_SCR_CH4_UNUSED] = { + .channel = BCM_NS2_GENPLL_SCR_CH4_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 22, 16, 0), + .mdiv = REG_VAL(0x14, 16, 8), + }, + [BCM_NS2_GENPLL_SCR_CH5_UNUSED] = { + .channel = BCM_NS2_GENPLL_SCR_CH5_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 23, 17, 0), + .mdiv = REG_VAL(0x14, 24, 8), + }, +}; + +static void __init ns2_genpll_scr_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &genpll_scr, NULL, 0, genpll_scr_clk, + ARRAY_SIZE(genpll_scr_clk)); +} +CLK_OF_DECLARE(ns2_genpll_src_clk, "brcm,ns2-genpll-scr", + ns2_genpll_scr_clk_init); + +static const struct iproc_pll_ctrl genpll_sw = { + .flags = IPROC_CLK_AON | IPROC_CLK_PLL_SPLIT_STAT_CTRL, + .aon = AON_VAL(0x0, 2, 9, 8), + .reset = RESET_VAL(0x4, 2, 1), + .dig_filter = DF_VAL(0x0, 9, 3, 5, 4, 2, 3), + .ndiv_int = REG_VAL(0x8, 4, 10), + .pdiv = REG_VAL(0x8, 0, 4), + .vco_ctrl = VCO_CTRL_VAL(0x10, 0xc), + .status = REG_VAL(0x0, 13, 1), +}; + +static const struct iproc_clk_ctrl genpll_sw_clk[] = { + /* bypass_shift, the last value passed into ENABLE_VAL(), is not defined + * in NS2. However, it doesn't appear to be used anywhere, so setting + * it to 0. + */ + [BCM_NS2_GENPLL_SW_RPE_CLK] = { + .channel = BCM_NS2_GENPLL_SW_RPE_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 18, 12, 0), + .mdiv = REG_VAL(0x18, 0, 8), + }, + [BCM_NS2_GENPLL_SW_250_CLK] = { + .channel = BCM_NS2_GENPLL_SW_250_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 19, 13, 0), + .mdiv = REG_VAL(0x18, 8, 8), + }, + [BCM_NS2_GENPLL_SW_NIC_CLK] = { + .channel = BCM_NS2_GENPLL_SW_NIC_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 20, 14, 0), + .mdiv = REG_VAL(0x14, 0, 8), + }, + [BCM_NS2_GENPLL_SW_CHIMP_CLK] = { + .channel = BCM_NS2_GENPLL_SW_CHIMP_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 21, 15, 0), + .mdiv = REG_VAL(0x14, 8, 8), + }, + [BCM_NS2_GENPLL_SW_PORT_CLK] = { + .channel = BCM_NS2_GENPLL_SW_PORT_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 22, 16, 0), + .mdiv = REG_VAL(0x14, 16, 8), + }, + [BCM_NS2_GENPLL_SW_SDIO_CLK] = { + .channel = BCM_NS2_GENPLL_SW_SDIO_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 23, 17, 0), + .mdiv = REG_VAL(0x14, 24, 8), + }, +}; + +static void __init ns2_genpll_sw_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &genpll_sw, NULL, 0, genpll_sw_clk, + ARRAY_SIZE(genpll_sw_clk)); +} +CLK_OF_DECLARE(ns2_genpll_sw_clk, "brcm,ns2-genpll-sw", + ns2_genpll_sw_clk_init); + +static const struct iproc_pll_ctrl lcpll_ddr = { + .flags = IPROC_CLK_AON | IPROC_CLK_PLL_SPLIT_STAT_CTRL, + .aon = AON_VAL(0x0, 2, 1, 0), + .reset = RESET_VAL(0x4, 2, 1), + .dig_filter = DF_VAL(0x0, 9, 3, 5, 4, 1, 4), + .ndiv_int = REG_VAL(0x8, 4, 10), + .pdiv = REG_VAL(0x8, 0, 4), + .vco_ctrl = VCO_CTRL_VAL(0x10, 0xc), + .status = REG_VAL(0x0, 0, 1), +}; + +static const struct iproc_clk_ctrl lcpll_ddr_clk[] = { + /* bypass_shift, the last value passed into ENABLE_VAL(), is not defined + * in NS2. However, it doesn't appear to be used anywhere, so setting + * it to 0. + */ + [BCM_NS2_LCPLL_DDR_PCIE_SATA_USB_CLK] = { + .channel = BCM_NS2_LCPLL_DDR_PCIE_SATA_USB_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 18, 12, 0), + .mdiv = REG_VAL(0x14, 0, 8), + }, + [BCM_NS2_LCPLL_DDR_DDR_CLK] = { + .channel = BCM_NS2_LCPLL_DDR_DDR_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 19, 13, 0), + .mdiv = REG_VAL(0x14, 8, 8), + }, + [BCM_NS2_LCPLL_DDR_CH2_UNUSED] = { + .channel = BCM_NS2_LCPLL_DDR_CH2_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 20, 14, 0), + .mdiv = REG_VAL(0x10, 0, 8), + }, + [BCM_NS2_LCPLL_DDR_CH3_UNUSED] = { + .channel = BCM_NS2_LCPLL_DDR_CH3_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 21, 15, 0), + .mdiv = REG_VAL(0x10, 8, 8), + }, + [BCM_NS2_LCPLL_DDR_CH4_UNUSED] = { + .channel = BCM_NS2_LCPLL_DDR_CH4_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 22, 16, 0), + .mdiv = REG_VAL(0x10, 16, 8), + }, + [BCM_NS2_LCPLL_DDR_CH5_UNUSED] = { + .channel = BCM_NS2_LCPLL_DDR_CH5_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 23, 17, 0), + .mdiv = REG_VAL(0x10, 24, 8), + }, +}; + +static void __init ns2_lcpll_ddr_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &lcpll_ddr, NULL, 0, lcpll_ddr_clk, + ARRAY_SIZE(lcpll_ddr_clk)); +} +CLK_OF_DECLARE(ns2_lcpll_ddr_clk, "brcm,ns2-lcpll-ddr", + ns2_lcpll_ddr_clk_init); + +static const struct iproc_pll_ctrl lcpll_ports = { + .flags = IPROC_CLK_AON | IPROC_CLK_PLL_SPLIT_STAT_CTRL, + .aon = AON_VAL(0x0, 2, 5, 4), + .reset = RESET_VAL(0x4, 2, 1), + .dig_filter = DF_VAL(0x0, 9, 3, 5, 4, 1, 4), + .ndiv_int = REG_VAL(0x8, 4, 10), + .pdiv = REG_VAL(0x8, 0, 4), + .vco_ctrl = VCO_CTRL_VAL(0x10, 0xc), + .status = REG_VAL(0x0, 0, 1), +}; + +static const struct iproc_clk_ctrl lcpll_ports_clk[] = { + /* bypass_shift, the last value passed into ENABLE_VAL(), is not defined + * in NS2. However, it doesn't appear to be used anywhere, so setting + * it to 0. + */ + [BCM_NS2_LCPLL_PORTS_WAN_CLK] = { + .channel = BCM_NS2_LCPLL_PORTS_WAN_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 18, 12, 0), + .mdiv = REG_VAL(0x14, 0, 8), + }, + [BCM_NS2_LCPLL_PORTS_RGMII_CLK] = { + .channel = BCM_NS2_LCPLL_PORTS_RGMII_CLK, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 19, 13, 0), + .mdiv = REG_VAL(0x14, 8, 8), + }, + [BCM_NS2_LCPLL_PORTS_CH2_UNUSED] = { + .channel = BCM_NS2_LCPLL_PORTS_CH2_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 20, 14, 0), + .mdiv = REG_VAL(0x10, 0, 8), + }, + [BCM_NS2_LCPLL_PORTS_CH3_UNUSED] = { + .channel = BCM_NS2_LCPLL_PORTS_CH3_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 21, 15, 0), + .mdiv = REG_VAL(0x10, 8, 8), + }, + [BCM_NS2_LCPLL_PORTS_CH4_UNUSED] = { + .channel = BCM_NS2_LCPLL_PORTS_CH4_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 22, 16, 0), + .mdiv = REG_VAL(0x10, 16, 8), + }, + [BCM_NS2_LCPLL_PORTS_CH5_UNUSED] = { + .channel = BCM_NS2_LCPLL_PORTS_CH5_UNUSED, + .flags = IPROC_CLK_AON, + .enable = ENABLE_VAL(0x0, 23, 17, 0), + .mdiv = REG_VAL(0x10, 24, 8), + }, +}; + +static void __init ns2_lcpll_ports_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &lcpll_ports, NULL, 0, lcpll_ports_clk, + ARRAY_SIZE(lcpll_ports_clk)); +} +CLK_OF_DECLARE(ns2_lcpll_ports_clk, "brcm,ns2-lcpll-ports", + ns2_lcpll_ports_clk_init); diff --git a/include/dt-bindings/clock/bcm-ns2.h b/include/dt-bindings/clock/bcm-ns2.h new file mode 100644 index 000000000000..d99c7a2e70cb --- /dev/null +++ b/include/dt-bindings/clock/bcm-ns2.h @@ -0,0 +1,72 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2015 Broadcom Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Broadcom Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CLOCK_BCM_NS2_H +#define _CLOCK_BCM_NS2_H + +/* GENPLL SCR clock channel ID */ +#define BCM_NS2_GENPLL_SCR 0 +#define BCM_NS2_GENPLL_SCR_SCR_CLK 1 +#define BCM_NS2_GENPLL_SCR_FS_CLK 2 +#define BCM_NS2_GENPLL_SCR_AUDIO_CLK 3 +#define BCM_NS2_GENPLL_SCR_CH3_UNUSED 4 +#define BCM_NS2_GENPLL_SCR_CH4_UNUSED 5 +#define BCM_NS2_GENPLL_SCR_CH5_UNUSED 6 + +/* GENPLL SW clock channel ID */ +#define BCM_NS2_GENPLL_SW 0 +#define BCM_NS2_GENPLL_SW_RPE_CLK 1 +#define BCM_NS2_GENPLL_SW_250_CLK 2 +#define BCM_NS2_GENPLL_SW_NIC_CLK 3 +#define BCM_NS2_GENPLL_SW_CHIMP_CLK 4 +#define BCM_NS2_GENPLL_SW_PORT_CLK 5 +#define BCM_NS2_GENPLL_SW_SDIO_CLK 6 + +/* LCPLL DDR clock channel ID */ +#define BCM_NS2_LCPLL_DDR 0 +#define BCM_NS2_LCPLL_DDR_PCIE_SATA_USB_CLK 1 +#define BCM_NS2_LCPLL_DDR_DDR_CLK 2 +#define BCM_NS2_LCPLL_DDR_CH2_UNUSED 3 +#define BCM_NS2_LCPLL_DDR_CH3_UNUSED 4 +#define BCM_NS2_LCPLL_DDR_CH4_UNUSED 5 +#define BCM_NS2_LCPLL_DDR_CH5_UNUSED 6 + +/* LCPLL PORTS clock channel ID */ +#define BCM_NS2_LCPLL_PORTS 0 +#define BCM_NS2_LCPLL_PORTS_WAN_CLK 1 +#define BCM_NS2_LCPLL_PORTS_RGMII_CLK 2 +#define BCM_NS2_LCPLL_PORTS_CH2_UNUSED 3 +#define BCM_NS2_LCPLL_PORTS_CH3_UNUSED 4 +#define BCM_NS2_LCPLL_PORTS_CH4_UNUSED 5 +#define BCM_NS2_LCPLL_PORTS_CH5_UNUSED 6 + +#endif /* _CLOCK_BCM_NS2_H */ -- cgit v1.2.3-59-g8ed1b