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