sun9i_a80_ccu.c revision 1.1.2.2 1 /* $NetBSD: sun9i_a80_ccu.c,v 1.1.2.2 2017/12/03 11:35:56 jdolecek Exp $ */
2
3 /*-
4 * Copyright (c) 2017 Jared McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30
31 __KERNEL_RCSID(1, "$NetBSD: sun9i_a80_ccu.c,v 1.1.2.2 2017/12/03 11:35:56 jdolecek Exp $");
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/device.h>
36 #include <sys/systm.h>
37
38 #include <dev/fdt/fdtvar.h>
39
40 #include <arm/sunxi/sunxi_ccu.h>
41 #include <arm/sunxi/sun9i_a80_ccu.h>
42
43 /* CCU */
44 #define PLL_PERIPH0_CTRL_REG 0x00c
45 #define PLL_PERIPH1_CTRL_REG 0x02c
46 #define GTBUS_CLK_CFG_REG 0x05c
47 #define AHB0_CLK_CFG_REG 0x060
48 #define AHB1_CLK_CFG_REG 0x064
49 #define AHB2_CLK_CFG_REG 0x068
50 #define APB0_CLK_CFG_REG 0x070
51 #define APB1_CLK_CFG_REG 0x074
52
53 /* CCU_SCLK */
54 #define SDMMC0_CLK_REG 0x410
55 #define SDMMC1_CLK_REG 0x414
56 #define SDMMC2_CLK_REG 0x418
57 #define BUS_CLK_GATING_REG0 0x580
58 #define BUS_CLK_GATING_REG1 0x584
59 #define BUS_CLK_GATING_REG2 0x588
60 #define BUS_CLK_GATING_REG3 0x590
61 #define BUS_CLK_GATING_REG4 0x594
62 #define BUS_SOFT_RST_REG0 0x5a0
63 #define BUS_SOFT_RST_REG1 0x5a4
64 #define BUS_SOFT_RST_REG2 0x5a8
65 #define BUS_SOFT_RST_REG3 0x5b0
66 #define BUS_SOFT_RST_REG4 0x5b4
67
68 static int sun9i_a80_ccu_match(device_t, cfdata_t, void *);
69 static void sun9i_a80_ccu_attach(device_t, device_t, void *);
70
71 static const char * compatible[] = {
72 "allwinner,sun9i-a80-ccu",
73 NULL
74 };
75
76 CFATTACH_DECL_NEW(sunxi_a80_ccu, sizeof(struct sunxi_ccu_softc),
77 sun9i_a80_ccu_match, sun9i_a80_ccu_attach, NULL, NULL);
78
79 static struct sunxi_ccu_reset sun9i_a80_ccu_resets[] = {
80 SUNXI_CCU_RESET(A80_RST_BUS_FD, BUS_SOFT_RST_REG0, 0),
81 SUNXI_CCU_RESET(A80_RST_BUS_GPU_CTRL, BUS_SOFT_RST_REG0, 3),
82 SUNXI_CCU_RESET(A80_RST_BUS_SS, BUS_SOFT_RST_REG0, 5),
83 SUNXI_CCU_RESET(A80_RST_BUS_MMC, BUS_SOFT_RST_REG0, 8),
84 SUNXI_CCU_RESET(A80_RST_BUS_NAND1, BUS_SOFT_RST_REG0, 12),
85 SUNXI_CCU_RESET(A80_RST_BUS_NAND0, BUS_SOFT_RST_REG0, 13),
86 SUNXI_CCU_RESET(A80_RST_BUS_TS, BUS_SOFT_RST_REG0, 18),
87 SUNXI_CCU_RESET(A80_RST_BUS_SPI0, BUS_SOFT_RST_REG0, 20),
88 SUNXI_CCU_RESET(A80_RST_BUS_SPI1, BUS_SOFT_RST_REG0, 21),
89 SUNXI_CCU_RESET(A80_RST_BUS_SPI2, BUS_SOFT_RST_REG0, 22),
90 SUNXI_CCU_RESET(A80_RST_BUS_SPI3, BUS_SOFT_RST_REG0, 23),
91
92 SUNXI_CCU_RESET(A80_RST_BUS_OTG_PHY, BUS_SOFT_RST_REG1, 1),
93 SUNXI_CCU_RESET(A80_RST_BUS_MSGBOX, BUS_SOFT_RST_REG1, 21),
94 SUNXI_CCU_RESET(A80_RST_BUS_SPINLOCK, BUS_SOFT_RST_REG1, 22),
95 SUNXI_CCU_RESET(A80_RST_BUS_HSTIMER, BUS_SOFT_RST_REG1, 23),
96 SUNXI_CCU_RESET(A80_RST_BUS_DMA, BUS_SOFT_RST_REG1, 24),
97
98 SUNXI_CCU_RESET(A80_RST_BUS_LCD0, BUS_SOFT_RST_REG2, 0),
99 SUNXI_CCU_RESET(A80_RST_BUS_LCD1, BUS_SOFT_RST_REG2, 1),
100 SUNXI_CCU_RESET(A80_RST_BUS_CSI, BUS_SOFT_RST_REG2, 4),
101 SUNXI_CCU_RESET(A80_RST_BUS_DE, BUS_SOFT_RST_REG2, 7),
102 SUNXI_CCU_RESET(A80_RST_BUS_MP, BUS_SOFT_RST_REG2, 8),
103 SUNXI_CCU_RESET(A80_RST_BUS_GPU, BUS_SOFT_RST_REG2, 9),
104
105 SUNXI_CCU_RESET(A80_RST_BUS_LRADC, BUS_SOFT_RST_REG3, 15),
106 SUNXI_CCU_RESET(A80_RST_BUS_GPADC, BUS_SOFT_RST_REG3, 17),
107
108 SUNXI_CCU_RESET(A80_RST_BUS_I2C0, BUS_SOFT_RST_REG4, 0),
109 SUNXI_CCU_RESET(A80_RST_BUS_I2C1, BUS_SOFT_RST_REG4, 1),
110 SUNXI_CCU_RESET(A80_RST_BUS_I2C2, BUS_SOFT_RST_REG4, 2),
111 SUNXI_CCU_RESET(A80_RST_BUS_I2C3, BUS_SOFT_RST_REG4, 3),
112 SUNXI_CCU_RESET(A80_RST_BUS_I2C4, BUS_SOFT_RST_REG4, 4),
113 SUNXI_CCU_RESET(A80_RST_BUS_UART0, BUS_SOFT_RST_REG4, 16),
114 SUNXI_CCU_RESET(A80_RST_BUS_UART1, BUS_SOFT_RST_REG4, 17),
115 SUNXI_CCU_RESET(A80_RST_BUS_UART2, BUS_SOFT_RST_REG4, 18),
116 SUNXI_CCU_RESET(A80_RST_BUS_UART3, BUS_SOFT_RST_REG4, 19),
117 SUNXI_CCU_RESET(A80_RST_BUS_UART4, BUS_SOFT_RST_REG4, 20),
118 SUNXI_CCU_RESET(A80_RST_BUS_UART5, BUS_SOFT_RST_REG4, 21),
119 };
120
121 static const char *gtbus_parents[] = { "hosc", "pll_periph0", "pll_periph1" };
122 static const char *ahb0_parents[] = { "gtbus", "pll_periph0", "pll_periph1" };
123 static const char *ahb1_parents[] = { "gtbus", "pll_periph0", "pll_periph1" };
124 static const char *ahb2_parents[] = { "hosc", "pll_periph0", "pll_periph1" };
125 static const char *apb_parents[] = { "hosc", "pll_periph0" };
126 static const char *mmc_parents[] = { "hosc", "pll_periph0" };
127
128 static struct sunxi_ccu_clk sun9i_a80_ccu_clks[] = {
129 SUNXI_CCU_NKMP(A80_CLK_PLL_PERIPH0, "pll_periph0", "hosc",
130 PLL_PERIPH0_CTRL_REG, /* reg */
131 __BITS(15,8), /* n */
132 __BIT(16), /* k */
133 0, /* m */
134 __BIT(18), /* p */
135 __BIT(31), /* enable */
136 SUNXI_CCU_NKMP_FACTOR_N_EXACT),
137 SUNXI_CCU_NKMP(A80_CLK_PLL_PERIPH1, "pll_periph1", "hosc",
138 PLL_PERIPH1_CTRL_REG, /* reg */
139 __BITS(15,8), /* n */
140 __BIT(16), /* k */
141 0, /* m */
142 __BIT(18), /* p */
143 __BIT(31), /* enable */
144 SUNXI_CCU_NKMP_FACTOR_N_EXACT),
145
146 SUNXI_CCU_DIV(A80_CLK_GTBUS, "gtbus", gtbus_parents,
147 GTBUS_CLK_CFG_REG, /* reg */
148 __BITS(1,0), /* div */
149 __BITS(25,24), /* sel */
150 0),
151
152 SUNXI_CCU_DIV(A80_CLK_AHB0, "ahb0", ahb0_parents,
153 AHB0_CLK_CFG_REG, /* reg */
154 __BITS(1,0), /* div */
155 __BITS(25,24), /* sel */
156 SUNXI_CCU_DIV_POWER_OF_TWO),
157
158 SUNXI_CCU_DIV(A80_CLK_AHB1, "ahb1", ahb1_parents,
159 AHB1_CLK_CFG_REG, /* reg */
160 __BITS(1,0), /* div */
161 __BITS(25,24), /* sel */
162 SUNXI_CCU_DIV_POWER_OF_TWO),
163
164 SUNXI_CCU_DIV(A80_CLK_AHB2, "ahb2", ahb2_parents,
165 AHB2_CLK_CFG_REG, /* reg */
166 __BITS(1,0), /* div */
167 __BITS(25,24), /* sel */
168 SUNXI_CCU_DIV_POWER_OF_TWO),
169
170 SUNXI_CCU_DIV(A80_CLK_APB0, "apb0", apb_parents,
171 APB0_CLK_CFG_REG, /* reg */
172 __BITS(1,0), /* div */
173 __BIT(24), /* sel */
174 SUNXI_CCU_DIV_POWER_OF_TWO),
175
176 SUNXI_CCU_NM(A80_CLK_APB1, "apb1", apb_parents,
177 APB1_CLK_CFG_REG, /* reg */
178 __BITS(17,16), /* n */
179 __BITS(4,0), /* m */
180 __BIT(24), /* sel */
181 0, /* enable */
182 SUNXI_CCU_NM_POWER_OF_TWO),
183
184 SUNXI_CCU_NM(A80_CLK_MMC0, "mmc0", mmc_parents,
185 SDMMC0_CLK_REG, /* reg */
186 __BITS(17,16), /* n */
187 __BITS(3,0), /* m */
188 __BITS(27,24), /* sel */
189 __BIT(31), /* enable */
190 SUNXI_CCU_NM_POWER_OF_TWO),
191 SUNXI_CCU_PHASE(A80_CLK_MMC0_SAMPLE, "mmc0_sample", "mmc0",
192 SDMMC0_CLK_REG, __BITS(22,20)),
193 SUNXI_CCU_PHASE(A80_CLK_MMC0_OUTPUT, "mmc0_output", "mmc0",
194 SDMMC0_CLK_REG, __BITS(10,8)),
195 SUNXI_CCU_NM(A80_CLK_MMC1, "mmc1", mmc_parents,
196 SDMMC1_CLK_REG, /* reg */
197 __BITS(17,16), /* n */
198 __BITS(3,0), /* m */
199 __BITS(27,24), /* sel */
200 __BIT(31), /* enable */
201 SUNXI_CCU_NM_POWER_OF_TWO),
202 SUNXI_CCU_PHASE(A80_CLK_MMC1_SAMPLE, "mmc1_sample", "mmc1",
203 SDMMC1_CLK_REG, __BITS(22,20)),
204 SUNXI_CCU_PHASE(A80_CLK_MMC1_OUTPUT, "mmc1_output", "mmc1",
205 SDMMC1_CLK_REG, __BITS(10,8)),
206 SUNXI_CCU_NM(A80_CLK_MMC2, "mmc2", mmc_parents,
207 SDMMC2_CLK_REG, /* reg */
208 __BITS(17,16), /* n */
209 __BITS(3,0), /* m */
210 __BITS(27,24), /* sel */
211 __BIT(31), /* enable */
212 SUNXI_CCU_NM_POWER_OF_TWO),
213 SUNXI_CCU_PHASE(A80_CLK_MMC2_SAMPLE, "mmc2_sample", "mmc2",
214 SDMMC2_CLK_REG, __BITS(22,20)),
215 SUNXI_CCU_PHASE(A80_CLK_MMC2_OUTPUT, "mmc2_output", "mmc2",
216 SDMMC2_CLK_REG, __BITS(10,8)),
217
218 SUNXI_CCU_GATE(A80_CLK_BUS_FD, "ahb0-fd", "ahb0",
219 BUS_CLK_GATING_REG0, 0),
220 SUNXI_CCU_GATE(A80_CLK_BUS_GPU_CTRL, "ahb0-gpu-ctrl", "ahb0",
221 BUS_CLK_GATING_REG0, 3),
222 SUNXI_CCU_GATE(A80_CLK_BUS_SS, "ahb0-ss", "ahb0",
223 BUS_CLK_GATING_REG0, 5),
224 SUNXI_CCU_GATE(A80_CLK_BUS_MMC, "ahb0-mmc", "ahb0",
225 BUS_CLK_GATING_REG0, 8),
226 SUNXI_CCU_GATE(A80_CLK_BUS_NAND1, "ahb0-nand1", "ahb0",
227 BUS_CLK_GATING_REG0, 12),
228 SUNXI_CCU_GATE(A80_CLK_BUS_NAND0, "ahb0-nand0", "ahb0",
229 BUS_CLK_GATING_REG0, 13),
230 SUNXI_CCU_GATE(A80_CLK_BUS_TS, "ahb0-ts", "ahb0",
231 BUS_CLK_GATING_REG0, 18),
232 SUNXI_CCU_GATE(A80_CLK_BUS_SPI0, "ahb0-spi0", "ahb0",
233 BUS_CLK_GATING_REG0, 20),
234 SUNXI_CCU_GATE(A80_CLK_BUS_SPI1, "ahb0-spi1", "ahb0",
235 BUS_CLK_GATING_REG0, 21),
236 SUNXI_CCU_GATE(A80_CLK_BUS_SPI2, "ahb0-spi2", "ahb0",
237 BUS_CLK_GATING_REG0, 22),
238 SUNXI_CCU_GATE(A80_CLK_BUS_SPI3, "ahb0-spi3", "ahb0",
239 BUS_CLK_GATING_REG0, 23),
240
241 SUNXI_CCU_GATE(A80_CLK_BUS_USB, "ahb1-usb", "ahb1",
242 BUS_CLK_GATING_REG1, 1),
243 SUNXI_CCU_GATE(A80_CLK_BUS_MSGBOX, "ahb1-msgbox", "ahb1",
244 BUS_CLK_GATING_REG1, 21),
245 SUNXI_CCU_GATE(A80_CLK_BUS_SPINLOCK, "ahb1-spinlock", "ahb1",
246 BUS_CLK_GATING_REG1, 22),
247 SUNXI_CCU_GATE(A80_CLK_BUS_HSTIMER, "ahb1-hstimer", "ahb1",
248 BUS_CLK_GATING_REG1, 23),
249 SUNXI_CCU_GATE(A80_CLK_BUS_DMA, "ahb1-dma", "ahb1",
250 BUS_CLK_GATING_REG1, 24),
251
252 SUNXI_CCU_GATE(A80_CLK_BUS_LCD0, "ahb2-lcd0", "ahb2",
253 BUS_CLK_GATING_REG2, 0),
254 SUNXI_CCU_GATE(A80_CLK_BUS_LCD1, "ahb2-lcd1", "ahb2",
255 BUS_CLK_GATING_REG2, 1),
256 SUNXI_CCU_GATE(A80_CLK_BUS_CSI, "ahb2-csi", "ahb2",
257 BUS_CLK_GATING_REG2, 4),
258 SUNXI_CCU_GATE(A80_CLK_BUS_DE, "ahb2-de", "ahb2",
259 BUS_CLK_GATING_REG2, 7),
260 SUNXI_CCU_GATE(A80_CLK_BUS_MP, "ahb2-mp", "ahb2",
261 BUS_CLK_GATING_REG2, 8),
262
263 SUNXI_CCU_GATE(A80_CLK_BUS_PIO, "apb0-pio", "apb0",
264 BUS_CLK_GATING_REG3, 5),
265 SUNXI_CCU_GATE(A80_CLK_BUS_LRADC, "apb0-lradc", "apb0",
266 BUS_CLK_GATING_REG3, 15),
267 SUNXI_CCU_GATE(A80_CLK_BUS_GPADC, "apb0-gpadc", "apb0",
268 BUS_CLK_GATING_REG3, 17),
269
270 SUNXI_CCU_GATE(A80_CLK_BUS_I2C0, "apb1-i2c0", "apb1",
271 BUS_CLK_GATING_REG4, 0),
272 SUNXI_CCU_GATE(A80_CLK_BUS_I2C1, "apb1-i2c1", "apb1",
273 BUS_CLK_GATING_REG4, 1),
274 SUNXI_CCU_GATE(A80_CLK_BUS_I2C2, "apb1-i2c2", "apb1",
275 BUS_CLK_GATING_REG4, 2),
276 SUNXI_CCU_GATE(A80_CLK_BUS_I2C3, "apb1-i2c3", "apb1",
277 BUS_CLK_GATING_REG4, 3),
278 SUNXI_CCU_GATE(A80_CLK_BUS_I2C4, "apb1-i2c4", "apb1",
279 BUS_CLK_GATING_REG4, 4),
280 SUNXI_CCU_GATE(A80_CLK_BUS_UART0, "apb1-uart0", "apb1",
281 BUS_CLK_GATING_REG4, 16),
282 SUNXI_CCU_GATE(A80_CLK_BUS_UART1, "apb1-uart1", "apb1",
283 BUS_CLK_GATING_REG4, 17),
284 SUNXI_CCU_GATE(A80_CLK_BUS_UART2, "apb1-uart2", "apb1",
285 BUS_CLK_GATING_REG4, 18),
286 SUNXI_CCU_GATE(A80_CLK_BUS_UART3, "apb1-uart3", "apb1",
287 BUS_CLK_GATING_REG4, 19),
288 SUNXI_CCU_GATE(A80_CLK_BUS_UART4, "apb1-uart4", "apb1",
289 BUS_CLK_GATING_REG4, 20),
290 SUNXI_CCU_GATE(A80_CLK_BUS_UART5, "apb1-uart5", "apb1",
291 BUS_CLK_GATING_REG4, 21),
292 };
293
294 static int
295 sun9i_a80_ccu_match(device_t parent, cfdata_t cf, void *aux)
296 {
297 struct fdt_attach_args * const faa = aux;
298
299 return of_match_compatible(faa->faa_phandle, compatible);
300 }
301
302 static void
303 sun9i_a80_ccu_attach(device_t parent, device_t self, void *aux)
304 {
305 struct sunxi_ccu_softc * const sc = device_private(self);
306 struct fdt_attach_args * const faa = aux;
307
308 sc->sc_dev = self;
309 sc->sc_phandle = faa->faa_phandle;
310 sc->sc_bst = faa->faa_bst;
311
312 sc->sc_resets = sun9i_a80_ccu_resets;
313 sc->sc_nresets = __arraycount(sun9i_a80_ccu_resets);
314
315 sc->sc_clks = sun9i_a80_ccu_clks;
316 sc->sc_nclks = __arraycount(sun9i_a80_ccu_clks);
317
318 if (sunxi_ccu_attach(sc) != 0)
319 return;
320
321 aprint_naive("\n");
322 aprint_normal(": A80 CCU\n");
323
324 sunxi_ccu_print(sc);
325 }
326