xref: /freebsd/sys/arm64/coresight/coresight_tmc.c (revision d0b2dbfa)
1 /*-
2  * Copyright (c) 2018-2020 Ruslan Bukin <br@bsdpad.com>
3  * All rights reserved.
4  *
5  * This software was developed by SRI International and the University of
6  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
7  * ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/rman.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <machine/bus.h>
39 
40 #include <arm64/coresight/coresight.h>
41 #include <arm64/coresight/coresight_tmc.h>
42 
43 #include "coresight_if.h"
44 
45 #define	TMC_DEBUG
46 #undef TMC_DEBUG
47 
48 #ifdef TMC_DEBUG
49 #define	dprintf(fmt, ...)	printf(fmt, ##__VA_ARGS__)
50 #else
51 #define	dprintf(fmt, ...)
52 #endif
53 
54 static struct resource_spec tmc_spec[] = {
55 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
56 	{ -1, 0 }
57 };
58 
59 static int
60 tmc_start(device_t dev)
61 {
62 	struct tmc_softc *sc;
63 	uint32_t reg;
64 
65 	sc = device_get_softc(dev);
66 
67 	if (bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN)
68 		return (-1);
69 
70 	/* Enable TMC */
71 	bus_write_4(sc->res, TMC_CTL, CTL_TRACECAPTEN);
72 	if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0)
73 		panic("Not enabled\n");
74 
75 	do {
76 		reg = bus_read_4(sc->res, TMC_STS);
77 	} while ((reg & STS_TMCREADY) == 1);
78 
79 	if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0)
80 		panic("Not enabled\n");
81 
82 	return (0);
83 }
84 
85 static int
86 tmc_stop(device_t dev)
87 {
88 	struct tmc_softc *sc;
89 	uint32_t reg;
90 
91 	sc = device_get_softc(dev);
92 
93 	reg = bus_read_4(sc->res, TMC_CTL);
94 	reg &= ~CTL_TRACECAPTEN;
95 	bus_write_4(sc->res, TMC_CTL, reg);
96 
97 	do {
98 		reg = bus_read_4(sc->res, TMC_STS);
99 	} while ((reg & STS_TMCREADY) == 1);
100 
101 	return (0);
102 }
103 
104 static int
105 tmc_configure_etf(device_t dev)
106 {
107 	struct tmc_softc *sc;
108 	uint32_t reg;
109 
110 	sc = device_get_softc(dev);
111 
112 	do {
113 		reg = bus_read_4(sc->res, TMC_STS);
114 	} while ((reg & STS_TMCREADY) == 0);
115 
116 	bus_write_4(sc->res, TMC_MODE, MODE_HW_FIFO);
117 	bus_write_4(sc->res, TMC_FFCR, FFCR_EN_FMT | FFCR_EN_TI);
118 
119 	tmc_start(dev);
120 
121 	dprintf("%s: STS %x, CTL %x, RSZ %x, RRP %x, RWP %x, "
122 	    "LBUFLEVEL %x, CBUFLEVEL %x\n", __func__,
123 	    bus_read_4(sc->res, TMC_STS),
124 	    bus_read_4(sc->res, TMC_CTL),
125 	    bus_read_4(sc->res, TMC_RSZ),
126 	    bus_read_4(sc->res, TMC_RRP),
127 	    bus_read_4(sc->res, TMC_RWP),
128 	    bus_read_4(sc->res, TMC_CBUFLEVEL),
129 	    bus_read_4(sc->res, TMC_LBUFLEVEL));
130 
131 	return (0);
132 }
133 
134 static int
135 tmc_configure_etr(device_t dev, struct endpoint *endp,
136     struct coresight_event *event)
137 {
138 	struct tmc_softc *sc;
139 	uint32_t reg;
140 
141 	sc = device_get_softc(dev);
142 
143 	tmc_stop(dev);
144 
145 	do {
146 		reg = bus_read_4(sc->res, TMC_STS);
147 	} while ((reg & STS_TMCREADY) == 0);
148 
149 	/* Configure TMC */
150 	bus_write_4(sc->res, TMC_MODE, MODE_CIRCULAR_BUFFER);
151 
152 	reg = AXICTL_PROT_CTRL_BIT1;
153 	reg |= AXICTL_WRBURSTLEN_16;
154 
155 	/*
156 	 * SG operation is broken on DragonBoard 410c
157 	 * reg |= AXICTL_SG_MODE;
158 	 */
159 
160 	reg |= AXICTL_AXCACHE_OS;
161 	bus_write_4(sc->res, TMC_AXICTL, reg);
162 
163 	reg = FFCR_EN_FMT | FFCR_EN_TI | FFCR_FON_FLIN |
164 	    FFCR_FON_TRIG_EVT | FFCR_TRIGON_TRIGIN;
165 	bus_write_4(sc->res, TMC_FFCR, reg);
166 
167 	bus_write_4(sc->res, TMC_TRG, 8);
168 
169 	bus_write_4(sc->res, TMC_DBALO, event->etr.low);
170 	bus_write_4(sc->res, TMC_DBAHI, event->etr.high);
171 	bus_write_4(sc->res, TMC_RSZ, event->etr.bufsize / 4);
172 
173 	bus_write_4(sc->res, TMC_RRP, event->etr.low);
174 	bus_write_4(sc->res, TMC_RWP, event->etr.low);
175 
176 	reg = bus_read_4(sc->res, TMC_STS);
177 	reg &= ~STS_FULL;
178 	bus_write_4(sc->res, TMC_STS, reg);
179 
180 	tmc_start(dev);
181 
182 	return (0);
183 }
184 
185 static int
186 tmc_init(device_t dev)
187 {
188 	struct tmc_softc *sc;
189 	uint32_t reg;
190 
191 	sc = device_get_softc(dev);
192 
193 	/* Unlock Coresight */
194 	bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
195 
196 	/* Unlock TMC */
197 	bus_write_4(sc->res, TMC_LAR, CORESIGHT_UNLOCK);
198 
199 	reg = bus_read_4(sc->res, TMC_DEVID);
200 	reg &= DEVID_CONFIGTYPE_M;
201 	switch (reg) {
202 	case DEVID_CONFIGTYPE_ETR:
203 		sc->dev_type = CORESIGHT_ETR;
204 		dprintf(dev, "ETR configuration found\n");
205 		break;
206 	case DEVID_CONFIGTYPE_ETF:
207 		sc->dev_type = CORESIGHT_ETF;
208 		dprintf(dev, "ETF configuration found\n");
209 		if (sc->etf_configured == false) {
210 			tmc_configure_etf(dev);
211 			sc->etf_configured = true;
212 		}
213 		break;
214 	default:
215 		sc->dev_type = CORESIGHT_UNKNOWN;
216 		break;
217 	}
218 
219 	return (0);
220 }
221 
222 static int
223 tmc_enable(device_t dev, struct endpoint *endp,
224     struct coresight_event *event)
225 {
226 	struct tmc_softc *sc;
227 	uint32_t nev;
228 
229 	sc = device_get_softc(dev);
230 
231 	if (sc->dev_type == CORESIGHT_ETF)
232 		return (0);
233 
234 	KASSERT(sc->dev_type == CORESIGHT_ETR,
235 	    ("Wrong dev_type"));
236 
237 	/*
238 	 * Multiple CPUs can call this same time.
239 	 * We allow only one running configuration.
240 	 */
241 
242 	if (event->etr.flags & ETR_FLAG_ALLOCATE) {
243 		event->etr.flags &= ~ETR_FLAG_ALLOCATE;
244 		nev = atomic_fetchadd_int(&sc->nev, 1);
245 		if (nev == 0) {
246 			sc->event = event;
247 			tmc_stop(dev);
248 			tmc_configure_etr(dev, endp, event);
249 			tmc_start(dev);
250 		}
251 	}
252 
253 	return (0);
254 }
255 
256 static void
257 tmc_disable(device_t dev, struct endpoint *endp,
258     struct coresight_event *event)
259 {
260 	struct tmc_softc *sc;
261 	uint32_t nev;
262 
263 	sc = device_get_softc(dev);
264 
265 	/* ETF configuration is static */
266 	if (sc->dev_type == CORESIGHT_ETF)
267 		return;
268 
269 	KASSERT(sc->dev_type == CORESIGHT_ETR, ("Wrong dev_type"));
270 
271 	if (event->etr.flags & ETR_FLAG_RELEASE) {
272 		event->etr.flags &= ~ETR_FLAG_RELEASE;
273 		nev = atomic_fetchadd_int(&sc->nev, -1);
274 		if (nev == 1) {
275 			tmc_stop(dev);
276 			sc->event = NULL;
277 		}
278 	}
279 }
280 
281 static int
282 tmc_read(device_t dev, struct endpoint *endp,
283     struct coresight_event *event)
284 {
285 	struct tmc_softc *sc;
286 	uint32_t cur_ptr;
287 
288 	sc = device_get_softc(dev);
289 
290 	if (sc->dev_type == CORESIGHT_ETF)
291 		return (0);
292 
293 	/*
294 	 * Ensure the event we are reading information for
295 	 * is currently configured one.
296 	 */
297 	if (sc->event != event)
298 		return (0);
299 
300 	if (bus_read_4(sc->res, TMC_STS) & STS_FULL) {
301 		event->etr.offset = 0;
302 		event->etr.cycle++;
303 		tmc_stop(dev);
304 		tmc_start(dev);
305 	} else {
306 		cur_ptr = bus_read_4(sc->res, TMC_RWP);
307 		event->etr.offset = (cur_ptr - event->etr.low);
308 	}
309 
310 	return (0);
311 }
312 
313 int
314 tmc_attach(device_t dev)
315 {
316 	struct coresight_desc desc;
317 	struct tmc_softc *sc;
318 
319 	sc = device_get_softc(dev);
320 	sc->dev = dev;
321 
322 	if (bus_alloc_resources(dev, tmc_spec, &sc->res) != 0) {
323 		device_printf(dev, "cannot allocate resources for device\n");
324 		return (ENXIO);
325 	}
326 
327 	desc.pdata = sc->pdata;
328 	desc.dev = dev;
329 	desc.dev_type = CORESIGHT_TMC;
330 	coresight_register(&desc);
331 
332 	return (0);
333 }
334 
335 static device_method_t tmc_methods[] = {
336 	/* Device interface */
337 	DEVMETHOD(device_attach,	tmc_attach),
338 
339 	/* Coresight interface */
340 	DEVMETHOD(coresight_init,	tmc_init),
341 	DEVMETHOD(coresight_enable,	tmc_enable),
342 	DEVMETHOD(coresight_disable,	tmc_disable),
343 	DEVMETHOD(coresight_read,	tmc_read),
344 	DEVMETHOD_END
345 };
346 
347 DEFINE_CLASS_0(tmc, tmc_driver, tmc_methods, sizeof(struct tmc_softc));
348