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