1090 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>4 * Copyright (C) 2023 Vivo Communication Technology Co. Ltd.5 * Authors: Yangtao Li <frank.li@vivo.com>6 */7 8#include <dt-bindings/clock/thead,th1520-clk-ap.h>9#include <linux/bitfield.h>10#include <linux/clk-provider.h>11#include <linux/device.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/regmap.h>15 16#define TH1520_PLL_POSTDIV2 GENMASK(26, 24)17#define TH1520_PLL_POSTDIV1 GENMASK(22, 20)18#define TH1520_PLL_FBDIV GENMASK(19, 8)19#define TH1520_PLL_REFDIV GENMASK(5, 0)20#define TH1520_PLL_BYPASS BIT(30)21#define TH1520_PLL_DSMPD BIT(24)22#define TH1520_PLL_FRAC GENMASK(23, 0)23#define TH1520_PLL_FRAC_BITS 2424 25struct ccu_internal {26 u8 shift;27 u8 width;28};29 30struct ccu_div_internal {31 u8 shift;32 u8 width;33 u32 flags;34};35 36struct ccu_common {37 int clkid;38 struct regmap *map;39 u16 cfg0;40 u16 cfg1;41 struct clk_hw hw;42};43 44struct ccu_mux {45 struct ccu_internal mux;46 struct ccu_common common;47};48 49struct ccu_gate {50 u32 enable;51 struct ccu_common common;52};53 54struct ccu_div {55 u32 enable;56 struct ccu_div_internal div;57 struct ccu_internal mux;58 struct ccu_common common;59};60 61struct ccu_pll {62 struct ccu_common common;63};64 65#define TH_CCU_ARG(_shift, _width) \66 { \67 .shift = _shift, \68 .width = _width, \69 }70 71#define TH_CCU_DIV_FLAGS(_shift, _width, _flags) \72 { \73 .shift = _shift, \74 .width = _width, \75 .flags = _flags, \76 }77 78#define CCU_GATE(_clkid, _struct, _name, _parent, _reg, _gate, _flags) \79 struct ccu_gate _struct = { \80 .enable = _gate, \81 .common = { \82 .clkid = _clkid, \83 .cfg0 = _reg, \84 .hw.init = CLK_HW_INIT_PARENTS_DATA( \85 _name, \86 _parent, \87 &clk_gate_ops, \88 _flags), \89 } \90 }91 92static inline struct ccu_common *hw_to_ccu_common(struct clk_hw *hw)93{94 return container_of(hw, struct ccu_common, hw);95}96 97static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)98{99 struct ccu_common *common = hw_to_ccu_common(hw);100 101 return container_of(common, struct ccu_mux, common);102}103 104static inline struct ccu_pll *hw_to_ccu_pll(struct clk_hw *hw)105{106 struct ccu_common *common = hw_to_ccu_common(hw);107 108 return container_of(common, struct ccu_pll, common);109}110 111static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)112{113 struct ccu_common *common = hw_to_ccu_common(hw);114 115 return container_of(common, struct ccu_div, common);116}117 118static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)119{120 struct ccu_common *common = hw_to_ccu_common(hw);121 122 return container_of(common, struct ccu_gate, common);123}124 125static u8 ccu_get_parent_helper(struct ccu_common *common,126 struct ccu_internal *mux)127{128 unsigned int val;129 u8 parent;130 131 regmap_read(common->map, common->cfg0, &val);132 parent = val >> mux->shift;133 parent &= GENMASK(mux->width - 1, 0);134 135 return parent;136}137 138static int ccu_set_parent_helper(struct ccu_common *common,139 struct ccu_internal *mux,140 u8 index)141{142 return regmap_update_bits(common->map, common->cfg0,143 GENMASK(mux->width - 1, 0) << mux->shift,144 index << mux->shift);145}146 147static void ccu_disable_helper(struct ccu_common *common, u32 gate)148{149 if (!gate)150 return;151 regmap_update_bits(common->map, common->cfg0,152 gate, ~gate);153}154 155static int ccu_enable_helper(struct ccu_common *common, u32 gate)156{157 unsigned int val;158 int ret;159 160 if (!gate)161 return 0;162 163 ret = regmap_update_bits(common->map, common->cfg0, gate, gate);164 regmap_read(common->map, common->cfg0, &val);165 return ret;166}167 168static int ccu_is_enabled_helper(struct ccu_common *common, u32 gate)169{170 unsigned int val;171 172 if (!gate)173 return true;174 175 regmap_read(common->map, common->cfg0, &val);176 return val & gate;177}178 179static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,180 unsigned long parent_rate)181{182 struct ccu_div *cd = hw_to_ccu_div(hw);183 unsigned long rate;184 unsigned int val;185 186 regmap_read(cd->common.map, cd->common.cfg0, &val);187 val = val >> cd->div.shift;188 val &= GENMASK(cd->div.width - 1, 0);189 rate = divider_recalc_rate(hw, parent_rate, val, NULL,190 cd->div.flags, cd->div.width);191 192 return rate;193}194 195static u8 ccu_div_get_parent(struct clk_hw *hw)196{197 struct ccu_div *cd = hw_to_ccu_div(hw);198 199 return ccu_get_parent_helper(&cd->common, &cd->mux);200}201 202static int ccu_div_set_parent(struct clk_hw *hw, u8 index)203{204 struct ccu_div *cd = hw_to_ccu_div(hw);205 206 return ccu_set_parent_helper(&cd->common, &cd->mux, index);207}208 209static void ccu_div_disable(struct clk_hw *hw)210{211 struct ccu_div *cd = hw_to_ccu_div(hw);212 213 ccu_disable_helper(&cd->common, cd->enable);214}215 216static int ccu_div_enable(struct clk_hw *hw)217{218 struct ccu_div *cd = hw_to_ccu_div(hw);219 220 return ccu_enable_helper(&cd->common, cd->enable);221}222 223static int ccu_div_is_enabled(struct clk_hw *hw)224{225 struct ccu_div *cd = hw_to_ccu_div(hw);226 227 return ccu_is_enabled_helper(&cd->common, cd->enable);228}229 230static const struct clk_ops ccu_div_ops = {231 .disable = ccu_div_disable,232 .enable = ccu_div_enable,233 .is_enabled = ccu_div_is_enabled,234 .get_parent = ccu_div_get_parent,235 .set_parent = ccu_div_set_parent,236 .recalc_rate = ccu_div_recalc_rate,237 .determine_rate = clk_hw_determine_rate_no_reparent,238};239 240static unsigned long th1520_pll_vco_recalc_rate(struct clk_hw *hw,241 unsigned long parent_rate)242{243 struct ccu_pll *pll = hw_to_ccu_pll(hw);244 unsigned long div, mul, frac;245 unsigned int cfg0, cfg1;246 u64 rate = parent_rate;247 248 regmap_read(pll->common.map, pll->common.cfg0, &cfg0);249 regmap_read(pll->common.map, pll->common.cfg1, &cfg1);250 251 mul = FIELD_GET(TH1520_PLL_FBDIV, cfg0);252 div = FIELD_GET(TH1520_PLL_REFDIV, cfg0);253 if (!(cfg1 & TH1520_PLL_DSMPD)) {254 mul <<= TH1520_PLL_FRAC_BITS;255 frac = FIELD_GET(TH1520_PLL_FRAC, cfg1);256 mul += frac;257 div <<= TH1520_PLL_FRAC_BITS;258 }259 rate = parent_rate * mul;260 rate = rate / div;261 return rate;262}263 264static unsigned long th1520_pll_postdiv_recalc_rate(struct clk_hw *hw,265 unsigned long parent_rate)266{267 struct ccu_pll *pll = hw_to_ccu_pll(hw);268 unsigned long div, rate = parent_rate;269 unsigned int cfg0, cfg1;270 271 regmap_read(pll->common.map, pll->common.cfg0, &cfg0);272 regmap_read(pll->common.map, pll->common.cfg1, &cfg1);273 274 if (cfg1 & TH1520_PLL_BYPASS)275 return rate;276 277 div = FIELD_GET(TH1520_PLL_POSTDIV1, cfg0) *278 FIELD_GET(TH1520_PLL_POSTDIV2, cfg0);279 280 rate = rate / div;281 282 return rate;283}284 285static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw,286 unsigned long parent_rate)287{288 unsigned long rate = parent_rate;289 290 rate = th1520_pll_vco_recalc_rate(hw, rate);291 rate = th1520_pll_postdiv_recalc_rate(hw, rate);292 293 return rate;294}295 296static const struct clk_ops clk_pll_ops = {297 .recalc_rate = ccu_pll_recalc_rate,298};299 300static const struct clk_parent_data osc_24m_clk[] = {301 { .index = 0 }302};303 304static struct ccu_pll cpu_pll0_clk = {305 .common = {306 .clkid = CLK_CPU_PLL0,307 .cfg0 = 0x000,308 .cfg1 = 0x004,309 .hw.init = CLK_HW_INIT_PARENTS_DATA("cpu-pll0",310 osc_24m_clk,311 &clk_pll_ops,312 0),313 },314};315 316static struct ccu_pll cpu_pll1_clk = {317 .common = {318 .clkid = CLK_CPU_PLL1,319 .cfg0 = 0x010,320 .cfg1 = 0x014,321 .hw.init = CLK_HW_INIT_PARENTS_DATA("cpu-pll1",322 osc_24m_clk,323 &clk_pll_ops,324 0),325 },326};327 328static struct ccu_pll gmac_pll_clk = {329 .common = {330 .clkid = CLK_GMAC_PLL,331 .cfg0 = 0x020,332 .cfg1 = 0x024,333 .hw.init = CLK_HW_INIT_PARENTS_DATA("gmac-pll",334 osc_24m_clk,335 &clk_pll_ops,336 0),337 },338};339 340static const struct clk_hw *gmac_pll_clk_parent[] = {341 &gmac_pll_clk.common.hw342};343 344static const struct clk_parent_data gmac_pll_clk_pd[] = {345 { .hw = &gmac_pll_clk.common.hw }346};347 348static struct ccu_pll video_pll_clk = {349 .common = {350 .clkid = CLK_VIDEO_PLL,351 .cfg0 = 0x030,352 .cfg1 = 0x034,353 .hw.init = CLK_HW_INIT_PARENTS_DATA("video-pll",354 osc_24m_clk,355 &clk_pll_ops,356 0),357 },358};359 360static const struct clk_hw *video_pll_clk_parent[] = {361 &video_pll_clk.common.hw362};363 364static const struct clk_parent_data video_pll_clk_pd[] = {365 { .hw = &video_pll_clk.common.hw }366};367 368static struct ccu_pll dpu0_pll_clk = {369 .common = {370 .clkid = CLK_DPU0_PLL,371 .cfg0 = 0x040,372 .cfg1 = 0x044,373 .hw.init = CLK_HW_INIT_PARENTS_DATA("dpu0-pll",374 osc_24m_clk,375 &clk_pll_ops,376 0),377 },378};379 380static const struct clk_hw *dpu0_pll_clk_parent[] = {381 &dpu0_pll_clk.common.hw382};383 384static struct ccu_pll dpu1_pll_clk = {385 .common = {386 .clkid = CLK_DPU1_PLL,387 .cfg0 = 0x050,388 .cfg1 = 0x054,389 .hw.init = CLK_HW_INIT_PARENTS_DATA("dpu1-pll",390 osc_24m_clk,391 &clk_pll_ops,392 0),393 },394};395 396static const struct clk_hw *dpu1_pll_clk_parent[] = {397 &dpu1_pll_clk.common.hw398};399 400static struct ccu_pll tee_pll_clk = {401 .common = {402 .clkid = CLK_TEE_PLL,403 .cfg0 = 0x060,404 .cfg1 = 0x064,405 .hw.init = CLK_HW_INIT_PARENTS_DATA("tee-pll",406 osc_24m_clk,407 &clk_pll_ops,408 0),409 },410};411 412static const struct clk_parent_data c910_i0_parents[] = {413 { .hw = &cpu_pll0_clk.common.hw },414 { .index = 0 }415};416 417static struct ccu_mux c910_i0_clk = {418 .mux = TH_CCU_ARG(1, 1),419 .common = {420 .clkid = CLK_C910_I0,421 .cfg0 = 0x100,422 .hw.init = CLK_HW_INIT_PARENTS_DATA("c910-i0",423 c910_i0_parents,424 &clk_mux_ops,425 0),426 }427};428 429static const struct clk_parent_data c910_parents[] = {430 { .hw = &c910_i0_clk.common.hw },431 { .hw = &cpu_pll1_clk.common.hw }432};433 434static struct ccu_mux c910_clk = {435 .mux = TH_CCU_ARG(0, 1),436 .common = {437 .clkid = CLK_C910,438 .cfg0 = 0x100,439 .hw.init = CLK_HW_INIT_PARENTS_DATA("c910",440 c910_parents,441 &clk_mux_ops,442 0),443 }444};445 446static const struct clk_parent_data ahb2_cpusys_parents[] = {447 { .hw = &gmac_pll_clk.common.hw },448 { .index = 0 }449};450 451static struct ccu_div ahb2_cpusys_hclk = {452 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),453 .mux = TH_CCU_ARG(5, 1),454 .common = {455 .clkid = CLK_AHB2_CPUSYS_HCLK,456 .cfg0 = 0x120,457 .hw.init = CLK_HW_INIT_PARENTS_DATA("ahb2-cpusys-hclk",458 ahb2_cpusys_parents,459 &ccu_div_ops,460 0),461 },462};463 464static const struct clk_parent_data ahb2_cpusys_hclk_pd[] = {465 { .hw = &ahb2_cpusys_hclk.common.hw }466};467 468static const struct clk_hw *ahb2_cpusys_hclk_parent[] = {469 &ahb2_cpusys_hclk.common.hw,470};471 472static struct ccu_div apb3_cpusys_pclk = {473 .div = TH_CCU_ARG(0, 3),474 .common = {475 .clkid = CLK_APB3_CPUSYS_PCLK,476 .cfg0 = 0x130,477 .hw.init = CLK_HW_INIT_PARENTS_HW("apb3-cpusys-pclk",478 ahb2_cpusys_hclk_parent,479 &ccu_div_ops,480 0),481 },482};483 484static const struct clk_parent_data apb3_cpusys_pclk_pd[] = {485 { .hw = &apb3_cpusys_pclk.common.hw }486};487 488static struct ccu_div axi4_cpusys2_aclk = {489 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),490 .common = {491 .clkid = CLK_AXI4_CPUSYS2_ACLK,492 .cfg0 = 0x134,493 .hw.init = CLK_HW_INIT_PARENTS_HW("axi4-cpusys2-aclk",494 gmac_pll_clk_parent,495 &ccu_div_ops,496 0),497 },498};499 500static const struct clk_parent_data axi4_cpusys2_aclk_pd[] = {501 { .hw = &axi4_cpusys2_aclk.common.hw }502};503 504static const struct clk_parent_data axi_parents[] = {505 { .hw = &video_pll_clk.common.hw },506 { .index = 0 }507};508 509static struct ccu_div axi_aclk = {510 .div = TH_CCU_DIV_FLAGS(0, 4, CLK_DIVIDER_ONE_BASED),511 .mux = TH_CCU_ARG(5, 1),512 .common = {513 .clkid = CLK_AXI_ACLK,514 .cfg0 = 0x138,515 .hw.init = CLK_HW_INIT_PARENTS_DATA("axi-aclk",516 axi_parents,517 &ccu_div_ops,518 0),519 },520};521 522static const struct clk_parent_data axi_aclk_pd[] = {523 { .hw = &axi_aclk.common.hw }524};525 526static const struct clk_parent_data perisys_ahb_hclk_parents[] = {527 { .hw = &gmac_pll_clk.common.hw },528 { .index = 0 },529};530 531static struct ccu_div perisys_ahb_hclk = {532 .enable = BIT(6),533 .div = TH_CCU_DIV_FLAGS(0, 4, CLK_DIVIDER_ONE_BASED),534 .mux = TH_CCU_ARG(5, 1),535 .common = {536 .clkid = CLK_PERI_AHB_HCLK,537 .cfg0 = 0x140,538 .hw.init = CLK_HW_INIT_PARENTS_DATA("perisys-ahb-hclk",539 perisys_ahb_hclk_parents,540 &ccu_div_ops,541 0),542 },543};544 545static const struct clk_parent_data perisys_ahb_hclk_pd[] = {546 { .hw = &perisys_ahb_hclk.common.hw }547};548 549static const struct clk_hw *perisys_ahb_hclk_parent[] = {550 &perisys_ahb_hclk.common.hw551};552 553static struct ccu_div perisys_apb_pclk = {554 .div = TH_CCU_ARG(0, 3),555 .common = {556 .clkid = CLK_PERI_APB_PCLK,557 .cfg0 = 0x150,558 .hw.init = CLK_HW_INIT_PARENTS_HW("perisys-apb-pclk",559 perisys_ahb_hclk_parent,560 &ccu_div_ops,561 0),562 },563};564 565static const struct clk_parent_data perisys_apb_pclk_pd[] = {566 { .hw = &perisys_apb_pclk.common.hw }567};568 569static struct ccu_div peri2sys_apb_pclk = {570 .div = TH_CCU_DIV_FLAGS(4, 3, CLK_DIVIDER_ONE_BASED),571 .common = {572 .clkid = CLK_PERI2APB_PCLK,573 .cfg0 = 0x150,574 .hw.init = CLK_HW_INIT_PARENTS_HW("peri2sys-apb-pclk",575 gmac_pll_clk_parent,576 &ccu_div_ops,577 0),578 },579};580 581static const struct clk_parent_data peri2sys_apb_pclk_pd[] = {582 { .hw = &peri2sys_apb_pclk.common.hw }583};584 585static CLK_FIXED_FACTOR_FW_NAME(osc12m_clk, "osc_12m", "osc_24m", 2, 1, 0);586 587static const char * const out_parents[] = { "osc_24m", "osc_12m" };588 589static struct ccu_div out1_clk = {590 .enable = BIT(5),591 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),592 .mux = TH_CCU_ARG(4, 1),593 .common = {594 .clkid = CLK_OUT1,595 .cfg0 = 0x1b4,596 .hw.init = CLK_HW_INIT_PARENTS("out1",597 out_parents,598 &ccu_div_ops,599 0),600 },601};602 603static struct ccu_div out2_clk = {604 .enable = BIT(5),605 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),606 .mux = TH_CCU_ARG(4, 1),607 .common = {608 .clkid = CLK_OUT2,609 .cfg0 = 0x1b8,610 .hw.init = CLK_HW_INIT_PARENTS("out2",611 out_parents,612 &ccu_div_ops,613 0),614 },615};616 617static struct ccu_div out3_clk = {618 .enable = BIT(5),619 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),620 .mux = TH_CCU_ARG(4, 1),621 .common = {622 .clkid = CLK_OUT3,623 .cfg0 = 0x1bc,624 .hw.init = CLK_HW_INIT_PARENTS("out3",625 out_parents,626 &ccu_div_ops,627 0),628 },629};630 631static struct ccu_div out4_clk = {632 .enable = BIT(5),633 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),634 .mux = TH_CCU_ARG(4, 1),635 .common = {636 .clkid = CLK_OUT4,637 .cfg0 = 0x1c0,638 .hw.init = CLK_HW_INIT_PARENTS("out4",639 out_parents,640 &ccu_div_ops,641 0),642 },643};644 645static const struct clk_parent_data apb_parents[] = {646 { .hw = &gmac_pll_clk.common.hw },647 { .index = 0 },648};649 650static struct ccu_div apb_pclk = {651 .enable = BIT(5),652 .div = TH_CCU_DIV_FLAGS(0, 4, CLK_DIVIDER_ONE_BASED),653 .mux = TH_CCU_ARG(7, 1),654 .common = {655 .clkid = CLK_APB_PCLK,656 .cfg0 = 0x1c4,657 .hw.init = CLK_HW_INIT_PARENTS_DATA("apb-pclk",658 apb_parents,659 &ccu_div_ops,660 0),661 },662};663 664static const struct clk_hw *npu_parents[] = {665 &gmac_pll_clk.common.hw,666 &video_pll_clk.common.hw667};668 669static struct ccu_div npu_clk = {670 .enable = BIT(4),671 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),672 .mux = TH_CCU_ARG(6, 1),673 .common = {674 .clkid = CLK_NPU,675 .cfg0 = 0x1c8,676 .hw.init = CLK_HW_INIT_PARENTS_HW("npu",677 npu_parents,678 &ccu_div_ops,679 0),680 },681};682 683static struct ccu_div vi_clk = {684 .div = TH_CCU_DIV_FLAGS(16, 4, CLK_DIVIDER_ONE_BASED),685 .common = {686 .clkid = CLK_VI,687 .cfg0 = 0x1d0,688 .hw.init = CLK_HW_INIT_PARENTS_HW("vi",689 video_pll_clk_parent,690 &ccu_div_ops,691 0),692 },693};694 695static struct ccu_div vi_ahb_clk = {696 .div = TH_CCU_DIV_FLAGS(0, 4, CLK_DIVIDER_ONE_BASED),697 .common = {698 .clkid = CLK_VI_AHB,699 .cfg0 = 0x1d0,700 .hw.init = CLK_HW_INIT_PARENTS_HW("vi-ahb",701 video_pll_clk_parent,702 &ccu_div_ops,703 0),704 },705};706 707static struct ccu_div vo_axi_clk = {708 .enable = BIT(5),709 .div = TH_CCU_DIV_FLAGS(0, 4, CLK_DIVIDER_ONE_BASED),710 .common = {711 .clkid = CLK_VO_AXI,712 .cfg0 = 0x1dc,713 .hw.init = CLK_HW_INIT_PARENTS_HW("vo-axi",714 video_pll_clk_parent,715 &ccu_div_ops,716 0),717 },718};719 720static struct ccu_div vp_apb_clk = {721 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),722 .common = {723 .clkid = CLK_VP_APB,724 .cfg0 = 0x1e0,725 .hw.init = CLK_HW_INIT_PARENTS_HW("vp-apb",726 gmac_pll_clk_parent,727 &ccu_div_ops,728 0),729 },730};731 732static struct ccu_div vp_axi_clk = {733 .enable = BIT(15),734 .div = TH_CCU_DIV_FLAGS(8, 4, CLK_DIVIDER_ONE_BASED),735 .common = {736 .clkid = CLK_VP_AXI,737 .cfg0 = 0x1e0,738 .hw.init = CLK_HW_INIT_PARENTS_HW("vp-axi",739 video_pll_clk_parent,740 &ccu_div_ops,741 CLK_IGNORE_UNUSED),742 },743};744 745static struct ccu_div venc_clk = {746 .enable = BIT(5),747 .div = TH_CCU_DIV_FLAGS(0, 3, CLK_DIVIDER_ONE_BASED),748 .common = {749 .clkid = CLK_VENC,750 .cfg0 = 0x1e4,751 .hw.init = CLK_HW_INIT_PARENTS_HW("venc",752 gmac_pll_clk_parent,753 &ccu_div_ops,754 0),755 },756};757 758static struct ccu_div dpu0_clk = {759 .div = TH_CCU_DIV_FLAGS(0, 8, CLK_DIVIDER_ONE_BASED),760 .common = {761 .clkid = CLK_DPU0,762 .cfg0 = 0x1e8,763 .hw.init = CLK_HW_INIT_PARENTS_HW("dpu0",764 dpu0_pll_clk_parent,765 &ccu_div_ops,766 0),767 },768};769 770static struct ccu_div dpu1_clk = {771 .div = TH_CCU_DIV_FLAGS(0, 8, CLK_DIVIDER_ONE_BASED),772 .common = {773 .clkid = CLK_DPU1,774 .cfg0 = 0x1ec,775 .hw.init = CLK_HW_INIT_PARENTS_HW("dpu1",776 dpu1_pll_clk_parent,777 &ccu_div_ops,778 0),779 },780};781 782static CCU_GATE(CLK_BROM, brom_clk, "brom", ahb2_cpusys_hclk_pd, 0x100, BIT(4), 0);783static CCU_GATE(CLK_BMU, bmu_clk, "bmu", axi4_cpusys2_aclk_pd, 0x100, BIT(5), 0);784static CCU_GATE(CLK_AON2CPU_A2X, aon2cpu_a2x_clk, "aon2cpu-a2x", axi4_cpusys2_aclk_pd,785 0x134, BIT(8), 0);786static CCU_GATE(CLK_X2X_CPUSYS, x2x_cpusys_clk, "x2x-cpusys", axi4_cpusys2_aclk_pd,787 0x134, BIT(7), 0);788static CCU_GATE(CLK_CPU2AON_X2H, cpu2aon_x2h_clk, "cpu2aon-x2h", axi_aclk_pd, 0x138, BIT(8), 0);789static CCU_GATE(CLK_CPU2PERI_X2H, cpu2peri_x2h_clk, "cpu2peri-x2h", axi4_cpusys2_aclk_pd,790 0x140, BIT(9), 0);791static CCU_GATE(CLK_PERISYS_APB1_HCLK, perisys_apb1_hclk, "perisys-apb1-hclk", perisys_ahb_hclk_pd,792 0x150, BIT(9), 0);793static CCU_GATE(CLK_PERISYS_APB2_HCLK, perisys_apb2_hclk, "perisys-apb2-hclk", perisys_ahb_hclk_pd,794 0x150, BIT(10), 0);795static CCU_GATE(CLK_PERISYS_APB3_HCLK, perisys_apb3_hclk, "perisys-apb3-hclk", perisys_ahb_hclk_pd,796 0x150, BIT(11), 0);797static CCU_GATE(CLK_PERISYS_APB4_HCLK, perisys_apb4_hclk, "perisys-apb4-hclk", perisys_ahb_hclk_pd,798 0x150, BIT(12), 0);799static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, BIT(5), 0);800static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, BIT(13), 0);801static CCU_GATE(CLK_EMMC_SDIO, emmc_sdio_clk, "emmc-sdio", video_pll_clk_pd, 0x204, BIT(30), 0);802static CCU_GATE(CLK_GMAC1, gmac1_clk, "gmac1", gmac_pll_clk_pd, 0x204, BIT(26), 0);803static CCU_GATE(CLK_PADCTRL1, padctrl1_clk, "padctrl1", perisys_apb_pclk_pd, 0x204, BIT(24), 0);804static CCU_GATE(CLK_DSMART, dsmart_clk, "dsmart", perisys_apb_pclk_pd, 0x204, BIT(23), 0);805static CCU_GATE(CLK_PADCTRL0, padctrl0_clk, "padctrl0", perisys_apb_pclk_pd, 0x204, BIT(22), 0);806static CCU_GATE(CLK_GMAC_AXI, gmac_axi_clk, "gmac-axi", axi4_cpusys2_aclk_pd, 0x204, BIT(21), 0);807static CCU_GATE(CLK_GPIO3, gpio3_clk, "gpio3-clk", peri2sys_apb_pclk_pd, 0x204, BIT(20), 0);808static CCU_GATE(CLK_GMAC0, gmac0_clk, "gmac0", gmac_pll_clk_pd, 0x204, BIT(19), 0);809static CCU_GATE(CLK_PWM, pwm_clk, "pwm", perisys_apb_pclk_pd, 0x204, BIT(18), 0);810static CCU_GATE(CLK_QSPI0, qspi0_clk, "qspi0", video_pll_clk_pd, 0x204, BIT(17), 0);811static CCU_GATE(CLK_QSPI1, qspi1_clk, "qspi1", video_pll_clk_pd, 0x204, BIT(16), 0);812static CCU_GATE(CLK_SPI, spi_clk, "spi", video_pll_clk_pd, 0x204, BIT(15), 0);813static CCU_GATE(CLK_UART0_PCLK, uart0_pclk, "uart0-pclk", perisys_apb_pclk_pd, 0x204, BIT(14), 0);814static CCU_GATE(CLK_UART1_PCLK, uart1_pclk, "uart1-pclk", perisys_apb_pclk_pd, 0x204, BIT(13), 0);815static CCU_GATE(CLK_UART2_PCLK, uart2_pclk, "uart2-pclk", perisys_apb_pclk_pd, 0x204, BIT(12), 0);816static CCU_GATE(CLK_UART3_PCLK, uart3_pclk, "uart3-pclk", perisys_apb_pclk_pd, 0x204, BIT(11), 0);817static CCU_GATE(CLK_UART4_PCLK, uart4_pclk, "uart4-pclk", perisys_apb_pclk_pd, 0x204, BIT(10), 0);818static CCU_GATE(CLK_UART5_PCLK, uart5_pclk, "uart5-pclk", perisys_apb_pclk_pd, 0x204, BIT(9), 0);819static CCU_GATE(CLK_GPIO0, gpio0_clk, "gpio0-clk", perisys_apb_pclk_pd, 0x204, BIT(8), 0);820static CCU_GATE(CLK_GPIO1, gpio1_clk, "gpio1-clk", perisys_apb_pclk_pd, 0x204, BIT(7), 0);821static CCU_GATE(CLK_GPIO2, gpio2_clk, "gpio2-clk", peri2sys_apb_pclk_pd, 0x204, BIT(6), 0);822static CCU_GATE(CLK_I2C0, i2c0_clk, "i2c0", perisys_apb_pclk_pd, 0x204, BIT(5), 0);823static CCU_GATE(CLK_I2C1, i2c1_clk, "i2c1", perisys_apb_pclk_pd, 0x204, BIT(4), 0);824static CCU_GATE(CLK_I2C2, i2c2_clk, "i2c2", perisys_apb_pclk_pd, 0x204, BIT(3), 0);825static CCU_GATE(CLK_I2C3, i2c3_clk, "i2c3", perisys_apb_pclk_pd, 0x204, BIT(2), 0);826static CCU_GATE(CLK_I2C4, i2c4_clk, "i2c4", perisys_apb_pclk_pd, 0x204, BIT(1), 0);827static CCU_GATE(CLK_I2C5, i2c5_clk, "i2c5", perisys_apb_pclk_pd, 0x204, BIT(0), 0);828static CCU_GATE(CLK_SPINLOCK, spinlock_clk, "spinlock", ahb2_cpusys_hclk_pd, 0x208, BIT(10), 0);829static CCU_GATE(CLK_DMA, dma_clk, "dma", axi4_cpusys2_aclk_pd, 0x208, BIT(8), 0);830static CCU_GATE(CLK_MBOX0, mbox0_clk, "mbox0", apb3_cpusys_pclk_pd, 0x208, BIT(7), 0);831static CCU_GATE(CLK_MBOX1, mbox1_clk, "mbox1", apb3_cpusys_pclk_pd, 0x208, BIT(6), 0);832static CCU_GATE(CLK_MBOX2, mbox2_clk, "mbox2", apb3_cpusys_pclk_pd, 0x208, BIT(5), 0);833static CCU_GATE(CLK_MBOX3, mbox3_clk, "mbox3", apb3_cpusys_pclk_pd, 0x208, BIT(4), 0);834static CCU_GATE(CLK_WDT0, wdt0_clk, "wdt0", apb3_cpusys_pclk_pd, 0x208, BIT(3), 0);835static CCU_GATE(CLK_WDT1, wdt1_clk, "wdt1", apb3_cpusys_pclk_pd, 0x208, BIT(2), 0);836static CCU_GATE(CLK_TIMER0, timer0_clk, "timer0", apb3_cpusys_pclk_pd, 0x208, BIT(1), 0);837static CCU_GATE(CLK_TIMER1, timer1_clk, "timer1", apb3_cpusys_pclk_pd, 0x208, BIT(0), 0);838static CCU_GATE(CLK_SRAM0, sram0_clk, "sram0", axi_aclk_pd, 0x20c, BIT(4), 0);839static CCU_GATE(CLK_SRAM1, sram1_clk, "sram1", axi_aclk_pd, 0x20c, BIT(3), 0);840static CCU_GATE(CLK_SRAM2, sram2_clk, "sram2", axi_aclk_pd, 0x20c, BIT(2), 0);841static CCU_GATE(CLK_SRAM3, sram3_clk, "sram3", axi_aclk_pd, 0x20c, BIT(1), 0);842 843static CLK_FIXED_FACTOR_HW(gmac_pll_clk_100m, "gmac-pll-clk-100m",844 &gmac_pll_clk.common.hw, 10, 1, 0);845 846static const struct clk_parent_data uart_sclk_parents[] = {847 { .hw = &gmac_pll_clk_100m.hw },848 { .index = 0 },849};850 851static struct ccu_mux uart_sclk = {852 .mux = TH_CCU_ARG(0, 1),853 .common = {854 .clkid = CLK_UART_SCLK,855 .cfg0 = 0x210,856 .hw.init = CLK_HW_INIT_PARENTS_DATA("uart-sclk",857 uart_sclk_parents,858 &clk_mux_ops,859 0),860 }861};862 863static struct ccu_common *th1520_pll_clks[] = {864 &cpu_pll0_clk.common,865 &cpu_pll1_clk.common,866 &gmac_pll_clk.common,867 &video_pll_clk.common,868 &dpu0_pll_clk.common,869 &dpu1_pll_clk.common,870 &tee_pll_clk.common,871};872 873static struct ccu_common *th1520_div_clks[] = {874 &ahb2_cpusys_hclk.common,875 &apb3_cpusys_pclk.common,876 &axi4_cpusys2_aclk.common,877 &perisys_ahb_hclk.common,878 &perisys_apb_pclk.common,879 &axi_aclk.common,880 &peri2sys_apb_pclk.common,881 &out1_clk.common,882 &out2_clk.common,883 &out3_clk.common,884 &out4_clk.common,885 &apb_pclk.common,886 &npu_clk.common,887 &vi_clk.common,888 &vi_ahb_clk.common,889 &vo_axi_clk.common,890 &vp_apb_clk.common,891 &vp_axi_clk.common,892 &cpu2vp_clk.common,893 &venc_clk.common,894 &dpu0_clk.common,895 &dpu1_clk.common,896};897 898static struct ccu_common *th1520_mux_clks[] = {899 &c910_i0_clk.common,900 &c910_clk.common,901 &uart_sclk.common,902};903 904static struct ccu_common *th1520_gate_clks[] = {905 &emmc_sdio_clk.common,906 &aon2cpu_a2x_clk.common,907 &x2x_cpusys_clk.common,908 &brom_clk.common,909 &bmu_clk.common,910 &cpu2aon_x2h_clk.common,911 &cpu2peri_x2h_clk.common,912 &perisys_apb1_hclk.common,913 &perisys_apb2_hclk.common,914 &perisys_apb3_hclk.common,915 &perisys_apb4_hclk.common,916 &npu_axi_clk.common,917 &gmac1_clk.common,918 &padctrl1_clk.common,919 &dsmart_clk.common,920 &padctrl0_clk.common,921 &gmac_axi_clk.common,922 &gpio3_clk.common,923 &gmac0_clk.common,924 &pwm_clk.common,925 &qspi0_clk.common,926 &qspi1_clk.common,927 &spi_clk.common,928 &uart0_pclk.common,929 &uart1_pclk.common,930 &uart2_pclk.common,931 &uart3_pclk.common,932 &uart4_pclk.common,933 &uart5_pclk.common,934 &gpio0_clk.common,935 &gpio1_clk.common,936 &gpio2_clk.common,937 &i2c0_clk.common,938 &i2c1_clk.common,939 &i2c2_clk.common,940 &i2c3_clk.common,941 &i2c4_clk.common,942 &i2c5_clk.common,943 &spinlock_clk.common,944 &dma_clk.common,945 &mbox0_clk.common,946 &mbox1_clk.common,947 &mbox2_clk.common,948 &mbox3_clk.common,949 &wdt0_clk.common,950 &wdt1_clk.common,951 &timer0_clk.common,952 &timer1_clk.common,953 &sram0_clk.common,954 &sram1_clk.common,955 &sram2_clk.common,956 &sram3_clk.common,957};958 959#define NR_CLKS (CLK_UART_SCLK + 1)960 961static const struct regmap_config th1520_clk_regmap_config = {962 .reg_bits = 32,963 .val_bits = 32,964 .reg_stride = 4,965 .fast_io = true,966};967 968static int th1520_clk_probe(struct platform_device *pdev)969{970 struct device *dev = &pdev->dev;971 struct clk_hw_onecell_data *priv;972 973 struct regmap *map;974 void __iomem *base;975 struct clk_hw *hw;976 int ret, i;977 978 priv = devm_kzalloc(dev, struct_size(priv, hws, NR_CLKS), GFP_KERNEL);979 if (!priv)980 return -ENOMEM;981 982 priv->num = NR_CLKS;983 984 base = devm_platform_ioremap_resource(pdev, 0);985 if (IS_ERR(base))986 return PTR_ERR(base);987 988 map = devm_regmap_init_mmio(dev, base, &th1520_clk_regmap_config);989 if (IS_ERR(map))990 return PTR_ERR(map);991 992 for (i = 0; i < ARRAY_SIZE(th1520_pll_clks); i++) {993 struct ccu_pll *cp = hw_to_ccu_pll(&th1520_pll_clks[i]->hw);994 995 th1520_pll_clks[i]->map = map;996 997 ret = devm_clk_hw_register(dev, &th1520_pll_clks[i]->hw);998 if (ret)999 return ret;1000 1001 priv->hws[cp->common.clkid] = &cp->common.hw;1002 }1003 1004 for (i = 0; i < ARRAY_SIZE(th1520_div_clks); i++) {1005 struct ccu_div *cd = hw_to_ccu_div(&th1520_div_clks[i]->hw);1006 1007 th1520_div_clks[i]->map = map;1008 1009 ret = devm_clk_hw_register(dev, &th1520_div_clks[i]->hw);1010 if (ret)1011 return ret;1012 1013 priv->hws[cd->common.clkid] = &cd->common.hw;1014 }1015 1016 for (i = 0; i < ARRAY_SIZE(th1520_mux_clks); i++) {1017 struct ccu_mux *cm = hw_to_ccu_mux(&th1520_mux_clks[i]->hw);1018 const struct clk_init_data *init = cm->common.hw.init;1019 1020 th1520_mux_clks[i]->map = map;1021 hw = devm_clk_hw_register_mux_parent_data_table(dev,1022 init->name,1023 init->parent_data,1024 init->num_parents,1025 0,1026 base + cm->common.cfg0,1027 cm->mux.shift,1028 cm->mux.width,1029 0, NULL, NULL);1030 if (IS_ERR(hw))1031 return PTR_ERR(hw);1032 1033 priv->hws[cm->common.clkid] = hw;1034 }1035 1036 for (i = 0; i < ARRAY_SIZE(th1520_gate_clks); i++) {1037 struct ccu_gate *cg = hw_to_ccu_gate(&th1520_gate_clks[i]->hw);1038 1039 th1520_gate_clks[i]->map = map;1040 1041 hw = devm_clk_hw_register_gate_parent_data(dev,1042 cg->common.hw.init->name,1043 cg->common.hw.init->parent_data,1044 0, base + cg->common.cfg0,1045 ffs(cg->enable) - 1, 0, NULL);1046 if (IS_ERR(hw))1047 return PTR_ERR(hw);1048 1049 priv->hws[cg->common.clkid] = hw;1050 }1051 1052 ret = devm_clk_hw_register(dev, &osc12m_clk.hw);1053 if (ret)1054 return ret;1055 priv->hws[CLK_OSC12M] = &osc12m_clk.hw;1056 1057 ret = devm_clk_hw_register(dev, &gmac_pll_clk_100m.hw);1058 if (ret)1059 return ret;1060 priv->hws[CLK_PLL_GMAC_100M] = &gmac_pll_clk_100m.hw;1061 1062 ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv);1063 if (ret)1064 return ret;1065 1066 return 0;1067}1068 1069static const struct of_device_id th1520_clk_match[] = {1070 {1071 .compatible = "thead,th1520-clk-ap",1072 },1073 { /* sentinel */ },1074};1075MODULE_DEVICE_TABLE(of, th1520_clk_match);1076 1077static struct platform_driver th1520_clk_driver = {1078 .probe = th1520_clk_probe,1079 .driver = {1080 .name = "th1520-clk",1081 .of_match_table = th1520_clk_match,1082 },1083};1084module_platform_driver(th1520_clk_driver);1085 1086MODULE_DESCRIPTION("T-HEAD TH1520 AP Clock driver");1087MODULE_AUTHOR("Yangtao Li <frank.li@vivo.com>");1088MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");1089MODULE_LICENSE("GPL");1090