xref: /openbsd-src/sys/dev/fdt/hiclock.c (revision 37c734d33dee3fea3589b7f939107ac40734e75e)
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