diff options
| author | Tom Rini <[email protected]> | 2026-01-12 13:17:00 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-01-12 13:17:00 -0600 |
| commit | 8cfb0ad1a0cce40ad68b5bd94bbaddeded56eb07 (patch) | |
| tree | 4fdc01a545e1f6a8c57d46511cf03c562d9aa3cb /drivers | |
| parent | 1bcb2fe324180d0a8cfbdb0511737eba1d5b8550 (diff) | |
| parent | c8ebe42b3f5f753f2c84266e289a31e85e257110 (diff) | |
Merge patch series "clk: mediatek: implement of_xlate and dump"
David Lechner <[email protected]> says:
I started looking into fixing some bugs in the mt8365 clock driver and
realized that there was no way to inspect or debug the clock trees.
I set out to implement the dump function to help with this. The driver
architecture didn't make this easy since there was no way to know the
number of elements in each of the clock arrays. The first few patches
in this series are adding fields to the data structures to hold this
information.
Once that was fixed, I was still getting crashes due to other bugs. To
work around this, I implemented the of_xlate function to validate clk
IDs as early as possible and return errors instead of crashing when
requested IDs are invalid. This also makes use of the new size fields
to prevent out of bounds array accesses. There are a couple of drivers
that remap IDs, so there are a few extra patches to handle that as well.
Then finally, I was able to implement the dump function to print out the
clock tree information without crashing. In the v1 cover letter, there
is an example of the output (it is quite long and doesn't need to be
repeated here).
Link: https://lore.kernel.org/r/[email protected]
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/clk/mediatek/clk-mt7622.c | 21 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt7623.c | 24 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt7629.c | 23 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt7981.c | 13 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt7986.c | 11 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt7987.c | 9 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt7988.c | 18 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt8183.c | 7 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt8188.c | 28 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt8365.c | 10 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt8512.c | 10 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt8516.c | 7 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mt8518.c | 7 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mtk.c | 669 | ||||
| -rw-r--r-- | drivers/clk/mediatek/clk-mtk.h | 43 |
15 files changed, 697 insertions, 203 deletions
diff --git a/drivers/clk/mediatek/clk-mt7622.c b/drivers/clk/mediatek/clk-mt7622.c index 23b9787612a..16c6f024e72 100644 --- a/drivers/clk/mediatek/clk-mt7622.c +++ b/drivers/clk/mediatek/clk-mt7622.c @@ -604,6 +604,8 @@ static const struct mtk_clk_tree mt7622_apmixed_clk_tree = { .plls = apmixed_plls, .gates_offs = CLK_APMIXED_MAIN_CORE_EN, .gates = apmixed_cgs, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_gates = ARRAY_SIZE(apmixed_cgs), }; static const struct mtk_clk_tree mt7622_infra_clk_tree = { @@ -612,6 +614,8 @@ static const struct mtk_clk_tree mt7622_infra_clk_tree = { .gates_offs = CLK_INFRA_DBGCLK_PD, .muxes = infra_muxes, .gates = infra_cgs, + .num_muxes = ARRAY_SIZE(infra_muxes), + .num_gates = ARRAY_SIZE(infra_cgs), }; static const struct mtk_clk_tree mt7622_peri_clk_tree = { @@ -620,6 +624,8 @@ static const struct mtk_clk_tree mt7622_peri_clk_tree = { .gates_offs = CLK_PERI_THERM_PD, .muxes = peri_muxes, .gates = peri_cgs, + .num_muxes = ARRAY_SIZE(peri_muxes), + .num_gates = ARRAY_SIZE(peri_cgs), }; static const struct mtk_clk_tree mt7622_clk_tree = { @@ -629,6 +635,9 @@ static const struct mtk_clk_tree mt7622_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static int mt7622_mcucfg_probe(struct udevice *dev) @@ -683,7 +692,8 @@ static int mt7622_pericfg_probe(struct udevice *dev) static int mt7622_pciesys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, pcie_cgs); + return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, pcie_cgs, + ARRAY_SIZE(pcie_cgs)); } static int mt7622_pciesys_bind(struct udevice *dev) @@ -701,7 +711,8 @@ static int mt7622_pciesys_bind(struct udevice *dev) static int mt7622_ethsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, eth_cgs); + return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, eth_cgs, + ARRAY_SIZE(eth_cgs)); } static int mt7622_ethsys_bind(struct udevice *dev) @@ -719,12 +730,14 @@ static int mt7622_ethsys_bind(struct udevice *dev) static int mt7622_sgmiisys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, sgmii_cgs); + return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, sgmii_cgs, + ARRAY_SIZE(sgmii_cgs)); } static int mt7622_ssusbsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, ssusb_cgs); + return mtk_common_clk_gate_init(dev, &mt7622_clk_tree, ssusb_cgs, + ARRAY_SIZE(ssusb_cgs)); } static const struct udevice_id mt7622_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mt7623.c b/drivers/clk/mediatek/clk-mt7623.c index d0b80f48b0a..6ce1d729736 100644 --- a/drivers/clk/mediatek/clk-mt7623.c +++ b/drivers/clk/mediatek/clk-mt7623.c @@ -26,6 +26,7 @@ /* apmixedsys */ static const int pll_id_offs_map[] = { + [0 ... CLK_APMIXED_NR - 1] = -1, [CLK_APMIXED_ARMPLL] = 0, [CLK_APMIXED_MAINPLL] = 1, [CLK_APMIXED_UNIVPLL] = 2, @@ -92,6 +93,7 @@ static const struct mtk_pll_data apmixed_plls[] = { #define CLK_TOP_HDMITX_CLKDIG_CTS CLK_TOP_NR static const int top_id_offs_map[CLK_TOP_NR + 1] = { + [0 ... CLK_TOP_NR] = -1, /* Fixed CLK */ [CLK_TOP_DPI] = 0, [CLK_TOP_DMPLL] = 1, @@ -808,6 +810,7 @@ static const struct mtk_gate infra_cgs[] = { /* pericfg */ static const int peri_id_offs_map[] = { + [0 ... CLK_PERI_NR - 1] = -1, /* MUX CLK */ [CLK_PERI_UART0_SEL] = 1, [CLK_PERI_UART1_SEL] = 2, @@ -996,17 +999,23 @@ static const struct mtk_gate hif_cgs[] = { static const struct mtk_clk_tree mt7623_apmixedsys_clk_tree = { .xtal2_rate = 26 * MHZ, .id_offs_map = pll_id_offs_map, + .id_offs_map_size = ARRAY_SIZE(pll_id_offs_map), .plls = apmixed_plls, + .num_plls = ARRAY_SIZE(apmixed_plls), }; static const struct mtk_clk_tree mt7623_topckgen_clk_tree = { .xtal_rate = 26 * MHZ, .id_offs_map = top_id_offs_map, + .id_offs_map_size = ARRAY_SIZE(top_id_offs_map), .fdivs_offs = top_id_offs_map[CLK_TOP_SYSPLL], .muxes_offs = top_id_offs_map[CLK_TOP_AXI_SEL], .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static int mt7623_mcucfg_probe(struct udevice *dev) @@ -1053,16 +1062,19 @@ static const struct mtk_clk_tree mt7623_clk_gate_tree = { static int mt7623_infracfg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7623_clk_gate_tree, - infra_cgs); + return mtk_common_clk_gate_init(dev, &mt7623_clk_gate_tree, infra_cgs, + ARRAY_SIZE(infra_cgs)); } static const struct mtk_clk_tree mt7623_clk_peri_tree = { .id_offs_map = peri_id_offs_map, + .id_offs_map_size = ARRAY_SIZE(peri_id_offs_map), .muxes_offs = peri_id_offs_map[CLK_PERI_UART0_SEL], .gates_offs = peri_id_offs_map[CLK_PERI_NFI], .muxes = peri_muxes, .gates = peri_cgs, + .num_muxes = ARRAY_SIZE(peri_muxes), + .num_gates = ARRAY_SIZE(peri_cgs), .xtal_rate = 26 * MHZ, }; @@ -1073,14 +1085,14 @@ static int mt7623_pericfg_probe(struct udevice *dev) static int mt7623_hifsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7623_clk_gate_tree, - hif_cgs); + return mtk_common_clk_gate_init(dev, &mt7623_clk_gate_tree, hif_cgs, + ARRAY_SIZE(hif_cgs)); } static int mt7623_ethsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7623_clk_gate_tree, - eth_cgs); + return mtk_common_clk_gate_init(dev, &mt7623_clk_gate_tree, eth_cgs, + ARRAY_SIZE(eth_cgs)); } static int mt7623_ethsys_hifsys_bind(struct udevice *dev) diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c index 94fc5e51456..e4132f6195f 100644 --- a/drivers/clk/mediatek/clk-mt7629.c +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -572,6 +572,10 @@ static const struct mtk_clk_tree mt7629_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static const struct mtk_clk_tree mt7629_peri_clk_tree = { @@ -584,6 +588,10 @@ static const struct mtk_clk_tree mt7629_peri_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static int mt7629_mcucfg_probe(struct udevice *dev) @@ -626,17 +634,20 @@ static int mt7629_topckgen_probe(struct udevice *dev) static int mt7629_infracfg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, infra_cgs); + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, infra_cgs, + ARRAY_SIZE(infra_cgs)); } static int mt7629_pericfg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7629_peri_clk_tree, peri_cgs); + return mtk_common_clk_gate_init(dev, &mt7629_peri_clk_tree, peri_cgs, + ARRAY_SIZE(peri_cgs)); } static int mt7629_ethsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, eth_cgs); + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, eth_cgs, + ARRAY_SIZE(eth_cgs)); } static int mt7629_ethsys_bind(struct udevice *dev) @@ -654,12 +665,14 @@ static int mt7629_ethsys_bind(struct udevice *dev) static int mt7629_sgmiisys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, sgmii_cgs); + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, sgmii_cgs, + ARRAY_SIZE(sgmii_cgs)); } static int mt7629_ssusbsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, ssusb_cgs); + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, ssusb_cgs, + ARRAY_SIZE(ssusb_cgs)); } static const struct udevice_id mt7629_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mt7981.c b/drivers/clk/mediatek/clk-mt7981.c index 2fdb1845e9f..c8090688df0 100644 --- a/drivers/clk/mediatek/clk-mt7981.c +++ b/drivers/clk/mediatek/clk-mt7981.c @@ -513,6 +513,7 @@ static const struct mtk_clk_tree mt7981_fixed_pll_clk_tree = { .fdivs_offs = CLK_APMIXED_NR_CLK, .xtal_rate = 40 * MHZ, .fclks = fixed_pll_clks, + .num_fclks = ARRAY_SIZE(fixed_pll_clks), }; static const struct mtk_clk_tree mt7981_topckgen_clk_tree = { @@ -521,6 +522,9 @@ static const struct mtk_clk_tree mt7981_topckgen_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), .flags = CLK_BYPASS_XTAL | CLK_PARENT_TOPCKGEN, }; @@ -531,6 +535,9 @@ static const struct mtk_clk_tree mt7981_infracfg_clk_tree = { .fdivs = infra_fixed_divs, .muxes = infra_muxes, .gates = infracfg_gates, + .num_fdivs = ARRAY_SIZE(infra_fixed_divs), + .num_muxes = ARRAY_SIZE(infra_muxes), + .num_gates = ARRAY_SIZE(infracfg_gates), .flags = CLK_PARENT_INFRASYS, }; @@ -624,7 +631,7 @@ static const struct mtk_gate sgmii0_cgs[] = { static int mt7981_sgmii0sys_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7981_topckgen_clk_tree, - sgmii0_cgs); + sgmii0_cgs, ARRAY_SIZE(sgmii0_cgs)); } static const struct udevice_id mt7981_sgmii0sys_compat[] = { @@ -651,7 +658,7 @@ static const struct mtk_gate sgmii1_cgs[] = { static int mt7981_sgmii1sys_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7981_topckgen_clk_tree, - sgmii1_cgs); + sgmii1_cgs, ARRAY_SIZE(sgmii1_cgs)); } static const struct udevice_id mt7981_sgmii1sys_compat[] = { @@ -692,7 +699,7 @@ static const struct mtk_gate eth_cgs[] = { static int mt7981_ethsys_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7981_topckgen_clk_tree, - eth_cgs); + eth_cgs, ARRAY_SIZE(eth_cgs)); } static int mt7981_ethsys_bind(struct udevice *dev) diff --git a/drivers/clk/mediatek/clk-mt7986.c b/drivers/clk/mediatek/clk-mt7986.c index 16db5877056..735e824c874 100644 --- a/drivers/clk/mediatek/clk-mt7986.c +++ b/drivers/clk/mediatek/clk-mt7986.c @@ -519,6 +519,7 @@ static const struct mtk_clk_tree mt7986_fixed_pll_clk_tree = { .fdivs_offs = CLK_APMIXED_NR_CLK, .xtal_rate = 40 * MHZ, .fclks = fixed_pll_clks, + .num_fclks = ARRAY_SIZE(fixed_pll_clks), .flags = CLK_PARENT_APMIXED, }; @@ -528,6 +529,9 @@ static const struct mtk_clk_tree mt7986_topckgen_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), .flags = CLK_BYPASS_XTAL | CLK_PARENT_TOPCKGEN, }; @@ -538,6 +542,9 @@ static const struct mtk_clk_tree mt7986_infracfg_clk_tree = { .fdivs = infra_fixed_divs, .muxes = infra_muxes, .gates = infracfg_gates, + .num_fdivs = ARRAY_SIZE(infra_fixed_divs), + .num_muxes = ARRAY_SIZE(infra_muxes), + .num_gates = ARRAY_SIZE(infracfg_gates), .flags = CLK_PARENT_INFRASYS, }; @@ -629,8 +636,8 @@ static const struct mtk_gate eth_cgs[] = { static int mt7986_ethsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7986_topckgen_clk_tree, - eth_cgs); + return mtk_common_clk_gate_init(dev, &mt7986_topckgen_clk_tree, eth_cgs, + ARRAY_SIZE(eth_cgs)); } static int mt7986_ethsys_bind(struct udevice *dev) diff --git a/drivers/clk/mediatek/clk-mt7987.c b/drivers/clk/mediatek/clk-mt7987.c index caee8bf43e4..99ff57c5dc5 100644 --- a/drivers/clk/mediatek/clk-mt7987.c +++ b/drivers/clk/mediatek/clk-mt7987.c @@ -46,6 +46,7 @@ static const struct mtk_fixed_clk apmixedsys_mtk_plls[] = { static const struct mtk_clk_tree mt7987_fixed_pll_clk_tree = { .fdivs_offs = ARRAY_SIZE(apmixedsys_mtk_plls), .fclks = apmixedsys_mtk_plls, + .num_fclks = ARRAY_SIZE(apmixedsys_mtk_plls), .flags = CLK_PARENT_APMIXED, .xtal_rate = 40 * MHZ, }; @@ -442,6 +443,8 @@ static const struct mtk_clk_tree mt7987_topckgen_clk_tree = { .muxes_offs = CLK_TOP_NETSYS_SEL, .fdivs = topckgen_mtk_fixed_factors, .muxes = topckgen_mtk_muxes, + .num_fdivs = ARRAY_SIZE(topckgen_mtk_fixed_factors), + .num_muxes = ARRAY_SIZE(topckgen_mtk_muxes), .flags = CLK_BYPASS_XTAL | CLK_PARENT_TOPCKGEN, .xtal_rate = MT7987_XTAL_RATE, }; @@ -765,6 +768,8 @@ static const struct mtk_clk_tree mt7987_infracfg_clk_tree = { .gates_offs = CLK_INFRA_66M_GPT_BCK, .muxes = infracfg_mtk_mux, .gates = infracfg_mtk_gates, + .num_muxes = ARRAY_SIZE(infracfg_mtk_mux), + .num_gates = ARRAY_SIZE(infracfg_mtk_gates), .flags = CLK_BYPASS_XTAL, .xtal_rate = MT7987_XTAL_RATE, }; @@ -813,8 +818,8 @@ static const struct mtk_gate eth_cgs[] = { static int mt7987_ethsys_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt7987_topckgen_clk_tree, - eth_cgs); + return mtk_common_clk_gate_init(dev, &mt7987_topckgen_clk_tree, eth_cgs, + ARRAY_SIZE(eth_cgs)); } static int mt7987_ethsys_bind(struct udevice *dev) diff --git a/drivers/clk/mediatek/clk-mt7988.c b/drivers/clk/mediatek/clk-mt7988.c index bfbf401eb12..da1d2e89d61 100644 --- a/drivers/clk/mediatek/clk-mt7988.c +++ b/drivers/clk/mediatek/clk-mt7988.c @@ -773,6 +773,7 @@ static const struct mtk_gate infracfg_mtk_gates[] = { static const struct mtk_clk_tree mt7988_fixed_pll_clk_tree = { .fdivs_offs = ARRAY_SIZE(apmixedsys_mtk_plls), .fclks = apmixedsys_mtk_plls, + .num_fclks = ARRAY_SIZE(apmixedsys_mtk_plls), .flags = CLK_PARENT_APMIXED, .xtal_rate = 40 * MHZ, }; @@ -783,6 +784,9 @@ static const struct mtk_clk_tree mt7988_topckgen_clk_tree = { .fclks = topckgen_mtk_fixed_clks, .fdivs = topckgen_mtk_fixed_factors, .muxes = topckgen_mtk_muxes, + .num_fclks = ARRAY_SIZE(topckgen_mtk_fixed_clks), + .num_fdivs = ARRAY_SIZE(topckgen_mtk_fixed_factors), + .num_muxes = ARRAY_SIZE(topckgen_mtk_muxes), .flags = CLK_BYPASS_XTAL | CLK_PARENT_TOPCKGEN, .xtal_rate = 40 * MHZ, }; @@ -792,6 +796,8 @@ static const struct mtk_clk_tree mt7988_infracfg_clk_tree = { .gates_offs = CLK_INFRA_PCIE_PERI_26M_CK_P0, .muxes = infracfg_mtk_mux, .gates = infracfg_mtk_gates, + .num_muxes = ARRAY_SIZE(infracfg_mtk_mux), + .num_gates = ARRAY_SIZE(infracfg_mtk_gates), .flags = CLK_BYPASS_XTAL, .xtal_rate = 40 * MHZ, }; @@ -886,7 +892,8 @@ static const struct mtk_gate ethdma_mtk_gate[] = { static int mt7988_ethdma_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7988_topckgen_clk_tree, - ethdma_mtk_gate); + ethdma_mtk_gate, + ARRAY_SIZE(ethdma_mtk_gate)); } static int mt7988_ethdma_bind(struct udevice *dev) @@ -944,7 +951,8 @@ static const struct mtk_gate sgmiisys_0_mtk_gate[] = { static int mt7988_sgmiisys_0_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7988_topckgen_clk_tree, - sgmiisys_0_mtk_gate); + sgmiisys_0_mtk_gate, + ARRAY_SIZE(sgmiisys_0_mtk_gate)); } static const struct udevice_id mt7988_sgmiisys_0_compat[] = { @@ -988,7 +996,8 @@ static const struct mtk_gate sgmiisys_1_mtk_gate[] = { static int mt7988_sgmiisys_1_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7988_topckgen_clk_tree, - sgmiisys_1_mtk_gate); + sgmiisys_1_mtk_gate, + ARRAY_SIZE(sgmiisys_1_mtk_gate)); } static const struct udevice_id mt7988_sgmiisys_1_compat[] = { @@ -1034,7 +1043,8 @@ static const struct mtk_gate ethwarp_mtk_gate[] = { static int mt7988_ethwarp_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7988_topckgen_clk_tree, - ethwarp_mtk_gate); + ethwarp_mtk_gate, + ARRAY_SIZE(ethwarp_mtk_gate)); } static int mt7988_ethwarp_bind(struct udevice *dev) diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c index 9612a62e56a..5b41cf4b88c 100644 --- a/drivers/clk/mediatek/clk-mt8183.c +++ b/drivers/clk/mediatek/clk-mt8183.c @@ -599,6 +599,10 @@ static const struct mtk_clk_tree mt8183_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static const struct mtk_gate_regs infra0_cg_regs = { @@ -773,7 +777,8 @@ static int mt8183_topckgen_probe(struct udevice *dev) static int mt8183_infracfg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8183_clk_tree, infra_clks); + return mtk_common_clk_gate_init(dev, &mt8183_clk_tree, infra_clks, + ARRAY_SIZE(infra_clks)); } static const struct udevice_id mt8183_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mt8188.c b/drivers/clk/mediatek/clk-mt8188.c index 55dfadddfe3..a4cbb3213e3 100644 --- a/drivers/clk/mediatek/clk-mt8188.c +++ b/drivers/clk/mediatek/clk-mt8188.c @@ -85,6 +85,7 @@ static const struct mtk_clk_tree mt8188_apmixedsys_clk_tree = { .xtal_rate = 26 * MHZ, .xtal2_rate = 26 * MHZ, .plls = apmixed_plls, + .num_plls = ARRAY_SIZE(apmixed_plls), }; static const struct mtk_fixed_clk top_fixed_clks[] = { @@ -1359,11 +1360,15 @@ static const struct mtk_clk_tree mt8188_topckgen_clk_tree = { .xtal_rate = 26 * MHZ, .xtal2_rate = 26 * MHZ, .id_offs_map = mt8188_id_offs_map, + .id_offs_map_size = ARRAY_SIZE(mt8188_id_offs_map), .fdivs_offs = 8, /* CLK_TOP_MAINPLL_D3 */ .muxes_offs = 87, /* CLK_TOP_AXI */ .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static const struct mtk_gate_regs infra_ao0_cg_regs = { @@ -1690,33 +1695,44 @@ static int mt8188_topckgen_probe(struct udevice *dev) static int mt8188_topckgen_cg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8188_topckgen_cg_clk_tree, topckgen_cg_clks); + return mtk_common_clk_gate_init(dev, &mt8188_topckgen_cg_clk_tree, + topckgen_cg_clks, + ARRAY_SIZE(topckgen_cg_clks)); } static int mt8188_infracfg_ao_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8188_infracfg_ao_clk_tree, infracfg_ao_clks); + return mtk_common_clk_gate_init(dev, &mt8188_infracfg_ao_clk_tree, + infracfg_ao_clks, + ARRAY_SIZE(infracfg_ao_clks)); } static int mt8188_pericfg_ao_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8188_pericfg_ao_clk_tree, pericfg_ao_clks); + return mtk_common_clk_gate_init(dev, &mt8188_pericfg_ao_clk_tree, + pericfg_ao_clks, + ARRAY_SIZE(pericfg_ao_clks)); } static int mt8188_imp_iic_wrap_c_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8188_imp_iic_wrap_c_clk_tree, imp_iic_wrap_c_clks); + return mtk_common_clk_gate_init(dev, &mt8188_imp_iic_wrap_c_clk_tree, + imp_iic_wrap_c_clks, + ARRAY_SIZE(imp_iic_wrap_c_clks)); } static int mt8188_imp_iic_wrap_w_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8188_imp_iic_wrap_w_clk_tree, imp_iic_wrap_w_clks); + return mtk_common_clk_gate_init(dev, &mt8188_imp_iic_wrap_w_clk_tree, + imp_iic_wrap_w_clks, + ARRAY_SIZE(imp_iic_wrap_w_clks)); } static int mt8188_imp_iic_wrap_en_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt8188_imp_iic_wrap_en_clk_tree, - imp_iic_wrap_en_clks); + imp_iic_wrap_en_clks, + ARRAY_SIZE(imp_iic_wrap_en_clks)); } static const struct udevice_id mt8188_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mt8365.c b/drivers/clk/mediatek/clk-mt8365.c index 53eca73b98d..c88545fc7cf 100644 --- a/drivers/clk/mediatek/clk-mt8365.c +++ b/drivers/clk/mediatek/clk-mt8365.c @@ -490,6 +490,10 @@ static const struct mtk_clk_tree mt8365_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_divs, .muxes = top_muxes, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; /* topckgen cg */ @@ -701,12 +705,14 @@ static int mt8365_topckgen_probe(struct udevice *dev) static int mt8365_topckgen_cg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8365_clk_tree, top_clk_gates); + return mtk_common_clk_gate_init(dev, &mt8365_clk_tree, top_clk_gates, + ARRAY_SIZE(top_clk_gates)); } static int mt8365_infracfg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8365_clk_tree, ifr_clks); + return mtk_common_clk_gate_init(dev, &mt8365_clk_tree, ifr_clks, + ARRAY_SIZE(ifr_clks)); } static const struct udevice_id mt8365_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mt8512.c b/drivers/clk/mediatek/clk-mt8512.c index ab270673442..d4f6604c160 100644 --- a/drivers/clk/mediatek/clk-mt8512.c +++ b/drivers/clk/mediatek/clk-mt8512.c @@ -790,6 +790,10 @@ static const struct mtk_clk_tree mt8512_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static int mt8512_apmixedsys_probe(struct udevice *dev) @@ -804,12 +808,14 @@ static int mt8512_topckgen_probe(struct udevice *dev) static int mt8512_topckgen_cg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8512_clk_tree, top_clks); + return mtk_common_clk_gate_init(dev, &mt8512_clk_tree, top_clks, + ARRAY_SIZE(top_clks)); } static int mt8512_infracfg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8512_clk_tree, infra_clks); + return mtk_common_clk_gate_init(dev, &mt8512_clk_tree, infra_clks, + ARRAY_SIZE(infra_clks)); } static const struct udevice_id mt8512_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c index 623f88499f1..d5f922886a3 100644 --- a/drivers/clk/mediatek/clk-mt8516.c +++ b/drivers/clk/mediatek/clk-mt8516.c @@ -739,6 +739,10 @@ static const struct mtk_clk_tree mt8516_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static int mt8516_apmixedsys_probe(struct udevice *dev) @@ -753,7 +757,8 @@ static int mt8516_topckgen_probe(struct udevice *dev) static int mt8516_topckgen_cg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8516_clk_tree, top_clks); + return mtk_common_clk_gate_init(dev, &mt8516_clk_tree, top_clks, + ARRAY_SIZE(top_clks)); } static const struct udevice_id mt8516_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mt8518.c b/drivers/clk/mediatek/clk-mt8518.c index ba8cc584d46..92730f3f06c 100644 --- a/drivers/clk/mediatek/clk-mt8518.c +++ b/drivers/clk/mediatek/clk-mt8518.c @@ -1495,6 +1495,10 @@ static const struct mtk_clk_tree mt8518_clk_tree = { .fclks = top_fixed_clks, .fdivs = top_fixed_divs, .muxes = top_muxes, + .num_plls = ARRAY_SIZE(apmixed_plls), + .num_fclks = ARRAY_SIZE(top_fixed_clks), + .num_fdivs = ARRAY_SIZE(top_fixed_divs), + .num_muxes = ARRAY_SIZE(top_muxes), }; static int mt8518_apmixedsys_probe(struct udevice *dev) @@ -1509,7 +1513,8 @@ static int mt8518_topckgen_probe(struct udevice *dev) static int mt8518_topckgen_cg_probe(struct udevice *dev) { - return mtk_common_clk_gate_init(dev, &mt8518_clk_tree, top_clks); + return mtk_common_clk_gate_init(dev, &mt8518_clk_tree, top_clks, + ARRAY_SIZE(top_clks)); } static const struct udevice_id mt8518_apmixed_compat[] = { diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index f91777e968a..a3dd18363f6 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -35,16 +35,35 @@ /* shared functions */ -static int mtk_clk_get_id(struct clk *clk) +static const int mtk_common_clk_of_xlate(struct clk *clk, + struct ofnode_phandle_args *args, + const struct mtk_clk_tree *tree) { - struct mtk_clk_priv *priv = dev_get_priv(clk->dev); - int id = clk->id; + int id; + + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + id = args->args[0]; /* Remap the clk ID to the one expected by driver */ - if (priv->tree->id_offs_map) - id = priv->tree->id_offs_map[id]; + if (tree->id_offs_map) { + if (id >= tree->id_offs_map_size) + return -ENOENT; + + id = tree->id_offs_map[id]; + } + + /* Some IDs in the map may not be valid. */ + if (id < 0) + return -ENOENT; + + clk->id = id; + clk->data = 0; - return id; + return 0; } static int mtk_dummy_enable(struct clk *clk) @@ -110,13 +129,23 @@ static int mtk_gate_disable(void __iomem *base, const struct mtk_gate *gate) static ulong mtk_clk_find_parent_rate(struct clk *clk, int id, struct udevice *pdev) { - struct clk parent = { .id = id, }; + struct ofnode_phandle_args args = { + .args_count = 1, + .args = { id }, + }; + struct clk parent = { }; + int ret; if (pdev) parent.dev = pdev; else parent.dev = clk->dev; + args.node = dev_ofnode(parent.dev); + ret = ((struct clk_ops *)parent.dev->driver->ops)->of_xlate(&parent, &args); + if (ret) + return ret; + return clk_get_rate(&parent); } @@ -164,8 +193,133 @@ static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent, return 0; } +#if CONFIG_IS_ENABLED(CMD_CLK) +static void mtk_clk_print_dev_parent(struct udevice *parent) +{ + printf("Parent device: %s %s\n", parent->driver->name, parent->name); +} + +static void mtk_clk_print_mapped_id(int unmapped_id, int mapped_id, bool has_map) +{ + /* + * If there is a ID map, then having unmapped and mapped IDs differ is + * expected. On the other hand, if there is no map, then they should be + * the same, and it is a programming error if they differ. + */ + if (has_map) + printf(", (mapped ID: %u)", mapped_id); + else if (unmapped_id != mapped_id) + printf(", (error! should be %u)", mapped_id); +} + +static void mtk_clk_print_rate(struct udevice *dev, int mapped_id) +{ + struct clk clk = { + .dev = dev, + .id = mapped_id, + }; + long rate = clk_get_rate(&clk); + + if (rate < 0) + printf(", error! clk_get_rate() failed: %ld", rate); + else + printf(", Rate: %lu Hz", rate); +} + +static void mtk_clk_print_parent(const char *prefix, int parent, u32 flags) +{ + const char *parent_type_str; + + switch (flags & CLK_PARENT_MASK) { + case CLK_PARENT_APMIXED: + parent_type_str = "apmixedsys"; + break; + case CLK_PARENT_TOPCKGEN: + parent_type_str = "topckgen"; + break; + case CLK_PARENT_INFRASYS: + parent_type_str = "infrasys"; + break; + case CLK_PARENT_XTAL: + parent_type_str = "xtal"; + break; + case CLK_PARENT_MIXED: + parent_type_str = "mixed"; + break; + default: + parent_type_str = "default"; + break; + } + + printf("%s%s-%u", prefix, parent_type_str, parent); +} + +static void mtk_clk_print_single_parent(int parent, u32 flags) +{ + mtk_clk_print_parent(", Parent: ", parent, flags); +} + +static void mtk_clk_print_mux_parents(struct mtk_clk_priv *priv, + const struct mtk_composite *mux) +{ + const char *prefix = ""; + u32 selected; + int i; + + printf(", Parents: "); + + selected = readl(priv->base + mux->mux_reg); + selected &= mux->mux_mask << mux->mux_shift; + selected >>= mux->mux_shift; + + /* Print parents separated by "/" and selected parent enclosed in "*"s */ + for (i = 0; i < mux->num_parents; i++) { + if (i == selected) { + printf("%s", prefix); + prefix = "*"; + } + + if (mux->flags & CLK_PARENT_MIXED) { + const struct mtk_parent *parent = &mux->parent_flags[i]; + + mtk_clk_print_parent(prefix, parent->id, parent->flags); + } else { + mtk_clk_print_parent(prefix, mux->parent[i], mux->flags); + } + + prefix = "/"; + + if (i == selected) + printf("*"); + } +} +#endif + /* apmixedsys functions */ +static const int mtk_apmixedsys_of_xlate(struct clk *clk, + struct ofnode_phandle_args *args) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_clk_tree *tree = priv->tree; + int ret; + + ret = mtk_common_clk_of_xlate(clk, args, tree); + if (ret) + return ret; + + /* apmixedsys only uses plls and gates. */ + + if (tree->plls && clk->id < tree->num_plls) + return 0; + + if (tree->gates && clk->id >= tree->gates_offs && + clk->id < tree->gates_offs + tree->num_gates) + return 0; + + return -ENOENT; +} + static unsigned long __mtk_pll_recalc_rate(const struct mtk_pll_data *pll, u32 fin, u32 pcw, int postdiv) { @@ -274,15 +428,14 @@ static void mtk_pll_calc_values(struct mtk_clk_priv *priv, u32 id, static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate) { struct mtk_clk_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); u32 pcw = 0; u32 postdiv; - if (priv->tree->gates && id >= priv->tree->gates_offs) + if (priv->tree->gates && clk->id >= priv->tree->gates_offs) return -EINVAL; - mtk_pll_calc_values(priv, id, &pcw, &postdiv, rate); - mtk_pll_set_rate_regs(priv, id, pcw, postdiv); + mtk_pll_calc_values(priv, clk->id, &pcw, &postdiv, rate); + mtk_pll_set_rate_regs(priv, clk->id, pcw, postdiv); return 0; } @@ -291,18 +444,17 @@ static ulong mtk_apmixedsys_get_rate(struct clk *clk) { struct mtk_clk_priv *priv = dev_get_priv(clk->dev); const struct mtk_pll_data *pll; - int id = mtk_clk_get_id(clk); const struct mtk_gate *gate; u32 postdiv; u32 pcw; /* GATE handling */ - if (priv->tree->gates && id >= priv->tree->gates_offs) { - gate = &priv->tree->gates[id - priv->tree->gates_offs]; + if (priv->tree->gates && clk->id >= priv->tree->gates_offs) { + gate = &priv->tree->gates[clk->id - priv->tree->gates_offs]; return mtk_clk_find_parent_rate(clk, gate->parent, NULL); } - pll = &priv->tree->plls[id]; + pll = &priv->tree->plls[clk->id]; postdiv = (readl(priv->base + pll->pd_reg) >> pll->pd_shift) & POSTDIV_MASK; @@ -319,17 +471,16 @@ static int mtk_apmixedsys_enable(struct clk *clk) { struct mtk_clk_priv *priv = dev_get_priv(clk->dev); const struct mtk_pll_data *pll; - int id = mtk_clk_get_id(clk); const struct mtk_gate *gate; u32 r; /* GATE handling */ - if (priv->tree->gates && id >= priv->tree->gates_offs) { - gate = &priv->tree->gates[id - priv->tree->gates_offs]; + if (priv->tree->gates && clk->id >= priv->tree->gates_offs) { + gate = &priv->tree->gates[clk->id - priv->tree->gates_offs]; return mtk_gate_enable(priv->base, gate); } - pll = &priv->tree->plls[id]; + pll = &priv->tree->plls[clk->id]; r = readl(priv->base + pll->pwr_reg) | CON0_PWR_ON; writel(r, priv->base + pll->pwr_reg); @@ -358,17 +509,16 @@ static int mtk_apmixedsys_disable(struct clk *clk) { struct mtk_clk_priv *priv = dev_get_priv(clk->dev); const struct mtk_pll_data *pll; - int id = mtk_clk_get_id(clk); const struct mtk_gate *gate; u32 r; /* GATE handling */ - if (priv->tree->gates && id >= priv->tree->gates_offs) { - gate = &priv->tree->gates[id - priv->tree->gates_offs]; + if (priv->tree->gates && clk->id >= priv->tree->gates_offs) { + gate = &priv->tree->gates[clk->id - priv->tree->gates_offs]; return mtk_gate_disable(priv->base, gate); } - pll = &priv->tree->plls[id]; + pll = &priv->tree->plls[clk->id]; if (pll->flags & HAVE_RST_BAR) { r = readl(priv->base + pll->reg + REG_CON0); @@ -389,8 +539,65 @@ static int mtk_apmixedsys_disable(struct clk *clk) return 0; } +#if CONFIG_IS_ENABLED(CMD_CLK) +static void mtk_apmixedsys_dump(struct udevice *dev) +{ + struct mtk_clk_priv *priv = dev_get_priv(dev); + const struct mtk_clk_tree *tree = priv->tree; + u32 i; + + mtk_clk_print_dev_parent(priv->parent); + + for (i = 0; i < tree->num_plls; i++) { + const struct mtk_pll_data *pll = &tree->plls[i]; + + printf("[PLL%u] DT: %u", i, pll->id); + mtk_clk_print_mapped_id(pll->id, i, tree->id_offs_map); + mtk_clk_print_rate(dev, i); + printf("\n"); + } + + for (i = 0; i < tree->num_gates; i++) { + const struct mtk_gate *gate = &tree->gates[i]; + + printf("[GATE%u] DT: %u", i, gate->id); + mtk_clk_print_mapped_id(gate->id, i + tree->gates_offs, tree->id_offs_map); + mtk_clk_print_rate(dev, i + tree->gates_offs); + mtk_clk_print_single_parent(gate->parent, gate->flags); + printf("\n"); + } +} +#endif + /* topckgen functions */ +static const int mtk_topckgen_of_xlate(struct clk *clk, + struct ofnode_phandle_args *args) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_clk_tree *tree = priv->tree; + int ret; + + ret = mtk_common_clk_of_xlate(clk, args, tree); + if (ret) + return ret; + + /* topckgen only uses fclks, fdivs and muxes. */ + + if (tree->fclks && clk->id < tree->num_fclks) + return 0; + + if (tree->fdivs && clk->id >= tree->fdivs_offs && + clk->id < tree->fdivs_offs + tree->num_fdivs) + return 0; + + if (tree->muxes && clk->id >= tree->muxes_offs && + clk->id < tree->muxes_offs + tree->num_muxes) + return 0; + + return -ENOENT; +} + static ulong mtk_factor_recalc_rate(const struct mtk_fixed_factor *fdiv, ulong parent_rate) { @@ -421,26 +628,8 @@ static ulong mtk_topckgen_get_factor_rate(struct clk *clk, u32 off) rate = priv->tree->xtal_rate; } - return mtk_factor_recalc_rate(fdiv, rate); -} - -static ulong mtk_infrasys_get_factor_rate(struct clk *clk, u32 off) -{ - struct mtk_clk_priv *priv = dev_get_priv(clk->dev); - const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off]; - ulong rate; - - switch (fdiv->flags & CLK_PARENT_MASK) { - case CLK_PARENT_TOPCKGEN: - rate = mtk_clk_find_parent_rate(clk, fdiv->parent, - priv->parent); - break; - case CLK_PARENT_XTAL: - rate = priv->tree->xtal_rate; - break; - default: - rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL); - } + if (((long)rate) < 0) + return rate; return mtk_factor_recalc_rate(fdiv, rate); } @@ -504,95 +693,30 @@ static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk, } } -static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off) -{ - struct mtk_clk_priv *priv = dev_get_priv(clk->dev); - const struct mtk_composite *mux = &priv->tree->muxes[off]; - u32 index; - - index = readl(priv->base + mux->mux_reg); - index &= mux->mux_mask << mux->mux_shift; - index = index >> mux->mux_shift; - - /* - * Parents can be either from TOPCKGEN or INFRACFG, - * inspect the mtk_parent struct to check the source - */ - if (mux->flags & CLK_PARENT_MIXED) { - const struct mtk_parent *parent = &mux->parent_flags[index]; - - return mtk_find_parent_rate(priv, clk, parent->id, parent->flags); - } - - if (mux->parent[index] == CLK_XTAL && - !(priv->tree->flags & CLK_BYPASS_XTAL)) - return priv->tree->xtal_rate; - - return mtk_find_parent_rate(priv, clk, mux->parent[index], mux->flags); -} - static ulong mtk_topckgen_get_rate(struct clk *clk) { struct mtk_clk_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); - if (id < priv->tree->fdivs_offs) - return priv->tree->fclks[id].rate; - else if (id < priv->tree->muxes_offs) - return mtk_topckgen_get_factor_rate(clk, id - + if (clk->id < priv->tree->fdivs_offs) + return priv->tree->fclks[clk->id].rate; + else if (clk->id < priv->tree->muxes_offs) + return mtk_topckgen_get_factor_rate(clk, clk->id - priv->tree->fdivs_offs); else - return mtk_topckgen_get_mux_rate(clk, id - + return mtk_topckgen_get_mux_rate(clk, clk->id - priv->tree->muxes_offs); } -static ulong mtk_infrasys_get_rate(struct clk *clk) -{ - struct mtk_clk_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); - ulong rate; - - if (id < priv->tree->fdivs_offs) { - rate = priv->tree->fclks[id].rate; - } else if (id < priv->tree->muxes_offs) { - rate = mtk_infrasys_get_factor_rate(clk, id - - priv->tree->fdivs_offs); - /* No gates defined or ID is a MUX */ - } else if (!priv->tree->gates || id < priv->tree->gates_offs) { - rate = mtk_infrasys_get_mux_rate(clk, id - - priv->tree->muxes_offs); - /* Only valid with muxes + gates implementation */ - } else { - struct udevice *parent = NULL; - const struct mtk_gate *gate; - - gate = &priv->tree->gates[id - priv->tree->gates_offs]; - if (gate->flags & CLK_PARENT_TOPCKGEN) - parent = priv->parent; - /* - * Assume xtal_rate to be declared if some gates have - * XTAL as parent - */ - else if (gate->flags & CLK_PARENT_XTAL) - return priv->tree->xtal_rate; - - rate = mtk_clk_find_parent_rate(clk, gate->parent, parent); - } - - return rate; -} - static int mtk_clk_mux_enable(struct clk *clk) { struct mtk_clk_priv *priv = dev_get_priv(clk->dev); const struct mtk_composite *mux; - int id = mtk_clk_get_id(clk); u32 val; - if (id < priv->tree->muxes_offs) + if (clk->id < priv->tree->muxes_offs) return 0; - mux = &priv->tree->muxes[id - priv->tree->muxes_offs]; + mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs]; if (mux->gate_shift < 0) return 0; @@ -620,13 +744,12 @@ static int mtk_clk_mux_disable(struct clk *clk) { struct mtk_clk_priv *priv = dev_get_priv(clk->dev); const struct mtk_composite *mux; - int id = mtk_clk_get_id(clk); u32 val; - if (id < priv->tree->muxes_offs) + if (clk->id < priv->tree->muxes_offs) return 0; - mux = &priv->tree->muxes[id - priv->tree->muxes_offs]; + mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs]; if (mux->gate_shift < 0) return 0; @@ -647,10 +770,9 @@ static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent) { struct mtk_clk_priv *parent_priv = dev_get_priv(parent->dev); struct mtk_clk_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); u32 parent_type; - if (id < priv->tree->muxes_offs) + if (clk->id < priv->tree->muxes_offs) return 0; if (!parent_priv) @@ -658,62 +780,272 @@ static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent) parent_type = parent_priv->tree->flags & CLK_PARENT_MASK; return mtk_clk_mux_set_parent(priv->base, parent->id, parent_type, - &priv->tree->muxes[id - priv->tree->muxes_offs]); + &priv->tree->muxes[clk->id - priv->tree->muxes_offs]); } -/* CG functions */ +#if CONFIG_IS_ENABLED(CMD_CLK) +static void mtk_topckgen_dump(struct udevice *dev) +{ + struct mtk_clk_priv *priv = dev_get_priv(dev); + const struct mtk_clk_tree *tree = priv->tree; + u32 i; -static int mtk_clk_gate_enable(struct clk *clk) + mtk_clk_print_dev_parent(priv->parent); + + for (i = 0; i < tree->num_fclks; i++) { + const struct mtk_fixed_clk *fclk = &tree->fclks[i]; + + printf("[FCLK%u] DT: %u", i, fclk->id); + mtk_clk_print_mapped_id(fclk->id, i, tree->id_offs_map); + mtk_clk_print_rate(dev, i); + /* FIXME: fclk needs flags to fully determine parent. */ + mtk_clk_print_single_parent(fclk->parent, 0); + printf("\n"); + } + + for (i = 0; i < tree->num_fdivs; i++) { + const struct mtk_fixed_factor *fdiv = &tree->fdivs[i]; + + printf("[FDIV%u] DT: %u", i, fdiv->id); + mtk_clk_print_mapped_id(fdiv->id, i + tree->fdivs_offs, tree->id_offs_map); + mtk_clk_print_rate(dev, i + tree->fdivs_offs); + mtk_clk_print_single_parent(fdiv->parent, fdiv->flags); + printf(", Mult: %u, Div: %u\n", fdiv->mult, fdiv->div); + } + + for (i = 0; i < tree->num_muxes; i++) { + const struct mtk_composite *mux = &tree->muxes[i]; + + printf("[MUX%u] DT: %u", i, mux->id); + mtk_clk_print_mapped_id(mux->id, i + tree->muxes_offs, tree->id_offs_map); + mtk_clk_print_rate(dev, i + tree->muxes_offs); + mtk_clk_print_mux_parents(priv, mux); + printf("\n"); + } +} +#endif + +/* infrasys functions */ + +static const int mtk_infrasys_of_xlate(struct clk *clk, + struct ofnode_phandle_args *args) { - struct mtk_cg_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); - const struct mtk_gate *gate; + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_clk_tree *tree = priv->tree; + int ret; - if (id < priv->tree->gates_offs) - return -EINVAL; + ret = mtk_common_clk_of_xlate(clk, args, tree); + if (ret) + return ret; - gate = &priv->gates[id - priv->tree->gates_offs]; - return mtk_gate_enable(priv->base, gate); + /* ifrasys only uses fdivs, muxes and gates. */ + + if (tree->fdivs && clk->id >= tree->fdivs_offs && + clk->id < tree->fdivs_offs + tree->num_fdivs) + return 0; + + if (tree->muxes && clk->id >= tree->muxes_offs && + clk->id < tree->muxes_offs + tree->num_muxes) + return 0; + + if (tree->gates && clk->id >= tree->gates_offs && + clk->id < tree->gates_offs + tree->num_gates) + return 0; + + return -ENOENT; } static int mtk_clk_infrasys_enable(struct clk *clk) { struct mtk_cg_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); const struct mtk_gate *gate; /* MUX handling */ - if (!priv->tree->gates || id < priv->tree->gates_offs) + if (!priv->tree->gates || clk->id < priv->tree->gates_offs) return mtk_clk_mux_enable(clk); - gate = &priv->tree->gates[id - priv->tree->gates_offs]; + gate = &priv->tree->gates[clk->id - priv->tree->gates_offs]; return mtk_gate_enable(priv->base, gate); } -static int mtk_clk_gate_disable(struct clk *clk) +static int mtk_clk_infrasys_disable(struct clk *clk) { struct mtk_cg_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); const struct mtk_gate *gate; - if (id < priv->tree->gates_offs) - return -EINVAL; + /* MUX handling */ + if (!priv->tree->gates || clk->id < priv->tree->gates_offs) + return mtk_clk_mux_disable(clk); - gate = &priv->gates[id - priv->tree->gates_offs]; + gate = &priv->tree->gates[clk->id - priv->tree->gates_offs]; return mtk_gate_disable(priv->base, gate); } -static int mtk_clk_infrasys_disable(struct clk *clk) +static ulong mtk_infrasys_get_factor_rate(struct clk *clk, u32 off) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off]; + ulong rate; + + switch (fdiv->flags & CLK_PARENT_MASK) { + case CLK_PARENT_TOPCKGEN: + rate = mtk_clk_find_parent_rate(clk, fdiv->parent, + priv->parent); + break; + case CLK_PARENT_XTAL: + rate = priv->tree->xtal_rate; + break; + default: + rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL); + } + + if (((long)rate) < 0) + return rate; + + return mtk_factor_recalc_rate(fdiv, rate); +} + +static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_composite *mux = &priv->tree->muxes[off]; + u32 index; + + index = readl(priv->base + mux->mux_reg); + index &= mux->mux_mask << mux->mux_shift; + index = index >> mux->mux_shift; + + /* + * Parents can be either from TOPCKGEN or INFRACFG, + * inspect the mtk_parent struct to check the source + */ + if (mux->flags & CLK_PARENT_MIXED) { + const struct mtk_parent *parent = &mux->parent_flags[index]; + + return mtk_find_parent_rate(priv, clk, parent->id, parent->flags); + } + + if (mux->parent[index] == CLK_XTAL && + !(priv->tree->flags & CLK_BYPASS_XTAL)) + return priv->tree->xtal_rate; + + return mtk_find_parent_rate(priv, clk, mux->parent[index], mux->flags); +} + +static ulong mtk_infrasys_get_rate(struct clk *clk) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + ulong rate; + + if (clk->id < priv->tree->fdivs_offs) { + rate = priv->tree->fclks[clk->id].rate; + } else if (clk->id < priv->tree->muxes_offs) { + rate = mtk_infrasys_get_factor_rate(clk, clk->id - + priv->tree->fdivs_offs); + /* No gates defined or ID is a MUX */ + } else if (!priv->tree->gates || clk->id < priv->tree->gates_offs) { + rate = mtk_infrasys_get_mux_rate(clk, clk->id - + priv->tree->muxes_offs); + /* Only valid with muxes + gates implementation */ + } else { + struct udevice *parent = NULL; + const struct mtk_gate *gate; + + gate = &priv->tree->gates[clk->id - priv->tree->gates_offs]; + if (gate->flags & CLK_PARENT_TOPCKGEN) + parent = priv->parent; + /* + * Assume xtal_rate to be declared if some gates have + * XTAL as parent + */ + else if (gate->flags & CLK_PARENT_XTAL) + return priv->tree->xtal_rate; + + rate = mtk_clk_find_parent_rate(clk, gate->parent, parent); + } + + return rate; +} + +#if CONFIG_IS_ENABLED(CMD_CLK) +static void mtk_infrasys_dump(struct udevice *dev) +{ + struct mtk_clk_priv *priv = dev_get_priv(dev); + const struct mtk_clk_tree *tree = priv->tree; + u32 i; + + mtk_clk_print_dev_parent(priv->parent); + + for (i = 0; i < tree->num_fdivs; i++) { + const struct mtk_fixed_factor *fdiv = &tree->fdivs[i]; + + printf("[FDIV%u] DT: %u", i, fdiv->id); + mtk_clk_print_mapped_id(fdiv->id, i + tree->fdivs_offs, tree->id_offs_map); + mtk_clk_print_single_parent(fdiv->parent, fdiv->flags); + printf(", Mult: %u, Div: %u\n", fdiv->mult, fdiv->div); + } + + for (i = 0; i < tree->num_muxes; i++) { + const struct mtk_composite *mux = &tree->muxes[i]; + + printf("[MUX%u] DT: %u", i, mux->id); + mtk_clk_print_mapped_id(mux->id, i + tree->muxes_offs, tree->id_offs_map); + mtk_clk_print_mux_parents(priv, mux); + printf("\n"); + } + + for (i = 0; i < tree->num_gates; i++) { + const struct mtk_gate *gate = &tree->gates[i]; + + printf("[GATE%u] DT: %u", i, gate->id); + mtk_clk_print_mapped_id(gate->id, i + tree->gates_offs, tree->id_offs_map); + mtk_clk_print_single_parent(gate->parent, gate->flags); + printf("\n"); + } +} +#endif + +/* CG functions */ + +static const int mtk_clk_gate_of_xlate(struct clk *clk, + struct ofnode_phandle_args *args) +{ + struct mtk_cg_priv *priv = dev_get_priv(clk->dev); + const struct mtk_clk_tree *tree = priv->tree; + int ret; + + ret = mtk_common_clk_of_xlate(clk, args, tree); + if (ret) + return ret; + + if (clk->id >= tree->gates_offs && + clk->id < tree->gates_offs + priv->num_gates) + return 0; + + return -ENOENT; +} + +static int mtk_clk_gate_enable(struct clk *clk) { struct mtk_cg_priv *priv = dev_get_priv(clk->dev); - int id = mtk_clk_get_id(clk); const struct mtk_gate *gate; - /* MUX handling */ - if (!priv->tree->gates || id < priv->tree->gates_offs) - return mtk_clk_mux_disable(clk); + if (clk->id < priv->tree->gates_offs) + return -EINVAL; + + gate = &priv->gates[clk->id - priv->tree->gates_offs]; + return mtk_gate_enable(priv->base, gate); +} + +static int mtk_clk_gate_disable(struct clk *clk) +{ + struct mtk_cg_priv *priv = dev_get_priv(clk->dev); + const struct mtk_gate *gate; - gate = &priv->tree->gates[id - priv->tree->gates_offs]; + if (clk->id < priv->tree->gates_offs) + return -EINVAL; + + gate = &priv->gates[clk->id - priv->tree->gates_offs]; return mtk_gate_disable(priv->base, gate); } @@ -721,13 +1053,12 @@ static ulong mtk_clk_gate_get_rate(struct clk *clk) { struct mtk_cg_priv *priv = dev_get_priv(clk->dev); struct udevice *parent = priv->parent; - int id = mtk_clk_get_id(clk); const struct mtk_gate *gate; - if (id < priv->tree->gates_offs) + if (clk->id < priv->tree->gates_offs) return -EINVAL; - gate = &priv->gates[id - priv->tree->gates_offs]; + gate = &priv->gates[clk->id - priv->tree->gates_offs]; /* * With requesting a TOPCKGEN parent, make sure the dev parent * is actually topckgen. This might not be the case for an @@ -750,37 +1081,78 @@ static ulong mtk_clk_gate_get_rate(struct clk *clk) return mtk_clk_find_parent_rate(clk, gate->parent, parent); } +#if CONFIG_IS_ENABLED(CMD_CLK) +static void mtk_clk_gate_dump(struct udevice *dev) +{ + struct mtk_cg_priv *priv = dev_get_priv(dev); + const struct mtk_clk_tree *tree = priv->tree; + u32 i; + + mtk_clk_print_dev_parent(priv->parent); + + for (i = 0; i < priv->num_gates; i++) { + const struct mtk_gate *gate = &priv->gates[i]; + + printf("[GATE%u] DT: %u", i, gate->id); + mtk_clk_print_mapped_id(gate->id, i + tree->gates_offs, tree->id_offs_map); + mtk_clk_print_rate(dev, i + tree->gates_offs); + mtk_clk_print_single_parent(gate->parent, gate->flags); + printf("\n"); + } +} +#endif + const struct clk_ops mtk_clk_apmixedsys_ops = { + .of_xlate = mtk_apmixedsys_of_xlate, .enable = mtk_apmixedsys_enable, .disable = mtk_apmixedsys_disable, .set_rate = mtk_apmixedsys_set_rate, .get_rate = mtk_apmixedsys_get_rate, +#if CONFIG_IS_ENABLED(CMD_CLK) + .dump = mtk_apmixedsys_dump, +#endif }; const struct clk_ops mtk_clk_fixed_pll_ops = { + .of_xlate = mtk_topckgen_of_xlate, .enable = mtk_dummy_enable, .disable = mtk_dummy_enable, .get_rate = mtk_topckgen_get_rate, +#if CONFIG_IS_ENABLED(CMD_CLK) + .dump = mtk_topckgen_dump, +#endif }; const struct clk_ops mtk_clk_topckgen_ops = { + .of_xlate = mtk_topckgen_of_xlate, .enable = mtk_clk_mux_enable, .disable = mtk_clk_mux_disable, .get_rate = mtk_topckgen_get_rate, .set_parent = mtk_common_clk_set_parent, +#if CONFIG_IS_ENABLED(CMD_CLK) + .dump = mtk_topckgen_dump, +#endif }; const struct clk_ops mtk_clk_infrasys_ops = { + .of_xlate = mtk_infrasys_of_xlate, .enable = mtk_clk_infrasys_enable, .disable = mtk_clk_infrasys_disable, .get_rate = mtk_infrasys_get_rate, .set_parent = mtk_common_clk_set_parent, +#if CONFIG_IS_ENABLED(CMD_CLK) + .dump = mtk_infrasys_dump, +#endif }; const struct clk_ops mtk_clk_gate_ops = { + .of_xlate = mtk_clk_gate_of_xlate, .enable = mtk_clk_gate_enable, .disable = mtk_clk_gate_disable, .get_rate = mtk_clk_gate_get_rate, +#if CONFIG_IS_ENABLED(CMD_CLK) + .dump = mtk_clk_gate_dump, +#endif }; static int mtk_common_clk_init_drv(struct udevice *dev, @@ -824,7 +1196,7 @@ int mtk_common_clk_infrasys_init(struct udevice *dev, int mtk_common_clk_gate_init(struct udevice *dev, const struct mtk_clk_tree *tree, - const struct mtk_gate *gates) + const struct mtk_gate *gates, int num_gates) { struct mtk_cg_priv *priv = dev_get_priv(dev); struct udevice *parent; @@ -845,6 +1217,7 @@ int mtk_common_clk_gate_init(struct udevice *dev, priv->parent = parent; priv->tree = tree; priv->gates = gates; + priv->num_gates = num_gates; return 0; } diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 8ce7e52fd60..bd8899193c9 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -45,6 +45,7 @@ /* struct mtk_pll_data - hardware-specific PLLs data */ struct mtk_pll_data { + /* unmapped ID of clock */ const int id; u32 reg; u32 pwr_reg; @@ -65,8 +66,8 @@ struct mtk_pll_data { /** * struct mtk_fixed_clk - fixed clocks * - * @id: index of clocks - * @parent: index of parnet clocks + * @id: unmapped ID of clock + * @parent: unmapped ID of parent clock * @rate: fixed rate */ struct mtk_fixed_clk { @@ -84,8 +85,8 @@ struct mtk_fixed_clk { /** * struct mtk_fixed_factor - fixed multiplier and divider clocks * - * @id: index of clocks - * @parent: index of parnet clocks + * @id: unmapped ID of clock + * @parent: unmapped ID of parent clock * @mult: multiplier * @div: divider * @flag: hardware-specific flags @@ -110,7 +111,7 @@ struct mtk_fixed_factor { * struct mtk_parent - clock parent with flags. Needed for MUX that * parent with mixed infracfg and topckgen. * - * @id: index of parent clocks + * @id: unmapped ID of parent clocks * @flags: hardware-specific flags (parent location, * infracfg, topckgen, APMIXED, xtal ...) */ @@ -127,8 +128,8 @@ struct mtk_parent { /** * struct mtk_composite - aggregate clock of mux, divider and gate clocks * - * @id: index of clocks - * @parent: index of parent clocks + * @id: unmapped ID of clocks + * @parent: unmapped ID of parent clocks * @parent_flags: table of parent clocks with flags * @mux_reg: hardware-specific mux register * @gate_reg: hardware-specific gate register @@ -226,8 +227,8 @@ struct mtk_gate_regs { /** * struct mtk_gate - gate clocks * - * @id: index of gate clocks - * @parent: index of parnet clocks + * @id: unmapped ID of gate clocks + * @parent: unmapped ID of parent clocks * @regs: hardware-specific mux register * @shift: shift to the gate bit field * @flags: hardware-specific flags @@ -245,13 +246,17 @@ struct mtk_clk_tree { unsigned long xtal_rate; unsigned long xtal2_rate; /* - * Clock ID offset are remapped with an auxiliary table. - * Enable this by defining .id_offs_map. - * This is needed for upstream linux kernel <soc>-clk.h that - * have mixed clk ID and doesn't have clear distinction between - * ID for factor, mux and gates. + * Clock IDs may be remapped with an auxiliary table. Enable this by + * defining .id_offs_map and .id_offs_map_size. This is needed e.g. when + * the upstream Linux kernel <soc>-clk.h has mixed clk IDs and doesn't + * have clear distinction between ID for factor, mux and gates. When + * this is enabled, the struct clk->id will contained the mapped ID that + * is the index in the various arrays in this struct. The .id and + * .parent fields in the various mtk_* structs will contain the + * unmapped IDs as defined in the upstream Linux kernel <soc>-clk.h. */ - const int *id_offs_map; /* optional, table clk.h to driver ID */ + const int *id_offs_map; /* optional, maps clk.h ID to array index */ + const int id_offs_map_size; const int fdivs_offs; const int muxes_offs; const int gates_offs; @@ -260,6 +265,11 @@ struct mtk_clk_tree { const struct mtk_fixed_factor *fdivs; const struct mtk_composite *muxes; const struct mtk_gate *gates; + const int num_plls; + const int num_fclks; + const int num_fdivs; + const int num_muxes; + const int num_gates; u32 flags; }; @@ -274,6 +284,7 @@ struct mtk_cg_priv { void __iomem *base; const struct mtk_clk_tree *tree; const struct mtk_gate *gates; + int num_gates; }; extern const struct clk_ops mtk_clk_apmixedsys_ops; @@ -288,6 +299,6 @@ int mtk_common_clk_infrasys_init(struct udevice *dev, const struct mtk_clk_tree *tree); int mtk_common_clk_gate_init(struct udevice *dev, const struct mtk_clk_tree *tree, - const struct mtk_gate *gates); + const struct mtk_gate *gates, int num_gates); #endif /* __DRV_CLK_MTK_H */ |
