xref: /openbsd-src/sys/arch/armv7/omap/omclock.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
1*471aeecfSnaddy /*	$OpenBSD: omclock.c,v 1.2 2022/04/06 18:59:26 naddy Exp $	*/
24d149eb4Skettenis /*
34d149eb4Skettenis  * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
44d149eb4Skettenis  *
54d149eb4Skettenis  * Permission to use, copy, modify, and distribute this software for any
64d149eb4Skettenis  * purpose with or without fee is hereby granted, provided that the above
74d149eb4Skettenis  * copyright notice and this permission notice appear in all copies.
84d149eb4Skettenis  *
94d149eb4Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
104d149eb4Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
114d149eb4Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
124d149eb4Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
134d149eb4Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
144d149eb4Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
154d149eb4Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
164d149eb4Skettenis  */
174d149eb4Skettenis 
184d149eb4Skettenis #include <sys/param.h>
194d149eb4Skettenis #include <sys/systm.h>
204d149eb4Skettenis #include <sys/device.h>
214d149eb4Skettenis 
224d149eb4Skettenis #include <machine/bus.h>
234d149eb4Skettenis #include <machine/fdt.h>
244d149eb4Skettenis 
254d149eb4Skettenis #include <dev/ofw/openfirm.h>
264d149eb4Skettenis #include <dev/ofw/ofw_clock.h>
274d149eb4Skettenis #include <dev/ofw/fdt.h>
284d149eb4Skettenis 
294d149eb4Skettenis #define IDLEST_MASK		(0x3 << 16)
304d149eb4Skettenis #define IDLEST_FUNC		(0x0 << 16)
314d149eb4Skettenis #define IDLEST_TRANS		(0x1 << 16)
324d149eb4Skettenis #define IDLEST_IDLE		(0x2 << 16)
334d149eb4Skettenis #define IDLEST_DISABLED		(0x3 << 16)
344d149eb4Skettenis #define MODULEMODE_MASK		(0x3 << 0)
354d149eb4Skettenis #define MODULEMODE_DISABLED	(0x0 << 0)
364d149eb4Skettenis #define MODULEMODE_ENABLED	(0x2 << 0)
374d149eb4Skettenis 
384d149eb4Skettenis #define HREAD4(sc, reg)							\
394d149eb4Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
404d149eb4Skettenis #define HWRITE4(sc, reg, val)						\
414d149eb4Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
424d149eb4Skettenis #define HSET4(sc, reg, bits)						\
434d149eb4Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
444d149eb4Skettenis #define HCLR4(sc, reg, bits)						\
454d149eb4Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
464d149eb4Skettenis 
474d149eb4Skettenis struct omclock_softc {
484d149eb4Skettenis 	struct device		sc_dev;
494d149eb4Skettenis 	bus_space_tag_t		sc_iot;
504d149eb4Skettenis 	bus_space_handle_t	sc_ioh;
514d149eb4Skettenis 	int			sc_node;
524d149eb4Skettenis 
534d149eb4Skettenis 	struct clock_device	sc_cd;
544d149eb4Skettenis };
554d149eb4Skettenis 
564d149eb4Skettenis int	omclock_match(struct device *, void *, void *);
574d149eb4Skettenis void	omclock_attach(struct device *, struct device *, void *);
584d149eb4Skettenis 
59*471aeecfSnaddy const struct cfattach omclock_ca = {
604d149eb4Skettenis 	sizeof (struct omclock_softc), omclock_match, omclock_attach
614d149eb4Skettenis };
624d149eb4Skettenis 
634d149eb4Skettenis struct cfdriver omclock_cd = {
644d149eb4Skettenis 	NULL, "omclock", DV_DULL
654d149eb4Skettenis };
664d149eb4Skettenis 
674d149eb4Skettenis uint32_t omclock_get_frequency(void *, uint32_t *);
684d149eb4Skettenis int	omclock_set_frequency(void *, uint32_t *, uint32_t);
694d149eb4Skettenis void	omclock_enable(void *, uint32_t *, int);
704d149eb4Skettenis 
714d149eb4Skettenis int
omclock_match(struct device * parent,void * match,void * aux)724d149eb4Skettenis omclock_match(struct device *parent, void *match, void *aux)
734d149eb4Skettenis {
744d149eb4Skettenis 	struct fdt_attach_args *faa = aux;
754d149eb4Skettenis 
764d149eb4Skettenis 	return OF_is_compatible(faa->fa_node, "ti,clkctrl");
774d149eb4Skettenis }
784d149eb4Skettenis 
794d149eb4Skettenis void
omclock_attach(struct device * parent,struct device * self,void * aux)804d149eb4Skettenis omclock_attach(struct device *parent, struct device *self, void *aux)
814d149eb4Skettenis {
824d149eb4Skettenis 	struct omclock_softc *sc = (struct omclock_softc *)self;
834d149eb4Skettenis 	struct fdt_attach_args *faa = aux;
844d149eb4Skettenis 	char name[32];
854d149eb4Skettenis 
864d149eb4Skettenis 	if (faa->fa_nreg < 1) {
874d149eb4Skettenis 		printf(": no registers\n");
884d149eb4Skettenis 		return;
894d149eb4Skettenis 	}
904d149eb4Skettenis 
914d149eb4Skettenis 	sc->sc_iot = faa->fa_iot;
924d149eb4Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
934d149eb4Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
944d149eb4Skettenis 		printf(": can't map registers\n");
954d149eb4Skettenis 		return;
964d149eb4Skettenis 	}
974d149eb4Skettenis 
984d149eb4Skettenis 	sc->sc_node = faa->fa_node;
994d149eb4Skettenis 	if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) {
1004d149eb4Skettenis 		name[sizeof(name) - 1] = 0;
1014d149eb4Skettenis 		printf(": \"%s\"", name);
1024d149eb4Skettenis 	}
1034d149eb4Skettenis 
1044d149eb4Skettenis 	printf("\n");
1054d149eb4Skettenis 
1064d149eb4Skettenis 	sc->sc_cd.cd_node = faa->fa_node;
1074d149eb4Skettenis 	sc->sc_cd.cd_cookie = sc;
1084d149eb4Skettenis 	sc->sc_cd.cd_get_frequency = omclock_get_frequency;
1094d149eb4Skettenis 	sc->sc_cd.cd_set_frequency = omclock_set_frequency;
1104d149eb4Skettenis 	sc->sc_cd.cd_enable = omclock_enable;
1114d149eb4Skettenis 	clock_register(&sc->sc_cd);
1124d149eb4Skettenis }
1134d149eb4Skettenis 
1144d149eb4Skettenis uint32_t
omclock_get_frequency(void * cookie,uint32_t * cells)1154d149eb4Skettenis omclock_get_frequency(void *cookie, uint32_t *cells)
1164d149eb4Skettenis {
1174d149eb4Skettenis 	printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
1184d149eb4Skettenis 	return 0;
1194d149eb4Skettenis }
1204d149eb4Skettenis 
1214d149eb4Skettenis int
omclock_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)1224d149eb4Skettenis omclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1234d149eb4Skettenis {
1244d149eb4Skettenis 	printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
1254d149eb4Skettenis 	return -1;
1264d149eb4Skettenis }
1274d149eb4Skettenis 
1284d149eb4Skettenis void
omclock_enable(void * cookie,uint32_t * cells,int on)1294d149eb4Skettenis omclock_enable(void *cookie, uint32_t *cells, int on)
1304d149eb4Skettenis {
1314d149eb4Skettenis 	struct omclock_softc *sc = cookie;
1324d149eb4Skettenis 	uint32_t base = cells[0];
1334d149eb4Skettenis 	uint32_t idx = cells[1];
1344d149eb4Skettenis 	uint32_t reg;
1354d149eb4Skettenis 	int retry;
1364d149eb4Skettenis 
1374d149eb4Skettenis 	reg = HREAD4(sc, base);
1384d149eb4Skettenis 	if (idx == 0) {
1394d149eb4Skettenis 		reg &= ~MODULEMODE_MASK;
1404d149eb4Skettenis 		if (on)
1414d149eb4Skettenis 			reg |= MODULEMODE_ENABLED;
1424d149eb4Skettenis 		else
1434d149eb4Skettenis 			reg |= MODULEMODE_DISABLED;
1444d149eb4Skettenis 	} else {
1454d149eb4Skettenis 		if (on)
1464d149eb4Skettenis 			reg |= (1U << idx);
1474d149eb4Skettenis 		else
1484d149eb4Skettenis 			reg &= ~(1U << idx);
1494d149eb4Skettenis 	}
1504d149eb4Skettenis 	HWRITE4(sc, base, reg);
1514d149eb4Skettenis 
1524d149eb4Skettenis 	if (idx == 0) {
1534d149eb4Skettenis 		retry = 100;
1544d149eb4Skettenis 		while (--retry > 0) {
1554d149eb4Skettenis 			if ((HREAD4(sc, base) & IDLEST_MASK) == IDLEST_FUNC)
1564d149eb4Skettenis 				break;
1574d149eb4Skettenis 			delay(10);
1584d149eb4Skettenis 		}
1594d149eb4Skettenis 		/* XXX Hope for the best if this loop times out. */
1604d149eb4Skettenis 	}
1614d149eb4Skettenis }
162