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