xref: /openbsd-src/sys/arch/armv7/xilinx/zqclock.c (revision 6fd70764649c1845f55fe37082767b24713c0a89)
1*6fd70764Svisa /*	$OpenBSD: zqclock.c,v 1.1 2021/04/30 13:25:24 visa Exp $	*/
2*6fd70764Svisa 
3*6fd70764Svisa /*
4*6fd70764Svisa  * Copyright (c) 2021 Visa Hankala
5*6fd70764Svisa  *
6*6fd70764Svisa  * Permission to use, copy, modify, and/or distribute this software for any
7*6fd70764Svisa  * purpose with or without fee is hereby granted, provided that the above
8*6fd70764Svisa  * copyright notice and this permission notice appear in all copies.
9*6fd70764Svisa  *
10*6fd70764Svisa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*6fd70764Svisa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*6fd70764Svisa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*6fd70764Svisa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*6fd70764Svisa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*6fd70764Svisa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*6fd70764Svisa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*6fd70764Svisa  */
18*6fd70764Svisa 
19*6fd70764Svisa /*
20*6fd70764Svisa  * Driver for Xilinx Zynq-7000 clock controller.
21*6fd70764Svisa  */
22*6fd70764Svisa 
23*6fd70764Svisa #include <sys/param.h>
24*6fd70764Svisa #include <sys/systm.h>
25*6fd70764Svisa #include <sys/device.h>
26*6fd70764Svisa #include <sys/mutex.h>
27*6fd70764Svisa 
28*6fd70764Svisa #include <machine/bus.h>
29*6fd70764Svisa #include <machine/fdt.h>
30*6fd70764Svisa 
31*6fd70764Svisa #include <dev/ofw/fdt.h>
32*6fd70764Svisa #include <dev/ofw/openfirm.h>
33*6fd70764Svisa #include <dev/ofw/ofw_clock.h>
34*6fd70764Svisa #include <dev/ofw/ofw_misc.h>
35*6fd70764Svisa 
36*6fd70764Svisa #include <armv7/xilinx/slcreg.h>
37*6fd70764Svisa 
38*6fd70764Svisa #define CLK_ARM_PLL			0
39*6fd70764Svisa #define CLK_DDR_PLL			1
40*6fd70764Svisa #define CLK_IO_PLL			2
41*6fd70764Svisa #define CLK_CPU_6OR4X			3
42*6fd70764Svisa #define CLK_CPU_3OR2X			4
43*6fd70764Svisa #define CLK_CPU_2X			5
44*6fd70764Svisa #define CLK_CPU_1X			6
45*6fd70764Svisa #define CLK_DDR_2X			7
46*6fd70764Svisa #define CLK_DDR_3X			8
47*6fd70764Svisa #define CLK_DCI				9
48*6fd70764Svisa #define CLK_LQSPI			10
49*6fd70764Svisa #define CLK_SMC				11
50*6fd70764Svisa #define CLK_PCAP			12
51*6fd70764Svisa #define CLK_GEM0			13
52*6fd70764Svisa #define CLK_GEM1			14
53*6fd70764Svisa #define CLK_FCLK0			15
54*6fd70764Svisa #define CLK_FCLK1			16
55*6fd70764Svisa #define CLK_FCLK2			17
56*6fd70764Svisa #define CLK_FCLK3			18
57*6fd70764Svisa #define CLK_CAN0			19
58*6fd70764Svisa #define CLK_CAN1			20
59*6fd70764Svisa #define CLK_SDIO0			21
60*6fd70764Svisa #define CLK_SDIO1			22
61*6fd70764Svisa #define CLK_UART0			23
62*6fd70764Svisa #define CLK_UART1			24
63*6fd70764Svisa #define CLK_SPI0			25
64*6fd70764Svisa #define CLK_SPI1			26
65*6fd70764Svisa #define CLK_DMA				27
66*6fd70764Svisa 
67*6fd70764Svisa struct zqclock_softc {
68*6fd70764Svisa 	struct device		sc_dev;
69*6fd70764Svisa 	struct regmap		*sc_rm;
70*6fd70764Svisa 
71*6fd70764Svisa 	struct clock_device	sc_cd;
72*6fd70764Svisa 	uint32_t		sc_psclk_freq;		/* in Hz */
73*6fd70764Svisa };
74*6fd70764Svisa 
75*6fd70764Svisa int	zqclock_match(struct device *, void *, void *);
76*6fd70764Svisa void	zqclock_attach(struct device *, struct device *, void *);
77*6fd70764Svisa 
78*6fd70764Svisa void	zqclock_enable(void *, uint32_t *, int);
79*6fd70764Svisa uint32_t zqclock_get_frequency(void *, uint32_t *);
80*6fd70764Svisa int	zqclock_set_frequency(void *, uint32_t *, uint32_t);
81*6fd70764Svisa 
82*6fd70764Svisa const struct cfattach zqclock_ca = {
83*6fd70764Svisa 	sizeof(struct zqclock_softc), zqclock_match, zqclock_attach
84*6fd70764Svisa };
85*6fd70764Svisa 
86*6fd70764Svisa struct cfdriver zqclock_cd = {
87*6fd70764Svisa 	NULL, "zqclock", DV_DULL
88*6fd70764Svisa };
89*6fd70764Svisa 
90*6fd70764Svisa struct zqclock_clock {
91*6fd70764Svisa 	uint16_t		clk_ctl_reg;
92*6fd70764Svisa 	uint8_t			clk_has_div1;
93*6fd70764Svisa 	uint8_t			clk_index;
94*6fd70764Svisa };
95*6fd70764Svisa 
96*6fd70764Svisa const struct zqclock_clock zqclock_clocks[] = {
97*6fd70764Svisa 	[CLK_GEM0]		= { SLCR_GEM0_CLK_CTRL, 1, 0 },
98*6fd70764Svisa 	[CLK_GEM1]		= { SLCR_GEM1_CLK_CTRL, 1, 0 },
99*6fd70764Svisa 	[CLK_SDIO0]		= { SLCR_SDIO_CLK_CTRL, 0, 0 },
100*6fd70764Svisa 	[CLK_SDIO1]		= { SLCR_SDIO_CLK_CTRL, 0, 1 },
101*6fd70764Svisa 	[CLK_UART0]		= { SLCR_UART_CLK_CTRL, 0, 0 },
102*6fd70764Svisa 	[CLK_UART1]		= { SLCR_UART_CLK_CTRL, 0, 1 },
103*6fd70764Svisa };
104*6fd70764Svisa 
105*6fd70764Svisa int
zqclock_match(struct device * parent,void * match,void * aux)106*6fd70764Svisa zqclock_match(struct device *parent, void *match, void *aux)
107*6fd70764Svisa {
108*6fd70764Svisa 	struct fdt_attach_args *faa = aux;
109*6fd70764Svisa 
110*6fd70764Svisa 	return OF_is_compatible(faa->fa_node, "xlnx,ps7-clkc");
111*6fd70764Svisa }
112*6fd70764Svisa 
113*6fd70764Svisa void
zqclock_attach(struct device * parent,struct device * self,void * aux)114*6fd70764Svisa zqclock_attach(struct device *parent, struct device *self, void *aux)
115*6fd70764Svisa {
116*6fd70764Svisa 	struct fdt_attach_args *faa = aux;
117*6fd70764Svisa 	struct zqclock_softc *sc = (struct zqclock_softc *)self;
118*6fd70764Svisa 
119*6fd70764Svisa 	sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
120*6fd70764Svisa 	if (sc->sc_rm == NULL) {
121*6fd70764Svisa 		printf(": can't get regmap\n");
122*6fd70764Svisa 		return;
123*6fd70764Svisa 	}
124*6fd70764Svisa 
125*6fd70764Svisa 	sc->sc_psclk_freq = OF_getpropint(faa->fa_node, "ps-clk-frequency",
126*6fd70764Svisa 	    33333333);
127*6fd70764Svisa 
128*6fd70764Svisa 	printf(": %u MHz PS clock\n", (sc->sc_psclk_freq + 500000) / 1000000);
129*6fd70764Svisa 
130*6fd70764Svisa 	sc->sc_cd.cd_node = faa->fa_node;
131*6fd70764Svisa 	sc->sc_cd.cd_cookie = sc;
132*6fd70764Svisa 	sc->sc_cd.cd_enable = zqclock_enable;
133*6fd70764Svisa 	sc->sc_cd.cd_get_frequency = zqclock_get_frequency;
134*6fd70764Svisa 	sc->sc_cd.cd_set_frequency = zqclock_set_frequency;
135*6fd70764Svisa 	clock_register(&sc->sc_cd);
136*6fd70764Svisa }
137*6fd70764Svisa 
138*6fd70764Svisa const struct zqclock_clock *
zqclock_get_clock(uint32_t idx)139*6fd70764Svisa zqclock_get_clock(uint32_t idx)
140*6fd70764Svisa {
141*6fd70764Svisa 	const struct zqclock_clock *clock;
142*6fd70764Svisa 
143*6fd70764Svisa 	if (idx >= nitems(zqclock_clocks))
144*6fd70764Svisa 		return NULL;
145*6fd70764Svisa 
146*6fd70764Svisa 	clock = &zqclock_clocks[idx];
147*6fd70764Svisa 	if (clock->clk_ctl_reg == 0)
148*6fd70764Svisa 		return NULL;
149*6fd70764Svisa 
150*6fd70764Svisa 	return clock;
151*6fd70764Svisa }
152*6fd70764Svisa 
153*6fd70764Svisa uint32_t
zqclock_get_pll_frequency(struct zqclock_softc * sc,uint32_t clk_ctrl)154*6fd70764Svisa zqclock_get_pll_frequency(struct zqclock_softc *sc, uint32_t clk_ctrl)
155*6fd70764Svisa {
156*6fd70764Svisa 	uint32_t reg, val;
157*6fd70764Svisa 
158*6fd70764Svisa 	switch (clk_ctrl & SLCR_CLK_CTRL_SRCSEL_MASK) {
159*6fd70764Svisa 	case SLCR_CLK_CTRL_SRCSEL_ARM:
160*6fd70764Svisa 		reg = SLCR_ARM_PLL_CTRL;
161*6fd70764Svisa 		break;
162*6fd70764Svisa 	case SLCR_CLK_CTRL_SRCSEL_DDR:
163*6fd70764Svisa 		reg = SLCR_DDR_PLL_CTRL;
164*6fd70764Svisa 		break;
165*6fd70764Svisa 	default:
166*6fd70764Svisa 		reg = SLCR_IO_PLL_CTRL;
167*6fd70764Svisa 		break;
168*6fd70764Svisa 	}
169*6fd70764Svisa 
170*6fd70764Svisa 	val = zynq_slcr_read(sc->sc_rm, reg);
171*6fd70764Svisa 	return sc->sc_psclk_freq * ((val >> SLCR_PLL_CTRL_FDIV_SHIFT) &
172*6fd70764Svisa 	    SLCR_PLL_CTRL_FDIV_MASK);
173*6fd70764Svisa }
174*6fd70764Svisa 
175*6fd70764Svisa uint32_t
zqclock_get_frequency(void * cookie,uint32_t * cells)176*6fd70764Svisa zqclock_get_frequency(void *cookie, uint32_t *cells)
177*6fd70764Svisa {
178*6fd70764Svisa 	const struct zqclock_clock *clock;
179*6fd70764Svisa 	struct zqclock_softc *sc = cookie;
180*6fd70764Svisa 	uint32_t idx = cells[0];
181*6fd70764Svisa 	uint32_t ctl, div, freq;
182*6fd70764Svisa 
183*6fd70764Svisa 	clock = zqclock_get_clock(idx);
184*6fd70764Svisa 	if (clock == NULL)
185*6fd70764Svisa 		return 0;
186*6fd70764Svisa 
187*6fd70764Svisa 	mtx_enter(&zynq_slcr_lock);
188*6fd70764Svisa 
189*6fd70764Svisa 	ctl = zynq_slcr_read(sc->sc_rm, clock->clk_ctl_reg);
190*6fd70764Svisa 
191*6fd70764Svisa 	div = SLCR_CLK_CTRL_DIVISOR(ctl);
192*6fd70764Svisa 	if (clock->clk_has_div1)
193*6fd70764Svisa 		div *= SLCR_CLK_CTRL_DIVISOR1(ctl);
194*6fd70764Svisa 
195*6fd70764Svisa 	freq = zqclock_get_pll_frequency(sc, ctl);
196*6fd70764Svisa 	freq = (freq + div / 2) / div;
197*6fd70764Svisa 
198*6fd70764Svisa 	mtx_leave(&zynq_slcr_lock);
199*6fd70764Svisa 
200*6fd70764Svisa 	return freq;
201*6fd70764Svisa }
202*6fd70764Svisa 
203*6fd70764Svisa int
zqclock_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)204*6fd70764Svisa zqclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
205*6fd70764Svisa {
206*6fd70764Svisa 	static const uint32_t srcsels[] = {
207*6fd70764Svisa 		SLCR_CLK_CTRL_SRCSEL_IO,
208*6fd70764Svisa 		SLCR_CLK_CTRL_SRCSEL_ARM,
209*6fd70764Svisa 		SLCR_CLK_CTRL_SRCSEL_DDR,
210*6fd70764Svisa 	};
211*6fd70764Svisa 	const struct zqclock_clock *clock;
212*6fd70764Svisa 	struct zqclock_softc *sc = cookie;
213*6fd70764Svisa 	uint32_t idx = cells[0];
214*6fd70764Svisa 	uint32_t best_delta = ~0U;
215*6fd70764Svisa 	uint32_t best_div1 = 0;
216*6fd70764Svisa 	uint32_t best_si = 0;
217*6fd70764Svisa 	uint32_t best_pllf = 0;
218*6fd70764Svisa 	uint32_t ctl, div, div1, maxdiv1, si;
219*6fd70764Svisa 	int error = 0;
220*6fd70764Svisa 
221*6fd70764Svisa 	clock = zqclock_get_clock(idx);
222*6fd70764Svisa 	if (clock == NULL)
223*6fd70764Svisa 		return EINVAL;
224*6fd70764Svisa 
225*6fd70764Svisa 	if (freq == 0)
226*6fd70764Svisa 		return EINVAL;
227*6fd70764Svisa 
228*6fd70764Svisa 	mtx_enter(&zynq_slcr_lock);
229*6fd70764Svisa 
230*6fd70764Svisa 	maxdiv1 = 1;
231*6fd70764Svisa 	if (clock->clk_has_div1)
232*6fd70764Svisa 		maxdiv1 = SLCR_DIV_MASK;
233*6fd70764Svisa 
234*6fd70764Svisa 	/* Find PLL and divisors that give best frequency. */
235*6fd70764Svisa 	for (si = 0; si < nitems(srcsels); si++) {
236*6fd70764Svisa 		uint32_t delta, f, pllf;
237*6fd70764Svisa 
238*6fd70764Svisa 		pllf = zqclock_get_pll_frequency(sc, srcsels[si]);
239*6fd70764Svisa 		if (freq > pllf)
240*6fd70764Svisa 			continue;
241*6fd70764Svisa 
242*6fd70764Svisa 		for (div1 = 1; div1 <= maxdiv1; div1++) {
243*6fd70764Svisa 			div = (pllf + (freq * div1 / 2)) / (freq * div1);
244*6fd70764Svisa 			if (div > SLCR_DIV_MASK)
245*6fd70764Svisa 				continue;
246*6fd70764Svisa 			if (div == 0)
247*6fd70764Svisa 				break;
248*6fd70764Svisa 
249*6fd70764Svisa 			f = (pllf + (div * div1 / 2)) / (div * div1);
250*6fd70764Svisa 			delta = abs(f - freq);
251*6fd70764Svisa 			if (best_div1 == 0 || delta < best_delta) {
252*6fd70764Svisa 				best_delta = delta;
253*6fd70764Svisa 				best_div1 = div1;
254*6fd70764Svisa 				best_pllf = pllf;
255*6fd70764Svisa 				best_si = si;
256*6fd70764Svisa 
257*6fd70764Svisa 				if (delta == 0)
258*6fd70764Svisa 					goto found;
259*6fd70764Svisa 			}
260*6fd70764Svisa 		}
261*6fd70764Svisa 	}
262*6fd70764Svisa 
263*6fd70764Svisa 	if (best_div1 == 0) {
264*6fd70764Svisa 		error = EINVAL;
265*6fd70764Svisa 		goto out;
266*6fd70764Svisa 	}
267*6fd70764Svisa 
268*6fd70764Svisa found:
269*6fd70764Svisa 	div1 = best_div1;
270*6fd70764Svisa 	div = (best_pllf + (freq * div1 / 2)) / (freq * div1);
271*6fd70764Svisa 
272*6fd70764Svisa 	KASSERT(div > 0 && div <= SLCR_DIV_MASK);
273*6fd70764Svisa 	KASSERT(div1 > 0 && div1 <= SLCR_DIV_MASK);
274*6fd70764Svisa 
275*6fd70764Svisa 	ctl = zynq_slcr_read(sc->sc_rm, clock->clk_ctl_reg);
276*6fd70764Svisa 
277*6fd70764Svisa 	ctl &= ~SLCR_CLK_CTRL_SRCSEL_MASK;
278*6fd70764Svisa 	ctl |= srcsels[best_si];
279*6fd70764Svisa 	ctl &= ~(SLCR_DIV_MASK << SLCR_CLK_CTRL_DIVISOR_SHIFT);
280*6fd70764Svisa 	ctl |= (div & SLCR_DIV_MASK) << SLCR_CLK_CTRL_DIVISOR_SHIFT;
281*6fd70764Svisa 	if (clock->clk_has_div1) {
282*6fd70764Svisa 		ctl &= ~(SLCR_DIV_MASK << SLCR_CLK_CTRL_DIVISOR1_SHIFT);
283*6fd70764Svisa 		ctl |= (div1 & SLCR_DIV_MASK) << SLCR_CLK_CTRL_DIVISOR1_SHIFT;
284*6fd70764Svisa 	}
285*6fd70764Svisa 
286*6fd70764Svisa 	zynq_slcr_write(sc->sc_rm, clock->clk_ctl_reg, ctl);
287*6fd70764Svisa 
288*6fd70764Svisa out:
289*6fd70764Svisa 	mtx_leave(&zynq_slcr_lock);
290*6fd70764Svisa 
291*6fd70764Svisa 	return error;
292*6fd70764Svisa }
293*6fd70764Svisa 
294*6fd70764Svisa void
zqclock_enable(void * cookie,uint32_t * cells,int on)295*6fd70764Svisa zqclock_enable(void *cookie, uint32_t *cells, int on)
296*6fd70764Svisa {
297*6fd70764Svisa 	const struct zqclock_clock *clock;
298*6fd70764Svisa 	struct zqclock_softc *sc = cookie;
299*6fd70764Svisa 	uint32_t idx = cells[0];
300*6fd70764Svisa 	uint32_t ctl;
301*6fd70764Svisa 
302*6fd70764Svisa 	clock = zqclock_get_clock(idx);
303*6fd70764Svisa 	if (clock == NULL)
304*6fd70764Svisa 		return;
305*6fd70764Svisa 
306*6fd70764Svisa 	mtx_enter(&zynq_slcr_lock);
307*6fd70764Svisa 
308*6fd70764Svisa 	ctl = zynq_slcr_read(sc->sc_rm, clock->clk_ctl_reg);
309*6fd70764Svisa 	if (on)
310*6fd70764Svisa 		ctl |= SLCR_CLK_CTRL_CLKACT(clock->clk_index);
311*6fd70764Svisa 	else
312*6fd70764Svisa 		ctl &= ~SLCR_CLK_CTRL_CLKACT(clock->clk_index);
313*6fd70764Svisa 	zynq_slcr_write(sc->sc_rm, clock->clk_ctl_reg, ctl);
314*6fd70764Svisa 
315*6fd70764Svisa 	mtx_leave(&zynq_slcr_lock);
316*6fd70764Svisa }
317