From 4fd9028f446bb1120e5ce7b6abc176cf439223fe Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 25 Oct 2015 22:46:08 +0000 Subject: [PATCH] bcm53xx: add clk tree driver These patches are written by Broadcom and will be in mainline Linux kernel soon. I had some problems to get them backported to kernel 4.1, so currently they are only available for 4.3. Signed-off-by: Hauke Mehrtens SVN-Revision: 47253 --- target/linux/bcm53xx/config-4.3 | 1 + ...Fix-PLL-output-frequency-calculation.patch | 59 ++++ ...ygnus-Convert-all-macros-to-all-caps.patch | 292 ++++++++++++++++ .../045-clk-iproc-Add-PWRCTRL-support.patch | 120 +++++++ ...k-support-for-Broadcom-Northstar-Plu.patch | 219 ++++++++++++ ...lk-iproc-Add-PLL-base-write-function.patch | 223 ++++++++++++ .../048-clk-iproc-Split-off-dig_filter.patch | 158 +++++++++ ...eparate-status-and-control-variables.patch | 319 ++++++++++++++++++ ...ts-enable-clock-support-for-BCM5301X.patch | 153 +++++++++ .../301-ARM-BCM5301X-Add-SPROM.patch | 2 +- 10 files changed, 1545 insertions(+), 1 deletion(-) create mode 100644 target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch create mode 100644 target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch create mode 100644 target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch create mode 100644 target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch create mode 100644 target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch create mode 100644 target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch create mode 100644 target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch create mode 100644 target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch diff --git a/target/linux/bcm53xx/config-4.3 b/target/linux/bcm53xx/config-4.3 index 73c8062fa9..16705a157e 100644 --- a/target/linux/bcm53xx/config-4.3 +++ b/target/linux/bcm53xx/config-4.3 @@ -80,6 +80,7 @@ CONFIG_CLKSRC_MMIO=y CONFIG_CLKSRC_OF=y CONFIG_CLONE_BACKWARDS=y CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_IPROC=y CONFIG_CPU_32v6K=y CONFIG_CPU_32v7=y CONFIG_CPU_ABRT_EV7=y diff --git a/target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch b/target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch new file mode 100644 index 0000000000..20dd90e31c --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch @@ -0,0 +1,59 @@ +From 63243a4da7d0dfa19dcacd0a529782eeb2f86f92 Mon Sep 17 00:00:00 2001 +From: Simran Rai +Date: Mon, 19 Oct 2015 15:27:19 -0700 +Subject: [PATCH] clk: iproc: Fix PLL output frequency calculation + +This patch affects the clocks that use fractional ndivider in their +PLL output frequency calculation. Instead of 2^20 divide factor, the +clock's ndiv integer shift was used. Fixed the bug by replacing ndiv +integer shift with 2^20 factor. + +Signed-off-by: Simran Rai +Signed-off-by: Ray Jui +Reviewed-by: Scott Branden +Fixes: 5fe225c105fd ("clk: iproc: add initial common clock support") +Cc: # v4.1+ +Signed-off-by: Michael Turquette +--- + drivers/clk/bcm/clk-iproc-pll.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/drivers/clk/bcm/clk-iproc-pll.c ++++ b/drivers/clk/bcm/clk-iproc-pll.c +@@ -345,8 +345,8 @@ static unsigned long iproc_pll_recalc_ra + struct iproc_pll *pll = clk->pll; + const struct iproc_pll_ctrl *ctrl = pll->ctrl; + u32 val; +- u64 ndiv; +- unsigned int ndiv_int, ndiv_frac, pdiv; ++ u64 ndiv, ndiv_int, ndiv_frac; ++ unsigned int pdiv; + + if (parent_rate == 0) + return 0; +@@ -366,22 +366,19 @@ static unsigned long iproc_pll_recalc_ra + val = readl(pll->pll_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; ++ ndiv = ndiv_int << 20; + + if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { + val = readl(pll->pll_base + ctrl->ndiv_frac.offset); + ndiv_frac = (val >> ctrl->ndiv_frac.shift) & + bit_mask(ctrl->ndiv_frac.width); +- +- if (ndiv_frac != 0) +- ndiv = ((u64)ndiv_int << ctrl->ndiv_int.shift) | +- ndiv_frac; ++ ndiv += ndiv_frac; + } + + val = readl(pll->pll_base + ctrl->pdiv.offset); + pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width); + +- clk->rate = (ndiv * parent_rate) >> ctrl->ndiv_int.shift; ++ clk->rate = (ndiv * parent_rate) >> 20; + + if (pdiv == 0) + clk->rate *= 2; diff --git a/target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch b/target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch new file mode 100644 index 0000000000..f65aa9cf0b --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch @@ -0,0 +1,292 @@ +From b5116083e227fa478e20d5ed945430088aa1a00b Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 15:48:25 -0400 +Subject: [PATCH 44/50] 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 +--- + drivers/clk/bcm/clk-cygnus.c | 146 +++++++++++++++++++++---------------------- + 1 file changed, 73 insertions(+), 73 deletions(-) + +--- 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,cygn + 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,cygn + + 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 + 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_in + 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) diff --git a/target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch b/target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch new file mode 100644 index 0000000000..318bd5ca4e --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch @@ -0,0 +1,120 @@ +From 7c70cb333deb6e2f88da9c94ddd6b3b00c97b93a Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 15:48:26 -0400 +Subject: [PATCH 45/50] 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 +--- + drivers/clk/bcm/clk-iproc-pll.c | 55 ++++++++++++++++++++++++++++------------- + drivers/clk/bcm/clk-iproc.h | 6 +++++ + 2 files changed, 44 insertions(+), 17 deletions(-) + +--- 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_p + 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 + 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) { +@@ -607,9 +629,8 @@ void __init iproc_pll_clk_setup(struct d + 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) { +@@ -692,9 +713,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: +--- a/drivers/clk/bcm/clk-iproc.h ++++ b/drivers/clk/bcm/clk-iproc.h +@@ -49,6 +49,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 + * + * VCO frequency = diff --git a/target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch b/target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch new file mode 100644 index 0000000000..c8eda8d102 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch @@ -0,0 +1,219 @@ +From d358480591b34d081806ecb5a9474930a4d59f8a Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 15:48:27 -0400 +Subject: [PATCH 46/50] 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 +--- + 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 + +--- a/drivers/clk/bcm/Makefile ++++ b/drivers/clk/bcm/Makefile +@@ -4,3 +4,5 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281 + 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 +--- /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); +--- /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 */ diff --git a/target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch b/target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch new file mode 100644 index 0000000000..2f07cc6656 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch @@ -0,0 +1,223 @@ +From acbb7a3de7e4d83b23c0bbb3eaf77d15a041d865 Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 15:48:28 -0400 +Subject: [PATCH 47/50] 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 +--- + drivers/clk/bcm/clk-iproc-pll.c | 80 +++++++++++++++++------------------------ + 1 file changed, 33 insertions(+), 47 deletions(-) + +--- 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 ipro + 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_p + 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 + 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 + 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 ip + + 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 + 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 + /* 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 + 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 + 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); + +@@ -464,14 +458,12 @@ static int iproc_clk_enable(struct clk_h + /* 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; + } +@@ -488,9 +480,7 @@ static void iproc_clk_disable(struct clk + + 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, +@@ -559,9 +549,7 @@ static int iproc_clk_set_rate(struct clk + 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; +@@ -588,9 +576,7 @@ static void iproc_pll_sw_cfg(struct ipro + + 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); + } + } + diff --git a/target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch b/target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch new file mode 100644 index 0000000000..528311f8d6 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch @@ -0,0 +1,158 @@ +From fb9e4932d17ad32786d03cb672fb62f2b337acf5 Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 15:48:29 -0400 +Subject: [PATCH 48/50] 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 +--- + 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(-) + +--- 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 genpl + .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,cygn + 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 mipip + 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), +--- 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 + 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); + } +--- 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; +--- 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-arm + 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 + 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), diff --git a/target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch b/target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch new file mode 100644 index 0000000000..1e7cbc0d89 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch @@ -0,0 +1,319 @@ +From eeb32564795a3584dba6281f445ff2aa552be36b Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 15:48:30 -0400 +Subject: [PATCH 49/50] 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 +--- + drivers/clk/bcm/clk-iproc-pll.c | 96 ++++++++++++++++++++++++----------------- + drivers/clk/bcm/clk-iproc.h | 6 +++ + 2 files changed, 62 insertions(+), 40 deletions(-) + +--- 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 ipro + 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 + 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_p + } + + 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 + 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 ip + 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 + 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 + /* 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 + 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_ra + 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,19 +384,19 @@ static unsigned long iproc_pll_recalc_ra + * + * ((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 = ndiv_int << 20; + + 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); + ndiv += 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) >> 20; +@@ -460,14 +461,14 @@ static int iproc_clk_enable(struct clk_h + 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; + } +@@ -482,9 +483,9 @@ static void iproc_clk_disable(struct clk + 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, +@@ -499,7 +500,7 @@ static unsigned long iproc_clk_recalc_ra + 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; +@@ -546,14 +547,14 @@ static int iproc_clk_set_rate(struct clk + 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; +@@ -578,9 +579,10 @@ static void iproc_pll_sw_cfg(struct ipro + 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); + } + } + +@@ -615,8 +617,8 @@ void __init iproc_pll_clk_setup(struct d + 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 */ +@@ -629,6 +631,16 @@ void __init iproc_pll_clk_setup(struct d + 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; + +@@ -699,6 +711,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); + +@@ -706,7 +722,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); +--- a/drivers/clk/bcm/clk-iproc.h ++++ b/drivers/clk/bcm/clk-iproc.h +@@ -55,6 +55,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 + * + * VCO frequency = diff --git a/target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch b/target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch new file mode 100644 index 0000000000..a9a5246c0c --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch @@ -0,0 +1,153 @@ +From e96ef422d0095fe9ae39b03c0805a0db8ff7e382 Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Tue, 13 Oct 2015 17:22:25 -0400 +Subject: [PATCH 50/50] ARM: dts: enable clock support for BCM5301X + +Replace current device tree dummy clocks with real clock support for +Broadcom Northstar SoCs. + +Signed-off-by: Jon Mason +--- + arch/arm/boot/dts/bcm5301x.dtsi | 88 ++++++++++++++++++++++++++++++++--------- + 1 file changed, 69 insertions(+), 19 deletions(-) + +--- a/arch/arm/boot/dts/bcm5301x.dtsi ++++ b/arch/arm/boot/dts/bcm5301x.dtsi +@@ -8,6 +8,7 @@ + * Licensed under the GNU/GPL. See COPYING for details. + */ + ++#include + #include + #include + #include +@@ -42,41 +43,48 @@ + + mpcore { + compatible = "simple-bus"; +- ranges = <0x00000000 0x19020000 0x00003000>; ++ ranges = <0x00000000 0x19000000 0x00023000>; + #address-cells = <1>; + #size-cells = <1>; + +- scu@0000 { ++ a9pll: arm_clk@00000 { ++ #clock-cells = <0>; ++ compatible = "brcm,nsp-armpll"; ++ clocks = <&osc>; ++ reg = <0x00000 0x1000>; ++ }; ++ ++ scu@20000 { + compatible = "arm,cortex-a9-scu"; +- reg = <0x0000 0x100>; ++ reg = <0x20000 0x100>; + }; + +- timer@0200 { ++ timer@20200 { + compatible = "arm,cortex-a9-global-timer"; +- reg = <0x0200 0x100>; ++ reg = <0x20200 0x100>; + interrupts = ; +- clocks = <&clk_periph>; ++ clocks = <&periph_clk>; + }; + +- local-timer@0600 { ++ local-timer@20600 { + compatible = "arm,cortex-a9-twd-timer"; +- reg = <0x0600 0x100>; ++ reg = <0x20600 0x100>; + interrupts = ; +- clocks = <&clk_periph>; ++ clocks = <&periph_clk>; + }; + +- gic: interrupt-controller@1000 { ++ gic: interrupt-controller@21000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; +- reg = <0x1000 0x1000>, +- <0x0100 0x100>; ++ reg = <0x21000 0x1000>, ++ <0x20100 0x100>; + }; + +- L2: cache-controller@2000 { ++ L2: cache-controller@22000 { + compatible = "arm,pl310-cache"; +- reg = <0x2000 0x1000>; ++ reg = <0x22000 0x1000>; + cache-unified; + arm,shared-override; + prefetch-data = <1>; +@@ -94,14 +102,37 @@ + + clocks { + #address-cells = <1>; +- #size-cells = <0>; ++ #size-cells = <1>; ++ ranges; + +- /* As long as we do not have a real clock driver us this +- * fixed clock */ +- clk_periph: periph { ++ osc: oscillator { ++ #clock-cells = <0>; + compatible = "fixed-clock"; ++ clock-frequency = <25000000>; ++ }; ++ ++ iprocmed: iprocmed { + #clock-cells = <0>; +- clock-frequency = <400000000>; ++ compatible = "fixed-factor-clock"; ++ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>; ++ clock-div = <2>; ++ clock-mult = <1>; ++ }; ++ ++ iprocslow: iprocslow { ++ #clock-cells = <0>; ++ compatible = "fixed-factor-clock"; ++ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>; ++ clock-div = <4>; ++ clock-mult = <1>; ++ }; ++ ++ periph_clk: periph_clk { ++ #clock-cells = <0>; ++ compatible = "fixed-factor-clock"; ++ clocks = <&a9pll>; ++ clock-div = <2>; ++ clock-mult = <1>; + }; + }; + +@@ -189,4 +220,23 @@ + + brcm,nand-has-wp; + }; ++ ++ lcpll0: lcpll0@1800c100 { ++ #clock-cells = <1>; ++ compatible = "brcm,nsp-lcpll0"; ++ reg = <0x1800c100 0x14>; ++ clocks = <&osc>; ++ clock-output-names = "lcpll0", "pcie_phy", "sdio", ++ "ddr_phy"; ++ }; ++ ++ genpll: genpll@1800c140 { ++ #clock-cells = <1>; ++ compatible = "brcm,nsp-genpll"; ++ reg = <0x1800c140 0x24>; ++ clocks = <&osc>; ++ clock-output-names = "genpll", "phy", "ethernetclk", ++ "usbclk", "iprocfast", "sata1", ++ "sata2"; ++ }; + }; diff --git a/target/linux/bcm53xx/patches-4.3/301-ARM-BCM5301X-Add-SPROM.patch b/target/linux/bcm53xx/patches-4.3/301-ARM-BCM5301X-Add-SPROM.patch index 9ca76b3d4c..ed6cc73bcc 100644 --- a/target/linux/bcm53xx/patches-4.3/301-ARM-BCM5301X-Add-SPROM.patch +++ b/target/linux/bcm53xx/patches-4.3/301-ARM-BCM5301X-Add-SPROM.patch @@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki --- a/arch/arm/boot/dts/bcm5301x.dtsi +++ b/arch/arm/boot/dts/bcm5301x.dtsi -@@ -105,6 +105,10 @@ +@@ -136,6 +136,10 @@ }; };