1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. |
4 | * |
5 | * Description: CoreSight System Trace Macrocell driver |
6 | * |
7 | * Initial implementation by Pratik Patel |
8 | * (C) 2014-2015 Pratik Patel <pratikp@codeaurora.org> |
9 | * |
10 | * Serious refactoring, code cleanup and upgrading to the Coresight upstream |
11 | * framework by Mathieu Poirier |
12 | * (C) 2015-2016 Mathieu Poirier <mathieu.poirier@linaro.org> |
13 | * |
14 | * Guaranteed timing and support for various packet type coming from the |
15 | * generic STM API by Chunyan Zhang |
16 | * (C) 2015-2016 Chunyan Zhang <zhang.chunyan@linaro.org> |
17 | */ |
18 | #include <asm/local.h> |
19 | #include <linux/acpi.h> |
20 | #include <linux/amba/bus.h> |
21 | #include <linux/bitmap.h> |
22 | #include <linux/clk.h> |
23 | #include <linux/coresight.h> |
24 | #include <linux/coresight-stm.h> |
25 | #include <linux/err.h> |
26 | #include <linux/kernel.h> |
27 | #include <linux/moduleparam.h> |
28 | #include <linux/of_address.h> |
29 | #include <linux/perf_event.h> |
30 | #include <linux/pm_runtime.h> |
31 | #include <linux/stm.h> |
32 | |
33 | #include "coresight-priv.h" |
34 | #include "coresight-trace-id.h" |
35 | |
36 | #define STMDMASTARTR 0xc04 |
37 | #define STMDMASTOPR 0xc08 |
38 | #define STMDMASTATR 0xc0c |
39 | #define STMDMACTLR 0xc10 |
40 | #define STMDMAIDR 0xcfc |
41 | #define STMHEER 0xd00 |
42 | #define STMHETER 0xd20 |
43 | #define STMHEBSR 0xd60 |
44 | #define STMHEMCR 0xd64 |
45 | #define STMHEMASTR 0xdf4 |
46 | #define STMHEFEAT1R 0xdf8 |
47 | #define STMHEIDR 0xdfc |
48 | #define STMSPER 0xe00 |
49 | #define STMSPTER 0xe20 |
50 | #define STMPRIVMASKR 0xe40 |
51 | #define STMSPSCR 0xe60 |
52 | #define STMSPMSCR 0xe64 |
53 | #define STMSPOVERRIDER 0xe68 |
54 | #define STMSPMOVERRIDER 0xe6c |
55 | #define STMSPTRIGCSR 0xe70 |
56 | #define STMTCSR 0xe80 |
57 | #define STMTSSTIMR 0xe84 |
58 | #define STMTSFREQR 0xe8c |
59 | #define STMSYNCR 0xe90 |
60 | #define STMAUXCR 0xe94 |
61 | #define STMSPFEAT1R 0xea0 |
62 | #define STMSPFEAT2R 0xea4 |
63 | #define STMSPFEAT3R 0xea8 |
64 | #define STMITTRIGGER 0xee8 |
65 | #define STMITATBDATA0 0xeec |
66 | #define STMITATBCTR2 0xef0 |
67 | #define STMITATBID 0xef4 |
68 | #define STMITATBCTR0 0xef8 |
69 | |
70 | #define STM_32_CHANNEL 32 |
71 | #define BYTES_PER_CHANNEL 256 |
72 | #define STM_TRACE_BUF_SIZE 4096 |
73 | #define STM_SW_MASTER_END 127 |
74 | |
75 | /* Register bit definition */ |
76 | #define STMTCSR_BUSY_BIT 23 |
77 | /* Reserve the first 10 channels for kernel usage */ |
78 | #define STM_CHANNEL_OFFSET 0 |
79 | |
80 | enum stm_pkt_type { |
81 | STM_PKT_TYPE_DATA = 0x98, |
82 | STM_PKT_TYPE_FLAG = 0xE8, |
83 | STM_PKT_TYPE_TRIG = 0xF8, |
84 | }; |
85 | |
86 | #define stm_channel_addr(drvdata, ch) (drvdata->chs.base + \ |
87 | (ch * BYTES_PER_CHANNEL)) |
88 | #define stm_channel_off(type, opts) (type & ~opts) |
89 | |
90 | static int boot_nr_channel; |
91 | |
92 | /* |
93 | * Not really modular but using module_param is the easiest way to |
94 | * remain consistent with existing use cases for now. |
95 | */ |
96 | module_param_named( |
97 | boot_nr_channel, boot_nr_channel, int, S_IRUGO |
98 | ); |
99 | |
100 | /* |
101 | * struct channel_space - central management entity for extended ports |
102 | * @base: memory mapped base address where channels start. |
103 | * @phys: physical base address of channel region. |
104 | * @guaraneed: is the channel delivery guaranteed. |
105 | */ |
106 | struct channel_space { |
107 | void __iomem *base; |
108 | phys_addr_t phys; |
109 | unsigned long *guaranteed; |
110 | }; |
111 | |
112 | DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm" ); |
113 | |
114 | /** |
115 | * struct stm_drvdata - specifics associated to an STM component |
116 | * @base: memory mapped base address for this component. |
117 | * @atclk: optional clock for the core parts of the STM. |
118 | * @csdev: component vitals needed by the framework. |
119 | * @spinlock: only one at a time pls. |
120 | * @chs: the channels accociated to this STM. |
121 | * @stm: structure associated to the generic STM interface. |
122 | * @traceid: value of the current ID for this component. |
123 | * @write_bytes: Maximus bytes this STM can write at a time. |
124 | * @stmsper: settings for register STMSPER. |
125 | * @stmspscr: settings for register STMSPSCR. |
126 | * @numsp: the total number of stimulus port support by this STM. |
127 | * @stmheer: settings for register STMHEER. |
128 | * @stmheter: settings for register STMHETER. |
129 | * @stmhebsr: settings for register STMHEBSR. |
130 | */ |
131 | struct stm_drvdata { |
132 | void __iomem *base; |
133 | struct clk *atclk; |
134 | struct coresight_device *csdev; |
135 | spinlock_t spinlock; |
136 | struct channel_space chs; |
137 | struct stm_data stm; |
138 | u8 traceid; |
139 | u32 write_bytes; |
140 | u32 stmsper; |
141 | u32 stmspscr; |
142 | u32 numsp; |
143 | u32 stmheer; |
144 | u32 stmheter; |
145 | u32 stmhebsr; |
146 | }; |
147 | |
148 | static void stm_hwevent_enable_hw(struct stm_drvdata *drvdata) |
149 | { |
150 | CS_UNLOCK(addr: drvdata->base); |
151 | |
152 | writel_relaxed(drvdata->stmhebsr, drvdata->base + STMHEBSR); |
153 | writel_relaxed(drvdata->stmheter, drvdata->base + STMHETER); |
154 | writel_relaxed(drvdata->stmheer, drvdata->base + STMHEER); |
155 | writel_relaxed(0x01 | /* Enable HW event tracing */ |
156 | 0x04, /* Error detection on event tracing */ |
157 | drvdata->base + STMHEMCR); |
158 | |
159 | CS_LOCK(addr: drvdata->base); |
160 | } |
161 | |
162 | static void stm_port_enable_hw(struct stm_drvdata *drvdata) |
163 | { |
164 | CS_UNLOCK(addr: drvdata->base); |
165 | /* ATB trigger enable on direct writes to TRIG locations */ |
166 | writel_relaxed(0x10, |
167 | drvdata->base + STMSPTRIGCSR); |
168 | writel_relaxed(drvdata->stmspscr, drvdata->base + STMSPSCR); |
169 | writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); |
170 | |
171 | CS_LOCK(addr: drvdata->base); |
172 | } |
173 | |
174 | static void stm_enable_hw(struct stm_drvdata *drvdata) |
175 | { |
176 | if (drvdata->stmheer) |
177 | stm_hwevent_enable_hw(drvdata); |
178 | |
179 | stm_port_enable_hw(drvdata); |
180 | |
181 | CS_UNLOCK(addr: drvdata->base); |
182 | |
183 | /* 4096 byte between synchronisation packets */ |
184 | writel_relaxed(0xFFF, drvdata->base + STMSYNCR); |
185 | writel_relaxed((drvdata->traceid << 16 | /* trace id */ |
186 | 0x02 | /* timestamp enable */ |
187 | 0x01), /* global STM enable */ |
188 | drvdata->base + STMTCSR); |
189 | |
190 | CS_LOCK(addr: drvdata->base); |
191 | } |
192 | |
193 | static int stm_enable(struct coresight_device *csdev, struct perf_event *event, |
194 | enum cs_mode mode) |
195 | { |
196 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: csdev->dev.parent); |
197 | |
198 | if (mode != CS_MODE_SYSFS) |
199 | return -EINVAL; |
200 | |
201 | if (!coresight_take_mode(csdev, new_mode: mode)) { |
202 | /* Someone is already using the tracer */ |
203 | return -EBUSY; |
204 | } |
205 | |
206 | pm_runtime_get_sync(dev: csdev->dev.parent); |
207 | |
208 | spin_lock(lock: &drvdata->spinlock); |
209 | stm_enable_hw(drvdata); |
210 | spin_unlock(lock: &drvdata->spinlock); |
211 | |
212 | dev_dbg(&csdev->dev, "STM tracing enabled\n" ); |
213 | return 0; |
214 | } |
215 | |
216 | static void stm_hwevent_disable_hw(struct stm_drvdata *drvdata) |
217 | { |
218 | CS_UNLOCK(addr: drvdata->base); |
219 | |
220 | writel_relaxed(0x0, drvdata->base + STMHEMCR); |
221 | writel_relaxed(0x0, drvdata->base + STMHEER); |
222 | writel_relaxed(0x0, drvdata->base + STMHETER); |
223 | |
224 | CS_LOCK(addr: drvdata->base); |
225 | } |
226 | |
227 | static void stm_port_disable_hw(struct stm_drvdata *drvdata) |
228 | { |
229 | CS_UNLOCK(addr: drvdata->base); |
230 | |
231 | writel_relaxed(0x0, drvdata->base + STMSPER); |
232 | writel_relaxed(0x0, drvdata->base + STMSPTRIGCSR); |
233 | |
234 | CS_LOCK(addr: drvdata->base); |
235 | } |
236 | |
237 | static void stm_disable_hw(struct stm_drvdata *drvdata) |
238 | { |
239 | u32 val; |
240 | |
241 | CS_UNLOCK(addr: drvdata->base); |
242 | |
243 | val = readl_relaxed(drvdata->base + STMTCSR); |
244 | val &= ~0x1; /* clear global STM enable [0] */ |
245 | writel_relaxed(val, drvdata->base + STMTCSR); |
246 | |
247 | CS_LOCK(addr: drvdata->base); |
248 | |
249 | stm_port_disable_hw(drvdata); |
250 | if (drvdata->stmheer) |
251 | stm_hwevent_disable_hw(drvdata); |
252 | } |
253 | |
254 | static void stm_disable(struct coresight_device *csdev, |
255 | struct perf_event *event) |
256 | { |
257 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: csdev->dev.parent); |
258 | struct csdev_access *csa = &csdev->access; |
259 | |
260 | /* |
261 | * For as long as the tracer isn't disabled another entity can't |
262 | * change its status. As such we can read the status here without |
263 | * fearing it will change under us. |
264 | */ |
265 | if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { |
266 | spin_lock(lock: &drvdata->spinlock); |
267 | stm_disable_hw(drvdata); |
268 | spin_unlock(lock: &drvdata->spinlock); |
269 | |
270 | /* Wait until the engine has completely stopped */ |
271 | coresight_timeout(csa, STMTCSR, STMTCSR_BUSY_BIT, value: 0); |
272 | |
273 | pm_runtime_put(dev: csdev->dev.parent); |
274 | |
275 | coresight_set_mode(csdev, new_mode: CS_MODE_DISABLED); |
276 | dev_dbg(&csdev->dev, "STM tracing disabled\n" ); |
277 | } |
278 | } |
279 | |
280 | static const struct coresight_ops_source stm_source_ops = { |
281 | .enable = stm_enable, |
282 | .disable = stm_disable, |
283 | }; |
284 | |
285 | static const struct coresight_ops stm_cs_ops = { |
286 | .source_ops = &stm_source_ops, |
287 | }; |
288 | |
289 | static inline bool stm_addr_unaligned(const void *addr, u8 write_bytes) |
290 | { |
291 | return ((unsigned long)addr & (write_bytes - 1)); |
292 | } |
293 | |
294 | static void stm_send(void __iomem *addr, const void *data, |
295 | u32 size, u8 write_bytes) |
296 | { |
297 | u8 paload[8]; |
298 | |
299 | if (stm_addr_unaligned(addr: data, write_bytes)) { |
300 | memcpy(paload, data, size); |
301 | data = paload; |
302 | } |
303 | |
304 | /* now we are 64bit/32bit aligned */ |
305 | switch (size) { |
306 | #ifdef CONFIG_64BIT |
307 | case 8: |
308 | writeq_relaxed(*(u64 *)data, addr); |
309 | break; |
310 | #endif |
311 | case 4: |
312 | writel_relaxed(*(u32 *)data, addr); |
313 | break; |
314 | case 2: |
315 | writew_relaxed(*(u16 *)data, addr); |
316 | break; |
317 | case 1: |
318 | writeb_relaxed(*(u8 *)data, addr); |
319 | break; |
320 | default: |
321 | break; |
322 | } |
323 | } |
324 | |
325 | static int stm_generic_link(struct stm_data *stm_data, |
326 | unsigned int master, unsigned int channel) |
327 | { |
328 | struct stm_drvdata *drvdata = container_of(stm_data, |
329 | struct stm_drvdata, stm); |
330 | if (!drvdata || !drvdata->csdev) |
331 | return -EINVAL; |
332 | |
333 | return coresight_enable_sysfs(csdev: drvdata->csdev); |
334 | } |
335 | |
336 | static void stm_generic_unlink(struct stm_data *stm_data, |
337 | unsigned int master, unsigned int channel) |
338 | { |
339 | struct stm_drvdata *drvdata = container_of(stm_data, |
340 | struct stm_drvdata, stm); |
341 | if (!drvdata || !drvdata->csdev) |
342 | return; |
343 | |
344 | coresight_disable_sysfs(csdev: drvdata->csdev); |
345 | } |
346 | |
347 | static phys_addr_t |
348 | stm_mmio_addr(struct stm_data *stm_data, unsigned int master, |
349 | unsigned int channel, unsigned int nr_chans) |
350 | { |
351 | struct stm_drvdata *drvdata = container_of(stm_data, |
352 | struct stm_drvdata, stm); |
353 | phys_addr_t addr; |
354 | |
355 | addr = drvdata->chs.phys + channel * BYTES_PER_CHANNEL; |
356 | |
357 | if (offset_in_page(addr) || |
358 | offset_in_page(nr_chans * BYTES_PER_CHANNEL)) |
359 | return 0; |
360 | |
361 | return addr; |
362 | } |
363 | |
364 | static long stm_generic_set_options(struct stm_data *stm_data, |
365 | unsigned int master, |
366 | unsigned int channel, |
367 | unsigned int nr_chans, |
368 | unsigned long options) |
369 | { |
370 | struct stm_drvdata *drvdata = container_of(stm_data, |
371 | struct stm_drvdata, stm); |
372 | if (!(drvdata && coresight_get_mode(csdev: drvdata->csdev))) |
373 | return -EINVAL; |
374 | |
375 | if (channel >= drvdata->numsp) |
376 | return -EINVAL; |
377 | |
378 | switch (options) { |
379 | case STM_OPTION_GUARANTEED: |
380 | set_bit(nr: channel, addr: drvdata->chs.guaranteed); |
381 | break; |
382 | |
383 | case STM_OPTION_INVARIANT: |
384 | clear_bit(nr: channel, addr: drvdata->chs.guaranteed); |
385 | break; |
386 | |
387 | default: |
388 | return -EINVAL; |
389 | } |
390 | |
391 | return 0; |
392 | } |
393 | |
394 | static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, |
395 | unsigned int master, |
396 | unsigned int channel, |
397 | unsigned int packet, |
398 | unsigned int flags, |
399 | unsigned int size, |
400 | const unsigned char *payload) |
401 | { |
402 | void __iomem *ch_addr; |
403 | struct stm_drvdata *drvdata = container_of(stm_data, |
404 | struct stm_drvdata, stm); |
405 | unsigned int stm_flags; |
406 | |
407 | if (!(drvdata && coresight_get_mode(csdev: drvdata->csdev))) |
408 | return -EACCES; |
409 | |
410 | if (channel >= drvdata->numsp) |
411 | return -EINVAL; |
412 | |
413 | ch_addr = stm_channel_addr(drvdata, channel); |
414 | |
415 | stm_flags = (flags & STP_PACKET_TIMESTAMPED) ? |
416 | STM_FLAG_TIMESTAMPED : 0; |
417 | stm_flags |= test_bit(channel, drvdata->chs.guaranteed) ? |
418 | STM_FLAG_GUARANTEED : 0; |
419 | |
420 | if (size > drvdata->write_bytes) |
421 | size = drvdata->write_bytes; |
422 | else |
423 | size = rounddown_pow_of_two(size); |
424 | |
425 | switch (packet) { |
426 | case STP_PACKET_FLAG: |
427 | ch_addr += stm_channel_off(STM_PKT_TYPE_FLAG, stm_flags); |
428 | |
429 | /* |
430 | * The generic STM core sets a size of '0' on flag packets. |
431 | * As such send a flag packet of size '1' and tell the |
432 | * core we did so. |
433 | */ |
434 | stm_send(addr: ch_addr, data: payload, size: 1, write_bytes: drvdata->write_bytes); |
435 | size = 1; |
436 | break; |
437 | |
438 | case STP_PACKET_DATA: |
439 | stm_flags |= (flags & STP_PACKET_MARKED) ? STM_FLAG_MARKED : 0; |
440 | ch_addr += stm_channel_off(STM_PKT_TYPE_DATA, stm_flags); |
441 | stm_send(addr: ch_addr, data: payload, size, |
442 | write_bytes: drvdata->write_bytes); |
443 | break; |
444 | |
445 | default: |
446 | return -ENOTSUPP; |
447 | } |
448 | |
449 | return size; |
450 | } |
451 | |
452 | static ssize_t hwevent_enable_show(struct device *dev, |
453 | struct device_attribute *attr, char *buf) |
454 | { |
455 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
456 | unsigned long val = drvdata->stmheer; |
457 | |
458 | return scnprintf(buf, PAGE_SIZE, fmt: "%#lx\n" , val); |
459 | } |
460 | |
461 | static ssize_t hwevent_enable_store(struct device *dev, |
462 | struct device_attribute *attr, |
463 | const char *buf, size_t size) |
464 | { |
465 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
466 | unsigned long val; |
467 | int ret = 0; |
468 | |
469 | ret = kstrtoul(s: buf, base: 16, res: &val); |
470 | if (ret) |
471 | return -EINVAL; |
472 | |
473 | drvdata->stmheer = val; |
474 | /* HW event enable and trigger go hand in hand */ |
475 | drvdata->stmheter = val; |
476 | |
477 | return size; |
478 | } |
479 | static DEVICE_ATTR_RW(hwevent_enable); |
480 | |
481 | static ssize_t hwevent_select_show(struct device *dev, |
482 | struct device_attribute *attr, char *buf) |
483 | { |
484 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
485 | unsigned long val = drvdata->stmhebsr; |
486 | |
487 | return scnprintf(buf, PAGE_SIZE, fmt: "%#lx\n" , val); |
488 | } |
489 | |
490 | static ssize_t hwevent_select_store(struct device *dev, |
491 | struct device_attribute *attr, |
492 | const char *buf, size_t size) |
493 | { |
494 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
495 | unsigned long val; |
496 | int ret = 0; |
497 | |
498 | ret = kstrtoul(s: buf, base: 16, res: &val); |
499 | if (ret) |
500 | return -EINVAL; |
501 | |
502 | drvdata->stmhebsr = val; |
503 | |
504 | return size; |
505 | } |
506 | static DEVICE_ATTR_RW(hwevent_select); |
507 | |
508 | static ssize_t port_select_show(struct device *dev, |
509 | struct device_attribute *attr, char *buf) |
510 | { |
511 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
512 | unsigned long val; |
513 | |
514 | if (!coresight_get_mode(csdev: drvdata->csdev)) { |
515 | val = drvdata->stmspscr; |
516 | } else { |
517 | spin_lock(lock: &drvdata->spinlock); |
518 | val = readl_relaxed(drvdata->base + STMSPSCR); |
519 | spin_unlock(lock: &drvdata->spinlock); |
520 | } |
521 | |
522 | return scnprintf(buf, PAGE_SIZE, fmt: "%#lx\n" , val); |
523 | } |
524 | |
525 | static ssize_t port_select_store(struct device *dev, |
526 | struct device_attribute *attr, |
527 | const char *buf, size_t size) |
528 | { |
529 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
530 | unsigned long val, stmsper; |
531 | int ret = 0; |
532 | |
533 | ret = kstrtoul(s: buf, base: 16, res: &val); |
534 | if (ret) |
535 | return ret; |
536 | |
537 | spin_lock(lock: &drvdata->spinlock); |
538 | drvdata->stmspscr = val; |
539 | |
540 | if (coresight_get_mode(csdev: drvdata->csdev)) { |
541 | CS_UNLOCK(addr: drvdata->base); |
542 | /* Process as per ARM's TRM recommendation */ |
543 | stmsper = readl_relaxed(drvdata->base + STMSPER); |
544 | writel_relaxed(0x0, drvdata->base + STMSPER); |
545 | writel_relaxed(drvdata->stmspscr, drvdata->base + STMSPSCR); |
546 | writel_relaxed(stmsper, drvdata->base + STMSPER); |
547 | CS_LOCK(addr: drvdata->base); |
548 | } |
549 | spin_unlock(lock: &drvdata->spinlock); |
550 | |
551 | return size; |
552 | } |
553 | static DEVICE_ATTR_RW(port_select); |
554 | |
555 | static ssize_t port_enable_show(struct device *dev, |
556 | struct device_attribute *attr, char *buf) |
557 | { |
558 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
559 | unsigned long val; |
560 | |
561 | if (!coresight_get_mode(csdev: drvdata->csdev)) { |
562 | val = drvdata->stmsper; |
563 | } else { |
564 | spin_lock(lock: &drvdata->spinlock); |
565 | val = readl_relaxed(drvdata->base + STMSPER); |
566 | spin_unlock(lock: &drvdata->spinlock); |
567 | } |
568 | |
569 | return scnprintf(buf, PAGE_SIZE, fmt: "%#lx\n" , val); |
570 | } |
571 | |
572 | static ssize_t port_enable_store(struct device *dev, |
573 | struct device_attribute *attr, |
574 | const char *buf, size_t size) |
575 | { |
576 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
577 | unsigned long val; |
578 | int ret = 0; |
579 | |
580 | ret = kstrtoul(s: buf, base: 16, res: &val); |
581 | if (ret) |
582 | return ret; |
583 | |
584 | spin_lock(lock: &drvdata->spinlock); |
585 | drvdata->stmsper = val; |
586 | |
587 | if (coresight_get_mode(csdev: drvdata->csdev)) { |
588 | CS_UNLOCK(addr: drvdata->base); |
589 | writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); |
590 | CS_LOCK(addr: drvdata->base); |
591 | } |
592 | spin_unlock(lock: &drvdata->spinlock); |
593 | |
594 | return size; |
595 | } |
596 | static DEVICE_ATTR_RW(port_enable); |
597 | |
598 | static ssize_t traceid_show(struct device *dev, |
599 | struct device_attribute *attr, char *buf) |
600 | { |
601 | unsigned long val; |
602 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: dev->parent); |
603 | |
604 | val = drvdata->traceid; |
605 | return sprintf(buf, fmt: "%#lx\n" , val); |
606 | } |
607 | static DEVICE_ATTR_RO(traceid); |
608 | |
609 | static struct attribute *coresight_stm_attrs[] = { |
610 | &dev_attr_hwevent_enable.attr, |
611 | &dev_attr_hwevent_select.attr, |
612 | &dev_attr_port_enable.attr, |
613 | &dev_attr_port_select.attr, |
614 | &dev_attr_traceid.attr, |
615 | NULL, |
616 | }; |
617 | |
618 | static struct attribute *coresight_stm_mgmt_attrs[] = { |
619 | coresight_simple_reg32(tcsr, STMTCSR), |
620 | coresight_simple_reg32(tsfreqr, STMTSFREQR), |
621 | coresight_simple_reg32(syncr, STMSYNCR), |
622 | coresight_simple_reg32(sper, STMSPER), |
623 | coresight_simple_reg32(spter, STMSPTER), |
624 | coresight_simple_reg32(privmaskr, STMPRIVMASKR), |
625 | coresight_simple_reg32(spscr, STMSPSCR), |
626 | coresight_simple_reg32(spmscr, STMSPMSCR), |
627 | coresight_simple_reg32(spfeat1r, STMSPFEAT1R), |
628 | coresight_simple_reg32(spfeat2r, STMSPFEAT2R), |
629 | coresight_simple_reg32(spfeat3r, STMSPFEAT3R), |
630 | coresight_simple_reg32(devid, CORESIGHT_DEVID), |
631 | NULL, |
632 | }; |
633 | |
634 | static const struct attribute_group coresight_stm_group = { |
635 | .attrs = coresight_stm_attrs, |
636 | }; |
637 | |
638 | static const struct attribute_group coresight_stm_mgmt_group = { |
639 | .attrs = coresight_stm_mgmt_attrs, |
640 | .name = "mgmt" , |
641 | }; |
642 | |
643 | static const struct attribute_group *coresight_stm_groups[] = { |
644 | &coresight_stm_group, |
645 | &coresight_stm_mgmt_group, |
646 | NULL, |
647 | }; |
648 | |
649 | #ifdef CONFIG_OF |
650 | static int of_stm_get_stimulus_area(struct device *dev, struct resource *res) |
651 | { |
652 | const char *name = NULL; |
653 | int index = 0, found = 0; |
654 | struct device_node *np = dev->of_node; |
655 | |
656 | while (!of_property_read_string_index(np, propname: "reg-names" , index, output: &name)) { |
657 | if (strcmp("stm-stimulus-base" , name)) { |
658 | index++; |
659 | continue; |
660 | } |
661 | |
662 | /* We have a match and @index is where it's at */ |
663 | found = 1; |
664 | break; |
665 | } |
666 | |
667 | if (!found) |
668 | return -EINVAL; |
669 | |
670 | return of_address_to_resource(dev: np, index, r: res); |
671 | } |
672 | #else |
673 | static inline int of_stm_get_stimulus_area(struct device *dev, |
674 | struct resource *res) |
675 | { |
676 | return -ENOENT; |
677 | } |
678 | #endif |
679 | |
680 | #ifdef CONFIG_ACPI |
681 | static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res) |
682 | { |
683 | int rc; |
684 | bool found_base = false; |
685 | struct resource_entry *rent; |
686 | LIST_HEAD(res_list); |
687 | |
688 | struct acpi_device *adev = ACPI_COMPANION(dev); |
689 | |
690 | rc = acpi_dev_get_resources(adev, list: &res_list, NULL, NULL); |
691 | if (rc < 0) |
692 | return rc; |
693 | |
694 | /* |
695 | * The stimulus base for STM device must be listed as the second memory |
696 | * resource, followed by the programming base address as described in |
697 | * "Section 2.3 Resources" in ACPI for CoreSightTM 1.0 Platform Design |
698 | * document (DEN0067). |
699 | */ |
700 | rc = -ENOENT; |
701 | list_for_each_entry(rent, &res_list, node) { |
702 | if (resource_type(res: rent->res) != IORESOURCE_MEM) |
703 | continue; |
704 | if (found_base) { |
705 | *res = *rent->res; |
706 | rc = 0; |
707 | break; |
708 | } |
709 | |
710 | found_base = true; |
711 | } |
712 | |
713 | acpi_dev_free_resource_list(list: &res_list); |
714 | return rc; |
715 | } |
716 | #else |
717 | static inline int acpi_stm_get_stimulus_area(struct device *dev, |
718 | struct resource *res) |
719 | { |
720 | return -ENOENT; |
721 | } |
722 | #endif |
723 | |
724 | static int stm_get_stimulus_area(struct device *dev, struct resource *res) |
725 | { |
726 | struct fwnode_handle *fwnode = dev_fwnode(dev); |
727 | |
728 | if (is_of_node(fwnode)) |
729 | return of_stm_get_stimulus_area(dev, res); |
730 | else if (is_acpi_node(fwnode)) |
731 | return acpi_stm_get_stimulus_area(dev, res); |
732 | return -ENOENT; |
733 | } |
734 | |
735 | static u32 stm_fundamental_data_size(struct stm_drvdata *drvdata) |
736 | { |
737 | u32 stmspfeat2r; |
738 | |
739 | if (!IS_ENABLED(CONFIG_64BIT)) |
740 | return 4; |
741 | |
742 | stmspfeat2r = readl_relaxed(drvdata->base + STMSPFEAT2R); |
743 | |
744 | /* |
745 | * bit[15:12] represents the fundamental data size |
746 | * 0 - 32-bit data |
747 | * 1 - 64-bit data |
748 | */ |
749 | return BMVAL(stmspfeat2r, 12, 15) ? 8 : 4; |
750 | } |
751 | |
752 | static u32 stm_num_stimulus_port(struct stm_drvdata *drvdata) |
753 | { |
754 | u32 numsp; |
755 | |
756 | numsp = readl_relaxed(drvdata->base + CORESIGHT_DEVID); |
757 | /* |
758 | * NUMPS in STMDEVID is 17 bit long and if equal to 0x0, |
759 | * 32 stimulus ports are supported. |
760 | */ |
761 | numsp &= 0x1ffff; |
762 | if (!numsp) |
763 | numsp = STM_32_CHANNEL; |
764 | return numsp; |
765 | } |
766 | |
767 | static void stm_init_default_data(struct stm_drvdata *drvdata) |
768 | { |
769 | /* Don't use port selection */ |
770 | drvdata->stmspscr = 0x0; |
771 | /* |
772 | * Enable all channel regardless of their number. When port |
773 | * selection isn't used (see above) STMSPER applies to all |
774 | * 32 channel group available, hence setting all 32 bits to 1 |
775 | */ |
776 | drvdata->stmsper = ~0x0; |
777 | |
778 | /* Set invariant transaction timing on all channels */ |
779 | bitmap_clear(map: drvdata->chs.guaranteed, start: 0, nbits: drvdata->numsp); |
780 | } |
781 | |
782 | static void stm_init_generic_data(struct stm_drvdata *drvdata, |
783 | const char *name) |
784 | { |
785 | drvdata->stm.name = name; |
786 | |
787 | /* |
788 | * MasterIDs are assigned at HW design phase. As such the core is |
789 | * using a single master for interaction with this device. |
790 | */ |
791 | drvdata->stm.sw_start = 1; |
792 | drvdata->stm.sw_end = 1; |
793 | drvdata->stm.hw_override = true; |
794 | drvdata->stm.sw_nchannels = drvdata->numsp; |
795 | drvdata->stm.sw_mmiosz = BYTES_PER_CHANNEL; |
796 | drvdata->stm.packet = stm_generic_packet; |
797 | drvdata->stm.mmio_addr = stm_mmio_addr; |
798 | drvdata->stm.link = stm_generic_link; |
799 | drvdata->stm.unlink = stm_generic_unlink; |
800 | drvdata->stm.set_options = stm_generic_set_options; |
801 | } |
802 | |
803 | static int stm_probe(struct amba_device *adev, const struct amba_id *id) |
804 | { |
805 | int ret, trace_id; |
806 | void __iomem *base; |
807 | struct device *dev = &adev->dev; |
808 | struct coresight_platform_data *pdata = NULL; |
809 | struct stm_drvdata *drvdata; |
810 | struct resource *res = &adev->res; |
811 | struct resource ch_res; |
812 | struct coresight_desc desc = { 0 }; |
813 | |
814 | desc.name = coresight_alloc_device_name(devs: &stm_devs, dev); |
815 | if (!desc.name) |
816 | return -ENOMEM; |
817 | |
818 | drvdata = devm_kzalloc(dev, size: sizeof(*drvdata), GFP_KERNEL); |
819 | if (!drvdata) |
820 | return -ENOMEM; |
821 | |
822 | drvdata->atclk = devm_clk_get(dev: &adev->dev, id: "atclk" ); /* optional */ |
823 | if (!IS_ERR(ptr: drvdata->atclk)) { |
824 | ret = clk_prepare_enable(clk: drvdata->atclk); |
825 | if (ret) |
826 | return ret; |
827 | } |
828 | dev_set_drvdata(dev, data: drvdata); |
829 | |
830 | base = devm_ioremap_resource(dev, res); |
831 | if (IS_ERR(ptr: base)) |
832 | return PTR_ERR(ptr: base); |
833 | drvdata->base = base; |
834 | desc.access = CSDEV_ACCESS_IOMEM(base); |
835 | |
836 | ret = stm_get_stimulus_area(dev, res: &ch_res); |
837 | if (ret) |
838 | return ret; |
839 | drvdata->chs.phys = ch_res.start; |
840 | |
841 | base = devm_ioremap_resource(dev, res: &ch_res); |
842 | if (IS_ERR(ptr: base)) |
843 | return PTR_ERR(ptr: base); |
844 | drvdata->chs.base = base; |
845 | |
846 | drvdata->write_bytes = stm_fundamental_data_size(drvdata); |
847 | |
848 | if (boot_nr_channel) |
849 | drvdata->numsp = boot_nr_channel; |
850 | else |
851 | drvdata->numsp = stm_num_stimulus_port(drvdata); |
852 | |
853 | drvdata->chs.guaranteed = devm_bitmap_zalloc(dev, nbits: drvdata->numsp, |
854 | GFP_KERNEL); |
855 | if (!drvdata->chs.guaranteed) |
856 | return -ENOMEM; |
857 | |
858 | spin_lock_init(&drvdata->spinlock); |
859 | |
860 | stm_init_default_data(drvdata); |
861 | stm_init_generic_data(drvdata, name: desc.name); |
862 | |
863 | if (stm_register_device(parent: dev, stm_data: &drvdata->stm, THIS_MODULE)) { |
864 | dev_info(dev, |
865 | "%s : stm_register_device failed, probing deferred\n" , |
866 | desc.name); |
867 | return -EPROBE_DEFER; |
868 | } |
869 | |
870 | pdata = coresight_get_platform_data(dev); |
871 | if (IS_ERR(ptr: pdata)) { |
872 | ret = PTR_ERR(ptr: pdata); |
873 | goto stm_unregister; |
874 | } |
875 | adev->dev.platform_data = pdata; |
876 | |
877 | desc.type = CORESIGHT_DEV_TYPE_SOURCE; |
878 | desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE; |
879 | desc.ops = &stm_cs_ops; |
880 | desc.pdata = pdata; |
881 | desc.dev = dev; |
882 | desc.groups = coresight_stm_groups; |
883 | drvdata->csdev = coresight_register(desc: &desc); |
884 | if (IS_ERR(ptr: drvdata->csdev)) { |
885 | ret = PTR_ERR(ptr: drvdata->csdev); |
886 | goto stm_unregister; |
887 | } |
888 | |
889 | trace_id = coresight_trace_id_get_system_id(); |
890 | if (trace_id < 0) { |
891 | ret = trace_id; |
892 | goto cs_unregister; |
893 | } |
894 | drvdata->traceid = (u8)trace_id; |
895 | |
896 | pm_runtime_put(dev: &adev->dev); |
897 | |
898 | dev_info(&drvdata->csdev->dev, "%s initialized\n" , |
899 | (char *)coresight_get_uci_data(id)); |
900 | return 0; |
901 | |
902 | cs_unregister: |
903 | coresight_unregister(csdev: drvdata->csdev); |
904 | |
905 | stm_unregister: |
906 | stm_unregister_device(stm_data: &drvdata->stm); |
907 | return ret; |
908 | } |
909 | |
910 | static void stm_remove(struct amba_device *adev) |
911 | { |
912 | struct stm_drvdata *drvdata = dev_get_drvdata(dev: &adev->dev); |
913 | |
914 | coresight_trace_id_put_system_id(id: drvdata->traceid); |
915 | coresight_unregister(csdev: drvdata->csdev); |
916 | |
917 | stm_unregister_device(stm_data: &drvdata->stm); |
918 | } |
919 | |
920 | #ifdef CONFIG_PM |
921 | static int stm_runtime_suspend(struct device *dev) |
922 | { |
923 | struct stm_drvdata *drvdata = dev_get_drvdata(dev); |
924 | |
925 | if (drvdata && !IS_ERR(ptr: drvdata->atclk)) |
926 | clk_disable_unprepare(clk: drvdata->atclk); |
927 | |
928 | return 0; |
929 | } |
930 | |
931 | static int stm_runtime_resume(struct device *dev) |
932 | { |
933 | struct stm_drvdata *drvdata = dev_get_drvdata(dev); |
934 | |
935 | if (drvdata && !IS_ERR(ptr: drvdata->atclk)) |
936 | clk_prepare_enable(clk: drvdata->atclk); |
937 | |
938 | return 0; |
939 | } |
940 | #endif |
941 | |
942 | static const struct dev_pm_ops stm_dev_pm_ops = { |
943 | SET_RUNTIME_PM_OPS(stm_runtime_suspend, stm_runtime_resume, NULL) |
944 | }; |
945 | |
946 | static const struct amba_id stm_ids[] = { |
947 | CS_AMBA_ID_DATA(0x000bb962, "STM32" ), |
948 | CS_AMBA_ID_DATA(0x000bb963, "STM500" ), |
949 | { 0, 0, NULL }, |
950 | }; |
951 | |
952 | MODULE_DEVICE_TABLE(amba, stm_ids); |
953 | |
954 | static struct amba_driver stm_driver = { |
955 | .drv = { |
956 | .name = "coresight-stm" , |
957 | .owner = THIS_MODULE, |
958 | .pm = &stm_dev_pm_ops, |
959 | .suppress_bind_attrs = true, |
960 | }, |
961 | .probe = stm_probe, |
962 | .remove = stm_remove, |
963 | .id_table = stm_ids, |
964 | }; |
965 | |
966 | module_amba_driver(stm_driver); |
967 | |
968 | MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>" ); |
969 | MODULE_DESCRIPTION("Arm CoreSight System Trace Macrocell driver" ); |
970 | MODULE_LICENSE("GPL v2" ); |
971 | |