xref: /openbsd-src/sys/dev/fdt/qcaoss.c (revision fe62c2037e1c325af9b89215dcb1fc6e5b9ab677)
1*fe62c203Spatrick /*	$OpenBSD: qcaoss.c,v 1.1 2023/05/23 14:10:27 patrick Exp $	*/
2*fe62c203Spatrick /*
3*fe62c203Spatrick  * Copyright (c) 2023 Patrick Wildt <patrick@blueri.se>
4*fe62c203Spatrick  *
5*fe62c203Spatrick  * Permission to use, copy, modify, and distribute this software for any
6*fe62c203Spatrick  * purpose with or without fee is hereby granted, provided that the above
7*fe62c203Spatrick  * copyright notice and this permission notice appear in all copies.
8*fe62c203Spatrick  *
9*fe62c203Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*fe62c203Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*fe62c203Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*fe62c203Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*fe62c203Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*fe62c203Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*fe62c203Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*fe62c203Spatrick  */
17*fe62c203Spatrick 
18*fe62c203Spatrick #include <sys/param.h>
19*fe62c203Spatrick #include <sys/systm.h>
20*fe62c203Spatrick #include <sys/device.h>
21*fe62c203Spatrick #include <sys/malloc.h>
22*fe62c203Spatrick #include <sys/atomic.h>
23*fe62c203Spatrick 
24*fe62c203Spatrick #include <machine/bus.h>
25*fe62c203Spatrick #include <machine/fdt.h>
26*fe62c203Spatrick 
27*fe62c203Spatrick #include <dev/ofw/openfirm.h>
28*fe62c203Spatrick #include <dev/ofw/ofw_misc.h>
29*fe62c203Spatrick #include <dev/ofw/fdt.h>
30*fe62c203Spatrick 
31*fe62c203Spatrick #define AOSS_DESC_MAGIC			0x0
32*fe62c203Spatrick #define AOSS_DESC_VERSION		0x4
33*fe62c203Spatrick #define AOSS_DESC_FEATURES		0x8
34*fe62c203Spatrick #define AOSS_DESC_UCORE_LINK_STATE	0xc
35*fe62c203Spatrick #define AOSS_DESC_UCORE_LINK_STATE_ACK	0x10
36*fe62c203Spatrick #define AOSS_DESC_UCORE_CH_STATE	0x14
37*fe62c203Spatrick #define AOSS_DESC_UCORE_CH_STATE_ACK	0x18
38*fe62c203Spatrick #define AOSS_DESC_UCORE_MBOX_SIZE	0x1c
39*fe62c203Spatrick #define AOSS_DESC_UCORE_MBOX_OFFSET	0x20
40*fe62c203Spatrick #define AOSS_DESC_MCORE_LINK_STATE	0x24
41*fe62c203Spatrick #define AOSS_DESC_MCORE_LINK_STATE_ACK	0x28
42*fe62c203Spatrick #define AOSS_DESC_MCORE_CH_STATE	0x2c
43*fe62c203Spatrick #define AOSS_DESC_MCORE_CH_STATE_ACK	0x30
44*fe62c203Spatrick #define AOSS_DESC_MCORE_MBOX_SIZE	0x34
45*fe62c203Spatrick #define AOSS_DESC_MCORE_MBOX_OFFSET	0x38
46*fe62c203Spatrick 
47*fe62c203Spatrick #define AOSS_MAGIC			0x4d41494c
48*fe62c203Spatrick #define AOSS_VERSION			1
49*fe62c203Spatrick 
50*fe62c203Spatrick #define AOSS_STATE_UP			(0xffffU << 0)
51*fe62c203Spatrick #define AOSS_STATE_DOWN			(0xffffU << 16)
52*fe62c203Spatrick 
53*fe62c203Spatrick #define HREAD4(sc, reg)							\
54*fe62c203Spatrick 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
55*fe62c203Spatrick #define HWRITE4(sc, reg, val)						\
56*fe62c203Spatrick 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
57*fe62c203Spatrick 
58*fe62c203Spatrick struct qcaoss_softc {
59*fe62c203Spatrick 	struct device		sc_dev;
60*fe62c203Spatrick 	bus_space_tag_t		sc_iot;
61*fe62c203Spatrick 	bus_space_handle_t	sc_ioh;
62*fe62c203Spatrick 
63*fe62c203Spatrick 	size_t			sc_offset;
64*fe62c203Spatrick 	size_t			sc_size;
65*fe62c203Spatrick 
66*fe62c203Spatrick 	struct mbox_channel	*sc_mc;
67*fe62c203Spatrick };
68*fe62c203Spatrick 
69*fe62c203Spatrick struct qcaoss_softc *qcaoss_sc;
70*fe62c203Spatrick 
71*fe62c203Spatrick int	qcaoss_match(struct device *, void *, void *);
72*fe62c203Spatrick void	qcaoss_attach(struct device *, struct device *, void *);
73*fe62c203Spatrick 
74*fe62c203Spatrick const struct cfattach qcaoss_ca = {
75*fe62c203Spatrick 	sizeof (struct qcaoss_softc), qcaoss_match, qcaoss_attach
76*fe62c203Spatrick };
77*fe62c203Spatrick 
78*fe62c203Spatrick struct cfdriver qcaoss_cd = {
79*fe62c203Spatrick 	NULL, "qcaoss", DV_DULL
80*fe62c203Spatrick };
81*fe62c203Spatrick 
82*fe62c203Spatrick int
qcaoss_match(struct device * parent,void * match,void * aux)83*fe62c203Spatrick qcaoss_match(struct device *parent, void *match, void *aux)
84*fe62c203Spatrick {
85*fe62c203Spatrick 	struct fdt_attach_args *faa = aux;
86*fe62c203Spatrick 
87*fe62c203Spatrick 	return OF_is_compatible(faa->fa_node, "qcom,aoss-qmp");
88*fe62c203Spatrick }
89*fe62c203Spatrick 
90*fe62c203Spatrick void
qcaoss_attach(struct device * parent,struct device * self,void * aux)91*fe62c203Spatrick qcaoss_attach(struct device *parent, struct device *self, void *aux)
92*fe62c203Spatrick {
93*fe62c203Spatrick 	struct qcaoss_softc *sc = (struct qcaoss_softc *)self;
94*fe62c203Spatrick 	struct fdt_attach_args *faa = aux;
95*fe62c203Spatrick 	int i;
96*fe62c203Spatrick 
97*fe62c203Spatrick 	if (faa->fa_nreg < 1) {
98*fe62c203Spatrick 		printf(": no registers\n");
99*fe62c203Spatrick 		return;
100*fe62c203Spatrick 	}
101*fe62c203Spatrick 
102*fe62c203Spatrick 	sc->sc_iot = faa->fa_iot;
103*fe62c203Spatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
104*fe62c203Spatrick 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
105*fe62c203Spatrick 		printf(": can't map registers\n");
106*fe62c203Spatrick 		return;
107*fe62c203Spatrick 	}
108*fe62c203Spatrick 
109*fe62c203Spatrick 	sc->sc_mc = mbox_channel_idx(faa->fa_node, 0, NULL);
110*fe62c203Spatrick 	if (sc->sc_mc == NULL) {
111*fe62c203Spatrick 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
112*fe62c203Spatrick 		printf(": can't find mbox\n");
113*fe62c203Spatrick 		return;
114*fe62c203Spatrick 	}
115*fe62c203Spatrick 
116*fe62c203Spatrick 	if (HREAD4(sc, AOSS_DESC_MAGIC) != AOSS_MAGIC ||
117*fe62c203Spatrick 	    HREAD4(sc, AOSS_DESC_VERSION) != AOSS_VERSION) {
118*fe62c203Spatrick 		printf(": invalid QMP info\n");
119*fe62c203Spatrick 		return;
120*fe62c203Spatrick 	}
121*fe62c203Spatrick 
122*fe62c203Spatrick 	sc->sc_offset = HREAD4(sc, AOSS_DESC_MCORE_MBOX_OFFSET);
123*fe62c203Spatrick 	sc->sc_size = HREAD4(sc, AOSS_DESC_MCORE_MBOX_SIZE);
124*fe62c203Spatrick 	if (sc->sc_size == 0) {
125*fe62c203Spatrick 		printf(": invalid mailbox size\n");
126*fe62c203Spatrick 		return;
127*fe62c203Spatrick 	}
128*fe62c203Spatrick 
129*fe62c203Spatrick 	HWRITE4(sc, AOSS_DESC_UCORE_LINK_STATE_ACK,
130*fe62c203Spatrick 	    HREAD4(sc, AOSS_DESC_UCORE_LINK_STATE));
131*fe62c203Spatrick 
132*fe62c203Spatrick 	HWRITE4(sc, AOSS_DESC_MCORE_LINK_STATE, AOSS_STATE_UP);
133*fe62c203Spatrick 	mbox_send(sc->sc_mc, NULL, 0);
134*fe62c203Spatrick 
135*fe62c203Spatrick 	for (i = 1000; i > 0; i--) {
136*fe62c203Spatrick 		if (HREAD4(sc, AOSS_DESC_MCORE_LINK_STATE_ACK) == AOSS_STATE_UP)
137*fe62c203Spatrick 			break;
138*fe62c203Spatrick 		delay(1000);
139*fe62c203Spatrick 	}
140*fe62c203Spatrick 	if (i == 0) {
141*fe62c203Spatrick 		printf(": didn't get link state ack\n");
142*fe62c203Spatrick 		return;
143*fe62c203Spatrick 	}
144*fe62c203Spatrick 
145*fe62c203Spatrick 	HWRITE4(sc, AOSS_DESC_MCORE_CH_STATE, AOSS_STATE_UP);
146*fe62c203Spatrick 	mbox_send(sc->sc_mc, NULL, 0);
147*fe62c203Spatrick 
148*fe62c203Spatrick 	for (i = 1000; i > 0; i--) {
149*fe62c203Spatrick 		if (HREAD4(sc, AOSS_DESC_UCORE_CH_STATE) == AOSS_STATE_UP)
150*fe62c203Spatrick 			break;
151*fe62c203Spatrick 		delay(1000);
152*fe62c203Spatrick 	}
153*fe62c203Spatrick 	if (i == 0) {
154*fe62c203Spatrick 		printf(": didn't get open channel\n");
155*fe62c203Spatrick 		return;
156*fe62c203Spatrick 	}
157*fe62c203Spatrick 
158*fe62c203Spatrick 	HWRITE4(sc, AOSS_DESC_UCORE_CH_STATE_ACK, AOSS_STATE_UP);
159*fe62c203Spatrick 	mbox_send(sc->sc_mc, NULL, 0);
160*fe62c203Spatrick 
161*fe62c203Spatrick 	for (i = 1000; i > 0; i--) {
162*fe62c203Spatrick 		if (HREAD4(sc, AOSS_DESC_MCORE_CH_STATE_ACK) == AOSS_STATE_UP)
163*fe62c203Spatrick 			break;
164*fe62c203Spatrick 		delay(1000);
165*fe62c203Spatrick 	}
166*fe62c203Spatrick 	if (i == 0) {
167*fe62c203Spatrick 		printf(": didn't get channel ack\n");
168*fe62c203Spatrick 		return;
169*fe62c203Spatrick 	}
170*fe62c203Spatrick 
171*fe62c203Spatrick 	printf("\n");
172*fe62c203Spatrick 
173*fe62c203Spatrick 	qcaoss_sc = sc;
174*fe62c203Spatrick }
175*fe62c203Spatrick 
176*fe62c203Spatrick int
qcaoss_send(char * data,size_t len)177*fe62c203Spatrick qcaoss_send(char *data, size_t len)
178*fe62c203Spatrick {
179*fe62c203Spatrick 	struct qcaoss_softc *sc = qcaoss_sc;
180*fe62c203Spatrick 	uint32_t reg;
181*fe62c203Spatrick 	int i;
182*fe62c203Spatrick 
183*fe62c203Spatrick 	if (sc == NULL)
184*fe62c203Spatrick 		return ENXIO;
185*fe62c203Spatrick 
186*fe62c203Spatrick 	if (data == NULL || sizeof(uint32_t) + len > sc->sc_size ||
187*fe62c203Spatrick 	    (len % sizeof(uint32_t)) != 0)
188*fe62c203Spatrick 		return EINVAL;
189*fe62c203Spatrick 
190*fe62c203Spatrick 	/* Write data first, needs to be 32-bit access. */
191*fe62c203Spatrick 	for (i = 0; i < len; i += 4) {
192*fe62c203Spatrick 		memcpy(&reg, data + i, sizeof(reg));
193*fe62c203Spatrick 		HWRITE4(sc, sc->sc_offset + sizeof(uint32_t) + i, reg);
194*fe62c203Spatrick 	}
195*fe62c203Spatrick 
196*fe62c203Spatrick 	/* Commit transaction by writing length. */
197*fe62c203Spatrick 	HWRITE4(sc, sc->sc_offset, len);
198*fe62c203Spatrick 
199*fe62c203Spatrick 	/* Assert it's stored and inform peer. */
200*fe62c203Spatrick 	KASSERT(HREAD4(sc, sc->sc_offset) == len);
201*fe62c203Spatrick 	mbox_send(sc->sc_mc, NULL, 0);
202*fe62c203Spatrick 
203*fe62c203Spatrick 	for (i = 1000; i > 0; i--) {
204*fe62c203Spatrick 		if (HREAD4(sc, sc->sc_offset) == 0)
205*fe62c203Spatrick 			break;
206*fe62c203Spatrick 		delay(1000);
207*fe62c203Spatrick 	}
208*fe62c203Spatrick 	if (i == 0) {
209*fe62c203Spatrick 		printf("%s: timeout sending message\n", sc->sc_dev.dv_xname);
210*fe62c203Spatrick 		HWRITE4(sc, sc->sc_offset, 0);
211*fe62c203Spatrick 		return ETIMEDOUT;
212*fe62c203Spatrick 	}
213*fe62c203Spatrick 
214*fe62c203Spatrick 	return 0;
215*fe62c203Spatrick }
216