Commit | Line | Data |
---|---|---|
ad0dfdfd | 1 | // SPDX-License-Identifier: GPL-2.0 |
bc4bf7fe | 2 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. |
941943cf PG |
3 | * |
4 | * Description: CoreSight Trace Memory Controller driver | |
bc4bf7fe PP |
5 | */ |
6 | ||
7 | #include <linux/kernel.h> | |
bc4bf7fe PP |
8 | #include <linux/init.h> |
9 | #include <linux/types.h> | |
10 | #include <linux/device.h> | |
c5ff7344 | 11 | #include <linux/idr.h> |
bc4bf7fe PP |
12 | #include <linux/io.h> |
13 | #include <linux/err.h> | |
14 | #include <linux/fs.h> | |
15 | #include <linux/miscdevice.h> | |
c5ff7344 | 16 | #include <linux/mutex.h> |
ed2cfb2b | 17 | #include <linux/property.h> |
bc4bf7fe PP |
18 | #include <linux/uaccess.h> |
19 | #include <linux/slab.h> | |
20 | #include <linux/dma-mapping.h> | |
21 | #include <linux/spinlock.h> | |
32398ef6 | 22 | #include <linux/pm_runtime.h> |
bc4bf7fe PP |
23 | #include <linux/of.h> |
24 | #include <linux/coresight.h> | |
25 | #include <linux/amba/bus.h> | |
26 | ||
27 | #include "coresight-priv.h" | |
4c324b5f | 28 | #include "coresight-tmc.h" |
bc4bf7fe | 29 | |
6c6ed1e2 | 30 | void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) |
bc4bf7fe PP |
31 | { |
32 | /* Ensure formatter, unformatter and hardware fifo are empty */ | |
33 | if (coresight_timeout(drvdata->base, | |
580ff804 | 34 | TMC_STS, TMC_STS_TMCREADY_BIT, 1)) { |
bc4bf7fe | 35 | dev_err(drvdata->dev, |
67337e8d | 36 | "timeout while waiting for TMC to be Ready\n"); |
bc4bf7fe PP |
37 | } |
38 | } | |
39 | ||
6c6ed1e2 | 40 | void tmc_flush_and_stop(struct tmc_drvdata *drvdata) |
bc4bf7fe PP |
41 | { |
42 | u32 ffcr; | |
43 | ||
44 | ffcr = readl_relaxed(drvdata->base + TMC_FFCR); | |
45 | ffcr |= TMC_FFCR_STOP_ON_FLUSH; | |
46 | writel_relaxed(ffcr, drvdata->base + TMC_FFCR); | |
a8ab4268 | 47 | ffcr |= BIT(TMC_FFCR_FLUSHMAN_BIT); |
bc4bf7fe PP |
48 | writel_relaxed(ffcr, drvdata->base + TMC_FFCR); |
49 | /* Ensure flush completes */ | |
50 | if (coresight_timeout(drvdata->base, | |
51 | TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) { | |
52 | dev_err(drvdata->dev, | |
67337e8d | 53 | "timeout while waiting for completion of Manual Flush\n"); |
bc4bf7fe PP |
54 | } |
55 | ||
580ff804 | 56 | tmc_wait_for_tmcready(drvdata); |
bc4bf7fe PP |
57 | } |
58 | ||
6c6ed1e2 | 59 | void tmc_enable_hw(struct tmc_drvdata *drvdata) |
bc4bf7fe PP |
60 | { |
61 | writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); | |
62 | } | |
63 | ||
6c6ed1e2 | 64 | void tmc_disable_hw(struct tmc_drvdata *drvdata) |
bc4bf7fe PP |
65 | { |
66 | writel_relaxed(0x0, drvdata->base + TMC_CTL); | |
67 | } | |
68 | ||
bc4bf7fe PP |
69 | static int tmc_read_prepare(struct tmc_drvdata *drvdata) |
70 | { | |
b1789b79 | 71 | int ret = 0; |
bc4bf7fe | 72 | |
b1789b79 MP |
73 | switch (drvdata->config_type) { |
74 | case TMC_CONFIG_TYPE_ETB: | |
b1789b79 | 75 | case TMC_CONFIG_TYPE_ETF: |
4525412a | 76 | ret = tmc_read_prepare_etb(drvdata); |
b1789b79 MP |
77 | break; |
78 | case TMC_CONFIG_TYPE_ETR: | |
4525412a | 79 | ret = tmc_read_prepare_etr(drvdata); |
b1789b79 MP |
80 | break; |
81 | default: | |
82 | ret = -EINVAL; | |
bc4bf7fe | 83 | } |
b1789b79 | 84 | |
4525412a | 85 | if (!ret) |
41a75cdd | 86 | dev_dbg(drvdata->dev, "TMC read start\n"); |
4525412a | 87 | |
bc4bf7fe PP |
88 | return ret; |
89 | } | |
90 | ||
f74debbe | 91 | static int tmc_read_unprepare(struct tmc_drvdata *drvdata) |
bc4bf7fe | 92 | { |
4525412a | 93 | int ret = 0; |
bc4bf7fe | 94 | |
b1789b79 MP |
95 | switch (drvdata->config_type) { |
96 | case TMC_CONFIG_TYPE_ETB: | |
b1789b79 | 97 | case TMC_CONFIG_TYPE_ETF: |
4525412a | 98 | ret = tmc_read_unprepare_etb(drvdata); |
b1789b79 MP |
99 | break; |
100 | case TMC_CONFIG_TYPE_ETR: | |
4525412a | 101 | ret = tmc_read_unprepare_etr(drvdata); |
b1789b79 MP |
102 | break; |
103 | default: | |
4525412a | 104 | ret = -EINVAL; |
bc4bf7fe | 105 | } |
b1789b79 | 106 | |
4525412a | 107 | if (!ret) |
41a75cdd | 108 | dev_dbg(drvdata->dev, "TMC read end\n"); |
f74debbe MP |
109 | |
110 | return ret; | |
bc4bf7fe PP |
111 | } |
112 | ||
113 | static int tmc_open(struct inode *inode, struct file *file) | |
114 | { | |
f74debbe | 115 | int ret; |
bc4bf7fe PP |
116 | struct tmc_drvdata *drvdata = container_of(file->private_data, |
117 | struct tmc_drvdata, miscdev); | |
bc4bf7fe PP |
118 | |
119 | ret = tmc_read_prepare(drvdata); | |
120 | if (ret) | |
121 | return ret; | |
f74debbe | 122 | |
bc4bf7fe PP |
123 | nonseekable_open(inode, file); |
124 | ||
125 | dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__); | |
126 | return 0; | |
127 | } | |
128 | ||
3495722a SP |
129 | static inline ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, |
130 | loff_t pos, size_t len, char **bufpp) | |
131 | { | |
132 | switch (drvdata->config_type) { | |
133 | case TMC_CONFIG_TYPE_ETB: | |
134 | case TMC_CONFIG_TYPE_ETF: | |
135 | return tmc_etb_get_sysfs_trace(drvdata, pos, len, bufpp); | |
136 | case TMC_CONFIG_TYPE_ETR: | |
137 | return tmc_etr_get_sysfs_trace(drvdata, pos, len, bufpp); | |
138 | } | |
139 | ||
140 | return -EINVAL; | |
141 | } | |
142 | ||
bc4bf7fe PP |
143 | static ssize_t tmc_read(struct file *file, char __user *data, size_t len, |
144 | loff_t *ppos) | |
145 | { | |
3495722a SP |
146 | char *bufp; |
147 | ssize_t actual; | |
bc4bf7fe PP |
148 | struct tmc_drvdata *drvdata = container_of(file->private_data, |
149 | struct tmc_drvdata, miscdev); | |
3495722a SP |
150 | actual = tmc_get_sysfs_trace(drvdata, *ppos, len, &bufp); |
151 | if (actual <= 0) | |
152 | return 0; | |
bc4bf7fe | 153 | |
3495722a | 154 | if (copy_to_user(data, bufp, actual)) { |
bc4bf7fe PP |
155 | dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__); |
156 | return -EFAULT; | |
157 | } | |
158 | ||
3495722a SP |
159 | *ppos += actual; |
160 | dev_dbg(drvdata->dev, "%zu bytes copied\n", actual); | |
bc4bf7fe | 161 | |
3495722a | 162 | return actual; |
bc4bf7fe PP |
163 | } |
164 | ||
165 | static int tmc_release(struct inode *inode, struct file *file) | |
166 | { | |
f74debbe | 167 | int ret; |
bc4bf7fe PP |
168 | struct tmc_drvdata *drvdata = container_of(file->private_data, |
169 | struct tmc_drvdata, miscdev); | |
170 | ||
f74debbe MP |
171 | ret = tmc_read_unprepare(drvdata); |
172 | if (ret) | |
173 | return ret; | |
bc4bf7fe | 174 | |
bc4bf7fe PP |
175 | dev_dbg(drvdata->dev, "%s: released\n", __func__); |
176 | return 0; | |
177 | } | |
178 | ||
179 | static const struct file_operations tmc_fops = { | |
180 | .owner = THIS_MODULE, | |
181 | .open = tmc_open, | |
182 | .read = tmc_read, | |
183 | .release = tmc_release, | |
184 | .llseek = no_llseek, | |
185 | }; | |
186 | ||
4f1ff3de MP |
187 | static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid) |
188 | { | |
189 | enum tmc_mem_intf_width memwidth; | |
190 | ||
191 | /* | |
192 | * Excerpt from the TRM: | |
193 | * | |
194 | * DEVID::MEMWIDTH[10:8] | |
195 | * 0x2 Memory interface databus is 32 bits wide. | |
196 | * 0x3 Memory interface databus is 64 bits wide. | |
197 | * 0x4 Memory interface databus is 128 bits wide. | |
198 | * 0x5 Memory interface databus is 256 bits wide. | |
199 | */ | |
200 | switch (BMVAL(devid, 8, 10)) { | |
201 | case 0x2: | |
202 | memwidth = TMC_MEM_INTF_WIDTH_32BITS; | |
203 | break; | |
204 | case 0x3: | |
205 | memwidth = TMC_MEM_INTF_WIDTH_64BITS; | |
206 | break; | |
207 | case 0x4: | |
208 | memwidth = TMC_MEM_INTF_WIDTH_128BITS; | |
209 | break; | |
210 | case 0x5: | |
211 | memwidth = TMC_MEM_INTF_WIDTH_256BITS; | |
212 | break; | |
213 | default: | |
214 | memwidth = 0; | |
215 | } | |
216 | ||
217 | return memwidth; | |
218 | } | |
219 | ||
47675f6a SP |
220 | #define coresight_tmc_reg(name, offset) \ |
221 | coresight_simple_reg32(struct tmc_drvdata, name, offset) | |
222 | #define coresight_tmc_reg64(name, lo_off, hi_off) \ | |
223 | coresight_simple_reg64(struct tmc_drvdata, name, lo_off, hi_off) | |
224 | ||
225 | coresight_tmc_reg(rsz, TMC_RSZ); | |
226 | coresight_tmc_reg(sts, TMC_STS); | |
227 | coresight_tmc_reg(trg, TMC_TRG); | |
228 | coresight_tmc_reg(ctl, TMC_CTL); | |
229 | coresight_tmc_reg(ffsr, TMC_FFSR); | |
230 | coresight_tmc_reg(ffcr, TMC_FFCR); | |
231 | coresight_tmc_reg(mode, TMC_MODE); | |
232 | coresight_tmc_reg(pscr, TMC_PSCR); | |
2b455339 | 233 | coresight_tmc_reg(axictl, TMC_AXICTL); |
47675f6a SP |
234 | coresight_tmc_reg(devid, CORESIGHT_DEVID); |
235 | coresight_tmc_reg64(rrp, TMC_RRP, TMC_RRPHI); | |
236 | coresight_tmc_reg64(rwp, TMC_RWP, TMC_RWPHI); | |
2b455339 | 237 | coresight_tmc_reg64(dba, TMC_DBALO, TMC_DBAHI); |
7d83d177 MP |
238 | |
239 | static struct attribute *coresight_tmc_mgmt_attrs[] = { | |
240 | &dev_attr_rsz.attr, | |
241 | &dev_attr_sts.attr, | |
242 | &dev_attr_rrp.attr, | |
243 | &dev_attr_rwp.attr, | |
244 | &dev_attr_trg.attr, | |
245 | &dev_attr_ctl.attr, | |
246 | &dev_attr_ffsr.attr, | |
247 | &dev_attr_ffcr.attr, | |
248 | &dev_attr_mode.attr, | |
249 | &dev_attr_pscr.attr, | |
250 | &dev_attr_devid.attr, | |
2b455339 SP |
251 | &dev_attr_dba.attr, |
252 | &dev_attr_axictl.attr, | |
7d83d177 MP |
253 | NULL, |
254 | }; | |
a2d6e184 | 255 | |
0ef7528d BX |
256 | static ssize_t trigger_cntr_show(struct device *dev, |
257 | struct device_attribute *attr, char *buf) | |
bc4bf7fe PP |
258 | { |
259 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
260 | unsigned long val = drvdata->trigger_cntr; | |
261 | ||
262 | return sprintf(buf, "%#lx\n", val); | |
263 | } | |
264 | ||
265 | static ssize_t trigger_cntr_store(struct device *dev, | |
266 | struct device_attribute *attr, | |
267 | const char *buf, size_t size) | |
268 | { | |
269 | int ret; | |
270 | unsigned long val; | |
271 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
272 | ||
273 | ret = kstrtoul(buf, 16, &val); | |
274 | if (ret) | |
275 | return ret; | |
276 | ||
277 | drvdata->trigger_cntr = val; | |
278 | return size; | |
279 | } | |
280 | static DEVICE_ATTR_RW(trigger_cntr); | |
281 | ||
c34cc23f SP |
282 | static ssize_t buffer_size_show(struct device *dev, |
283 | struct device_attribute *attr, char *buf) | |
284 | { | |
285 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
286 | ||
287 | return sprintf(buf, "%#x\n", drvdata->size); | |
288 | } | |
289 | ||
290 | static ssize_t buffer_size_store(struct device *dev, | |
291 | struct device_attribute *attr, | |
292 | const char *buf, size_t size) | |
293 | { | |
294 | int ret; | |
295 | unsigned long val; | |
296 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
297 | ||
298 | /* Only permitted for TMC-ETRs */ | |
299 | if (drvdata->config_type != TMC_CONFIG_TYPE_ETR) | |
300 | return -EPERM; | |
301 | ||
302 | ret = kstrtoul(buf, 0, &val); | |
303 | if (ret) | |
304 | return ret; | |
305 | /* The buffer size should be page aligned */ | |
306 | if (val & (PAGE_SIZE - 1)) | |
307 | return -EINVAL; | |
308 | drvdata->size = val; | |
309 | return size; | |
310 | } | |
311 | ||
312 | static DEVICE_ATTR_RW(buffer_size); | |
313 | ||
7d83d177 | 314 | static struct attribute *coresight_tmc_attrs[] = { |
bc4bf7fe | 315 | &dev_attr_trigger_cntr.attr, |
c34cc23f | 316 | &dev_attr_buffer_size.attr, |
bc4bf7fe PP |
317 | NULL, |
318 | }; | |
bc4bf7fe | 319 | |
7d83d177 MP |
320 | static const struct attribute_group coresight_tmc_group = { |
321 | .attrs = coresight_tmc_attrs, | |
bc4bf7fe | 322 | }; |
bc4bf7fe | 323 | |
7d83d177 MP |
324 | static const struct attribute_group coresight_tmc_mgmt_group = { |
325 | .attrs = coresight_tmc_mgmt_attrs, | |
326 | .name = "mgmt", | |
327 | }; | |
328 | ||
329 | const struct attribute_group *coresight_tmc_groups[] = { | |
330 | &coresight_tmc_group, | |
331 | &coresight_tmc_mgmt_group, | |
bc4bf7fe PP |
332 | NULL, |
333 | }; | |
bc4bf7fe | 334 | |
ed2cfb2b SP |
335 | static inline bool tmc_etr_can_use_sg(struct tmc_drvdata *drvdata) |
336 | { | |
337 | return fwnode_property_present(drvdata->dev->fwnode, | |
338 | "arm,scatter-gather"); | |
339 | } | |
340 | ||
2884132a SP |
341 | /* Detect and initialise the capabilities of a TMC ETR */ |
342 | static int tmc_etr_setup_caps(struct tmc_drvdata *drvdata, | |
343 | u32 devid, void *dev_caps) | |
344 | { | |
08be8747 SP |
345 | int rc; |
346 | ||
ff11f5bc SP |
347 | u32 dma_mask = 0; |
348 | ||
2884132a SP |
349 | /* Set the unadvertised capabilities */ |
350 | tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps); | |
351 | ||
ed2cfb2b | 352 | if (!(devid & TMC_DEVID_NOSCAT) && tmc_etr_can_use_sg(drvdata)) |
2e219345 | 353 | tmc_etr_set_cap(drvdata, TMC_ETR_SG); |
ff11f5bc SP |
354 | |
355 | /* Check if the AXI address width is available */ | |
356 | if (devid & TMC_DEVID_AXIAW_VALID) | |
357 | dma_mask = ((devid >> TMC_DEVID_AXIAW_SHIFT) & | |
358 | TMC_DEVID_AXIAW_MASK); | |
359 | ||
2884132a | 360 | /* |
ff11f5bc SP |
361 | * Unless specified in the device configuration, ETR uses a 40-bit |
362 | * AXI master in place of the embedded SRAM of ETB/ETF. | |
2884132a | 363 | */ |
ff11f5bc SP |
364 | switch (dma_mask) { |
365 | case 32: | |
366 | case 40: | |
367 | case 44: | |
368 | case 48: | |
369 | case 52: | |
370 | dev_info(drvdata->dev, "Detected dma mask %dbits\n", dma_mask); | |
371 | break; | |
372 | default: | |
373 | dma_mask = 40; | |
374 | } | |
375 | ||
08be8747 SP |
376 | rc = dma_set_mask_and_coherent(drvdata->dev, DMA_BIT_MASK(dma_mask)); |
377 | if (rc) | |
378 | dev_err(drvdata->dev, "Failed to setup DMA mask: %d\n", rc); | |
379 | return rc; | |
2884132a SP |
380 | } |
381 | ||
bc4bf7fe PP |
382 | static int tmc_probe(struct amba_device *adev, const struct amba_id *id) |
383 | { | |
384 | int ret = 0; | |
385 | u32 devid; | |
386 | void __iomem *base; | |
387 | struct device *dev = &adev->dev; | |
388 | struct coresight_platform_data *pdata = NULL; | |
389 | struct tmc_drvdata *drvdata; | |
390 | struct resource *res = &adev->res; | |
9486295a | 391 | struct coresight_desc desc = { 0 }; |
bc4bf7fe PP |
392 | struct device_node *np = adev->dev.of_node; |
393 | ||
394 | if (np) { | |
395 | pdata = of_get_coresight_platform_data(dev, np); | |
3afd0634 SP |
396 | if (IS_ERR(pdata)) { |
397 | ret = PTR_ERR(pdata); | |
398 | goto out; | |
399 | } | |
bc4bf7fe PP |
400 | adev->dev.platform_data = pdata; |
401 | } | |
402 | ||
3afd0634 | 403 | ret = -ENOMEM; |
bc4bf7fe PP |
404 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
405 | if (!drvdata) | |
3afd0634 SP |
406 | goto out; |
407 | ||
bc4bf7fe PP |
408 | drvdata->dev = &adev->dev; |
409 | dev_set_drvdata(dev, drvdata); | |
410 | ||
411 | /* Validity for the resource is already checked by the AMBA core */ | |
412 | base = devm_ioremap_resource(dev, res); | |
3afd0634 SP |
413 | if (IS_ERR(base)) { |
414 | ret = PTR_ERR(base); | |
415 | goto out; | |
416 | } | |
bc4bf7fe PP |
417 | |
418 | drvdata->base = base; | |
419 | ||
420 | spin_lock_init(&drvdata->spinlock); | |
421 | ||
bc4bf7fe PP |
422 | devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); |
423 | drvdata->config_type = BMVAL(devid, 6, 7); | |
4f1ff3de | 424 | drvdata->memwidth = tmc_get_memwidth(devid); |
8d03cfd1 MP |
425 | /* This device is not associated with a session */ |
426 | drvdata->pid = -1; | |
bc4bf7fe PP |
427 | |
428 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { | |
429 | if (np) | |
430 | ret = of_property_read_u32(np, | |
431 | "arm,buffer-size", | |
432 | &drvdata->size); | |
433 | if (ret) | |
434 | drvdata->size = SZ_1M; | |
435 | } else { | |
436 | drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; | |
437 | } | |
438 | ||
9486295a SP |
439 | desc.pdata = pdata; |
440 | desc.dev = dev; | |
441 | desc.groups = coresight_tmc_groups; | |
bc4bf7fe | 442 | |
99ac6f12 SP |
443 | switch (drvdata->config_type) { |
444 | case TMC_CONFIG_TYPE_ETB: | |
9486295a SP |
445 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
446 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; | |
447 | desc.ops = &tmc_etb_cs_ops; | |
99ac6f12 SP |
448 | break; |
449 | case TMC_CONFIG_TYPE_ETR: | |
9486295a SP |
450 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
451 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; | |
452 | desc.ops = &tmc_etr_cs_ops; | |
e85fa28e ML |
453 | ret = tmc_etr_setup_caps(drvdata, devid, |
454 | coresight_get_uci_data(id)); | |
a3959c50 RM |
455 | if (ret) |
456 | goto out; | |
c5ff7344 MP |
457 | idr_init(&drvdata->idr); |
458 | mutex_init(&drvdata->idr_mutex); | |
99ac6f12 SP |
459 | break; |
460 | case TMC_CONFIG_TYPE_ETF: | |
9486295a SP |
461 | desc.type = CORESIGHT_DEV_TYPE_LINKSINK; |
462 | desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; | |
463 | desc.ops = &tmc_etf_cs_ops; | |
99ac6f12 SP |
464 | break; |
465 | default: | |
466 | pr_err("%s: Unsupported TMC config\n", pdata->name); | |
467 | ret = -EINVAL; | |
468 | goto out; | |
bc4bf7fe PP |
469 | } |
470 | ||
9486295a | 471 | drvdata->csdev = coresight_register(&desc); |
bc4bf7fe PP |
472 | if (IS_ERR(drvdata->csdev)) { |
473 | ret = PTR_ERR(drvdata->csdev); | |
3afd0634 | 474 | goto out; |
bc4bf7fe PP |
475 | } |
476 | ||
477 | drvdata->miscdev.name = pdata->name; | |
478 | drvdata->miscdev.minor = MISC_DYNAMIC_MINOR; | |
479 | drvdata->miscdev.fops = &tmc_fops; | |
480 | ret = misc_register(&drvdata->miscdev); | |
481 | if (ret) | |
3afd0634 | 482 | coresight_unregister(drvdata->csdev); |
26355695 SP |
483 | else |
484 | pm_runtime_put(&adev->dev); | |
3afd0634 | 485 | out: |
bc4bf7fe PP |
486 | return ret; |
487 | } | |
488 | ||
6f964e7c | 489 | static const struct amba_id tmc_ids[] = { |
e85fa28e ML |
490 | CS_AMBA_ID(0x000bb961), |
491 | /* Coresight SoC 600 TMC-ETR/ETS */ | |
492 | CS_AMBA_ID_DATA(0x000bb9e8, (unsigned long)CORESIGHT_SOC_600_ETR_CAPS), | |
493 | /* Coresight SoC 600 TMC-ETB */ | |
494 | CS_AMBA_ID(0x000bb9e9), | |
495 | /* Coresight SoC 600 TMC-ETF */ | |
496 | CS_AMBA_ID(0x000bb9ea), | |
bc4bf7fe PP |
497 | { 0, 0}, |
498 | }; | |
499 | ||
500 | static struct amba_driver tmc_driver = { | |
501 | .drv = { | |
502 | .name = "coresight-tmc", | |
503 | .owner = THIS_MODULE, | |
b15f0fb6 | 504 | .suppress_bind_attrs = true, |
bc4bf7fe PP |
505 | }, |
506 | .probe = tmc_probe, | |
bc4bf7fe PP |
507 | .id_table = tmc_ids, |
508 | }; | |
941943cf | 509 | builtin_amba_driver(tmc_driver); |