xref: /openbsd/sys/arch/armv7/omap/omclock.c (revision 5dea098c)
1 /*	$OpenBSD: omclock.c,v 1.2 2022/04/06 18:59:26 naddy Exp $	*/
2 /*
3  * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 
22 #include <machine/bus.h>
23 #include <machine/fdt.h>
24 
25 #include <dev/ofw/openfirm.h>
26 #include <dev/ofw/ofw_clock.h>
27 #include <dev/ofw/fdt.h>
28 
29 #define IDLEST_MASK		(0x3 << 16)
30 #define IDLEST_FUNC		(0x0 << 16)
31 #define IDLEST_TRANS		(0x1 << 16)
32 #define IDLEST_IDLE		(0x2 << 16)
33 #define IDLEST_DISABLED		(0x3 << 16)
34 #define MODULEMODE_MASK		(0x3 << 0)
35 #define MODULEMODE_DISABLED	(0x0 << 0)
36 #define MODULEMODE_ENABLED	(0x2 << 0)
37 
38 #define HREAD4(sc, reg)							\
39 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
40 #define HWRITE4(sc, reg, val)						\
41 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
42 #define HSET4(sc, reg, bits)						\
43 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
44 #define HCLR4(sc, reg, bits)						\
45 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
46 
47 struct omclock_softc {
48 	struct device		sc_dev;
49 	bus_space_tag_t		sc_iot;
50 	bus_space_handle_t	sc_ioh;
51 	int			sc_node;
52 
53 	struct clock_device	sc_cd;
54 };
55 
56 int	omclock_match(struct device *, void *, void *);
57 void	omclock_attach(struct device *, struct device *, void *);
58 
59 const struct cfattach omclock_ca = {
60 	sizeof (struct omclock_softc), omclock_match, omclock_attach
61 };
62 
63 struct cfdriver omclock_cd = {
64 	NULL, "omclock", DV_DULL
65 };
66 
67 uint32_t omclock_get_frequency(void *, uint32_t *);
68 int	omclock_set_frequency(void *, uint32_t *, uint32_t);
69 void	omclock_enable(void *, uint32_t *, int);
70 
71 int
72 omclock_match(struct device *parent, void *match, void *aux)
73 {
74 	struct fdt_attach_args *faa = aux;
75 
76 	return OF_is_compatible(faa->fa_node, "ti,clkctrl");
77 }
78 
79 void
80 omclock_attach(struct device *parent, struct device *self, void *aux)
81 {
82 	struct omclock_softc *sc = (struct omclock_softc *)self;
83 	struct fdt_attach_args *faa = aux;
84 	char name[32];
85 
86 	if (faa->fa_nreg < 1) {
87 		printf(": no registers\n");
88 		return;
89 	}
90 
91 	sc->sc_iot = faa->fa_iot;
92 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
93 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
94 		printf(": can't map registers\n");
95 		return;
96 	}
97 
98 	sc->sc_node = faa->fa_node;
99 	if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) {
100 		name[sizeof(name) - 1] = 0;
101 		printf(": \"%s\"", name);
102 	}
103 
104 	printf("\n");
105 
106 	sc->sc_cd.cd_node = faa->fa_node;
107 	sc->sc_cd.cd_cookie = sc;
108 	sc->sc_cd.cd_get_frequency = omclock_get_frequency;
109 	sc->sc_cd.cd_set_frequency = omclock_set_frequency;
110 	sc->sc_cd.cd_enable = omclock_enable;
111 	clock_register(&sc->sc_cd);
112 }
113 
114 uint32_t
115 omclock_get_frequency(void *cookie, uint32_t *cells)
116 {
117 	printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
118 	return 0;
119 }
120 
121 int
122 omclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
123 {
124 	printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
125 	return -1;
126 }
127 
128 void
129 omclock_enable(void *cookie, uint32_t *cells, int on)
130 {
131 	struct omclock_softc *sc = cookie;
132 	uint32_t base = cells[0];
133 	uint32_t idx = cells[1];
134 	uint32_t reg;
135 	int retry;
136 
137 	reg = HREAD4(sc, base);
138 	if (idx == 0) {
139 		reg &= ~MODULEMODE_MASK;
140 		if (on)
141 			reg |= MODULEMODE_ENABLED;
142 		else
143 			reg |= MODULEMODE_DISABLED;
144 	} else {
145 		if (on)
146 			reg |= (1U << idx);
147 		else
148 			reg &= ~(1U << idx);
149 	}
150 	HWRITE4(sc, base, reg);
151 
152 	if (idx == 0) {
153 		retry = 100;
154 		while (--retry > 0) {
155 			if ((HREAD4(sc, base) & IDLEST_MASK) == IDLEST_FUNC)
156 				break;
157 			delay(10);
158 		}
159 		/* XXX Hope for the best if this loop times out. */
160 	}
161 }
162