1*37c734d3Snaddy /* $OpenBSD: hiclock.c,v 1.4 2022/06/28 23:43:12 naddy Exp $ */
20d0b934bSkettenis /*
3b9cecfffSkettenis * Copyright (c) 2018, 2019 Mark Kettenis <kettenis@openbsd.org>
40d0b934bSkettenis *
50d0b934bSkettenis * Permission to use, copy, modify, and distribute this software for any
60d0b934bSkettenis * purpose with or without fee is hereby granted, provided that the above
70d0b934bSkettenis * copyright notice and this permission notice appear in all copies.
80d0b934bSkettenis *
90d0b934bSkettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100d0b934bSkettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110d0b934bSkettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120d0b934bSkettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130d0b934bSkettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140d0b934bSkettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150d0b934bSkettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160d0b934bSkettenis */
170d0b934bSkettenis
180d0b934bSkettenis #include <sys/param.h>
190d0b934bSkettenis #include <sys/systm.h>
200d0b934bSkettenis #include <sys/device.h>
210d0b934bSkettenis
220d0b934bSkettenis #include <machine/intr.h>
230d0b934bSkettenis #include <machine/bus.h>
240d0b934bSkettenis #include <machine/fdt.h>
250d0b934bSkettenis
260d0b934bSkettenis #include <dev/ofw/openfirm.h>
270d0b934bSkettenis #include <dev/ofw/ofw_clock.h>
280d0b934bSkettenis #include <dev/ofw/ofw_misc.h>
290d0b934bSkettenis #include <dev/ofw/fdt.h>
300d0b934bSkettenis
310d0b934bSkettenis #define HREAD4(sc, reg) \
320d0b934bSkettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
330d0b934bSkettenis #define HWRITE4(sc, reg, val) \
340d0b934bSkettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
350d0b934bSkettenis
360d0b934bSkettenis /*
37b9cecfffSkettenis * This driver includes support for the preliminary device tree
38b9cecfffSkettenis * bindings used by the default UEFI firmware for the HiKey970 board.
39b9cecfffSkettenis * Support for these preliminary bindings will be dropped at some
40b9cecfffSkettenis * point in the future.
410d0b934bSkettenis */
420d0b934bSkettenis
430d0b934bSkettenis struct hiclock_softc {
440d0b934bSkettenis struct device sc_dev;
450d0b934bSkettenis bus_space_tag_t sc_iot;
460d0b934bSkettenis bus_space_handle_t sc_ioh;
47b9cecfffSkettenis bus_space_handle_t sc_ioh_set;
480d0b934bSkettenis
490d0b934bSkettenis struct clock_device sc_cd;
500d0b934bSkettenis };
510d0b934bSkettenis
520d0b934bSkettenis int hiclock_match(struct device *, void *, void *);
530d0b934bSkettenis void hiclock_attach(struct device *, struct device *, void *);
540d0b934bSkettenis
559fdf0c62Smpi const struct cfattach hiclock_ca = {
560d0b934bSkettenis sizeof (struct hiclock_softc), hiclock_match, hiclock_attach
570d0b934bSkettenis };
580d0b934bSkettenis
590d0b934bSkettenis struct cfdriver hiclock_cd = {
600d0b934bSkettenis NULL, "hiclock", DV_DULL
610d0b934bSkettenis };
620d0b934bSkettenis
63b9cecfffSkettenis struct hiclock_compat {
64b9cecfffSkettenis const char *compat;
65b9cecfffSkettenis uint32_t (*get_frequency)(void *, uint32_t *);
66b9cecfffSkettenis int (*set_frequency)(void *, uint32_t *, uint32_t);
67b9cecfffSkettenis void (*enable)(void *, uint32_t *, int);
68b9cecfffSkettenis };
69b9cecfffSkettenis
700d0b934bSkettenis uint32_t hiclock_get_frequency(void *, uint32_t *);
710d0b934bSkettenis void hiclock_enable(void *, uint32_t *, int);
720d0b934bSkettenis
73b9cecfffSkettenis uint32_t hi3670_crgctrl_get_frequency(void *, uint32_t *);
74b9cecfffSkettenis void hi3670_crgctrl_enable(void *, uint32_t *, int);
75b9cecfffSkettenis uint32_t hi3670_stub_get_frequency(void *, uint32_t *);
76b9cecfffSkettenis int hi3670_stub_set_frequency(void *, uint32_t *, uint32_t);
77b9cecfffSkettenis
78*37c734d3Snaddy const struct hiclock_compat hiclock_compat[] = {
79b9cecfffSkettenis /* Official Linux device tree bindings. */
80b9cecfffSkettenis {
81b9cecfffSkettenis .compat = "hisilicon,hi3670-crgctrl",
82b9cecfffSkettenis .get_frequency = hi3670_crgctrl_get_frequency,
83b9cecfffSkettenis .enable = hi3670_crgctrl_enable,
84b9cecfffSkettenis },
85b9cecfffSkettenis { .compat = "hisilicon,hi3670-pctrl" },
86b9cecfffSkettenis { .compat = "hisilicon,hi3670-pmuctrl" },
87b9cecfffSkettenis { .compat = "hisilicon,hi3670-pmctrl" },
88b9cecfffSkettenis { .compat = "hisilicon,hi3670-sctrl" },
89b9cecfffSkettenis { .compat = "hisilicon,hi3670-iomcu" },
90b9cecfffSkettenis { .compat = "hisilicon,hi3670-media1-crg" },
91b9cecfffSkettenis { .compat = "hisilicon,hi3670-media2-crg" },
92b9cecfffSkettenis
93b9cecfffSkettenis /* Preliminary device tree bindings for HiKey970. */
94b9cecfffSkettenis {
95b9cecfffSkettenis .compat = "hisilicon,kirin970-crgctrl",
96b9cecfffSkettenis .get_frequency = hi3670_crgctrl_get_frequency,
97b9cecfffSkettenis .enable = hi3670_crgctrl_enable,
98b9cecfffSkettenis },
99b9cecfffSkettenis { .compat = "hisilicon,kirin970-pctrl" },
100b9cecfffSkettenis { .compat = "hisilicon,kirin970-pmuctrl" },
101b9cecfffSkettenis { .compat = "hisilicon,kirin970-pmctrl" },
102b9cecfffSkettenis { .compat = "hisilicon,kirin970-sctrl" },
103b9cecfffSkettenis { .compat = "hisilicon,kirin970-iomcu" },
104b9cecfffSkettenis {
105b9cecfffSkettenis .compat = "hisilicon,kirin970-stub-clk",
106b9cecfffSkettenis .get_frequency = hi3670_stub_get_frequency,
107b9cecfffSkettenis .set_frequency = hi3670_stub_set_frequency,
108b9cecfffSkettenis },
109b9cecfffSkettenis { .compat = "hisilicon,media1-crg" },
110b9cecfffSkettenis { .compat = "hisilicon,media2-crg" },
111b9cecfffSkettenis };
112b9cecfffSkettenis
1130d0b934bSkettenis int
hiclock_match(struct device * parent,void * match,void * aux)1140d0b934bSkettenis hiclock_match(struct device *parent, void *match, void *aux)
1150d0b934bSkettenis {
1160d0b934bSkettenis struct fdt_attach_args *faa = aux;
117b9cecfffSkettenis int i;
1180d0b934bSkettenis
119b9cecfffSkettenis for (i = 0; i < nitems(hiclock_compat); i++) {
120b9cecfffSkettenis if (OF_is_compatible(faa->fa_node, hiclock_compat[i].compat))
1210d0b934bSkettenis return 10; /* Must beat syscon(4). */
122b9cecfffSkettenis }
1230d0b934bSkettenis
1240d0b934bSkettenis return 0;
1250d0b934bSkettenis }
1260d0b934bSkettenis
1270d0b934bSkettenis void
hiclock_attach(struct device * parent,struct device * self,void * aux)1280d0b934bSkettenis hiclock_attach(struct device *parent, struct device *self, void *aux)
1290d0b934bSkettenis {
1300d0b934bSkettenis struct hiclock_softc *sc = (struct hiclock_softc *)self;
1310d0b934bSkettenis struct fdt_attach_args *faa = aux;
132b9cecfffSkettenis int i;
1330d0b934bSkettenis
1340d0b934bSkettenis if (faa->fa_nreg < 1) {
1350d0b934bSkettenis printf(": no registers\n");
1360d0b934bSkettenis return;
1370d0b934bSkettenis }
1380d0b934bSkettenis
1390d0b934bSkettenis sc->sc_iot = faa->fa_iot;
1400d0b934bSkettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
1410d0b934bSkettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
1420d0b934bSkettenis printf(": can't map registers\n");
1430d0b934bSkettenis return;
1440d0b934bSkettenis }
1450d0b934bSkettenis
146b9cecfffSkettenis if (faa->fa_nreg > 1) {
147b9cecfffSkettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
148b9cecfffSkettenis faa->fa_reg[1].size, 0, &sc->sc_ioh_set)) {
149b9cecfffSkettenis printf(": can't map registers\n");
150b9cecfffSkettenis bus_space_unmap(sc->sc_iot, sc->sc_ioh,
151b9cecfffSkettenis faa->fa_reg[0].size);
152b9cecfffSkettenis return;
153b9cecfffSkettenis }
154b9cecfffSkettenis }
155b9cecfffSkettenis
1560d0b934bSkettenis if (OF_is_compatible(faa->fa_node, "syscon")) {
1570d0b934bSkettenis regmap_register(faa->fa_node, sc->sc_iot, sc->sc_ioh,
1580d0b934bSkettenis faa->fa_reg[0].size);
1590d0b934bSkettenis }
1600d0b934bSkettenis
1610d0b934bSkettenis printf("\n");
1620d0b934bSkettenis
1630d0b934bSkettenis sc->sc_cd.cd_node = faa->fa_node;
1640d0b934bSkettenis sc->sc_cd.cd_cookie = sc;
165b9cecfffSkettenis for (i = 0; i < nitems(hiclock_compat); i++) {
166b9cecfffSkettenis if (OF_is_compatible(faa->fa_node, hiclock_compat[i].compat)) {
167b9cecfffSkettenis sc->sc_cd.cd_get_frequency =
168b9cecfffSkettenis hiclock_compat[i].get_frequency;
169b9cecfffSkettenis sc->sc_cd.cd_set_frequency =
170b9cecfffSkettenis hiclock_compat[i].set_frequency;
171b9cecfffSkettenis sc->sc_cd.cd_enable = hiclock_compat[i].enable;
172b9cecfffSkettenis break;
1730d0b934bSkettenis }
174b9cecfffSkettenis }
175b9cecfffSkettenis if (sc->sc_cd.cd_get_frequency == NULL)
176b9cecfffSkettenis sc->sc_cd.cd_get_frequency = hiclock_get_frequency;
177b9cecfffSkettenis if (sc->sc_cd.cd_enable == NULL)
178b9cecfffSkettenis sc->sc_cd.cd_enable = hiclock_enable;
1790d0b934bSkettenis clock_register(&sc->sc_cd);
1800d0b934bSkettenis }
1810d0b934bSkettenis
182b9cecfffSkettenis /* Generic */
1830d0b934bSkettenis
1840d0b934bSkettenis uint32_t
hiclock_get_frequency(void * cookie,uint32_t * cells)1850d0b934bSkettenis hiclock_get_frequency(void *cookie, uint32_t *cells)
1860d0b934bSkettenis {
1870d0b934bSkettenis uint32_t idx = cells[0];
1880d0b934bSkettenis
1890d0b934bSkettenis printf("%s: 0x%08x\n", __func__, idx);
1900d0b934bSkettenis return 0;
1910d0b934bSkettenis }
1920d0b934bSkettenis
1930d0b934bSkettenis void
hiclock_enable(void * cookie,uint32_t * cells,int on)1940d0b934bSkettenis hiclock_enable(void *cookie, uint32_t *cells, int on)
1950d0b934bSkettenis {
1960d0b934bSkettenis uint32_t idx = cells[0];
1970d0b934bSkettenis
1980d0b934bSkettenis printf("%s: 0x%08x\n", __func__, idx);
1990d0b934bSkettenis }
200b9cecfffSkettenis
201b9cecfffSkettenis /* Hi3670 */
202b9cecfffSkettenis
203b9cecfffSkettenis #define HI3670_CLKIN_SYS 0
204b9cecfffSkettenis #define HI3670_CLK_PPLL0 3
205b9cecfffSkettenis #define HI3670_CLK_PPLL2 5
206b9cecfffSkettenis #define HI3670_CLK_PPLL3 6
207b9cecfffSkettenis
208b9cecfffSkettenis #define HI3670_CLK_SD_SYS 22
209b9cecfffSkettenis #define HI3670_CLK_SDIO_SYS 23
210b9cecfffSkettenis #define HI3670_CLK_GATE_ABB_USB 29
211b9cecfffSkettenis #define HI3670_CLK_MUX_SD_SYS 68
212b9cecfffSkettenis #define HI3670_CLK_MUX_SD_PLL 69
213b9cecfffSkettenis #define HI3670_CLK_MUX_SDIO_SYS 70
214b9cecfffSkettenis #define HI3670_CLK_MUX_SDIO_PLL 71
215b9cecfffSkettenis #define HI3670_CLK_DIV_SD 93
216b9cecfffSkettenis #define HI3670_CLK_DIV_SDIO 94
217b9cecfffSkettenis #define HI3670_HCLK_GATE_USB3OTG 147
218b9cecfffSkettenis #define HI3670_HCLK_GATE_USB3DVFS 148
219b9cecfffSkettenis #define HI3670_HCLK_GATE_SDIO 149
220b9cecfffSkettenis #define HI3670_CLK_GATE_SD 159
221b9cecfffSkettenis #define HI3670_HCLK_GATE_SD 160
222b9cecfffSkettenis #define HI3670_CLK_GATE_SDIO 161
223b9cecfffSkettenis #define HI3670_CLK_GATE_USB3OTG_REF 189
224b9cecfffSkettenis
225b9cecfffSkettenis uint32_t
hi3670_crgctrl_get_frequency(void * cookie,uint32_t * cells)226b9cecfffSkettenis hi3670_crgctrl_get_frequency(void *cookie, uint32_t *cells)
227b9cecfffSkettenis {
228b9cecfffSkettenis struct hiclock_softc *sc = cookie;
229b9cecfffSkettenis uint32_t idx = cells[0];
230b9cecfffSkettenis uint32_t reg, freq, div;
231b9cecfffSkettenis int mux;
232b9cecfffSkettenis
233b9cecfffSkettenis switch (idx) {
234b9cecfffSkettenis case HI3670_CLKIN_SYS:
235b9cecfffSkettenis return 19200000;
236b9cecfffSkettenis case HI3670_CLK_PPLL0:
237b9cecfffSkettenis return 1660000000;
238b9cecfffSkettenis case HI3670_CLK_PPLL2:
239b9cecfffSkettenis return 1920000000;
240b9cecfffSkettenis case HI3670_CLK_PPLL3:
241b9cecfffSkettenis return 1200000000;
242b9cecfffSkettenis case HI3670_CLK_SD_SYS:
243b9cecfffSkettenis case HI3670_CLK_SDIO_SYS:
244b9cecfffSkettenis idx = HI3670_CLKIN_SYS;
245b9cecfffSkettenis freq = hi3670_crgctrl_get_frequency(cookie, &idx);
246b9cecfffSkettenis return freq / 6;
247b9cecfffSkettenis case HI3670_CLK_MUX_SD_SYS:
248b9cecfffSkettenis reg = HREAD4(sc, 0x0b8);
249b9cecfffSkettenis mux = (reg >> 6) & 0x1;
250b9cecfffSkettenis idx = mux ? HI3670_CLK_DIV_SD : HI3670_CLK_SD_SYS;
251b9cecfffSkettenis return hi3670_crgctrl_get_frequency(cookie, &idx);
252b9cecfffSkettenis case HI3670_CLK_MUX_SD_PLL:
253b9cecfffSkettenis reg = HREAD4(sc, 0x0b8);
254b9cecfffSkettenis mux = (reg >> 4) & 0x3;
255b9cecfffSkettenis switch (mux) {
256b9cecfffSkettenis case 0:
257b9cecfffSkettenis idx = HI3670_CLK_PPLL0;
258b9cecfffSkettenis break;
259b9cecfffSkettenis case 1:
260b9cecfffSkettenis idx = HI3670_CLK_PPLL3;
261b9cecfffSkettenis break;
262b9cecfffSkettenis case 2:
263b9cecfffSkettenis case 3:
264b9cecfffSkettenis idx = HI3670_CLK_PPLL2;
265b9cecfffSkettenis break;
266b9cecfffSkettenis }
267b9cecfffSkettenis return hi3670_crgctrl_get_frequency(cookie, &idx);
268b9cecfffSkettenis case HI3670_CLK_DIV_SD:
269b9cecfffSkettenis reg = HREAD4(sc, 0x0b8);
270b9cecfffSkettenis div = (reg >> 0) & 0xf;
271b9cecfffSkettenis idx = HI3670_CLK_MUX_SD_PLL;
272b9cecfffSkettenis freq = hi3670_crgctrl_get_frequency(cookie, &idx);
273b9cecfffSkettenis return freq / (div + 1);
274b9cecfffSkettenis case HI3670_CLK_GATE_SD:
275b9cecfffSkettenis idx = HI3670_CLK_MUX_SD_SYS;
276b9cecfffSkettenis return hi3670_crgctrl_get_frequency(cookie, &idx);
277b9cecfffSkettenis case HI3670_CLK_GATE_SDIO:
278b9cecfffSkettenis idx = HI3670_CLK_MUX_SDIO_SYS;
279b9cecfffSkettenis return hi3670_crgctrl_get_frequency(cookie, &idx);
280b9cecfffSkettenis }
281b9cecfffSkettenis
282b9cecfffSkettenis printf("%s: 0x%08x\n", __func__, idx);
283b9cecfffSkettenis return 0;
284b9cecfffSkettenis }
285b9cecfffSkettenis
286b9cecfffSkettenis void
hi3670_crgctrl_enable(void * cookie,uint32_t * cells,int on)287b9cecfffSkettenis hi3670_crgctrl_enable(void *cookie, uint32_t *cells, int on)
288b9cecfffSkettenis {
289b9cecfffSkettenis uint32_t idx = cells[0];
290b9cecfffSkettenis
291b9cecfffSkettenis switch (idx) {
292b9cecfffSkettenis case HI3670_CLK_GATE_ABB_USB:
293b9cecfffSkettenis case HI3670_HCLK_GATE_USB3OTG:
294b9cecfffSkettenis case HI3670_HCLK_GATE_USB3DVFS:
295b9cecfffSkettenis case HI3670_CLK_GATE_SD:
296b9cecfffSkettenis case HI3670_HCLK_GATE_SD:
297b9cecfffSkettenis case HI3670_CLK_GATE_USB3OTG_REF:
298b9cecfffSkettenis /* Enabled by default. */
299b9cecfffSkettenis return;
300b9cecfffSkettenis }
301b9cecfffSkettenis
302b9cecfffSkettenis printf("%s: 0x%08x\n", __func__, idx);
303b9cecfffSkettenis }
304b9cecfffSkettenis
305b9cecfffSkettenis #define HI3670_CLK_STUB_CLUSTER0 0
306b9cecfffSkettenis #define HI3670_CLK_STUB_CLUSTER1 1
307b9cecfffSkettenis
308b9cecfffSkettenis uint32_t
hi3670_stub_get_frequency(void * cookie,uint32_t * cells)309b9cecfffSkettenis hi3670_stub_get_frequency(void *cookie, uint32_t *cells)
310b9cecfffSkettenis {
311b9cecfffSkettenis struct hiclock_softc *sc = cookie;
312b9cecfffSkettenis uint32_t idx = cells[0];
313b9cecfffSkettenis uint32_t reg;
314b9cecfffSkettenis
315b9cecfffSkettenis switch (idx) {
316b9cecfffSkettenis case HI3670_CLK_STUB_CLUSTER0:
317b9cecfffSkettenis reg = HREAD4(sc, 0x070);
318b9cecfffSkettenis return reg * 1000000;
319b9cecfffSkettenis case HI3670_CLK_STUB_CLUSTER1:
320b9cecfffSkettenis reg = HREAD4(sc, 0x074);
321b9cecfffSkettenis return reg * 1000000;
322b9cecfffSkettenis default:
323b9cecfffSkettenis break;
324b9cecfffSkettenis }
325b9cecfffSkettenis
326b9cecfffSkettenis printf("%s: 0x%08x\n", __func__, idx);
327b9cecfffSkettenis return 0;
328b9cecfffSkettenis }
329b9cecfffSkettenis
330b9cecfffSkettenis int
hi3670_stub_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)331b9cecfffSkettenis hi3670_stub_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
332b9cecfffSkettenis {
333b9cecfffSkettenis struct hiclock_softc *sc = cookie;
334b9cecfffSkettenis uint32_t idx = cells[0];
335b9cecfffSkettenis uint32_t reg;
336b9cecfffSkettenis
337b9cecfffSkettenis switch (idx) {
338b9cecfffSkettenis case HI3670_CLK_STUB_CLUSTER0:
339b9cecfffSkettenis reg = freq / 16000000;
340b9cecfffSkettenis reg |= (0xff << 16);
341b9cecfffSkettenis bus_space_write_4(sc->sc_iot, sc->sc_ioh_set, 0x280, reg);
342b9cecfffSkettenis return 0;
343b9cecfffSkettenis case HI3670_CLK_STUB_CLUSTER1:
344b9cecfffSkettenis reg = freq / 16000000;
345b9cecfffSkettenis reg |= (0xff << 16);
346b9cecfffSkettenis bus_space_write_4(sc->sc_iot, sc->sc_ioh_set, 0x270, reg);
347b9cecfffSkettenis return 0;
348b9cecfffSkettenis default:
349b9cecfffSkettenis break;
350b9cecfffSkettenis }
351b9cecfffSkettenis
352b9cecfffSkettenis printf("%s: 0x%08x\n", __func__, idx);
353b9cecfffSkettenis return -1;
354b9cecfffSkettenis }
355