1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2020 frank@allwinnertech.com
4 */
5
6 #include <linux/clk-provider.h>
7 #include <linux/module.h>
8 #include <linux/of_address.h>
9 #include <linux/platform_device.h>
10
11 #include "ccu_common.h"
12 #include "ccu_reset.h"
13
14 #include "ccu_div.h"
15 #include "ccu_gate.h"
16 #include "ccu_mp.h"
17 #include "ccu_nm.h"
18
19 #include "ccu-sun50iw12-r.h"
20
21
22 static const char * const cpus_r_apb_parents[] = { "dcxo24M", "osc32k",
23 "iosc", "pll-periph0" };
24 static const struct ccu_mux_var_prediv cpus_r_apb_predivs[] = {
25 { .index = 3, .shift = 0, .width = 5 },
26 };
27
28 static struct ccu_div cpus_clk = {
29 .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
30
31 .mux = {
32 .shift = 24,
33 .width = 2,
34
35 .var_predivs = cpus_r_apb_predivs,
36 .n_var_predivs = ARRAY_SIZE(cpus_r_apb_predivs),
37 },
38
39 .common = {
40 .reg = 0x000,
41 .features = CCU_FEATURE_VARIABLE_PREDIV,
42 .hw.init = CLK_HW_INIT_PARENTS("cpus",
43 cpus_r_apb_parents,
44 &ccu_div_ops,
45 0),
46 },
47 };
48
49 static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb", &cpus_clk.common.hw, 1, 1, 0);
50
51 static struct ccu_div r_apb0_clk = {
52 .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
53
54 .mux = {
55 .shift = 24,
56 .width = 2,
57
58 .var_predivs = cpus_r_apb_predivs,
59 .n_var_predivs = ARRAY_SIZE(cpus_r_apb_predivs),
60 },
61
62 .common = {
63 .reg = 0x0C,
64 .features = CCU_FEATURE_VARIABLE_PREDIV,
65 .hw.init = CLK_HW_INIT_PARENTS("r-apb0",
66 cpus_r_apb_parents,
67 &ccu_div_ops,
68 0),
69 },
70 };
71
72 static struct ccu_div r_apb1_clk = {
73 .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
74
75 .mux = {
76 .shift = 24,
77 .width = 2,
78
79 .var_predivs = cpus_r_apb_predivs,
80 .n_var_predivs = ARRAY_SIZE(cpus_r_apb_predivs),
81 },
82
83 .common = {
84 .reg = 0x10,
85 .features = CCU_FEATURE_VARIABLE_PREDIV,
86 .hw.init = CLK_HW_INIT_PARENTS("r-apb1",
87 cpus_r_apb_parents,
88 &ccu_div_ops,
89 0),
90 },
91 };
92
93 static const char * const r_timer_parents[] = { "dcxo24M", "iosc",
94 "osc32k", "r-ahb" };
95 static struct ccu_div r_apb0_timer0_clk = {
96 .enable = BIT(0),
97 .div = _SUNXI_CCU_DIV_FLAGS(1, 3, CLK_DIVIDER_POWER_OF_TWO),
98 .mux = _SUNXI_CCU_MUX(4, 2),
99 .common = {
100 .reg = 0x110,
101 .hw.init = CLK_HW_INIT_PARENTS("r-timer0",
102 r_timer_parents,
103 &ccu_div_ops,
104 0),
105 },
106 };
107
108 static struct ccu_div r_apb0_timer1_clk = {
109 .enable = BIT(0),
110 .div = _SUNXI_CCU_DIV_FLAGS(1, 3, CLK_DIVIDER_POWER_OF_TWO),
111 .mux = _SUNXI_CCU_MUX(4, 2),
112 .common = {
113 .reg = 0x114,
114 .hw.init = CLK_HW_INIT_PARENTS("r-timer1",
115 r_timer_parents,
116 &ccu_div_ops,
117 0),
118 },
119 };
120
121 static struct ccu_div r_apb0_timer2_clk = {
122 .enable = BIT(0),
123 .div = _SUNXI_CCU_DIV_FLAGS(1, 3, CLK_DIVIDER_POWER_OF_TWO),
124 .mux = _SUNXI_CCU_MUX(4, 2),
125 .common = {
126 .reg = 0x118,
127 .hw.init = CLK_HW_INIT_PARENTS("r-timer2",
128 r_timer_parents,
129 &ccu_div_ops,
130 0),
131 },
132 };
133 static SUNXI_CCU_GATE(bus_r_apb0_timer0_clk, "bus-r-timer0", "r-apb0",
134 0x11c, BIT(0), 0);
135
136 static SUNXI_CCU_MP_WITH_MUX_GATE(r_apb0_edid_clk, "r-edid",
137 cpus_r_apb_parents, 0x124,
138 0, 5, /* M */
139 8, 2, /* P */
140 24, 2, /* mux */
141 BIT(31), /* gate */
142 0);
143
144 static SUNXI_CCU_GATE(bus_r_apb0_wdt1_clk, "bus-r-wdt1", "r-apb0",
145 0x12c, BIT(0), 0);
146
147 static const char * const r_pwm_parents[] = { "dcxo24M", "osc32k",
148 "iosc" };
149 static SUNXI_CCU_MUX_WITH_GATE(r_apb0_pwm_clk, "r-pwm",
150 r_pwm_parents, 0x130,
151 24, 2, /* mux */
152 BIT(31), /* gate */
153 0);
154
155 static SUNXI_CCU_GATE(bus_r_apb0_pwm_clk, "bus-r-pwm", "r-apb0",
156 0x13c, BIT(0), 0);
157
158 static SUNXI_CCU_GATE(bus_apb1_r_uart_clk, "bus-r-uart", "r-apb1",
159 0x18c, BIT(0), 0);
160 static SUNXI_CCU_GATE(bus_r_apb1_i2c0_clk, "bus-r-i2c0", "r-apb1",
161 0x19c, BIT(0), 0);
162 static SUNXI_CCU_GATE(bus_r_apb1_i2c1_clk, "bus-r-i2c1", "r-apb1",
163 0x19c, BIT(1), 0);
164
165 static SUNXI_CCU_GATE(bus_r_apb1_ppu_clk, "bus-r-ppu", "r-apb1",
166 0x1ac, BIT(0), 0);
167
168 static SUNXI_CCU_GATE(bus_r_apb1_bus_tzma_clk, "bus-r-tzma", "r-apb1",
169 0x1b0, BIT(0), 0);
170
171 static SUNXI_CCU_GATE(bus_r_cpus_bist_clk, "bus-r-cpus_bist", "r-apb1",
172 0x1bc, BIT(0), 0);
173
174 static const char * const r_ir_parents[] = { "osc32k", "dcxo24M" };
175 static SUNXI_CCU_MP_WITH_MUX_GATE(r_apb0_ir_clk, "r-ir",
176 r_ir_parents, 0x1c0,
177 0, 5, /* M */
178 8, 2, /* P */
179 24, 1, /* mux */
180 BIT(31), /* gate */
181 0);
182
183 static SUNXI_CCU_GATE(bus_r_apb0_ir_clk, "bus-r-ir", "r-apb0",
184 0x1cc, BIT(0), 0);
185
186 static SUNXI_CCU_GATE(bus_r_ahb_rtc_clk, "bus-r-rtc", "r-ahb",
187 0x20c, BIT(0), 0);
188
189 static SUNXI_CCU_GATE(bus_r_ahb_cpucfg_clk, "bus-r-cpucfg", "r-ahb",
190 0x22c, BIT(0), 0);
191
192 static struct ccu_common *sun50iw12_r_ccu_clks[] = {
193 &cpus_clk.common,
194 &r_apb0_clk.common,
195 &r_apb1_clk.common,
196 &r_apb0_timer0_clk.common,
197 &r_apb0_timer1_clk.common,
198 &r_apb0_timer2_clk.common,
199 &bus_r_apb0_timer0_clk.common,
200 &r_apb0_edid_clk.common,
201 &bus_r_apb0_wdt1_clk.common,
202 &r_apb0_pwm_clk.common,
203 &bus_r_apb0_pwm_clk.common,
204 &bus_apb1_r_uart_clk.common,
205 &bus_r_apb1_i2c0_clk.common,
206 &bus_r_apb1_i2c1_clk.common,
207 &bus_r_apb1_ppu_clk.common,
208 &bus_r_apb1_bus_tzma_clk.common,
209 &bus_r_cpus_bist_clk.common,
210 &r_apb0_ir_clk.common,
211 &bus_r_apb0_ir_clk.common,
212 &bus_r_ahb_rtc_clk.common,
213 &bus_r_ahb_cpucfg_clk.common,
214 };
215
216 static struct clk_hw_onecell_data sun50iw12_r_hw_clks = {
217 .hws = {
218 [CLK_CPUS] = &cpus_clk.common.hw,
219 [CLK_R_AHB] = &r_ahb_clk.hw,
220 [CLK_R_APB0] = &r_apb0_clk.common.hw,
221 [CLK_R_APB1] = &r_apb1_clk.common.hw,
222 [CLK_R_APB0_TIMER0] = &r_apb0_timer0_clk.common.hw,
223 [CLK_R_APB0_TIMER1] = &r_apb0_timer1_clk.common.hw,
224 [CLK_R_APB0_TIMER2] = &r_apb0_timer2_clk.common.hw,
225 [CLK_R_APB0_BUS_TIMER0] = &bus_r_apb0_timer0_clk.common.hw,
226 [CLK_R_APB0_EDID] = &r_apb0_edid_clk.common.hw,
227 [CLK_R_APB0_BUS_WDT1] = &bus_r_apb0_wdt1_clk.common.hw,
228 [CLK_R_APB0_PWM] = &r_apb0_pwm_clk.common.hw,
229 [CLK_R_APB0_BUS_PWM] = &bus_r_apb0_pwm_clk.common.hw,
230 [CLK_R_APB1_BUS_UART] = &bus_apb1_r_uart_clk.common.hw,
231 [CLK_R_APB1_BUS_I2C0] = &bus_r_apb1_i2c0_clk.common.hw,
232 [CLK_R_APB1_BUS_I2C1] = &bus_r_apb1_i2c1_clk.common.hw,
233 [CLK_R_APB1_BUS_PPU] = &bus_r_apb1_ppu_clk.common.hw,
234 [CLK_R_APB1_BUS_TZMA] = &bus_r_apb1_bus_tzma_clk.common.hw,
235 [CLK_R_CPUS_BUS_BIST] = &bus_r_cpus_bist_clk.common.hw,
236 [CLK_R_APB0_IR] = &r_apb0_ir_clk.common.hw,
237 [CLK_R_APB0_BUS_IR] = &bus_r_apb0_ir_clk.common.hw,
238 [CLK_R_AHB_BUS_RTC] = &bus_r_ahb_rtc_clk.common.hw,
239 [CLK_R_AHB_BUS_CPUCFG] = &bus_r_ahb_cpucfg_clk.common.hw,
240 },
241 .num = CLK_NUMBER,
242 };
243
244 static struct ccu_reset_map sun50iw12_r_ccu_resets[] = {
245 [RST_R_APB0_BUS_TIMER0] = { 0x11c, BIT(16) },
246 [RST_R_APB0_BUS_EDID] = { 0x120, BIT(16) },
247 [RST_R_APB0_BUS_PWM] = { 0x13c, BIT(16) },
248 [RST_R_APB1_BUS_UART0] = { 0x18c, BIT(16) },
249 [RST_R_APB1_BUS_I2C0] = { 0x19c, BIT(16) },
250 [RST_R_APB1_BUS_I2C1] = { 0x19c, BIT(17) },
251 [RST_R_APB1_BUS_PPU] = { 0x1ac, BIT(16) },
252 [RST_R_APB0_BUS_IR_RX] = { 0x1cc, BIT(16) },
253 [RST_R_AHB_BUS_RTC] = { 0x20c, BIT(16) },
254 [RST_R_AHB_BUS_CPUCFG] = { 0x22c, BIT(16) },
255 [RST_R_MODULE] = { 0x260, BIT(0) },
256 };
257
258 static const struct sunxi_ccu_desc sun50iw12_r_ccu_desc = {
259 .ccu_clks = sun50iw12_r_ccu_clks,
260 .num_ccu_clks = ARRAY_SIZE(sun50iw12_r_ccu_clks),
261
262 .hw_clks = &sun50iw12_r_hw_clks,
263
264 .resets = sun50iw12_r_ccu_resets,
265 .num_resets = ARRAY_SIZE(sun50iw12_r_ccu_resets),
266 };
267
of_sun50iw12_r_ccu_init(struct device_node * node)268 static void __init of_sun50iw12_r_ccu_init(struct device_node *node)
269 {
270 void __iomem *reg;
271 int ret;
272
273 reg = of_iomap(node, 0);
274 if (IS_ERR(reg))
275 return;
276
277 ret = sunxi_ccu_probe(node, reg, &sun50iw12_r_ccu_desc);
278 if (ret)
279 return;
280
281 sunxi_ccu_sleep_init(reg, sun50iw12_r_ccu_clks,
282 ARRAY_SIZE(sun50iw12_r_ccu_clks),
283 NULL, 0);
284 }
285
286 CLK_OF_DECLARE(sun50iw12_r_ccu_init, "allwinner,sun50iw12-r-ccu", of_sun50iw12_r_ccu_init);
287