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