1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * StarFive JH7110 System-Top-Group Clock Driver |
4 | * |
5 | * Copyright (C) 2022 Emil Renner Berthing <kernel@esmil.dk> |
6 | * Copyright (C) 2022 StarFive Technology Co., Ltd. |
7 | */ |
8 | |
9 | #include <linux/clk-provider.h> |
10 | #include <linux/io.h> |
11 | #include <linux/platform_device.h> |
12 | |
13 | #include <dt-bindings/clock/starfive,jh7110-crg.h> |
14 | |
15 | #include "clk-starfive-jh7110.h" |
16 | |
17 | /* external clocks */ |
18 | #define JH7110_STGCLK_OSC (JH7110_STGCLK_END + 0) |
19 | #define JH7110_STGCLK_HIFI4_CORE (JH7110_STGCLK_END + 1) |
20 | #define JH7110_STGCLK_STG_AXIAHB (JH7110_STGCLK_END + 2) |
21 | #define JH7110_STGCLK_USB_125M (JH7110_STGCLK_END + 3) |
22 | #define JH7110_STGCLK_CPU_BUS (JH7110_STGCLK_END + 4) |
23 | #define JH7110_STGCLK_HIFI4_AXI (JH7110_STGCLK_END + 5) |
24 | #define JH7110_STGCLK_NOCSTG_BUS (JH7110_STGCLK_END + 6) |
25 | #define JH7110_STGCLK_APB_BUS (JH7110_STGCLK_END + 7) |
26 | #define JH7110_STGCLK_EXT_END (JH7110_STGCLK_END + 8) |
27 | |
28 | static const struct jh71x0_clk_data jh7110_stgclk_data[] = { |
29 | /* hifi4 */ |
30 | JH71X0_GATE(JH7110_STGCLK_HIFI4_CLK_CORE, "hifi4_clk_core" , 0, |
31 | JH7110_STGCLK_HIFI4_CORE), |
32 | /* usb */ |
33 | JH71X0_GATE(JH7110_STGCLK_USB0_APB, "usb0_apb" , 0, JH7110_STGCLK_APB_BUS), |
34 | JH71X0_GATE(JH7110_STGCLK_USB0_UTMI_APB, "usb0_utmi_apb" , 0, JH7110_STGCLK_APB_BUS), |
35 | JH71X0_GATE(JH7110_STGCLK_USB0_AXI, "usb0_axi" , 0, JH7110_STGCLK_STG_AXIAHB), |
36 | JH71X0_GDIV(JH7110_STGCLK_USB0_LPM, "usb0_lpm" , 0, 2, JH7110_STGCLK_OSC), |
37 | JH71X0_GDIV(JH7110_STGCLK_USB0_STB, "usb0_stb" , 0, 4, JH7110_STGCLK_OSC), |
38 | JH71X0_GATE(JH7110_STGCLK_USB0_APP_125, "usb0_app_125" , 0, JH7110_STGCLK_USB_125M), |
39 | JH71X0__DIV(JH7110_STGCLK_USB0_REFCLK, "usb0_refclk" , 2, JH7110_STGCLK_OSC), |
40 | /* pci-e */ |
41 | JH71X0_GATE(JH7110_STGCLK_PCIE0_AXI_MST0, "pcie0_axi_mst0" , 0, |
42 | JH7110_STGCLK_STG_AXIAHB), |
43 | JH71X0_GATE(JH7110_STGCLK_PCIE0_APB, "pcie0_apb" , 0, JH7110_STGCLK_APB_BUS), |
44 | JH71X0_GATE(JH7110_STGCLK_PCIE0_TL, "pcie0_tl" , 0, JH7110_STGCLK_STG_AXIAHB), |
45 | JH71X0_GATE(JH7110_STGCLK_PCIE1_AXI_MST0, "pcie1_axi_mst0" , 0, |
46 | JH7110_STGCLK_STG_AXIAHB), |
47 | JH71X0_GATE(JH7110_STGCLK_PCIE1_APB, "pcie1_apb" , 0, JH7110_STGCLK_APB_BUS), |
48 | JH71X0_GATE(JH7110_STGCLK_PCIE1_TL, "pcie1_tl" , 0, JH7110_STGCLK_STG_AXIAHB), |
49 | JH71X0_GATE(JH7110_STGCLK_PCIE_SLV_MAIN, "pcie_slv_main" , CLK_IS_CRITICAL, |
50 | JH7110_STGCLK_STG_AXIAHB), |
51 | /* security */ |
52 | JH71X0_GATE(JH7110_STGCLK_SEC_AHB, "sec_ahb" , 0, JH7110_STGCLK_STG_AXIAHB), |
53 | JH71X0_GATE(JH7110_STGCLK_SEC_MISC_AHB, "sec_misc_ahb" , 0, JH7110_STGCLK_STG_AXIAHB), |
54 | /* stg mtrx */ |
55 | JH71X0_GATE(JH7110_STGCLK_GRP0_MAIN, "mtrx_grp0_main" , CLK_IS_CRITICAL, |
56 | JH7110_STGCLK_CPU_BUS), |
57 | JH71X0_GATE(JH7110_STGCLK_GRP0_BUS, "mtrx_grp0_bus" , CLK_IS_CRITICAL, |
58 | JH7110_STGCLK_NOCSTG_BUS), |
59 | JH71X0_GATE(JH7110_STGCLK_GRP0_STG, "mtrx_grp0_stg" , CLK_IS_CRITICAL, |
60 | JH7110_STGCLK_STG_AXIAHB), |
61 | JH71X0_GATE(JH7110_STGCLK_GRP1_MAIN, "mtrx_grp1_main" , CLK_IS_CRITICAL, |
62 | JH7110_STGCLK_CPU_BUS), |
63 | JH71X0_GATE(JH7110_STGCLK_GRP1_BUS, "mtrx_grp1_bus" , CLK_IS_CRITICAL, |
64 | JH7110_STGCLK_NOCSTG_BUS), |
65 | JH71X0_GATE(JH7110_STGCLK_GRP1_STG, "mtrx_grp1_stg" , CLK_IS_CRITICAL, |
66 | JH7110_STGCLK_STG_AXIAHB), |
67 | JH71X0_GATE(JH7110_STGCLK_GRP1_HIFI, "mtrx_grp1_hifi" , CLK_IS_CRITICAL, |
68 | JH7110_STGCLK_HIFI4_AXI), |
69 | /* e24_rvpi */ |
70 | JH71X0_GDIV(JH7110_STGCLK_E2_RTC, "e2_rtc" , 0, 24, JH7110_STGCLK_OSC), |
71 | JH71X0_GATE(JH7110_STGCLK_E2_CORE, "e2_core" , 0, JH7110_STGCLK_STG_AXIAHB), |
72 | JH71X0_GATE(JH7110_STGCLK_E2_DBG, "e2_dbg" , 0, JH7110_STGCLK_STG_AXIAHB), |
73 | /* dw_sgdma1p */ |
74 | JH71X0_GATE(JH7110_STGCLK_DMA1P_AXI, "dma1p_axi" , 0, JH7110_STGCLK_STG_AXIAHB), |
75 | JH71X0_GATE(JH7110_STGCLK_DMA1P_AHB, "dma1p_ahb" , 0, JH7110_STGCLK_STG_AXIAHB), |
76 | }; |
77 | |
78 | static struct clk_hw *jh7110_stgclk_get(struct of_phandle_args *clkspec, void *data) |
79 | { |
80 | struct jh71x0_clk_priv *priv = data; |
81 | unsigned int idx = clkspec->args[0]; |
82 | |
83 | if (idx < JH7110_STGCLK_END) |
84 | return &priv->reg[idx].hw; |
85 | |
86 | return ERR_PTR(error: -EINVAL); |
87 | } |
88 | |
89 | static int jh7110_stgcrg_probe(struct platform_device *pdev) |
90 | { |
91 | struct jh71x0_clk_priv *priv; |
92 | unsigned int idx; |
93 | int ret; |
94 | |
95 | priv = devm_kzalloc(dev: &pdev->dev, struct_size(priv, reg, JH7110_STGCLK_END), |
96 | GFP_KERNEL); |
97 | if (!priv) |
98 | return -ENOMEM; |
99 | |
100 | spin_lock_init(&priv->rmw_lock); |
101 | priv->dev = &pdev->dev; |
102 | priv->base = devm_platform_ioremap_resource(pdev, index: 0); |
103 | if (IS_ERR(ptr: priv->base)) |
104 | return PTR_ERR(ptr: priv->base); |
105 | |
106 | for (idx = 0; idx < JH7110_STGCLK_END; idx++) { |
107 | u32 max = jh7110_stgclk_data[idx].max; |
108 | struct clk_parent_data parents[4] = {}; |
109 | struct clk_init_data init = { |
110 | .name = jh7110_stgclk_data[idx].name, |
111 | .ops = starfive_jh71x0_clk_ops(max), |
112 | .parent_data = parents, |
113 | .num_parents = |
114 | ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, |
115 | .flags = jh7110_stgclk_data[idx].flags, |
116 | }; |
117 | struct jh71x0_clk *clk = &priv->reg[idx]; |
118 | const char *fw_name[JH7110_STGCLK_EXT_END - JH7110_STGCLK_END] = { |
119 | "osc" , |
120 | "hifi4_core" , |
121 | "stg_axiahb" , |
122 | "usb_125m" , |
123 | "cpu_bus" , |
124 | "hifi4_axi" , |
125 | "nocstg_bus" , |
126 | "apb_bus" |
127 | }; |
128 | unsigned int i; |
129 | |
130 | for (i = 0; i < init.num_parents; i++) { |
131 | unsigned int pidx = jh7110_stgclk_data[idx].parents[i]; |
132 | |
133 | if (pidx < JH7110_STGCLK_END) |
134 | parents[i].hw = &priv->reg[pidx].hw; |
135 | else if (pidx < JH7110_STGCLK_EXT_END) |
136 | parents[i].fw_name = fw_name[pidx - JH7110_STGCLK_END]; |
137 | } |
138 | |
139 | clk->hw.init = &init; |
140 | clk->idx = idx; |
141 | clk->max_div = max & JH71X0_CLK_DIV_MASK; |
142 | |
143 | ret = devm_clk_hw_register(dev: &pdev->dev, hw: &clk->hw); |
144 | if (ret) |
145 | return ret; |
146 | } |
147 | |
148 | ret = devm_of_clk_add_hw_provider(dev: &pdev->dev, get: jh7110_stgclk_get, data: priv); |
149 | if (ret) |
150 | return ret; |
151 | |
152 | return jh7110_reset_controller_register(priv, adev_name: "rst-stg" , adev_id: 2); |
153 | } |
154 | |
155 | static const struct of_device_id jh7110_stgcrg_match[] = { |
156 | { .compatible = "starfive,jh7110-stgcrg" }, |
157 | { /* sentinel */ } |
158 | }; |
159 | MODULE_DEVICE_TABLE(of, jh7110_stgcrg_match); |
160 | |
161 | static struct platform_driver jh7110_stgcrg_driver = { |
162 | .probe = jh7110_stgcrg_probe, |
163 | .driver = { |
164 | .name = "clk-starfive-jh7110-stg" , |
165 | .of_match_table = jh7110_stgcrg_match, |
166 | }, |
167 | }; |
168 | module_platform_driver(jh7110_stgcrg_driver); |
169 | |
170 | MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>" ); |
171 | MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>" ); |
172 | MODULE_DESCRIPTION("StarFive JH7110 System-Top-Group clock driver" ); |
173 | MODULE_LICENSE("GPL" ); |
174 | |