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