diff options
Diffstat (limited to 'drivers/clk/meson/gxbb.c')
-rw-r--r-- | drivers/clk/meson/gxbb.c | 649 |
1 files changed, 616 insertions, 33 deletions
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 1c1ec137a3cc..ad5f027af1a2 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -20,6 +20,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/init.h> @@ -120,7 +121,7 @@ static const struct pll_rate_table sys_pll_rate_table[] = { { /* sentinel */ }, }; -static const struct pll_rate_table gp0_pll_rate_table[] = { +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), @@ -248,6 +249,35 @@ static const struct pll_rate_table gp0_pll_rate_table[] = { { /* 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), + { /* sentinel */ }, +}; + static const struct clk_div_table cpu_div_table[] = { { .val = 1, .div = 1 }, { .val = 2, .div = 2 }, @@ -352,6 +382,13 @@ static struct meson_clk_pll gxbb_sys_pll = { }, }; +struct pll_params_table gxbb_gp0_params_table[] = { + PLL_PARAM(HHI_GP0_PLL_CNTL, 0x6a000228), + PLL_PARAM(HHI_GP0_PLL_CNTL2, 0x69c80000), + PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a5590c4), + PLL_PARAM(HHI_GP0_PLL_CNTL4, 0x0000500d), +}; + static struct meson_clk_pll gxbb_gp0_pll = { .m = { .reg_off = HHI_GP0_PLL_CNTL, @@ -368,8 +405,57 @@ static struct meson_clk_pll gxbb_gp0_pll = { .shift = 16, .width = 2, }, - .rate_table = gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(gp0_pll_rate_table), + .params = { + .params_table = gxbb_gp0_params_table, + .params_count = ARRAY_SIZE(gxbb_gp0_params_table), + .no_init_reset = true, + .clear_reset_for_lock = true, + }, + .rate_table = gxbb_gp0_pll_rate_table, + .rate_count = ARRAY_SIZE(gxbb_gp0_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +struct pll_params_table gxl_gp0_params_table[] = { + PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), + PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), + PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), + PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), + PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), + PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), +}; + +static struct meson_clk_pll gxl_gp0_pll = { + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .params = { + .params_table = gxl_gp0_params_table, + .params_count = ARRAY_SIZE(gxl_gp0_params_table), + .no_init_reset = true, + .reset_lock_loop = true, + }, + .rate_table = gxl_gp0_pll_rate_table, + .rate_count = ARRAY_SIZE(gxl_gp0_pll_rate_table), .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", @@ -441,15 +527,25 @@ static struct meson_clk_mpll gxbb_mpll0 = { .shift = 0, .width = 14, }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, .n2 = { .reg_off = HHI_MPLL_CNTL7, .shift = 16, .width = 9, }, + .en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 14, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", - .ops = &meson_clk_mpll_ro_ops, + .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, @@ -461,15 +557,25 @@ static struct meson_clk_mpll gxbb_mpll1 = { .shift = 0, .width = 14, }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, .n2 = { .reg_off = HHI_MPLL_CNTL8, .shift = 16, .width = 9, }, + .en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 14, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", - .ops = &meson_clk_mpll_ro_ops, + .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, @@ -481,15 +587,25 @@ static struct meson_clk_mpll gxbb_mpll2 = { .shift = 0, .width = 14, }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, .n2 = { .reg_off = HHI_MPLL_CNTL9, .shift = 16, .width = 9, }, + .en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 14, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2", - .ops = &meson_clk_mpll_ro_ops, + .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, @@ -604,6 +720,237 @@ static struct clk_gate gxbb_sar_adc_clk = { }, }; +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch. + */ + +static u32 mux_table_mali_0_1[] = {0, 1, 2, 3, 4, 5, 6, 7}; +static const char *gxbb_mali_0_1_parent_names[] = { + "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", + "fclk_div4", "fclk_div3", "fclk_div5" +}; + +static struct clk_mux gxbb_mali_0_sel = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .table = mux_table_mali_0_1, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_mux_ops, + /* + * bits 10:9 selects from 8 possible parents: + * xtal, gp0_pll, mpll2, mpll1, fclk_div7, + * fclk_div4, fclk_div3, fclk_div5 + */ + .parent_names = gxbb_mali_0_1_parent_names, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_divider gxbb_mali_0_div = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "mali_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_gate gxbb_mali_0 = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "mali_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_mux gxbb_mali_1_sel = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .table = mux_table_mali_0_1, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_mux_ops, + /* + * bits 10:9 selects from 8 possible parents: + * xtal, gp0_pll, mpll2, mpll1, fclk_div7, + * fclk_div4, fclk_div3, fclk_div5 + */ + .parent_names = gxbb_mali_0_1_parent_names, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_divider gxbb_mali_1_div = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "mali_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_gate gxbb_mali_1 = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "mali_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 mux_table_mali[] = {0, 1}; +static const char *gxbb_mali_parent_names[] = { + "mali_0", "mali_1" +}; + +static struct clk_mux gxbb_mali = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + .table = mux_table_mali, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_mux_ops, + .parent_names = gxbb_mali_parent_names, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_mux gxbb_cts_amclk_sel = { + .reg = (void *) HHI_AUD_CLK_CNTL, + .mask = 0x3, + .shift = 9, + /* Default parent unknown (register reset value: 0) */ + .table = (u32[]){ 1, 2, 3 }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_sel", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct meson_clk_audio_divider gxbb_cts_amclk_div = { + .div = { + .reg_off = HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, + }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_div", + .ops = &meson_clk_audio_divider_ops, + .parent_names = (const char *[]){ "cts_amclk_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, + }, +}; + +static struct clk_gate gxbb_cts_amclk = { + .reg = (void *) HHI_AUD_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "cts_amclk_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_mux gxbb_cts_mclk_i958_sel = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .mask = 0x3, + .shift = 25, + /* Default parent unknown (register reset value: 0) */ + .table = (u32[]){ 1, 2, 3 }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_mclk_i958_sel", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_divider gxbb_cts_mclk_i958_div = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .shift = 16, + .width = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_mclk_i958_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, + }, +}; + +static struct clk_gate gxbb_cts_mclk_i958 = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_mclk_i958", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "cts_mclk_i958_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_mux gxbb_cts_i958 = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .mask = 0x1, + .shift = 27, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_i958", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" }, + .num_parents = 2, + /* + *The parent is specific to origin of the audio data. Let the + * consumer choose the appropriate parent + */ + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); @@ -797,6 +1144,140 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_SAR_ADC_CLK] = &gxbb_sar_adc_clk.hw, [CLKID_SAR_ADC_SEL] = &gxbb_sar_adc_clk_sel.hw, [CLKID_SAR_ADC_DIV] = &gxbb_sar_adc_clk_div.hw, + [CLKID_MALI_0_SEL] = &gxbb_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &gxbb_mali_0_div.hw, + [CLKID_MALI_0] = &gxbb_mali_0.hw, + [CLKID_MALI_1_SEL] = &gxbb_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &gxbb_mali_1_div.hw, + [CLKID_MALI_1] = &gxbb_mali_1.hw, + [CLKID_MALI] = &gxbb_mali.hw, + [CLKID_CTS_AMCLK] = &gxbb_cts_amclk.hw, + [CLKID_CTS_AMCLK_SEL] = &gxbb_cts_amclk_sel.hw, + [CLKID_CTS_AMCLK_DIV] = &gxbb_cts_amclk_div.hw, + [CLKID_CTS_MCLK_I958] = &gxbb_cts_mclk_i958.hw, + [CLKID_CTS_MCLK_I958_SEL] = &gxbb_cts_mclk_i958_sel.hw, + [CLKID_CTS_MCLK_I958_DIV] = &gxbb_cts_mclk_i958_div.hw, + [CLKID_CTS_I958] = &gxbb_cts_i958.hw, + }, + .num = NR_CLKS, +}; + +static struct clk_hw_onecell_data gxl_hw_onecell_data = { + .hws = { + [CLKID_SYS_PLL] = &gxbb_sys_pll.hw, + [CLKID_CPUCLK] = &gxbb_cpu_clk.hw, + [CLKID_HDMI_PLL] = &gxbb_hdmi_pll.hw, + [CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, + [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_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw, + [CLKID_CLK81] = &gxbb_clk81.hw, + [CLKID_MPLL0] = &gxbb_mpll0.hw, + [CLKID_MPLL1] = &gxbb_mpll1.hw, + [CLKID_MPLL2] = &gxbb_mpll2.hw, + [CLKID_DDR] = &gxbb_ddr.hw, + [CLKID_DOS] = &gxbb_dos.hw, + [CLKID_ISA] = &gxbb_isa.hw, + [CLKID_PL301] = &gxbb_pl301.hw, + [CLKID_PERIPHS] = &gxbb_periphs.hw, + [CLKID_SPICC] = &gxbb_spicc.hw, + [CLKID_I2C] = &gxbb_i2c.hw, + [CLKID_SAR_ADC] = &gxbb_sar_adc.hw, + [CLKID_SMART_CARD] = &gxbb_smart_card.hw, + [CLKID_RNG0] = &gxbb_rng0.hw, + [CLKID_UART0] = &gxbb_uart0.hw, + [CLKID_SDHC] = &gxbb_sdhc.hw, + [CLKID_STREAM] = &gxbb_stream.hw, + [CLKID_ASYNC_FIFO] = &gxbb_async_fifo.hw, + [CLKID_SDIO] = &gxbb_sdio.hw, + [CLKID_ABUF] = &gxbb_abuf.hw, + [CLKID_HIU_IFACE] = &gxbb_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &gxbb_assist_misc.hw, + [CLKID_SPI] = &gxbb_spi.hw, + [CLKID_I2S_SPDIF] = &gxbb_i2s_spdif.hw, + [CLKID_ETH] = &gxbb_eth.hw, + [CLKID_DEMUX] = &gxbb_demux.hw, + [CLKID_AIU_GLUE] = &gxbb_aiu_glue.hw, + [CLKID_IEC958] = &gxbb_iec958.hw, + [CLKID_I2S_OUT] = &gxbb_i2s_out.hw, + [CLKID_AMCLK] = &gxbb_amclk.hw, + [CLKID_AIFIFO2] = &gxbb_aififo2.hw, + [CLKID_MIXER] = &gxbb_mixer.hw, + [CLKID_MIXER_IFACE] = &gxbb_mixer_iface.hw, + [CLKID_ADC] = &gxbb_adc.hw, + [CLKID_BLKMV] = &gxbb_blkmv.hw, + [CLKID_AIU] = &gxbb_aiu.hw, + [CLKID_UART1] = &gxbb_uart1.hw, + [CLKID_G2D] = &gxbb_g2d.hw, + [CLKID_USB0] = &gxbb_usb0.hw, + [CLKID_USB1] = &gxbb_usb1.hw, + [CLKID_RESET] = &gxbb_reset.hw, + [CLKID_NAND] = &gxbb_nand.hw, + [CLKID_DOS_PARSER] = &gxbb_dos_parser.hw, + [CLKID_USB] = &gxbb_usb.hw, + [CLKID_VDIN1] = &gxbb_vdin1.hw, + [CLKID_AHB_ARB0] = &gxbb_ahb_arb0.hw, + [CLKID_EFUSE] = &gxbb_efuse.hw, + [CLKID_BOOT_ROM] = &gxbb_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &gxbb_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &gxbb_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &gxbb_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &gxbb_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &gxbb_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &gxbb_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &gxbb_mmc_pclk.hw, + [CLKID_DVIN] = &gxbb_dvin.hw, + [CLKID_UART2] = &gxbb_uart2.hw, + [CLKID_SANA] = &gxbb_sana.hw, + [CLKID_VPU_INTR] = &gxbb_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &gxbb_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A53] = &gxbb_clk81_a53.hw, + [CLKID_VCLK2_VENCI0] = &gxbb_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &gxbb_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &gxbb_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &gxbb_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT0] = &gxbb_gclk_venci_int0.hw, + [CLKID_GCLK_VENCI_INT] = &gxbb_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &gxbb_dac_clk.hw, + [CLKID_AOCLK_GATE] = &gxbb_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &gxbb_iec958_gate.hw, + [CLKID_ENC480P] = &gxbb_enc480p.hw, + [CLKID_RNG1] = &gxbb_rng1.hw, + [CLKID_GCLK_VENCI_INT1] = &gxbb_gclk_venci_int1.hw, + [CLKID_VCLK2_VENCLMCC] = &gxbb_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &gxbb_vclk2_vencl.hw, + [CLKID_VCLK_OTHER] = &gxbb_vclk_other.hw, + [CLKID_EDP] = &gxbb_edp.hw, + [CLKID_AO_MEDIA_CPU] = &gxbb_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &gxbb_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &gxbb_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &gxbb_ao_iface.hw, + [CLKID_AO_I2C] = &gxbb_ao_i2c.hw, + [CLKID_SD_EMMC_A] = &gxbb_emmc_a.hw, + [CLKID_SD_EMMC_B] = &gxbb_emmc_b.hw, + [CLKID_SD_EMMC_C] = &gxbb_emmc_c.hw, + [CLKID_SAR_ADC_CLK] = &gxbb_sar_adc_clk.hw, + [CLKID_SAR_ADC_SEL] = &gxbb_sar_adc_clk_sel.hw, + [CLKID_SAR_ADC_DIV] = &gxbb_sar_adc_clk_div.hw, + [CLKID_MALI_0_SEL] = &gxbb_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &gxbb_mali_0_div.hw, + [CLKID_MALI_0] = &gxbb_mali_0.hw, + [CLKID_MALI_1_SEL] = &gxbb_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &gxbb_mali_1_div.hw, + [CLKID_MALI_1] = &gxbb_mali_1.hw, + [CLKID_MALI] = &gxbb_mali.hw, + [CLKID_CTS_AMCLK] = &gxbb_cts_amclk.hw, + [CLKID_CTS_AMCLK_SEL] = &gxbb_cts_amclk_sel.hw, + [CLKID_CTS_AMCLK_DIV] = &gxbb_cts_amclk_div.hw, + [CLKID_CTS_MCLK_I958] = &gxbb_cts_mclk_i958.hw, + [CLKID_CTS_MCLK_I958_SEL] = &gxbb_cts_mclk_i958_sel.hw, + [CLKID_CTS_MCLK_I958_DIV] = &gxbb_cts_mclk_i958_div.hw, + [CLKID_CTS_I958] = &gxbb_cts_i958.hw, }, .num = NR_CLKS, }; @@ -810,13 +1291,20 @@ static struct meson_clk_pll *const gxbb_clk_plls[] = { &gxbb_gp0_pll, }; +static struct meson_clk_pll *const gxl_clk_plls[] = { + &gxbb_fixed_pll, + &gxbb_hdmi_pll, + &gxbb_sys_pll, + &gxl_gp0_pll, +}; + static struct meson_clk_mpll *const gxbb_clk_mplls[] = { &gxbb_mpll0, &gxbb_mpll1, &gxbb_mpll2, }; -static struct clk_gate *gxbb_clk_gates[] = { +static struct clk_gate *const gxbb_clk_gates[] = { &gxbb_clk81, &gxbb_ddr, &gxbb_dos, @@ -900,16 +1388,105 @@ static struct clk_gate *gxbb_clk_gates[] = { &gxbb_emmc_b, &gxbb_emmc_c, &gxbb_sar_adc_clk, + &gxbb_mali_0, + &gxbb_mali_1, + &gxbb_cts_amclk, + &gxbb_cts_mclk_i958, +}; + +static struct clk_mux *const gxbb_clk_muxes[] = { + &gxbb_mpeg_clk_sel, + &gxbb_sar_adc_clk_sel, + &gxbb_mali_0_sel, + &gxbb_mali_1_sel, + &gxbb_mali, + &gxbb_cts_amclk_sel, + &gxbb_cts_mclk_i958_sel, + &gxbb_cts_i958, +}; + +static struct clk_divider *const gxbb_clk_dividers[] = { + &gxbb_mpeg_clk_div, + &gxbb_sar_adc_clk_div, + &gxbb_mali_0_div, + &gxbb_mali_1_div, + &gxbb_cts_mclk_i958_div, +}; + +static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { + &gxbb_cts_amclk_div, +}; + +struct clkc_data { + struct clk_gate *const *clk_gates; + unsigned int clk_gates_count; + struct meson_clk_mpll *const *clk_mplls; + unsigned int clk_mplls_count; + struct meson_clk_pll *const *clk_plls; + unsigned int clk_plls_count; + struct clk_mux *const *clk_muxes; + unsigned int clk_muxes_count; + struct clk_divider *const *clk_dividers; + unsigned int clk_dividers_count; + struct meson_clk_audio_divider *const *clk_audio_dividers; + unsigned int clk_audio_dividers_count; + struct meson_clk_cpu *cpu_clk; + struct clk_hw_onecell_data *hw_onecell_data; +}; + +static const struct clkc_data gxbb_clkc_data = { + .clk_gates = gxbb_clk_gates, + .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), + .clk_mplls = gxbb_clk_mplls, + .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), + .clk_plls = gxbb_clk_plls, + .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), + .clk_muxes = gxbb_clk_muxes, + .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), + .clk_dividers = gxbb_clk_dividers, + .clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers), + .clk_audio_dividers = gxbb_audio_dividers, + .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), + .cpu_clk = &gxbb_cpu_clk, + .hw_onecell_data = &gxbb_hw_onecell_data, +}; + +static const struct clkc_data gxl_clkc_data = { + .clk_gates = gxbb_clk_gates, + .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), + .clk_mplls = gxbb_clk_mplls, + .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), + .clk_plls = gxl_clk_plls, + .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), + .clk_muxes = gxbb_clk_muxes, + .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), + .clk_dividers = gxbb_clk_dividers, + .clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers), + .clk_audio_dividers = gxbb_audio_dividers, + .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), + .cpu_clk = &gxbb_cpu_clk, + .hw_onecell_data = &gxl_hw_onecell_data, +}; + +static const struct of_device_id clkc_match_table[] = { + { .compatible = "amlogic,gxbb-clkc", .data = &gxbb_clkc_data }, + { .compatible = "amlogic,gxl-clkc", .data = &gxl_clkc_data }, + {}, }; static int gxbb_clkc_probe(struct platform_device *pdev) { + const struct clkc_data *clkc_data; void __iomem *clk_base; int ret, clkid, i; struct clk_hw *parent_hw; struct clk *parent_clk; struct device *dev = &pdev->dev; + clkc_data = of_device_get_match_data(&pdev->dev); + if (!clkc_data) + return -EINVAL; + /* Generic clocks and PLLs */ clk_base = of_iomap(dev->of_node, 0); if (!clk_base) { @@ -918,34 +1495,45 @@ static int gxbb_clkc_probe(struct platform_device *pdev) } /* Populate base address for PLLs */ - for (i = 0; i < ARRAY_SIZE(gxbb_clk_plls); i++) - gxbb_clk_plls[i]->base = clk_base; + for (i = 0; i < clkc_data->clk_plls_count; i++) + clkc_data->clk_plls[i]->base = clk_base; /* Populate base address for MPLLs */ - for (i = 0; i < ARRAY_SIZE(gxbb_clk_mplls); i++) - gxbb_clk_mplls[i]->base = clk_base; + for (i = 0; i < clkc_data->clk_mplls_count; i++) + clkc_data->clk_mplls[i]->base = clk_base; /* Populate the base address for CPU clk */ - gxbb_cpu_clk.base = clk_base; + clkc_data->cpu_clk->base = clk_base; + + /* Populate base address for gates */ + for (i = 0; i < clkc_data->clk_gates_count; i++) + clkc_data->clk_gates[i]->reg = clk_base + + (u64)clkc_data->clk_gates[i]->reg; - /* Populate the base address for the MPEG clks */ - gxbb_mpeg_clk_sel.reg = clk_base + (u64)gxbb_mpeg_clk_sel.reg; - gxbb_mpeg_clk_div.reg = clk_base + (u64)gxbb_mpeg_clk_div.reg; + /* Populate base address for muxes */ + for (i = 0; i < clkc_data->clk_muxes_count; i++) + clkc_data->clk_muxes[i]->reg = clk_base + + (u64)clkc_data->clk_muxes[i]->reg; - /* Populate the base address for the SAR ADC clks */ - gxbb_sar_adc_clk_sel.reg = clk_base + (u64)gxbb_sar_adc_clk_sel.reg; - gxbb_sar_adc_clk_div.reg = clk_base + (u64)gxbb_sar_adc_clk_div.reg; + /* Populate base address for dividers */ + for (i = 0; i < clkc_data->clk_dividers_count; i++) + clkc_data->clk_dividers[i]->reg = clk_base + + (u64)clkc_data->clk_dividers[i]->reg; - /* Populate base address for gates */ - for (i = 0; i < ARRAY_SIZE(gxbb_clk_gates); i++) - gxbb_clk_gates[i]->reg = clk_base + - (u64)gxbb_clk_gates[i]->reg; + /* Populate base address for the audio dividers */ + for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) + clkc_data->clk_audio_dividers[i]->base = clk_base; /* * register all clks */ - for (clkid = 0; clkid < NR_CLKS; clkid++) { - ret = devm_clk_hw_register(dev, gxbb_hw_onecell_data.hws[clkid]); + for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { + /* array might be sparse */ + if (!clkc_data->hw_onecell_data->hws[clkid]) + continue; + + ret = devm_clk_hw_register(dev, + clkc_data->hw_onecell_data->hws[clkid]); if (ret) goto iounmap; } @@ -964,9 +1552,9 @@ static int gxbb_clkc_probe(struct platform_device *pdev) * a new clk_hw, and this hack will no longer work. Releasing the ccr * feature before that time solves the problem :-) */ - parent_hw = clk_hw_get_parent(&gxbb_cpu_clk.hw); + parent_hw = clk_hw_get_parent(&clkc_data->cpu_clk->hw); parent_clk = parent_hw->clk; - ret = clk_notifier_register(parent_clk, &gxbb_cpu_clk.clk_nb); + ret = clk_notifier_register(parent_clk, &clkc_data->cpu_clk->clk_nb); if (ret) { pr_err("%s: failed to register clock notifier for cpu_clk\n", __func__); @@ -974,23 +1562,18 @@ static int gxbb_clkc_probe(struct platform_device *pdev) } return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - &gxbb_hw_onecell_data); + clkc_data->hw_onecell_data); iounmap: iounmap(clk_base); return ret; } -static const struct of_device_id gxbb_clkc_match_table[] = { - { .compatible = "amlogic,gxbb-clkc" }, - { } -}; - static struct platform_driver gxbb_driver = { .probe = gxbb_clkc_probe, .driver = { .name = "gxbb-clkc", - .of_match_table = gxbb_clkc_match_table, + .of_match_table = clkc_match_table, }, }; |