1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2017,2018 Emmanuel Vadot <manu@freebsd.org>
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/clk/clk_div.h>
42#include <dev/clk/clk_fixed.h>
43#include <dev/clk/clk_mux.h>
44
45#include <dev/clk/allwinner/aw_ccung.h>
46
47#include <dt-bindings/clock/sun50i-a64-ccu.h>
48#include <dt-bindings/reset/sun50i-a64-ccu.h>
49
50/* Non-exported clocks */
51
52#define	CLK_OSC_12M			0
53#define	CLK_PLL_CPUX			1
54#define	CLK_PLL_AUDIO_BASE		2
55#define	CLK_PLL_AUDIO		3
56#define	CLK_PLL_AUDIO_2X		4
57#define	CLK_PLL_AUDIO_4X		5
58#define	CLK_PLL_AUDIO_8X		6
59#define	CLK_PLL_VIDEO0		7
60#define	CLK_PLL_VIDEO0_2X		8
61#define	CLK_PLL_VE			9
62#define	CLK_PLL_DDR0		10
63#define	CLK_PLL_PERIPH0_2X		12
64#define	CLK_PLL_PERIPH1		13
65#define	CLK_PLL_PERIPH1_2X		14
66#define	CLK_PLL_VIDEO1		15
67#define	CLK_PLL_GPU			16
68#define	CLK_PLL_MIPI		17
69#define	CLK_PLL_HSIC		18
70#define	CLK_PLL_DE			19
71#define	CLK_PLL_DDR1		20
72#define	CLK_CPUX			21
73#define	CLK_AXI			22
74#define	CLK_APB			23
75#define	CLK_AHB1			24
76#define	CLK_APB1			25
77#define	CLK_APB2			26
78#define	CLK_AHB2			27
79#define	CLK_DRAM			94
80
81#define	CLK_MBUS			112
82
83static struct aw_ccung_reset a64_ccu_resets[] = {
84	CCU_RESET(RST_USB_PHY0, 0x0cc, 0)
85	CCU_RESET(RST_USB_PHY1, 0x0cc, 1)
86	CCU_RESET(RST_USB_HSIC, 0x0cc, 2)
87
88	CCU_RESET(RST_BUS_MIPI_DSI, 0x2c0, 1)
89	CCU_RESET(RST_BUS_CE, 0x2c0, 5)
90	CCU_RESET(RST_BUS_DMA, 0x2c0, 6)
91	CCU_RESET(RST_BUS_MMC0, 0x2c0, 8)
92	CCU_RESET(RST_BUS_MMC1, 0x2c0, 9)
93	CCU_RESET(RST_BUS_MMC2, 0x2c0, 10)
94	CCU_RESET(RST_BUS_NAND, 0x2c0, 13)
95	CCU_RESET(RST_BUS_DRAM, 0x2c0, 14)
96	CCU_RESET(RST_BUS_EMAC, 0x2c0, 17)
97	CCU_RESET(RST_BUS_TS, 0x2c0, 18)
98	CCU_RESET(RST_BUS_HSTIMER, 0x2c0, 19)
99	CCU_RESET(RST_BUS_SPI0, 0x2c0, 20)
100	CCU_RESET(RST_BUS_SPI1, 0x2c0, 21)
101	CCU_RESET(RST_BUS_OTG, 0x2c0, 23)
102	CCU_RESET(RST_BUS_EHCI0, 0x2c0, 24)
103	CCU_RESET(RST_BUS_EHCI1, 0x2c0, 25)
104	CCU_RESET(RST_BUS_OHCI0, 0x2c0, 28)
105	CCU_RESET(RST_BUS_OHCI1, 0x2c0, 29)
106
107	CCU_RESET(RST_BUS_VE, 0x2c4, 0)
108	CCU_RESET(RST_BUS_TCON0, 0x2c4, 3)
109	CCU_RESET(RST_BUS_TCON1, 0x2c4, 4)
110	CCU_RESET(RST_BUS_DEINTERLACE, 0x2c4, 5)
111	CCU_RESET(RST_BUS_CSI, 0x2c4, 8)
112	CCU_RESET(RST_BUS_HDMI0, 0x2c4, 10)
113	CCU_RESET(RST_BUS_HDMI1, 0x2c4, 11)
114	CCU_RESET(RST_BUS_DE, 0x2c4, 12)
115	CCU_RESET(RST_BUS_GPU, 0x2c4, 20)
116	CCU_RESET(RST_BUS_MSGBOX, 0x2c4, 21)
117	CCU_RESET(RST_BUS_SPINLOCK, 0x2c4, 22)
118	CCU_RESET(RST_BUS_DBG, 0x2c4, 31)
119
120	CCU_RESET(RST_BUS_LVDS, 0x2C8, 31)
121
122	CCU_RESET(RST_BUS_CODEC, 0x2D0, 0)
123	CCU_RESET(RST_BUS_SPDIF, 0x2D0, 1)
124	CCU_RESET(RST_BUS_THS, 0x2D0, 8)
125	CCU_RESET(RST_BUS_I2S0, 0x2D0, 12)
126	CCU_RESET(RST_BUS_I2S1, 0x2D0, 13)
127	CCU_RESET(RST_BUS_I2S2, 0x2D0, 14)
128
129	CCU_RESET(RST_BUS_I2C0, 0x2D8, 0)
130	CCU_RESET(RST_BUS_I2C1, 0x2D8, 1)
131	CCU_RESET(RST_BUS_I2C2, 0x2D8, 2)
132	CCU_RESET(RST_BUS_SCR, 0x2D8, 5)
133	CCU_RESET(RST_BUS_UART0, 0x2D8, 16)
134	CCU_RESET(RST_BUS_UART1, 0x2D8, 17)
135	CCU_RESET(RST_BUS_UART2, 0x2D8, 18)
136	CCU_RESET(RST_BUS_UART3, 0x2D8, 19)
137	CCU_RESET(RST_BUS_UART4, 0x2D8, 20)
138};
139
140static struct aw_ccung_gate a64_ccu_gates[] = {
141	CCU_GATE(CLK_BUS_MIPI_DSI, "bus-mipi-dsi", "ahb1", 0x60, 1)
142	CCU_GATE(CLK_BUS_CE, "bus-ce", "ahb1", 0x60, 5)
143	CCU_GATE(CLK_BUS_DMA, "bus-dma", "ahb1", 0x60, 6)
144	CCU_GATE(CLK_BUS_MMC0, "bus-mmc0", "ahb1", 0x60, 8)
145	CCU_GATE(CLK_BUS_MMC1, "bus-mmc1", "ahb1", 0x60, 9)
146	CCU_GATE(CLK_BUS_MMC2, "bus-mmc2", "ahb1", 0x60, 10)
147	CCU_GATE(CLK_BUS_NAND, "bus-nand", "ahb1", 0x60, 13)
148	CCU_GATE(CLK_BUS_DRAM, "bus-dram", "ahb1", 0x60, 14)
149	CCU_GATE(CLK_BUS_EMAC, "bus-emac", "ahb2", 0x60, 16)
150	CCU_GATE(CLK_BUS_TS, "bus-ts", "ahb1", 0x60, 18)
151	CCU_GATE(CLK_BUS_HSTIMER, "bus-hstimer", "ahb1", 0x60, 19)
152	CCU_GATE(CLK_BUS_SPI0, "bus-spi0", "ahb1", 0x60, 20)
153	CCU_GATE(CLK_BUS_SPI1, "bus-spi1", "ahb1", 0x60, 21)
154	CCU_GATE(CLK_BUS_OTG, "bus-otg", "ahb1", 0x60, 23)
155	CCU_GATE(CLK_BUS_EHCI0, "bus-ehci0", "ahb1", 0x60, 24)
156	CCU_GATE(CLK_BUS_EHCI1, "bus-ehci1", "ahb2", 0x60, 25)
157	CCU_GATE(CLK_BUS_OHCI0, "bus-ohci0", "ahb1", 0x60, 28)
158	CCU_GATE(CLK_BUS_OHCI1, "bus-ohci1", "ahb2", 0x60, 29)
159
160	CCU_GATE(CLK_BUS_VE, "bus-ve", "ahb1", 0x64, 0)
161	CCU_GATE(CLK_BUS_TCON0, "bus-tcon0", "ahb1", 0x64, 3)
162	CCU_GATE(CLK_BUS_TCON1, "bus-tcon1", "ahb1", 0x64, 4)
163	CCU_GATE(CLK_BUS_DEINTERLACE, "bus-deinterlace", "ahb1", 0x64, 5)
164	CCU_GATE(CLK_BUS_CSI, "bus-csi", "ahb1", 0x64, 8)
165	CCU_GATE(CLK_BUS_HDMI, "bus-hdmi", "ahb1", 0x64, 11)
166	CCU_GATE(CLK_BUS_DE, "bus-de", "ahb1", 0x64, 12)
167	CCU_GATE(CLK_BUS_GPU, "bus-gpu", "ahb1", 0x64, 20)
168	CCU_GATE(CLK_BUS_MSGBOX, "bus-msgbox", "ahb1", 0x64, 21)
169	CCU_GATE(CLK_BUS_SPINLOCK, "bus-spinlock", "ahb1", 0x64, 22)
170
171	CCU_GATE(CLK_BUS_CODEC, "bus-codec", "apb1", 0x68, 0)
172	CCU_GATE(CLK_BUS_SPDIF, "bus-spdif", "apb1", 0x68, 1)
173	CCU_GATE(CLK_BUS_PIO, "bus-pio", "apb1", 0x68, 5)
174	CCU_GATE(CLK_BUS_THS, "bus-ths", "apb1", 0x68, 8)
175	CCU_GATE(CLK_BUS_I2S0, "bus-i2s0", "apb1", 0x68, 12)
176	CCU_GATE(CLK_BUS_I2S1, "bus-i2s1", "apb1", 0x68, 13)
177	CCU_GATE(CLK_BUS_I2S2, "bus-i2s2", "apb1", 0x68, 14)
178
179	CCU_GATE(CLK_BUS_I2C0, "bus-i2c0", "apb2", 0x6C, 0)
180	CCU_GATE(CLK_BUS_I2C1, "bus-i2c1", "apb2", 0x6C, 1)
181	CCU_GATE(CLK_BUS_I2C2, "bus-i2c2", "apb2", 0x6C, 2)
182	CCU_GATE(CLK_BUS_SCR, "bus-src", "apb2", 0x6C, 5)
183	CCU_GATE(CLK_BUS_UART0, "bus-uart0", "apb2", 0x6C, 16)
184	CCU_GATE(CLK_BUS_UART1, "bus-uart1", "apb2", 0x6C, 17)
185	CCU_GATE(CLK_BUS_UART2, "bus-uart2", "apb2", 0x6C, 18)
186	CCU_GATE(CLK_BUS_UART3, "bus-uart3", "apb2", 0x6C, 19)
187	CCU_GATE(CLK_BUS_UART4, "bus-uart4", "apb2", 0x6C, 20)
188
189	CCU_GATE(CLK_BUS_DBG, "bus-dbg", "ahb1", 0x70, 7)
190
191	CCU_GATE(CLK_THS, "ths", "thsdiv", 0x74, 31)
192
193	CCU_GATE(CLK_USB_PHY0, "usb-phy0", "osc24M", 0xcc, 8)
194	CCU_GATE(CLK_USB_PHY1, "usb-phy1", "osc24M", 0xcc, 9)
195	CCU_GATE(CLK_USB_HSIC, "usb-hsic", "pll_hsic", 0xcc, 10)
196	CCU_GATE(CLK_USB_HSIC_12M, "usb-hsic-12M", "osc12M", 0xcc, 11)
197	CCU_GATE(CLK_USB_OHCI0, "usb-ohci0", "osc12M", 0xcc, 16)
198	CCU_GATE(CLK_USB_OHCI1, "usb-ohci1", "usb-ohci0", 0xcc, 17)
199
200	CCU_GATE(CLK_DRAM_VE, "dram-ve", "dram", 0x100, 0)
201	CCU_GATE(CLK_DRAM_CSI, "dram-csi", "dram", 0x100, 1)
202	CCU_GATE(CLK_DRAM_DEINTERLACE, "dram-deinterlace", "dram", 0x100, 2)
203	CCU_GATE(CLK_DRAM_TS, "dram-ts", "dram", 0x100, 3)
204
205	CCU_GATE(CLK_CSI_MISC, "csi-misc", "osc24M", 0x130, 31)
206
207	CCU_GATE(CLK_AC_DIG_4X, "ac-dig-4x", "pll_audio-4x", 0x140, 30)
208	CCU_GATE(CLK_AC_DIG, "ac-dig", "pll_audio", 0x140, 31)
209
210	CCU_GATE(CLK_AVS, "avs", "osc24M", 0x144, 31)
211
212	CCU_GATE(CLK_HDMI_DDC, "hdmi-ddc", "osc24M", 0x154, 31)
213};
214
215static const char *osc12m_parents[] = {"osc24M"};
216FIXED_CLK(osc12m_clk,
217    CLK_OSC_12M,			/* id */
218    "osc12M",				/* name */
219    osc12m_parents,			/* parent */
220    0,					/* freq */
221    1,					/* mult */
222    2,					/* div */
223    0);					/* flags */
224
225static const char *pll_cpux_parents[] = {"osc24M"};
226NKMP_CLK(pll_cpux_clk,
227    CLK_PLL_CPUX,				/* id */
228    "pll_cpux", pll_cpux_parents,		/* name, parents */
229    0x00,					/* offset */
230    8, 5, 0, 0,					/* n factor */
231    4, 2, 0, 0,					/* k factor */
232    0, 2, 0, 0,					/* m factor */
233    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* p factor */
234    31,						/* gate */
235    28, 1000,					/* lock */
236    AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK | AW_CLK_SCALE_CHANGE);		/* flags */
237
238static const char *pll_audio_parents[] = {"osc24M"};
239NKMP_CLK(pll_audio_clk,
240    CLK_PLL_AUDIO,				/* id */
241    "pll_audio", pll_audio_parents,		/* name, parents */
242    0x08,					/* offset */
243    8, 7, 0, 0,					/* n factor */
244    0, 0, 1, AW_CLK_FACTOR_FIXED,		/* k factor (fake) */
245    0, 5, 0, 0,					/* m factor */
246    16, 4, 0, 0,				/* p factor */
247    31,						/* gate */
248    28, 1000,					/* lock */
249    AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK);		/* flags */
250
251static const char *pll_audio_mult_parents[] = {"pll_audio"};
252FIXED_CLK(pll_audio_2x_clk,
253    CLK_PLL_AUDIO_2X,			/* id */
254    "pll_audio-2x",			/* name */
255    pll_audio_mult_parents,		/* parent */
256    0,					/* freq */
257    2,					/* mult */
258    1,					/* div */
259    0);					/* flags */
260FIXED_CLK(pll_audio_4x_clk,
261    CLK_PLL_AUDIO_4X,			/* id */
262    "pll_audio-4x",			/* name */
263    pll_audio_mult_parents,		/* parent */
264    0,					/* freq */
265    4,					/* mult */
266    1,					/* div */
267    0);					/* flags */
268FIXED_CLK(pll_audio_8x_clk,
269    CLK_PLL_AUDIO_8X,			/* id */
270    "pll_audio-8x",			/* name */
271    pll_audio_mult_parents,		/* parent */
272    0,					/* freq */
273    8,					/* mult */
274    1,					/* div */
275    0);					/* flags */
276
277static const char *pll_video0_parents[] = {"osc24M"};
278FRAC_CLK(pll_video0_clk,
279    CLK_PLL_VIDEO0,				/* id */
280    "pll_video0", pll_video0_parents,		/* name, parents */
281    0x10,					/* offset */
282    8, 7, 0, 0,					/* n factor */
283    0, 4, 0, 0,					/* m factor */
284    31, 28, 1000,				/* gate, lock, lock retries */
285    AW_CLK_HAS_LOCK,				/* flags */
286    270000000, 297000000,			/* freq0, freq1 */
287    24, 25,					/* mode sel, freq sel */
288    192000000, 600000000);			/* min freq, max freq */
289static const char *pll_video0_2x_parents[] = {"pll_video0"};
290FIXED_CLK(pll_video0_2x_clk,
291    CLK_PLL_VIDEO0_2X,			/* id */
292    "pll_video0-2x",			/* name */
293    pll_video0_2x_parents,		/* parent */
294    0,					/* freq */
295    2,					/* mult */
296    1,					/* div */
297    0);					/* flags */
298
299static const char *pll_ve_parents[] = {"osc24M"};
300FRAC_CLK(pll_ve_clk,
301    CLK_PLL_VE,					/* id */
302    "pll_ve", pll_ve_parents,			/* name, parents */
303    0x18,					/* offset */
304    8, 7, 0, 0,					/* n factor */
305    0, 4, 0, 0,					/* m factor */
306    31, 28, 1000,				/* gate, lock, lock retries */
307    AW_CLK_HAS_LOCK,				/* flags */
308    270000000, 297000000,			/* freq0, freq1 */
309    24, 25,					/* mode sel, freq sel */
310    192000000, 600000000);			/* min freq, max freq */
311
312static const char *pll_ddr0_parents[] = {"osc24M"};
313NKMP_CLK_WITH_UPDATE(pll_ddr0_clk,
314    CLK_PLL_DDR0,				/* id */
315    "pll_ddr0", pll_ddr0_parents,		/* name, parents */
316    0x20,					/* offset */
317    8, 5, 0, 0,					/* n factor */
318    4, 2, 0, 0,					/* k factor */
319    0, 2, 0, 0,					/* m factor */
320    0, 0, 1, AW_CLK_FACTOR_FIXED,		/* p factor (fake) */
321    31,						/* gate */
322    28, 1000,					/* lock */
323    20,						/* update */
324    AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK);		/* flags */
325
326static const char *pll_periph0_2x_parents[] = {"osc24M"};
327static const char *pll_periph0_parents[] = {"pll_periph0_2x"};
328NKMP_CLK(pll_periph0_2x_clk,
329    CLK_PLL_PERIPH0_2X,				/* id */
330    "pll_periph0_2x", pll_periph0_2x_parents,	/* name, parents */
331    0x28,					/* offset */
332    8, 5, 0, 0,					/* n factor */
333    4, 2, 0, 0,					/* k factor */
334    0, 0, 2, AW_CLK_FACTOR_FIXED,		/* m factor (fake) */
335    0, 0, 1, AW_CLK_FACTOR_FIXED,		/* p factor (fake) */
336    31,						/* gate */
337    28, 1000,					/* lock */
338    AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK);		/* flags */
339FIXED_CLK(pll_periph0_clk,
340    CLK_PLL_PERIPH0,			/* id */
341    "pll_periph0",			/* name */
342    pll_periph0_parents,		/* parent */
343    0,					/* freq */
344    1,					/* mult */
345    2,					/* div */
346    0);					/* flags */
347
348static const char *pll_periph1_2x_parents[] = {"osc24M"};
349static const char *pll_periph1_parents[] = {"pll_periph1_2x"};
350NKMP_CLK(pll_periph1_2x_clk,
351    CLK_PLL_PERIPH1_2X,				/* id */
352    "pll_periph1_2x", pll_periph1_2x_parents,	/* name, parents */
353    0x2C,					/* offset */
354    8, 5, 0, 0,					/* n factor */
355    4, 2, 0, 0,					/* k factor */
356    0, 0, 2, AW_CLK_FACTOR_FIXED,		/* m factor (fake) */
357    0, 0, 1, AW_CLK_FACTOR_FIXED,		/* p factor (fake) */
358    31,						/* gate */
359    28, 1000,					/* lock */
360    AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK);		/* flags */
361FIXED_CLK(pll_periph1_clk,
362    CLK_PLL_PERIPH1,			/* id */
363    "pll_periph1",			/* name */
364    pll_periph1_parents,		/* parent */
365    0,					/* freq */
366    1,					/* mult */
367    2,					/* div */
368    0);					/* flags */
369
370static const char *pll_video1_parents[] = {"osc24M"};
371FRAC_CLK(pll_video1_clk,
372    CLK_PLL_VIDEO1,				/* id */
373    "pll_video1", pll_video1_parents,		/* name, parents */
374    0x30,					/* offset */
375    8, 7, 0, 0,					/* n factor */
376    0, 4, 0, 0,					/* m factor */
377    31, 28, 1000,				/* gate, lock, lock retries */
378    AW_CLK_HAS_LOCK,				/* flags */
379    270000000, 297000000,			/* freq0, freq1 */
380    24, 25,					/* mode sel, freq sel */
381    192000000, 600000000);			/* min freq, max freq */
382
383static const char *pll_gpu_parents[] = {"osc24M"};
384FRAC_CLK(pll_gpu_clk,
385    CLK_PLL_GPU,				/* id */
386    "pll_gpu", pll_gpu_parents,			/* name, parents */
387    0x38,					/* offset */
388    8, 7, 0, 0,					/* n factor */
389    0, 4, 0, 0,					/* m factor */
390    31, 28, 1000,				/* gate, lock, lock retries */
391    AW_CLK_HAS_LOCK,				/* flags */
392    270000000, 297000000,			/* freq0, freq1 */
393    24, 25,					/* mode sel, freq sel */
394    192000000, 600000000);			/* min freq, max freq */
395
396static const char *pll_mipi_parents[] = {"pll_video0"};
397MIPI_CLK(pll_mipi_clk,
398  CLK_PLL_MIPI,
399  "pll_mipi", pll_mipi_parents,
400  0x40,
401  4, 2, AW_CLK_FACTOR_MIN_VALUE, 2,
402  0, 3,
403  8, 4,
404  31, 28);
405
406static const char *pll_hsic_parents[] = {"osc24M"};
407FRAC_CLK(pll_hsic_clk,
408    CLK_PLL_HSIC,				/* id */
409    "pll_hsic", pll_hsic_parents,		/* name, parents */
410    0x44,					/* offset */
411    8, 7, 0, 0,					/* n factor */
412    0, 4, 0, 0,					/* m factor */
413    31, 28, 1000,				/* gate, lock, lock retries */
414    AW_CLK_HAS_LOCK,				/* flags */
415    270000000, 297000000,			/* freq0, freq1 */
416    24, 25,					/* mode sel, freq sel */
417    192000000, 600000000);			/* min freq, max freq */
418
419static const char *pll_de_parents[] = {"osc24M"};
420FRAC_CLK(pll_de_clk,
421    CLK_PLL_DE,					/* id */
422    "pll_de", pll_de_parents,			/* name, parents */
423    0x48,					/* offset */
424    8, 7, 0, 0,					/* n factor */
425    0, 4, 0, 0,					/* m factor */
426    31, 28, 1000,				/* gate, lock, lock retries */
427    AW_CLK_HAS_LOCK,				/* flags */
428    270000000, 297000000,			/* freq0, freq1 */
429    24, 25,					/* mode sel, freq sel */
430    192000000, 600000000);			/* min freq, max freq */
431
432static const char *pll_ddr1_parents[] = {"osc24M"};
433NKMP_CLK_WITH_UPDATE(pll_ddr1_clk,
434    CLK_PLL_DDR1,				/* id */
435    "pll_ddr1", pll_ddr1_parents,		/* name, parents */
436    0x4C,					/* offset */
437    8, 7, 0, 0,					/* n factor */
438    0, 0, 1, AW_CLK_FACTOR_FIXED,		/* k factor (fake) */
439    0, 2, 0, 0,					/* m factor */
440    0, 0, 1, AW_CLK_FACTOR_FIXED,		/* p factor (fake) */
441    31,						/* gate */
442    28, 1000,					/* lock */
443    20,						/* update */
444    AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK);		/* flags */
445
446static const char *cpux_parents[] = {"osc32k", "osc24M", "pll_cpux"};
447MUX_CLK(cpux_clk,
448    CLK_CPUX,			/* id */
449    "cpux", cpux_parents,	/* name, parents */
450    0x50, 16, 2);		/* offset, shift, width */
451
452static const char *axi_parents[] = {"cpux"};
453DIV_CLK(axi_clk,
454    CLK_AXI,			/* id */
455    "axi", axi_parents,		/* name, parents */
456    0x50,			/* offset */
457    0, 2,			/* shift, width */
458    0, NULL);			/* flags, div table */
459
460static const char *apb_parents[] = {"cpux"};
461DIV_CLK(apb_clk,
462    CLK_APB,			/* id */
463    "apb", apb_parents,		/* name, parents */
464    0x50,			/* offset */
465    8, 2,			/* shift, width */
466    0, NULL);			/* flags, div table */
467
468static const char *ahb1_parents[] = {"osc32k", "osc24M", "axi", "pll_periph0"};
469PREDIV_CLK(ahb1_clk, CLK_AHB1,					/* id */
470    "ahb1", ahb1_parents,					/* name, parents */
471    0x54,							/* offset */
472    12, 2,							/* mux */
473    4, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,			/* div */
474    6, 2, 0, AW_CLK_FACTOR_HAS_COND,				/* prediv */
475    12, 2, 3);							/* prediv condition */
476
477static const char *apb1_parents[] = {"ahb1"};
478static struct clk_div_table apb1_div_table[] = {
479	{ .value = 0, .divider = 2, },
480	{ .value = 1, .divider = 2, },
481	{ .value = 2, .divider = 4, },
482	{ .value = 3, .divider = 8, },
483	{ },
484};
485DIV_CLK(apb1_clk,
486    CLK_APB1,			/* id */
487    "apb1", apb1_parents,	/* name, parents */
488    0x54,			/* offset */
489    8, 2,			/* shift, width */
490    CLK_DIV_WITH_TABLE,		/* flags */
491    apb1_div_table);		/* div table */
492
493static const char *apb2_parents[] = {"osc32k", "osc24M", "pll_periph0_2x", "pll_periph0_2x"};
494NM_CLK(apb2_clk,
495    CLK_APB2,					/* id */
496    "apb2", apb2_parents,			/* name, parents */
497    0x58,					/* offset */
498    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
499    0, 5, 0, 0,					/* m factor */
500    24, 2,					/* mux */
501    0,						/* gate */
502    AW_CLK_HAS_MUX);
503
504static const char *ahb2_parents[] = {"ahb1", "pll_periph0"};
505PREDIV_CLK(ahb2_clk, CLK_AHB2,					/* id */
506    "ahb2", ahb2_parents,					/* name, parents */
507    0x5c,							/* offset */
508    0, 2,							/* mux */
509    0, 0, 1, AW_CLK_FACTOR_FIXED,				/* div */
510    0, 0, 2, AW_CLK_FACTOR_HAS_COND | AW_CLK_FACTOR_FIXED,	/* prediv */
511    0, 2, 1);							/* prediv condition */
512
513static const char *ths_parents[] = {"osc24M"};
514static struct clk_div_table ths_div_table[] = {
515	{ .value = 0, .divider = 1, },
516	{ .value = 1, .divider = 2, },
517	{ .value = 2, .divider = 4, },
518	{ .value = 3, .divider = 6, },
519	{ },
520};
521DIV_CLK(ths_clk,
522    0,				/* id */
523    "thsdiv", ths_parents,	/* name, parents */
524    0x74,			/* offset */
525    0, 2,			/* div shift, div width */
526    CLK_DIV_WITH_TABLE,		/* flags */
527    ths_div_table);		/* div table */
528
529static const char *mod_parents[] = {"osc24M", "pll_periph0_2x", "pll_periph1_2x"};
530NM_CLK(nand_clk,
531    CLK_NAND, "nand", mod_parents,		/* id, name, parents */
532    0x80,					/* offset */
533    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
534    0, 4, 0, 0,					/* m factor */
535    24, 2,					/* mux */
536    31,						/* gate */
537    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX);		/* flags */
538
539NM_CLK(mmc0_clk,
540    CLK_MMC0, "mmc0", mod_parents,		/* id, name, parents */
541    0x88,					/* offset */
542    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
543    0, 4, 0, 0,					/* m factor */
544    24, 2,					/* mux */
545    31,						/* gate */
546    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
547    AW_CLK_REPARENT);				/* flags */
548
549NM_CLK(mmc1_clk,
550    CLK_MMC1, "mmc1", mod_parents,		/* id, name, parents */
551    0x8c,					/* offset */
552    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
553    0, 4, 0, 0,					/* m factor */
554    24, 2,					/* mux */
555    31,						/* gate */
556    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
557    AW_CLK_REPARENT);				/* flags */
558
559NM_CLK(mmc2_clk,
560    CLK_MMC2, "mmc2", mod_parents,		/* id, name, parents */
561    0x90,					/* offset */
562    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
563    0, 4, 0, 0,					/* m factor */
564    24, 2,					/* mux */
565    31,						/* gate */
566    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
567    AW_CLK_REPARENT);				/* flags */
568
569static const char *ts_parents[] = {"osc24M", "pll_periph0"};
570NM_CLK(ts_clk,
571    CLK_TS, "ts", ts_parents,			/* id, name, parents */
572    0x98,					/* offset */
573    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
574    0, 4, 0, 0,					/* m factor */
575    24, 2,					/* mux */
576    31,						/* gate */
577    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX);		/* flags */
578
579NM_CLK(ce_clk,
580    CLK_CE, "ce", mod_parents,			/* id, name, parents */
581    0x9C,					/* offset */
582    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
583    0, 4, 0, 0,					/* m factor */
584    24, 2,					/* mux */
585    31,						/* gate */
586    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX);		/* flags */
587
588NM_CLK(spi0_clk,
589    CLK_SPI0, "spi0", mod_parents,		/* id, name, parents */
590    0xA0,					/* offset */
591    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
592    0, 4, 0, 0,					/* m factor */
593    24, 2,					/* mux */
594    31,						/* gate */
595    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
596    AW_CLK_REPARENT);				/* flags */
597
598NM_CLK(spi1_clk,
599    CLK_SPI1, "spi1", mod_parents,		/* id, name, parents */
600    0xA4,					/* offset */
601    16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO,	/* n factor */
602    0, 4, 0, 0,					/* m factor */
603    24, 2,					/* mux */
604    31,						/* gate */
605    AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
606    AW_CLK_REPARENT);				/* flags */
607
608static const char *i2s_parents[] = {"pll_audio-8x", "pll_audio-4x", "pll_audio-2x", "pll_audio"};
609MUX_CLK(i2s0mux_clk,
610    0, "i2s0mux", i2s_parents,			/* id, name, parents */
611    0xb0, 16, 2);				/* offset, mux shift, mux width */
612MUX_CLK(i2s1mux_clk,
613    0, "i2s1mux", i2s_parents,			/* id, name, parents */
614    0xb4, 16, 2);				/* offset, mux shift, mux width */
615MUX_CLK(i2s2mux_clk,
616    0, "i2s2mux", i2s_parents,			/* id, name, parents */
617    0xb8, 16, 2);				/* offset, mux shift, mux width */
618
619static const char *spdif_parents[] = {"pll_audio"};
620M_CLK(spdif_clk,
621    CLK_SPDIF, "spdif", spdif_parents,		/* id, name, parents */
622    0xC0,					/* offset */
623    0, 4, 0, 0,					/* m factor */
624    0, 0,					/* mux */
625    31,						/* gate */
626    AW_CLK_HAS_GATE);				/* flags */
627
628/* USBPHY clk sel */
629
630/* DRAM needs update bit */
631static const char *dram_parents[] = {"pll_ddr0", "pll_ddr1"};
632M_CLK(dram_clk,
633    CLK_DRAM, "dram", dram_parents,		/* id, name, parents */
634    0xF4,					/* offset */
635    0, 2, 0, 0,					/* m factor */
636    20, 2,					/* mux */
637    0,						/* gate */
638    AW_CLK_HAS_MUX);				/* flags */
639
640static const char *de_parents[] = {"pll_periph0_2x", "pll_de"};
641M_CLK(de_clk,
642    CLK_DE, "de", de_parents,			/* id, name, parents */
643    0x104,					/* offset */
644    0, 4, 0, 0,					/* m factor */
645    24, 2,					/* mux */
646    31,						/* gate */
647    AW_CLK_HAS_MUX | AW_CLK_HAS_GATE);		/* flags */
648
649static const char *tcon0_parents[] = {"pll_mipi", NULL, "pll_video0-2x"};
650MUX_CLK(tcon0_clk,
651    CLK_TCON0,			/* id */
652    "tcon0", tcon0_parents,	/* name, parents */
653    0x118, 24, 2);		/* offset, shift, width */
654
655static const char *tcon1_parents[] = {"pll_video0", NULL, "pll_video1"};
656M_CLK(tcon1_clk,
657    CLK_TCON1, "tcon1", tcon1_parents,	/* id, name, parents */
658    0x11C,				/* offset */
659    0, 5, 0, 0,				/* m factor */
660    24, 2,				/* mux */
661    31,					/* gate */
662    AW_CLK_HAS_MUX | AW_CLK_HAS_GATE |
663    AW_CLK_SET_PARENT);			/* flags */
664
665static const char *deinterlace_parents[] = {"pll_periph0", "pll_periph1"};
666M_CLK(deinterlace_clk,
667    CLK_DEINTERLACE, "deinterlace", deinterlace_parents,	/* id, name, parents */
668    0x124,					/* offset */
669    0, 4, 0, 0,					/* m factor */
670    24, 2,					/* mux */
671    31,						/* gate */
672    AW_CLK_HAS_MUX | AW_CLK_HAS_GATE);		/* flags */
673
674static const char *csi_sclk_parents[] = {"pll_periph0", "pll_periph1"};
675M_CLK(csi_sclk_clk,
676    CLK_CSI_SCLK, "csi-sclk", csi_sclk_parents,	/* id, name, parents */
677    0x134,					/* offset */
678    16, 4, 0, 0,				/* m factor */
679    24, 2,					/* mux */
680    31,						/* gate */
681    AW_CLK_HAS_MUX | AW_CLK_HAS_GATE);		/* flags */
682
683static const char *csi_mclk_parents[] = {"osc24M", "pll_video0", "pll_periph1"};
684M_CLK(csi_mclk_clk,
685    CLK_CSI_MCLK, "csi-mclk", csi_mclk_parents,	/* id, name, parents */
686    0x134,					/* offset */
687    0, 4, 0, 0,					/* m factor */
688    8, 2,					/* mux */
689    15,						/* gate */
690    AW_CLK_HAS_MUX | AW_CLK_HAS_GATE);		/* flags */
691
692static const char *ve_parents[] = {"pll_ve"};
693M_CLK(ve_clk,
694    CLK_VE, "ve", ve_parents,			/* id, name, parents */
695    0x13C,					/* offset */
696    16, 3, 0, 0,				/* m factor */
697    0, 0,					/* mux */
698    31,						/* gate */
699    AW_CLK_HAS_GATE);				/* flags */
700
701static const char *hdmi_parents[] = {"pll_video0"};
702M_CLK(hdmi_clk,
703    CLK_HDMI, "hdmi", hdmi_parents,		/* id, name, parents */
704    0x150,					/* offset */
705    0, 4, 0, 0,					/* m factor */
706    24, 2,					/* mux */
707    31,						/* gate */
708    AW_CLK_HAS_MUX | AW_CLK_HAS_GATE | AW_CLK_SET_PARENT);		/* flags */
709
710static const char *mbus_parents[] = {"osc24M", "pll_periph0_2x", "pll_ddr0"};
711M_CLK(mbus_clk,
712    CLK_MBUS, "mbus", mbus_parents,		/* id, name, parents */
713    0x15C,					/* offset */
714    0, 3, 0, 0,					/* m factor */
715    24, 2,					/* mux */
716    31,						/* gate */
717    AW_CLK_HAS_MUX | AW_CLK_HAS_GATE);		/* flags */
718
719static const char *gpu_parents[] = {"pll_gpu"};
720M_CLK(gpu_clk,
721    CLK_GPU, "gpu", gpu_parents,		/* id, name, parents */
722    0x1A0,					/* offset */
723    0, 2, 0, 0,					/* m factor */
724    0, 0,					/* mux */
725    31,						/* gate */
726    AW_CLK_HAS_GATE);				/* flags */
727
728static struct aw_ccung_clk a64_ccu_clks[] = {
729	{ .type = AW_CLK_NKMP, .clk.nkmp = &pll_cpux_clk},
730	{ .type = AW_CLK_NKMP, .clk.nkmp = &pll_audio_clk},
731	{ .type = AW_CLK_FRAC, .clk.frac = &pll_video0_clk},
732	{ .type = AW_CLK_FRAC, .clk.frac = &pll_ve_clk},
733	{ .type = AW_CLK_NKMP, .clk.nkmp = &pll_ddr0_clk},
734	{ .type = AW_CLK_NKMP, .clk.nkmp = &pll_periph0_2x_clk},
735	{ .type = AW_CLK_NKMP, .clk.nkmp = &pll_periph1_2x_clk},
736	{ .type = AW_CLK_FRAC, .clk.frac = &pll_video1_clk},
737	{ .type = AW_CLK_FRAC, .clk.frac = &pll_gpu_clk},
738	{ .type = AW_CLK_MIPI, .clk.mipi = &pll_mipi_clk},
739	{ .type = AW_CLK_FRAC, .clk.frac = &pll_hsic_clk},
740	{ .type = AW_CLK_FRAC, .clk.frac = &pll_de_clk},
741	{ .type = AW_CLK_NKMP, .clk.nkmp = &pll_ddr1_clk},
742
743	{ .type = AW_CLK_NM, .clk.nm = &apb2_clk},
744	{ .type = AW_CLK_NM, .clk.nm = &nand_clk},
745	{ .type = AW_CLK_NM, .clk.nm = &mmc0_clk},
746	{ .type = AW_CLK_NM, .clk.nm = &mmc1_clk},
747	{ .type = AW_CLK_NM, .clk.nm = &mmc2_clk},
748	{ .type = AW_CLK_NM, .clk.nm = &ts_clk},
749	{ .type = AW_CLK_NM, .clk.nm = &ce_clk},
750	{ .type = AW_CLK_NM, .clk.nm = &spi0_clk},
751	{ .type = AW_CLK_NM, .clk.nm = &spi1_clk},
752	{ .type = AW_CLK_M, .clk.m = &spdif_clk},
753	{ .type = AW_CLK_M, .clk.m = &dram_clk},
754	{ .type = AW_CLK_M, .clk.m = &de_clk},
755	{ .type = AW_CLK_M, .clk.m = &tcon1_clk},
756	{ .type = AW_CLK_M, .clk.m = &deinterlace_clk},
757	{ .type = AW_CLK_M, .clk.m = &csi_sclk_clk},
758	{ .type = AW_CLK_M, .clk.m = &csi_mclk_clk},
759	{ .type = AW_CLK_M, .clk.m = &ve_clk},
760	{ .type = AW_CLK_M, .clk.m = &hdmi_clk},
761	{ .type = AW_CLK_M, .clk.m = &mbus_clk},
762	{ .type = AW_CLK_M, .clk.m = &gpu_clk},
763	{ .type = AW_CLK_PREDIV_MUX, .clk.prediv_mux = &ahb1_clk},
764	{ .type = AW_CLK_PREDIV_MUX, .clk.prediv_mux = &ahb2_clk},
765	{ .type = AW_CLK_MUX, .clk.mux = &cpux_clk},
766	{ .type = AW_CLK_MUX, .clk.mux = &i2s0mux_clk},
767	{ .type = AW_CLK_MUX, .clk.mux = &i2s1mux_clk},
768	{ .type = AW_CLK_MUX, .clk.mux = &i2s2mux_clk},
769	{ .type = AW_CLK_MUX, .clk.mux = &tcon0_clk},
770	{ .type = AW_CLK_DIV, .clk.div = &axi_clk},
771	{ .type = AW_CLK_DIV, .clk.div = &apb1_clk},
772	{ .type = AW_CLK_DIV, .clk.div = &apb_clk},
773	{ .type = AW_CLK_DIV, .clk.div = &ths_clk},
774	{ .type = AW_CLK_FIXED, .clk.fixed = &osc12m_clk},
775	{ .type = AW_CLK_FIXED, .clk.fixed = &pll_periph0_clk},
776	{ .type = AW_CLK_FIXED, .clk.fixed = &pll_periph1_clk},
777	{ .type = AW_CLK_FIXED, .clk.fixed = &pll_audio_2x_clk},
778	{ .type = AW_CLK_FIXED, .clk.fixed = &pll_audio_4x_clk},
779	{ .type = AW_CLK_FIXED, .clk.fixed = &pll_audio_8x_clk},
780	{ .type = AW_CLK_FIXED, .clk.fixed = &pll_video0_2x_clk},
781};
782
783static struct aw_clk_init a64_init_clks[] = {
784	{"ahb1", "pll_periph0", 0, false},
785	{"ahb2", "pll_periph0", 0, false},
786	{"dram", "pll_ddr0", 0, false},
787	{"pll_de", NULL, 432000000, true},
788	{"de", "pll_de", 0, true},
789};
790
791static int
792ccu_a64_probe(device_t dev)
793{
794
795	if (!ofw_bus_status_okay(dev))
796		return (ENXIO);
797
798	if (!ofw_bus_is_compatible(dev, "allwinner,sun50i-a64-ccu"))
799		return (ENXIO);
800
801	device_set_desc(dev, "Allwinner A64 Clock Control Unit NG");
802	return (BUS_PROBE_DEFAULT);
803}
804
805static int
806ccu_a64_attach(device_t dev)
807{
808	struct aw_ccung_softc *sc;
809
810	sc = device_get_softc(dev);
811
812	sc->resets = a64_ccu_resets;
813	sc->nresets = nitems(a64_ccu_resets);
814	sc->gates = a64_ccu_gates;
815	sc->ngates = nitems(a64_ccu_gates);
816	sc->clks = a64_ccu_clks;
817	sc->nclks = nitems(a64_ccu_clks);
818	sc->clk_init = a64_init_clks;
819	sc->n_clk_init = nitems(a64_init_clks);
820
821	return (aw_ccung_attach(dev));
822}
823
824static device_method_t ccu_a64ng_methods[] = {
825	/* Device interface */
826	DEVMETHOD(device_probe,		ccu_a64_probe),
827	DEVMETHOD(device_attach,	ccu_a64_attach),
828
829	DEVMETHOD_END
830};
831
832DEFINE_CLASS_1(ccu_a64ng, ccu_a64ng_driver, ccu_a64ng_methods,
833  sizeof(struct aw_ccung_softc), aw_ccung_driver);
834
835EARLY_DRIVER_MODULE(ccu_a64ng, simplebus, ccu_a64ng_driver, 0, 0,
836    BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
837