diff options
Diffstat (limited to 'drivers/clk/meson')
-rw-r--r-- | drivers/clk/meson/axg-audio.c | 34 | ||||
-rw-r--r-- | drivers/clk/meson/axg.c | 332 | ||||
-rw-r--r-- | drivers/clk/meson/axg.h | 8 | ||||
-rw-r--r-- | drivers/clk/meson/clk-pll.c | 156 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.h | 16 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.c | 518 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.h | 10 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b.c | 280 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b.h | 5 |
9 files changed, 732 insertions, 627 deletions
diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index a0ed41e73bde..5f6c860aa122 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -101,10 +101,16 @@ static const char * const mst_mux_parent_names[] = { "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", }; -#define AXG_MST_MCLK_MUX(_name, _reg) \ - AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \ +#define AXG_MST_MUX(_name, _reg, _flag) \ + AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ mst_mux_parent_names, CLK_SET_RATE_PARENT) +#define AXG_MST_MCLK_MUX(_name, _reg) \ + AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) + +#define AXG_MST_SYS_MUX(_name, _reg) \ + AXG_MST_MUX(_name, _reg, 0) + static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); @@ -112,13 +118,19 @@ static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); + +#define AXG_MST_DIV(_name, _reg, _flag) \ + AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ + "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ + +#define AXG_MST_MCLK_DIV(_name, _reg) \ + AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) -#define AXG_MST_MCLK_DIV(_name, _reg) \ - AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \ - "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ +#define AXG_MST_SYS_DIV(_name, _reg) \ + AXG_MST_DIV(_name, _reg, 0) static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); @@ -127,12 +139,12 @@ static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -#define AXG_MST_MCLK_GATE(_name, _reg) \ - AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ +#define AXG_MST_MCLK_GATE(_name, _reg) \ + AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ CLK_SET_RATE_PARENT) static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 00ce62ad6416..c981159b02c0 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -22,8 +22,13 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static struct clk_regmap axg_fixed_pll = { +static struct clk_regmap axg_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -34,11 +39,6 @@ static struct clk_regmap axg_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -56,15 +56,39 @@ static struct clk_regmap axg_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; -static struct clk_regmap axg_sys_pll = { +static struct clk_regmap axg_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_regmap axg_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -75,11 +99,6 @@ static struct clk_regmap axg_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -92,102 +111,59 @@ static struct clk_regmap axg_sys_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; -static const struct pll_rate_table axg_gp0_pll_rate_table[] = { - PLL_RATE(240000000, 40, 1, 2), - PLL_RATE(246000000, 41, 1, 2), - PLL_RATE(252000000, 42, 1, 2), - PLL_RATE(258000000, 43, 1, 2), - PLL_RATE(264000000, 44, 1, 2), - PLL_RATE(270000000, 45, 1, 2), - PLL_RATE(276000000, 46, 1, 2), - PLL_RATE(282000000, 47, 1, 2), - PLL_RATE(288000000, 48, 1, 2), - PLL_RATE(294000000, 49, 1, 2), - PLL_RATE(300000000, 50, 1, 2), - PLL_RATE(306000000, 51, 1, 2), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(318000000, 53, 1, 2), - PLL_RATE(324000000, 54, 1, 2), - PLL_RATE(330000000, 55, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(342000000, 57, 1, 2), - PLL_RATE(348000000, 58, 1, 2), - PLL_RATE(354000000, 59, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(366000000, 61, 1, 2), - PLL_RATE(372000000, 62, 1, 2), - PLL_RATE(378000000, 63, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(390000000, 65, 1, 3), - PLL_RATE(396000000, 66, 1, 3), - PLL_RATE(402000000, 67, 1, 3), - PLL_RATE(408000000, 68, 1, 3), - PLL_RATE(480000000, 40, 1, 1), - PLL_RATE(492000000, 41, 1, 1), - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(756000000, 63, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(780000000, 65, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(804000000, 67, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(960000000, 40, 1, 0), - PLL_RATE(984000000, 41, 1, 0), - PLL_RATE(1008000000, 42, 1, 0), - PLL_RATE(1032000000, 43, 1, 0), - PLL_RATE(1056000000, 44, 1, 0), - PLL_RATE(1080000000, 45, 1, 0), - PLL_RATE(1104000000, 46, 1, 0), - PLL_RATE(1128000000, 47, 1, 0), - PLL_RATE(1152000000, 48, 1, 0), - PLL_RATE(1176000000, 49, 1, 0), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), - PLL_RATE(1560000000, 65, 1, 0), - PLL_RATE(1584000000, 66, 1, 0), - PLL_RATE(1608000000, 67, 1, 0), - PLL_RATE(1632000000, 68, 1, 0), +static struct clk_regmap axg_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct pll_params_table axg_gp0_pll_params_table[] = { + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), + PLL_PARAMS(67, 1), + PLL_PARAMS(68, 1), { /* sentinel */ }, }; @@ -197,11 +173,15 @@ static const struct reg_sequence axg_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, - { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, }; -static struct clk_regmap axg_gp0_pll = { +static struct clk_regmap axg_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -212,11 +192,6 @@ static struct clk_regmap axg_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_GP0_PLL_CNTL1, .shift = 0, @@ -232,29 +207,49 @@ static struct clk_regmap axg_gp0_pll = { .shift = 29, .width = 1, }, - .table = axg_gp0_pll_rate_table, + .table = axg_gp0_pll_params_table, .init_regs = axg_gp0_init_regs, .init_count = ARRAY_SIZE(axg_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp0_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static const struct reg_sequence axg_hifi_init_regs[] = { { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 }, { .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 }, - { .reg = HHI_HIFI_PLL_CNTL, .def = 0x40010250 }, }; -static struct clk_regmap axg_hifi_pll = { +static struct clk_regmap axg_hifi_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_HIFI_PLL_CNTL, .shift = 0, @@ -265,11 +260,6 @@ static struct clk_regmap axg_hifi_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_HIFI_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_HIFI_PLL_CNTL5, .shift = 0, @@ -285,19 +275,35 @@ static struct clk_regmap axg_hifi_pll = { .shift = 29, .width = 1, }, - .table = axg_gp0_pll_rate_table, + .table = axg_gp0_pll_params_table, .init_regs = axg_hifi_init_regs, .init_count = ARRAY_SIZE(axg_hifi_init_regs), .flags = CLK_MESON_PLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ - .name = "hifi_pll", + .name = "hifi_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HIFI_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "hifi_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_fixed_factor axg_fclk_div2_div = { .mult = 1, .div = 2, @@ -625,29 +631,31 @@ static struct clk_regmap axg_mpll3 = { }, }; -static const struct pll_rate_table axg_pcie_pll_rate_table[] = { +static const struct pll_params_table axg_pcie_pll_params_table[] = { { - .rate = 100000000, - .m = 200, - .n = 3, - .od = 1, - .od2 = 3, + .m = 200, + .n = 3, }, { /* sentinel */ }, }; static const struct reg_sequence axg_pcie_init_regs[] = { - { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa }, { .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e }, { .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 }, { .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 }, + { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, }; -static struct clk_regmap axg_pcie_pll = { +static struct clk_regmap axg_pcie_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_PCIE_PLL_CNTL, .shift = 0, @@ -658,16 +666,6 @@ static struct clk_regmap axg_pcie_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_PCIE_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .od2 = { - .reg_off = HHI_PCIE_PLL_CNTL6, - .shift = 6, - .width = 2, - }, .frac = { .reg_off = HHI_PCIE_PLL_CNTL1, .shift = 0, @@ -683,29 +681,63 @@ static struct clk_regmap axg_pcie_pll = { .shift = 29, .width = 1, }, - .table = axg_pcie_pll_rate_table, + .table = axg_pcie_pll_params_table, .init_regs = axg_pcie_init_regs, .init_count = ARRAY_SIZE(axg_pcie_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "pcie_pll", + .name = "pcie_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "pcie_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .shift = 6, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "pcie_pll_od" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap axg_pcie_mux = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_PCIE_PLL_CNTL6, .mask = 0x1, .shift = 2, + /* skip the parent mpll3, reserved for debug */ + .table = (u32[]){ 1 }, }, .hw.init = &(struct clk_init_data){ .name = "pcie_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "mpll3", "pcie_pll" }, - .num_parents = 2, + .parent_names = (const char *[]){ "pcie_pll" }, + .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; @@ -1107,6 +1139,12 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw, [CLKID_GEN_CLK] = &axg_gen_clk.hw, + [CLKID_SYS_PLL_DCO] = &axg_sys_pll_dco.hw, + [CLKID_FIXED_PLL_DCO] = &axg_fixed_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &axg_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw, + [CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1185,6 +1223,8 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_fclk_div4, &axg_fclk_div5, &axg_fclk_div7, + &axg_pcie_pll_dco, + &axg_pcie_pll_od, &axg_pcie_pll, &axg_pcie_mux, &axg_pcie_ref, @@ -1194,6 +1234,12 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_gen_clk_sel, &axg_gen_clk_div, &axg_gen_clk, + &axg_fixed_pll_dco, + &axg_sys_pll_dco, + &axg_gp0_pll_dco, + &axg_hifi_pll_dco, + &axg_pcie_pll_dco, + &axg_pcie_pll_od, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index 1d04144a1b2c..0431dabac629 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -133,8 +133,14 @@ #define CLKID_PCIE_REF 78 #define CLKID_GEN_CLK_SEL 82 #define CLKID_GEN_CLK_DIV 83 +#define CLKID_SYS_PLL_DCO 85 +#define CLKID_FIXED_PLL_DCO 86 +#define CLKID_GP0_PLL_DCO 87 +#define CLKID_HIFI_PLL_DCO 88 +#define CLKID_PCIE_PLL_DCO 89 +#define CLKID_PCIE_PLL_OD 90 -#define NR_CLKS 85 +#define NR_CLKS 91 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/axg-clkc.h> diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 3e04617ac47f..f5b5b3fabe3c 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -11,15 +11,19 @@ * In the most basic form, a Meson PLL is composed as follows: * * PLL - * +------------------------------+ - * | | - * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out - * | ^ ^ | - * +------------------------------+ - * | | - * FREF VCO + * +--------------------------------+ + * | | + * | +--+ | + * in >>-----[ /N ]--->| | +-----+ | + * | | |------| DCO |---->> out + * | +--------->| | +--v--+ | + * | | +--+ | | + * | | | | + * | +--[ *(M + (F/Fmax) ]<--+ | + * | | + * +--------------------------------+ * - * out = in * (m + frac / frac_max) / (n << sum(ods)) + * out = in * (m + frac / frac_max) / n */ #include <linux/clk-provider.h> @@ -41,12 +45,11 @@ meson_clk_pll_data(struct clk_regmap *clk) } static unsigned long __pll_params_to_rate(unsigned long parent_rate, - const struct pll_rate_table *pllt, + const struct pll_params_table *pllt, u16 frac, struct meson_clk_pll_data *pll) { u64 rate = (u64)parent_rate * pllt->m; - unsigned int od = pllt->od + pllt->od2 + pllt->od3; if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { u64 frac_rate = (u64)parent_rate * frac; @@ -55,7 +58,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate, (1 << pll->frac.width)); } - return DIV_ROUND_UP_ULL(rate, pllt->n << od); + return DIV_ROUND_UP_ULL(rate, pllt->n); } static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, @@ -63,20 +66,11 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - struct pll_rate_table pllt; + struct pll_params_table pllt; u16 frac; pllt.n = meson_parm_read(clk->map, &pll->n); pllt.m = meson_parm_read(clk->map, &pll->m); - pllt.od = meson_parm_read(clk->map, &pll->od); - - pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ? - meson_parm_read(clk->map, &pll->od2) : - 0; - - pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ? - meson_parm_read(clk->map, &pll->od3) : - 0; frac = MESON_PARM_APPLICABLE(&pll->frac) ? meson_parm_read(clk->map, &pll->frac) : @@ -87,14 +81,12 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, static u16 __pll_params_with_frac(unsigned long rate, unsigned long parent_rate, - const struct pll_rate_table *pllt, + const struct pll_params_table *pllt, struct meson_clk_pll_data *pll) { u16 frac_max = (1 << pll->frac.width); u64 val = (u64)rate * pllt->n; - val <<= pllt->od + pllt->od2 + pllt->od3; - if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); else @@ -105,29 +97,50 @@ static u16 __pll_params_with_frac(unsigned long rate, return min((u16)val, (u16)(frac_max - 1)); } -static const struct pll_rate_table * +static bool meson_clk_pll_is_better(unsigned long rate, + unsigned long best, + unsigned long now, + struct meson_clk_pll_data *pll) +{ + if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || + MESON_PARM_APPLICABLE(&pll->frac)) { + /* Round down */ + if (now < rate && best < now) + return true; + } else { + /* Round Closest */ + if (abs(now - rate) < abs(best - rate)) + return true; + } + + return false; +} + +static const struct pll_params_table * meson_clk_get_pll_settings(unsigned long rate, + unsigned long parent_rate, struct meson_clk_pll_data *pll) { - const struct pll_rate_table *table = pll->table; - unsigned int i = 0; + const struct pll_params_table *table = pll->table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; if (!table) return NULL; - /* Find the first table element exceeding rate */ - while (table[i].rate && table[i].rate <= rate) - i++; + for (i = 0; table[i].n; i++) { + now = __pll_params_to_rate(parent_rate, &table[i], 0, pll); - if (i != 0) { - if (MESON_PARM_APPLICABLE(&pll->frac) || - !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || - (abs(rate - table[i - 1].rate) < - abs(rate - table[i].rate))) - i--; + /* If we get an exact match, don't bother any further */ + if (now == rate) { + return &table[i]; + } else if (meson_clk_pll_is_better(rate, best, now, pll)) { + best = now; + best_i = i; + } } - return (struct pll_rate_table *)&table[i]; + return (struct pll_params_table *)&table[best_i]; } static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -135,16 +148,18 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_rate_table *pllt = - meson_clk_get_pll_settings(rate, pll); + const struct pll_params_table *pllt = + meson_clk_get_pll_settings(rate, *parent_rate, pll); + unsigned long round; u16 frac; if (!pllt) return meson_clk_pll_recalc_rate(hw, *parent_rate); - if (!MESON_PARM_APPLICABLE(&pll->frac) - || rate == pllt->rate) - return pllt->rate; + round = __pll_params_to_rate(*parent_rate, pllt, 0, pll); + + if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round) + return round; /* * The rate provided by the setting is not an exact match, let's @@ -185,12 +200,45 @@ static void meson_clk_pll_init(struct clk_hw *hw) } } +static int meson_clk_pll_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* Make sure the pll is in reset */ + meson_parm_write(clk->map, &pll->rst, 1); + + /* Enable the pll */ + meson_parm_write(clk->map, &pll->en, 1); + + /* Take the pll out reset */ + meson_parm_write(clk->map, &pll->rst, 0); + + if (meson_clk_pll_wait_lock(hw)) + return -EIO; + + return 0; +} + +static void meson_clk_pll_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* Put the pll is in reset */ + meson_parm_write(clk->map, &pll->rst, 1); + + /* Disable the pll */ + meson_parm_write(clk->map, &pll->en, 0); +} + static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_rate_table *pllt; + const struct pll_params_table *pllt; + unsigned int enabled; unsigned long old_rate; u16 frac = 0; @@ -199,32 +247,28 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, old_rate = rate; - pllt = meson_clk_get_pll_settings(rate, pll); + pllt = meson_clk_get_pll_settings(rate, parent_rate, pll); if (!pllt) return -EINVAL; - /* Put the pll in reset to write the params */ - meson_parm_write(clk->map, &pll->rst, 1); + enabled = meson_parm_read(clk->map, &pll->en); + if (enabled) + meson_clk_pll_disable(hw); meson_parm_write(clk->map, &pll->n, pllt->n); meson_parm_write(clk->map, &pll->m, pllt->m); - meson_parm_write(clk->map, &pll->od, pllt->od); - if (MESON_PARM_APPLICABLE(&pll->od2)) - meson_parm_write(clk->map, &pll->od2, pllt->od2); - - if (MESON_PARM_APPLICABLE(&pll->od3)) - meson_parm_write(clk->map, &pll->od3, pllt->od3); if (MESON_PARM_APPLICABLE(&pll->frac)) { frac = __pll_params_with_frac(rate, parent_rate, pllt, pll); meson_parm_write(clk->map, &pll->frac, frac); } - /* make sure the reset is cleared at this point */ - meson_parm_write(clk->map, &pll->rst, 0); + /* If the pll is stopped, bail out now */ + if (!enabled) + return 0; - if (meson_clk_pll_wait_lock(hw)) { + if (meson_clk_pll_enable(hw)) { pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", __func__, old_rate); /* @@ -244,6 +288,8 @@ const struct clk_ops meson_clk_pll_ops = { .recalc_rate = meson_clk_pll_recalc_rate, .round_rate = meson_clk_pll_round_rate, .set_rate = meson_clk_pll_set_rate, + .enable = meson_clk_pll_enable, + .disable = meson_clk_pll_disable }; const struct clk_ops meson_clk_pll_ro_ops = { diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 24cec16b6038..6b96d55c047d 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -43,37 +43,29 @@ static inline void meson_parm_write(struct regmap *map, struct parm *p, } -struct pll_rate_table { - unsigned long rate; +struct pll_params_table { u16 m; u16 n; - u16 od; - u16 od2; - u16 od3; }; -#define PLL_RATE(_r, _m, _n, _od) \ +#define PLL_PARAMS(_m, _n) \ { \ - .rate = (_r), \ .m = (_m), \ .n = (_n), \ - .od = (_od), \ } #define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) struct meson_clk_pll_data { + struct parm en; struct parm m; struct parm n; struct parm frac; - struct parm od; - struct parm od2; - struct parm od3; struct parm l; struct parm rst; const struct reg_sequence *init_regs; unsigned int init_count; - const struct pll_rate_table *table; + const struct pll_params_table *table; u8 flags; }; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 86d3ae58e84c..9309cfaaa464 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -18,165 +18,77 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = { - PLL_RATE(96000000, 32, 1, 3), - PLL_RATE(99000000, 33, 1, 3), - PLL_RATE(102000000, 34, 1, 3), - PLL_RATE(105000000, 35, 1, 3), - PLL_RATE(108000000, 36, 1, 3), - PLL_RATE(111000000, 37, 1, 3), - PLL_RATE(114000000, 38, 1, 3), - PLL_RATE(117000000, 39, 1, 3), - PLL_RATE(120000000, 40, 1, 3), - PLL_RATE(123000000, 41, 1, 3), - PLL_RATE(126000000, 42, 1, 3), - PLL_RATE(129000000, 43, 1, 3), - PLL_RATE(132000000, 44, 1, 3), - PLL_RATE(135000000, 45, 1, 3), - PLL_RATE(138000000, 46, 1, 3), - PLL_RATE(141000000, 47, 1, 3), - PLL_RATE(144000000, 48, 1, 3), - PLL_RATE(147000000, 49, 1, 3), - PLL_RATE(150000000, 50, 1, 3), - PLL_RATE(153000000, 51, 1, 3), - PLL_RATE(156000000, 52, 1, 3), - PLL_RATE(159000000, 53, 1, 3), - PLL_RATE(162000000, 54, 1, 3), - PLL_RATE(165000000, 55, 1, 3), - PLL_RATE(168000000, 56, 1, 3), - PLL_RATE(171000000, 57, 1, 3), - PLL_RATE(174000000, 58, 1, 3), - PLL_RATE(177000000, 59, 1, 3), - PLL_RATE(180000000, 60, 1, 3), - PLL_RATE(183000000, 61, 1, 3), - PLL_RATE(186000000, 62, 1, 3), - PLL_RATE(192000000, 32, 1, 2), - PLL_RATE(198000000, 33, 1, 2), - PLL_RATE(204000000, 34, 1, 2), - PLL_RATE(210000000, 35, 1, 2), - PLL_RATE(216000000, 36, 1, 2), - PLL_RATE(222000000, 37, 1, 2), - PLL_RATE(228000000, 38, 1, 2), - PLL_RATE(234000000, 39, 1, 2), - PLL_RATE(240000000, 40, 1, 2), - PLL_RATE(246000000, 41, 1, 2), - PLL_RATE(252000000, 42, 1, 2), - PLL_RATE(258000000, 43, 1, 2), - PLL_RATE(264000000, 44, 1, 2), - PLL_RATE(270000000, 45, 1, 2), - PLL_RATE(276000000, 46, 1, 2), - PLL_RATE(282000000, 47, 1, 2), - PLL_RATE(288000000, 48, 1, 2), - PLL_RATE(294000000, 49, 1, 2), - PLL_RATE(300000000, 50, 1, 2), - PLL_RATE(306000000, 51, 1, 2), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(318000000, 53, 1, 2), - PLL_RATE(324000000, 54, 1, 2), - PLL_RATE(330000000, 55, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(342000000, 57, 1, 2), - PLL_RATE(348000000, 58, 1, 2), - PLL_RATE(354000000, 59, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(366000000, 61, 1, 2), - PLL_RATE(372000000, 62, 1, 2), - PLL_RATE(384000000, 32, 1, 1), - PLL_RATE(396000000, 33, 1, 1), - PLL_RATE(408000000, 34, 1, 1), - PLL_RATE(420000000, 35, 1, 1), - PLL_RATE(432000000, 36, 1, 1), - PLL_RATE(444000000, 37, 1, 1), - PLL_RATE(456000000, 38, 1, 1), - PLL_RATE(468000000, 39, 1, 1), - PLL_RATE(480000000, 40, 1, 1), - PLL_RATE(492000000, 41, 1, 1), - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 32, 1, 0), - PLL_RATE(792000000, 33, 1, 0), - PLL_RATE(816000000, 34, 1, 0), - PLL_RATE(840000000, 35, 1, 0), - PLL_RATE(864000000, 36, 1, 0), - PLL_RATE(888000000, 37, 1, 0), - PLL_RATE(912000000, 38, 1, 0), - PLL_RATE(936000000, 39, 1, 0), - PLL_RATE(960000000, 40, 1, 0), - PLL_RATE(984000000, 41, 1, 0), - PLL_RATE(1008000000, 42, 1, 0), - PLL_RATE(1032000000, 43, 1, 0), - PLL_RATE(1056000000, 44, 1, 0), - PLL_RATE(1080000000, 45, 1, 0), - PLL_RATE(1104000000, 46, 1, 0), - PLL_RATE(1128000000, 47, 1, 0), - PLL_RATE(1152000000, 48, 1, 0), - PLL_RATE(1176000000, 49, 1, 0), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), +static const struct pll_params_table gxbb_gp0_pll_params_table[] = { + PLL_PARAMS(32, 1), + PLL_PARAMS(33, 1), + PLL_PARAMS(34, 1), + PLL_PARAMS(35, 1), + PLL_PARAMS(36, 1), + PLL_PARAMS(37, 1), + PLL_PARAMS(38, 1), + PLL_PARAMS(39, 1), + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), { /* sentinel */ }, }; -static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(756000000, 63, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(780000000, 65, 1, 1), - PLL_RATE(792000000, 66, 1, 1), +static const struct pll_params_table gxl_gp0_pll_params_table[] = { + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), { /* sentinel */ }, }; -static struct clk_regmap gxbb_fixed_pll = { +static struct clk_regmap gxbb_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -187,11 +99,6 @@ static struct clk_regmap gxbb_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -209,11 +116,29 @@ static struct clk_regmap gxbb_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ }, }; @@ -228,8 +153,13 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { }, }; -static struct clk_regmap gxbb_hdmi_pll = { +static struct clk_regmap gxbb_hdmi_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_HDMI_PLL_CNTL, .shift = 0, @@ -245,21 +175,6 @@ static struct clk_regmap gxbb_hdmi_pll = { .shift = 0, .width = 12, }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 16, - .width = 2, - }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 22, - .width = 2, - }, - .od3 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 18, - .width = 2, - }, .l = { .reg_off = HHI_HDMI_PLL_CNTL, .shift = 31, @@ -272,74 +187,121 @@ static struct clk_regmap gxbb_hdmi_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll", + .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ .flags = CLK_GET_RATE_NOCACHE, }, }; +static struct clk_regmap gxbb_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 22, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap gxl_hdmi_pll = { - .data = &(struct meson_clk_pll_data){ - .m = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .frac = { - /* - * On gxl, there is a register shift due to - * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb, - * so we compute the register offset based on the PLL - * base to get it right - */ - .reg_off = HHI_HDMI_PLL_CNTL + 4, - .shift = 0, - .width = 12, - }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 21, - .width = 2, - }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 23, - .width = 2, - }, - .od3 = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 19, - .width = 2, - }, - .l = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 31, - .width = 1, - }, - .rst = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 29, - .width = 1, - }, + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", - .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od2" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap gxbb_sys_pll = { +static struct clk_regmap gxbb_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -350,11 +312,6 @@ static struct clk_regmap gxbb_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -367,11 +324,26 @@ static struct clk_regmap gxbb_sys_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -379,11 +351,15 @@ static const struct reg_sequence gxbb_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, - { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 }, }; -static struct clk_regmap gxbb_gp0_pll = { +static struct clk_regmap gxbb_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -394,11 +370,6 @@ static struct clk_regmap gxbb_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 31, @@ -409,16 +380,15 @@ static struct clk_regmap gxbb_gp0_pll = { .shift = 29, .width = 1, }, - .table = gxbb_gp0_pll_rate_table, + .table = gxbb_gp0_pll_params_table, .init_regs = gxbb_gp0_init_regs, .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -428,11 +398,15 @@ static const struct reg_sequence gxl_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, - { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, }; -static struct clk_regmap gxl_gp0_pll = { +static struct clk_regmap gxl_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -443,11 +417,6 @@ static struct clk_regmap gxl_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_GP0_PLL_CNTL1, .shift = 0, @@ -463,16 +432,31 @@ static struct clk_regmap gxl_gp0_pll = { .shift = 29, .width = 1, }, - .table = gxl_gp0_pll_rate_table, + .table = gxl_gp0_pll_params_table, .init_regs = gxl_gp0_init_regs, .init_count = ARRAY_SIZE(gxl_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp0_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -1933,6 +1917,12 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxbb_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxbb_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxbb_gp0_pll_dco.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1948,7 +1938,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw, [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, - [CLKID_GP0_PLL] = &gxl_gp0_pll.hw, + [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, [CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw, [CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw, [CLKID_CLK81] = &gxbb_clk81.hw, @@ -2098,19 +2088,29 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxl_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxl_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxl_gp0_pll_dco.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, }; static struct clk_regmap *const gxbb_clk_regmaps[] = { - &gxbb_gp0_pll, + &gxbb_gp0_pll_dco, &gxbb_hdmi_pll, + &gxbb_hdmi_pll_od, + &gxbb_hdmi_pll_od2, }; static struct clk_regmap *const gxl_clk_regmaps[] = { - &gxl_gp0_pll, + &gxl_gp0_pll_dco, &gxl_hdmi_pll, + &gxl_hdmi_pll_od, + &gxl_hdmi_pll_od2, }; static struct clk_regmap *const gx_clk_regmaps[] = { @@ -2265,6 +2265,10 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_gen_clk_sel, &gxbb_gen_clk_div, &gxbb_gen_clk, + &gxbb_fixed_pll_dco, + &gxbb_hdmi_pll_dco, + &gxbb_sys_pll_dco, + &gxbb_gp0_pll, }; struct clkc_data { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index 20dfb1daf5b8..72bc077d9663 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -159,8 +159,14 @@ #define CLKID_VDEC_HEVC_DIV 155 #define CLKID_GEN_CLK_SEL 157 #define CLKID_GEN_CLK_DIV 158 - -#define NR_CLKS 160 +#define CLKID_FIXED_PLL_DCO 160 +#define CLKID_HDMI_PLL_DCO 161 +#define CLKID_HDMI_PLL_OD 162 +#define CLKID_HDMI_PLL_OD2 163 +#define CLKID_SYS_PLL_DCO 164 +#define CLKID_GP0_PLL_DCO 165 + +#define NR_CLKS 166 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/gxbb-clkc.h> diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 7447d96a265f..346b9e165b7a 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -11,7 +11,6 @@ #include <linux/clk-provider.h> #include <linux/init.h> #include <linux/of_address.h> -#include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -22,66 +21,27 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static void __iomem *clk_base; - struct meson8b_clk_reset { struct reset_controller_dev reset; - void __iomem *base; + struct regmap *regmap; }; -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(408000000, 68, 1, 2), - PLL_RATE(432000000, 72, 1, 2), - PLL_RATE(456000000, 76, 1, 2), - PLL_RATE(480000000, 80, 1, 2), - PLL_RATE(504000000, 84, 1, 2), - PLL_RATE(528000000, 88, 1, 2), - PLL_RATE(552000000, 92, 1, 2), - PLL_RATE(576000000, 96, 1, 2), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(840000000, 70, 1, 1), - PLL_RATE(864000000, 72, 1, 1), - PLL_RATE(888000000, 74, 1, 1), - PLL_RATE(912000000, 76, 1, 1), - PLL_RATE(936000000, 78, 1, 1), - PLL_RATE(960000000, 80, 1, 1), - PLL_RATE(984000000, 82, 1, 1), - PLL_RATE(1008000000, 84, 1, 1), - PLL_RATE(1032000000, 86, 1, 1), - PLL_RATE(1056000000, 88, 1, 1), - PLL_RATE(1080000000, 90, 1, 1), - PLL_RATE(1104000000, 92, 1, 1), - PLL_RATE(1128000000, 94, 1, 1), - PLL_RATE(1152000000, 96, 1, 1), - PLL_RATE(1176000000, 98, 1, 1), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), +static const struct pll_params_table sys_pll_params_table[] = { + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), { /* sentinel */ }, }; @@ -94,8 +54,13 @@ static struct clk_fixed_rate meson8b_xtal = { }, }; -static struct clk_regmap meson8b_fixed_pll = { +static struct clk_regmap meson8b_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -106,11 +71,6 @@ static struct clk_regmap meson8b_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -128,16 +88,39 @@ static struct clk_regmap meson8b_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; -static struct clk_regmap meson8b_vid_pll = { +static struct clk_regmap meson8b_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_regmap meson8b_vid_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_VID_PLL_CNTL, .shift = 0, @@ -148,11 +131,6 @@ static struct clk_regmap meson8b_vid_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_VID_PLL_CNTL, .shift = 31, @@ -165,16 +143,36 @@ static struct clk_regmap meson8b_vid_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "vid_pll", + .name = "vid_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; -static struct clk_regmap meson8b_sys_pll = { +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "vid_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -185,11 +183,6 @@ static struct clk_regmap meson8b_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -200,14 +193,29 @@ static struct clk_regmap meson8b_sys_pll = { .shift = 29, .width = 1, }, - .table = sys_pll_rate_table, + .table = sys_pll_params_table, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap meson8b_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -879,6 +887,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_PLL_VID_DCO] = &meson8b_vid_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -987,6 +998,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_nand_clk_sel, &meson8b_nand_clk_div, &meson8b_nand_clk_gate, + &meson8b_fixed_pll_dco, + &meson8b_vid_pll_dco, + &meson8b_sys_pll_dco, }; static const struct meson8b_clk_reset_line { @@ -1050,7 +1064,6 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, container_of(rcdev, struct meson8b_clk_reset, reset); unsigned long flags; const struct meson8b_clk_reset_line *reset; - u32 val; if (id >= ARRAY_SIZE(meson8b_clk_reset_bits)) return -EINVAL; @@ -1059,12 +1072,12 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, spin_lock_irqsave(&meson_clk_lock, flags); - val = readl(meson8b_clk_reset->base + reset->reg); if (assert) - val |= BIT(reset->bit_idx); + regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, + BIT(reset->bit_idx), BIT(reset->bit_idx)); else - val &= ~BIT(reset->bit_idx); - writel(val, meson8b_clk_reset->base + reset->reg); + regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, + BIT(reset->bit_idx), 0); spin_unlock_irqrestore(&meson_clk_lock, flags); @@ -1094,62 +1107,12 @@ static const struct regmap_config clkc_regmap_config = { .reg_stride = 4, }; -static int meson8b_clkc_probe(struct platform_device *pdev) -{ - int ret, i; - struct device *dev = &pdev->dev; - struct regmap *map; - - if (!clk_base) - return -ENXIO; - - map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); - if (IS_ERR(map)) - return PTR_ERR(map); - - /* Populate regmap for the regmap backed clocks */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) - meson8b_clk_regmaps[i]->map = map; - - /* - * register all clks - * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 - */ - for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { - /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); - if (ret) - return ret; - } - - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - &meson8b_hw_onecell_data); -} - -static const struct of_device_id meson8b_clkc_match_table[] = { - { .compatible = "amlogic,meson8-clkc" }, - { .compatible = "amlogic,meson8b-clkc" }, - { .compatible = "amlogic,meson8m2-clkc" }, - { } -}; - -static struct platform_driver meson8b_driver = { - .probe = meson8b_clkc_probe, - .driver = { - .name = "meson8b-clkc", - .of_match_table = meson8b_clkc_match_table, - }, -}; - -builtin_platform_driver(meson8b_driver); - -static void __init meson8b_clkc_reset_init(struct device_node *np) +static void __init meson8b_clkc_init(struct device_node *np) { struct meson8b_clk_reset *rstc; - int ret; + void __iomem *clk_base; + struct regmap *map; + int i, ret; /* Generic clocks, PLLs and some of the reset-bits */ clk_base = of_iomap(np, 1); @@ -1158,12 +1121,16 @@ static void __init meson8b_clkc_reset_init(struct device_node *np) return; } + map = regmap_init_mmio(NULL, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return; + rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); if (!rstc) return; /* Reset Controller */ - rstc->base = clk_base; + rstc->regmap = map; rstc->reset.ops = &meson8b_clk_reset_ops; rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits); rstc->reset.of_node = np; @@ -1173,11 +1140,34 @@ static void __init meson8b_clkc_reset_init(struct device_node *np) __func__, ret); return; } + + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) + meson8b_clk_regmaps[i]->map = map; + + /* + * register all clks + * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 + */ + for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { + /* array might be sparse */ + if (!meson8b_hw_onecell_data.hws[i]) + continue; + + ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]); + if (ret) + return; + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &meson8b_hw_onecell_data); + if (ret) + pr_err("%s: failed to register clock provider\n", __func__); } CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 5d09412b5084..1c6fb180e6a2 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -75,8 +75,11 @@ #define CLKID_FCLK_DIV7_DIV 109 #define CLKID_NAND_SEL 110 #define CLKID_NAND_DIV 111 +#define CLKID_PLL_FIXED_DCO 113 +#define CLKID_PLL_VID_DCO 114 +#define CLKID_PLL_SYS_DCO 115 -#define CLK_NR_CLKS 113 +#define CLK_NR_CLKS 116 /* * include the CLKID and RESETID that have |