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