1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021, 2022 Soren Schmidt <sos@deepcore.dk>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bus.h>
31 #include <sys/rman.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <machine/bus.h>
35
36 #include <dev/fdt/simplebus.h>
37
38 #include <dev/ofw/ofw_bus.h>
39 #include <dev/ofw/ofw_bus_subr.h>
40
41 #include <dev/extres/clk/clk_div.h>
42 #include <dev/extres/clk/clk_fixed.h>
43 #include <dev/extres/clk/clk_mux.h>
44
45 #include <arm64/rockchip/clk/rk_cru.h>
46 #include <contrib/device-tree/include/dt-bindings/clock/rk3568-cru.h>
47
48
49 #define RK3568_PLLSEL_CON(x) ((x) * 0x20)
50 #define RK3568_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
51 #define RK3568_CLKGATE_CON(x) ((x) * 0x4 + 0x180)
52 #define RK3568_SOFTRST_CON(x) ((x) * 0x4 + 0x200)
53
54 #define PNAME(_name) static const char *_name[]
55
56 /* PLL clock */
57 #define RK_PLL(_id, _name, _pnames, _off, _shift) \
58 { \
59 .type = RK3328_CLK_PLL, \
60 .clk.pll = &(struct rk_clk_pll_def) { \
61 .clkdef.id = _id, \
62 .clkdef.name = _name, \
63 .clkdef.parent_names = _pnames, \
64 .clkdef.parent_cnt = nitems(_pnames), \
65 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
66 .base_offset = RK3568_PLLSEL_CON(_off), \
67 .mode_reg = 0x80, \
68 .mode_shift = _shift, \
69 .rates = rk3568_pll_rates, \
70 }, \
71 }
72
73 /* Composite */
74 #define RK_COMPOSITE(_id, _name, _pnames, _o, _ms, _mw, _ds, _dw, _go, _gw, _f)\
75 { \
76 .type = RK_CLK_COMPOSITE, \
77 .clk.composite = &(struct rk_clk_composite_def) { \
78 .clkdef.id = _id, \
79 .clkdef.name = _name, \
80 .clkdef.parent_names = _pnames, \
81 .clkdef.parent_cnt = nitems(_pnames), \
82 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
83 .muxdiv_offset = RK3568_CLKSEL_CON(_o), \
84 .mux_shift = _ms, \
85 .mux_width = _mw, \
86 .div_shift = _ds, \
87 .div_width = _dw, \
88 .gate_offset = RK3568_CLKGATE_CON(_go), \
89 .gate_shift = _gw, \
90 .flags = RK_CLK_COMPOSITE_HAVE_MUX | \
91 RK_CLK_COMPOSITE_HAVE_GATE | _f, \
92 }, \
93 }
94
95 /* Composite no mux */
96 #define RK_COMPNOMUX(_id, _name, _pname, _o, _ds, _dw, _go, _gw, _f) \
97 { \
98 .type = RK_CLK_COMPOSITE, \
99 .clk.composite = &(struct rk_clk_composite_def) { \
100 .clkdef.id = _id, \
101 .clkdef.name = _name, \
102 .clkdef.parent_names = (const char *[]){_pname}, \
103 .clkdef.parent_cnt = 1, \
104 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
105 .muxdiv_offset = RK3568_CLKSEL_CON(_o), \
106 .div_shift = _ds, \
107 .div_width = _dw, \
108 .gate_offset = RK3568_CLKGATE_CON(_go), \
109 .gate_shift = _gw, \
110 .flags = RK_CLK_COMPOSITE_HAVE_GATE | _f, \
111 }, \
112 }
113
114 /* Fixed factor mux/div */
115 #define RK_FACTOR(_id, _name, _pname, _mult, _div) \
116 { \
117 .type = RK_CLK_FIXED, \
118 .clk.fixed = &(struct clk_fixed_def) { \
119 .clkdef.id = _id, \
120 .clkdef.name = _name, \
121 .clkdef.parent_names = (const char *[]){_pname}, \
122 .clkdef.parent_cnt = 1, \
123 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
124 .mult = _mult, \
125 .div = _div, \
126 }, \
127 }
128
129 /* Fractional */
130 #define RK_FRACTION(_id, _name, _pname, _o, _go, _gw, _f) \
131 { \
132 .type = RK_CLK_FRACT, \
133 .clk.fract = &(struct rk_clk_fract_def) { \
134 .clkdef.id = _id, \
135 .clkdef.name = _name, \
136 .clkdef.parent_names = (const char *[]){_pname}, \
137 .clkdef.parent_cnt = 1, \
138 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
139 .offset = RK3568_CLKSEL_CON(_o), \
140 .gate_offset = RK3568_CLKGATE_CON(_go), \
141 .gate_shift = _gw, \
142 .flags = RK_CLK_FRACT_HAVE_GATE | _f, \
143 }, \
144 }
145
146 /* Multiplexer */
147 #define RK_MUX(_id, _name, _pnames, _o, _ms, _mw, _f) \
148 { \
149 .type = RK_CLK_MUX, \
150 .clk.mux = &(struct rk_clk_mux_def) { \
151 .clkdef.id = _id, \
152 .clkdef.name = _name, \
153 .clkdef.parent_names = _pnames, \
154 .clkdef.parent_cnt = nitems(_pnames), \
155 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
156 .offset = RK3568_CLKSEL_CON(_o), \
157 .shift = _ms, \
158 .width = _mw, \
159 .mux_flags = _f, \
160 }, \
161 }
162
163 #define RK_GATE(_id, _name, _pname, _o, _s) \
164 { \
165 .id = _id, \
166 .name = _name, \
167 .parent_name = _pname, \
168 .offset = RK3568_CLKGATE_CON(_o), \
169 .shift = _s, \
170 }
171
172 extern struct rk_clk_pll_rate rk3568_pll_rates[];
173
174 /* Parent clock defines */
175 PNAME(mux_pll_p) = { "xin24m" };
176 PNAME(xin24m_32k_p) = { "xin24m", "clk_rtc_32k" };
177 PNAME(sclk_uart0_p) = { "sclk_uart0_div", "sclk_uart0_frac", "xin24m" };
178 PNAME(clk_rtc32k_pmu_p) = { "clk_32k_pvtm", "xin32k", "clk_rtc32k_frac" };
179 PNAME(ppll_usb480m_cpll_gpll_p) = { "ppll", "usb480m", "cpll", "gpll"};
180 PNAME(clk_usbphy0_ref_p) = { "clk_ref24m", "xin_osc0_usbphy0_g" };
181 PNAME(clk_usbphy1_ref_p) = { "clk_ref24m", "xin_osc0_usbphy1_g" };
182 PNAME(clk_mipidsiphy0_ref_p) = { "clk_ref24m", "xin_osc0_mipidsiphy0_g" };
183 PNAME(clk_mipidsiphy1_ref_p) = { "clk_ref24m", "xin_osc0_mipidsiphy1_g" };
184 PNAME(clk_wifi_p) = { "clk_wifi_osc0", "clk_wifi_div" };
185 PNAME(clk_pciephy0_ref_p) = { "clk_pciephy0_osc0", "clk_pciephy0_div" };
186 PNAME(clk_pciephy1_ref_p) = { "clk_pciephy1_osc0", "clk_pciephy1_div" };
187 PNAME(clk_pciephy2_ref_p) = { "clk_pciephy2_osc0", "clk_pciephy2_div" };
188 PNAME(clk_hdmi_ref_p) = { "hpll", "hpll_ph0" };
189 PNAME(clk_pdpmu_p) = { "ppll", "gpll" };
190 PNAME(clk_pwm0_p) = { "xin24m", "clk_pdpmu" };
191
192 /* CLOCKS */
193 static struct rk_clk rk3568_clks[] = {
194 /* External clocks */
195 LINK("xin24m"),
196 LINK("cpll"),
197 LINK("gpll"),
198 LINK("usb480m"),
199 LINK("clk_32k_pvtm"),
200
201 /* SRC_CLK */
202 RK_MUX(CLK_RTC_32K, "clk_rtc_32k", clk_rtc32k_pmu_p, 0, 6, 2, 0),
203 RK_MUX(0, "sclk_uart0_mux", sclk_uart0_p, 4, 10, 2, 0),
204
205 /* PLL's */
206 RK_PLL(PLL_PPLL, "ppll", mux_pll_p, 0, 0),
207 RK_PLL(PLL_HPLL, "hpll", mux_pll_p, 2, 2),
208
209 /* PD_PMU */
210 RK_FACTOR(0, "ppll_ph0", "ppll", 1, 2),
211 RK_FACTOR(0, "ppll_ph180", "ppll", 1, 2),
212 RK_FACTOR(0, "hpll_ph0", "hpll", 1, 2),
213 RK_MUX(CLK_PDPMU, "clk_pdpmu", clk_pdpmu_p, 2, 15, 1, 0),
214 RK_COMPNOMUX(PCLK_PDPMU, "pclk_pdpmu", "clk_pdpmu", 2, 0, 5, 0, 2, 0),
215 RK_COMPNOMUX(CLK_I2C0, "clk_i2c0", "clk_pdpmu", 3, 0, 7, 1, 1, 0),
216 RK_FRACTION(CLK_RTC32K_FRAC, "clk_rtc32k_frac", "xin24m", 1, 0, 1, 0),
217 RK_COMPNOMUX(XIN_OSC0_DIV, "xin_osc0_div", "xin24m", 0, 0, 5, 0, 0, 0),
218 RK_COMPOSITE(CLK_UART0_DIV, "sclk_uart0_div",
219 ppll_usb480m_cpll_gpll_p, 4, 8, 2, 0, 7, 1, 3, 0),
220 RK_FRACTION(CLK_UART0_FRAC, "sclk_uart0_frac",
221 "sclk_uart0_div", 5, 1, 4, 0),
222 RK_MUX(DBCLK_GPIO0, "dbclk_gpio0_c", xin24m_32k_p, 6, 15, 1, 0),
223 RK_COMPOSITE(CLK_PWM0, "clk_pwm0", clk_pwm0_p, 6, 7, 1, 0, 7, 1, 7, 0),
224 RK_COMPNOMUX(CLK_REF24M, "clk_ref24m", "clk_pdpmu", 7, 0, 6, 2, 0, 0),
225 RK_MUX(CLK_USBPHY0_REF, "clk_usbphy0_ref",
226 clk_usbphy0_ref_p, 8, 0, 1, 0),
227 RK_MUX(CLK_USBPHY1_REF, "clk_usbphy1_ref",
228 clk_usbphy1_ref_p, 8, 1, 1, 0),
229 RK_MUX(CLK_MIPIDSIPHY0_REF, "clk_mipidsiphy0_ref",
230 clk_mipidsiphy0_ref_p, 8, 2, 1, 0),
231 RK_MUX(CLK_MIPIDSIPHY1_REF, "clk_mipidsiphy1_ref",
232 clk_mipidsiphy1_ref_p, 8, 3, 1, 0),
233 RK_COMPNOMUX(CLK_WIFI_DIV, "clk_wifi_div",
234 "clk_pdpmu", 8, 8, 6, 2, 5, 0),
235 RK_MUX(CLK_WIFI, "clk_wifi", clk_wifi_p, 8, 15, 1, 0),
236 RK_COMPNOMUX(CLK_PCIEPHY0_DIV, "clk_pciephy0_div",
237 "ppll_ph0", 9, 0, 3, 2, 7, 0),
238 RK_MUX(CLK_PCIEPHY0_REF, "clk_pciephy0_ref",
239 clk_pciephy0_ref_p, 9, 3, 1, 0),
240 RK_COMPNOMUX(CLK_PCIEPHY1_DIV, "clk_pciephy1_div",
241 "ppll_ph0", 9, 4, 3, 2, 9, 0),
242 RK_MUX(CLK_PCIEPHY1_REF, "clk_pciephy1_ref",
243 clk_pciephy1_ref_p, 9, 7, 1, 0),
244 RK_COMPNOMUX(CLK_PCIEPHY2_DIV, "clk_pciephy2_div",
245 "ppll_ph0", 9, 8, 3, 2, 11, 0),
246 RK_MUX(CLK_PCIEPHY2_REF, "clk_pciephy2_ref",
247 clk_pciephy2_ref_p, 9, 11, 1, 0),
248 RK_MUX(CLK_HDMI_REF, "clk_hdmi_ref", clk_hdmi_ref_p, 8, 7, 1, 0),
249 };
250
251 /* GATES */
252 static struct rk_cru_gate rk3568_gates[] = {
253 RK_GATE(PCLK_PMU, "pclk_pmu", "pclk_pdpmu", 0, 6),
254 RK_GATE(DBCLK_GPIO0, "dbclk_gpio0", "dbclk_gpio0_c", 1, 10),
255 RK_GATE(CLK_PMU, "clk_pmu", "xin24m", 0, 7),
256 RK_GATE(PCLK_I2C0, "pclk_i2c0", "pclk_pdpmu", 1, 0),
257 RK_GATE(PCLK_UART0, "pclk_uart0", "pclk_pdpmu", 1, 2),
258 RK_GATE(SCLK_UART0, "sclk_uart0", "sclk_uart0_mux", 1, 5),
259 RK_GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pdpmu", 1, 9),
260 RK_GATE(PCLK_PWM0, "pclk_pwm0", "pclk_pdpmu", 1, 6),
261 RK_GATE(CLK_CAPTURE_PWM0_NDFT, "clk_capture_pwm0_ndft", "xin24m", 1, 8),
262 RK_GATE(PCLK_PMUPVTM, "pclk_pmupvtm", "pclk_pdpmu", 1, 11),
263 RK_GATE(CLK_PMUPVTM, "clk_pmupvtm", "xin24m", 1, 12),
264 RK_GATE(CLK_CORE_PMUPVTM, "clk_core_pmupvtm", "xin24m", 1, 13),
265 RK_GATE(XIN_OSC0_USBPHY0_G, "xin_osc0_usbphy0_g", "xin24m", 2, 1),
266 RK_GATE(XIN_OSC0_USBPHY1_G, "xin_osc0_usbphy1_g", "xin24m", 2, 2),
267 RK_GATE(XIN_OSC0_MIPIDSIPHY0_G, "xin_osc0_mipidsiphy0_g",
268 "xin24m", 2, 3),
269 RK_GATE(XIN_OSC0_MIPIDSIPHY1_G, "xin_osc0_mipidsiphy1_g",
270 "xin24m", 2, 4),
271 RK_GATE(CLK_WIFI_OSC0, "clk_wifi_osc0", "xin24m", 2, 6),
272 RK_GATE(CLK_PCIEPHY0_OSC0, "clk_pciephy0_osc0", "xin24m", 2, 8),
273 RK_GATE(CLK_PCIEPHY1_OSC0, "clk_pciephy1_osc0", "xin24m", 2, 10),
274 RK_GATE(CLK_PCIEPHY2_OSC0, "clk_pciephy2_osc0", "xin24m", 2, 12),
275 RK_GATE(CLK_PCIE30PHY_REF_M, "clk_pcie30phy_ref_m", "ppll_ph0", 2, 13),
276 RK_GATE(CLK_PCIE30PHY_REF_N, "clk_pcie30phy_ref_n", "ppll_ph180", 2,14),
277 RK_GATE(XIN_OSC0_EDPPHY_G, "xin_osc0_edpphy_g", "xin24m", 2, 15),
278 };
279
280 static int
281 rk3568_pmucru_probe(device_t dev)
282 {
283
284 if (!ofw_bus_status_okay(dev))
285 return (ENXIO);
286
287 if (ofw_bus_is_compatible(dev, "rockchip,rk3568-pmucru")) {
288 device_set_desc(dev, "Rockchip RK3568 PMU Clock & Reset Unit");
289 return (BUS_PROBE_DEFAULT);
290 }
291
292 return (ENXIO);
293 }
294
295 static int
296 rk3568_pmucru_attach(device_t dev)
297 {
298 struct rk_cru_softc *sc;
299
300 sc = device_get_softc(dev);
301 sc->dev = dev;
302 sc->clks = rk3568_clks;
303 sc->nclks = nitems(rk3568_clks);
304 sc->gates = rk3568_gates;
305 sc->ngates = nitems(rk3568_gates);
306 sc->reset_offset = 0x200;
307 sc->reset_num = 4;
308
309 return (rk_cru_attach(dev));
310 }
311
312 static device_method_t methods[] = {
313 /* Device interface */
314 DEVMETHOD(device_probe, rk3568_pmucru_probe),
315 DEVMETHOD(device_attach, rk3568_pmucru_attach),
316
317 DEVMETHOD_END
318 };
319
320 DEFINE_CLASS_1(rk3568_pmucru, rk3568_pmucru_driver, methods,
321 sizeof(struct rk_cru_softc), rk_cru_driver);
322
323 EARLY_DRIVER_MODULE(rk3568_pmucru, simplebus, rk3568_pmucru_driver,
324 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
Cache object: 4eb4c241344d01ed74f0322828a142ca
|