Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. |
| 2 | * |
Paul Gortmaker | 941943c | 2016-02-17 17:52:03 -0700 | [diff] [blame] | 3 | * Description: CoreSight Trace Memory Controller driver |
| 4 | * |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 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 | |
| 15 | #include <linux/kernel.h> |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 16 | #include <linux/init.h> |
| 17 | #include <linux/types.h> |
| 18 | #include <linux/device.h> |
| 19 | #include <linux/io.h> |
| 20 | #include <linux/err.h> |
| 21 | #include <linux/fs.h> |
| 22 | #include <linux/miscdevice.h> |
| 23 | #include <linux/uaccess.h> |
| 24 | #include <linux/slab.h> |
| 25 | #include <linux/dma-mapping.h> |
| 26 | #include <linux/spinlock.h> |
Linus Walleij | 32398ef | 2015-05-19 10:55:13 -0600 | [diff] [blame] | 27 | #include <linux/pm_runtime.h> |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 28 | #include <linux/of.h> |
| 29 | #include <linux/coresight.h> |
| 30 | #include <linux/amba/bus.h> |
| 31 | |
| 32 | #include "coresight-priv.h" |
Mathieu Poirier | 4c324b5 | 2016-05-03 11:33:48 -0600 | [diff] [blame] | 33 | #include "coresight-tmc.h" |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 34 | |
Mathieu Poirier | 6c6ed1e | 2016-05-03 11:33:50 -0600 | [diff] [blame] | 35 | void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 36 | { |
| 37 | /* Ensure formatter, unformatter and hardware fifo are empty */ |
| 38 | if (coresight_timeout(drvdata->base, |
Mathieu Poirier | 580ff80 | 2016-05-03 11:33:44 -0600 | [diff] [blame] | 39 | TMC_STS, TMC_STS_TMCREADY_BIT, 1)) { |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 40 | dev_err(drvdata->dev, |
| 41 | "timeout observed when probing at offset %#x\n", |
| 42 | TMC_STS); |
| 43 | } |
| 44 | } |
| 45 | |
Mathieu Poirier | 6c6ed1e | 2016-05-03 11:33:50 -0600 | [diff] [blame] | 46 | void tmc_flush_and_stop(struct tmc_drvdata *drvdata) |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 47 | { |
| 48 | u32 ffcr; |
| 49 | |
| 50 | ffcr = readl_relaxed(drvdata->base + TMC_FFCR); |
| 51 | ffcr |= TMC_FFCR_STOP_ON_FLUSH; |
| 52 | writel_relaxed(ffcr, drvdata->base + TMC_FFCR); |
Mathieu Poirier | a8ab4268 | 2016-05-03 11:33:49 -0600 | [diff] [blame] | 53 | ffcr |= BIT(TMC_FFCR_FLUSHMAN_BIT); |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 54 | writel_relaxed(ffcr, drvdata->base + TMC_FFCR); |
| 55 | /* Ensure flush completes */ |
| 56 | if (coresight_timeout(drvdata->base, |
| 57 | TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) { |
| 58 | dev_err(drvdata->dev, |
| 59 | "timeout observed when probing at offset %#x\n", |
| 60 | TMC_FFCR); |
| 61 | } |
| 62 | |
Mathieu Poirier | 580ff80 | 2016-05-03 11:33:44 -0600 | [diff] [blame] | 63 | tmc_wait_for_tmcready(drvdata); |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 64 | } |
| 65 | |
Mathieu Poirier | 6c6ed1e | 2016-05-03 11:33:50 -0600 | [diff] [blame] | 66 | void tmc_enable_hw(struct tmc_drvdata *drvdata) |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 67 | { |
| 68 | writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); |
| 69 | } |
| 70 | |
Mathieu Poirier | 6c6ed1e | 2016-05-03 11:33:50 -0600 | [diff] [blame] | 71 | void tmc_disable_hw(struct tmc_drvdata *drvdata) |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 72 | { |
| 73 | writel_relaxed(0x0, drvdata->base + TMC_CTL); |
| 74 | } |
| 75 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 76 | static int tmc_read_prepare(struct tmc_drvdata *drvdata) |
| 77 | { |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 78 | int ret = 0; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 79 | |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 80 | switch (drvdata->config_type) { |
| 81 | case TMC_CONFIG_TYPE_ETB: |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 82 | case TMC_CONFIG_TYPE_ETF: |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 83 | ret = tmc_read_prepare_etb(drvdata); |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 84 | break; |
| 85 | case TMC_CONFIG_TYPE_ETR: |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 86 | ret = tmc_read_prepare_etr(drvdata); |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 87 | break; |
| 88 | default: |
| 89 | ret = -EINVAL; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 90 | } |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 91 | |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 92 | if (!ret) |
| 93 | dev_info(drvdata->dev, "TMC read start\n"); |
| 94 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 95 | return ret; |
| 96 | } |
| 97 | |
Mathieu Poirier | f74debb | 2016-05-03 11:33:53 -0600 | [diff] [blame] | 98 | static int tmc_read_unprepare(struct tmc_drvdata *drvdata) |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 99 | { |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 100 | int ret = 0; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 101 | |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 102 | switch (drvdata->config_type) { |
| 103 | case TMC_CONFIG_TYPE_ETB: |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 104 | case TMC_CONFIG_TYPE_ETF: |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 105 | ret = tmc_read_unprepare_etb(drvdata); |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 106 | break; |
| 107 | case TMC_CONFIG_TYPE_ETR: |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 108 | ret = tmc_read_unprepare_etr(drvdata); |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 109 | break; |
| 110 | default: |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 111 | ret = -EINVAL; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 112 | } |
Mathieu Poirier | b1789b7 | 2016-05-03 11:33:46 -0600 | [diff] [blame] | 113 | |
Mathieu Poirier | 4525412 | 2016-05-03 11:33:51 -0600 | [diff] [blame] | 114 | if (!ret) |
| 115 | dev_info(drvdata->dev, "TMC read end\n"); |
Mathieu Poirier | f74debb | 2016-05-03 11:33:53 -0600 | [diff] [blame] | 116 | |
| 117 | return ret; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | static int tmc_open(struct inode *inode, struct file *file) |
| 121 | { |
Mathieu Poirier | f74debb | 2016-05-03 11:33:53 -0600 | [diff] [blame] | 122 | int ret; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 123 | struct tmc_drvdata *drvdata = container_of(file->private_data, |
| 124 | struct tmc_drvdata, miscdev); |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 125 | |
| 126 | ret = tmc_read_prepare(drvdata); |
| 127 | if (ret) |
| 128 | return ret; |
Mathieu Poirier | f74debb | 2016-05-03 11:33:53 -0600 | [diff] [blame] | 129 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 130 | nonseekable_open(inode, file); |
| 131 | |
| 132 | dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__); |
| 133 | return 0; |
| 134 | } |
| 135 | |
| 136 | static ssize_t tmc_read(struct file *file, char __user *data, size_t len, |
| 137 | loff_t *ppos) |
| 138 | { |
| 139 | struct tmc_drvdata *drvdata = container_of(file->private_data, |
| 140 | struct tmc_drvdata, miscdev); |
| 141 | char *bufp = drvdata->buf + *ppos; |
| 142 | |
| 143 | if (*ppos + len > drvdata->size) |
| 144 | len = drvdata->size - *ppos; |
| 145 | |
| 146 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { |
| 147 | if (bufp == (char *)(drvdata->vaddr + drvdata->size)) |
| 148 | bufp = drvdata->vaddr; |
| 149 | else if (bufp > (char *)(drvdata->vaddr + drvdata->size)) |
| 150 | bufp -= drvdata->size; |
| 151 | if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size)) |
| 152 | len = (char *)(drvdata->vaddr + drvdata->size) - bufp; |
| 153 | } |
| 154 | |
| 155 | if (copy_to_user(data, bufp, len)) { |
| 156 | dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__); |
| 157 | return -EFAULT; |
| 158 | } |
| 159 | |
| 160 | *ppos += len; |
| 161 | |
Mathieu Poirier | 72f641f | 2015-03-30 14:13:35 -0600 | [diff] [blame] | 162 | dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", |
| 163 | __func__, len, (int)(drvdata->size - *ppos)); |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 164 | return len; |
| 165 | } |
| 166 | |
| 167 | static int tmc_release(struct inode *inode, struct file *file) |
| 168 | { |
Mathieu Poirier | f74debb | 2016-05-03 11:33:53 -0600 | [diff] [blame] | 169 | int ret; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 170 | struct tmc_drvdata *drvdata = container_of(file->private_data, |
| 171 | struct tmc_drvdata, miscdev); |
| 172 | |
Mathieu Poirier | f74debb | 2016-05-03 11:33:53 -0600 | [diff] [blame] | 173 | ret = tmc_read_unprepare(drvdata); |
| 174 | if (ret) |
| 175 | return ret; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 176 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 177 | dev_dbg(drvdata->dev, "%s: released\n", __func__); |
| 178 | return 0; |
| 179 | } |
| 180 | |
| 181 | static const struct file_operations tmc_fops = { |
| 182 | .owner = THIS_MODULE, |
| 183 | .open = tmc_open, |
| 184 | .read = tmc_read, |
| 185 | .release = tmc_release, |
| 186 | .llseek = no_llseek, |
| 187 | }; |
| 188 | |
Mathieu Poirier | 4f1ff3d | 2016-05-03 11:33:57 -0600 | [diff] [blame^] | 189 | static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid) |
| 190 | { |
| 191 | enum tmc_mem_intf_width memwidth; |
| 192 | |
| 193 | /* |
| 194 | * Excerpt from the TRM: |
| 195 | * |
| 196 | * DEVID::MEMWIDTH[10:8] |
| 197 | * 0x2 Memory interface databus is 32 bits wide. |
| 198 | * 0x3 Memory interface databus is 64 bits wide. |
| 199 | * 0x4 Memory interface databus is 128 bits wide. |
| 200 | * 0x5 Memory interface databus is 256 bits wide. |
| 201 | */ |
| 202 | switch (BMVAL(devid, 8, 10)) { |
| 203 | case 0x2: |
| 204 | memwidth = TMC_MEM_INTF_WIDTH_32BITS; |
| 205 | break; |
| 206 | case 0x3: |
| 207 | memwidth = TMC_MEM_INTF_WIDTH_64BITS; |
| 208 | break; |
| 209 | case 0x4: |
| 210 | memwidth = TMC_MEM_INTF_WIDTH_128BITS; |
| 211 | break; |
| 212 | case 0x5: |
| 213 | memwidth = TMC_MEM_INTF_WIDTH_256BITS; |
| 214 | break; |
| 215 | default: |
| 216 | memwidth = 0; |
| 217 | } |
| 218 | |
| 219 | return memwidth; |
| 220 | } |
| 221 | |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 222 | #define coresight_tmc_simple_func(name, offset) \ |
| 223 | coresight_simple_func(struct tmc_drvdata, name, offset) |
Mathieu Poirier | a2d6e18 | 2015-03-30 14:13:40 -0600 | [diff] [blame] | 224 | |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 225 | coresight_tmc_simple_func(rsz, TMC_RSZ); |
| 226 | coresight_tmc_simple_func(sts, TMC_STS); |
| 227 | coresight_tmc_simple_func(rrp, TMC_RRP); |
| 228 | coresight_tmc_simple_func(rwp, TMC_RWP); |
| 229 | coresight_tmc_simple_func(trg, TMC_TRG); |
| 230 | coresight_tmc_simple_func(ctl, TMC_CTL); |
| 231 | coresight_tmc_simple_func(ffsr, TMC_FFSR); |
| 232 | coresight_tmc_simple_func(ffcr, TMC_FFCR); |
| 233 | coresight_tmc_simple_func(mode, TMC_MODE); |
| 234 | coresight_tmc_simple_func(pscr, TMC_PSCR); |
| 235 | coresight_tmc_simple_func(devid, CORESIGHT_DEVID); |
Mathieu Poirier | a2d6e18 | 2015-03-30 14:13:40 -0600 | [diff] [blame] | 236 | |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 237 | static struct attribute *coresight_tmc_mgmt_attrs[] = { |
| 238 | &dev_attr_rsz.attr, |
| 239 | &dev_attr_sts.attr, |
| 240 | &dev_attr_rrp.attr, |
| 241 | &dev_attr_rwp.attr, |
| 242 | &dev_attr_trg.attr, |
| 243 | &dev_attr_ctl.attr, |
| 244 | &dev_attr_ffsr.attr, |
| 245 | &dev_attr_ffcr.attr, |
| 246 | &dev_attr_mode.attr, |
| 247 | &dev_attr_pscr.attr, |
| 248 | &dev_attr_devid.attr, |
| 249 | NULL, |
| 250 | }; |
Mathieu Poirier | a2d6e18 | 2015-03-30 14:13:40 -0600 | [diff] [blame] | 251 | |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 252 | ssize_t trigger_cntr_show(struct device *dev, |
| 253 | struct device_attribute *attr, char *buf) |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 254 | { |
| 255 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 256 | unsigned long val = drvdata->trigger_cntr; |
| 257 | |
| 258 | return sprintf(buf, "%#lx\n", val); |
| 259 | } |
| 260 | |
| 261 | static ssize_t trigger_cntr_store(struct device *dev, |
| 262 | struct device_attribute *attr, |
| 263 | const char *buf, size_t size) |
| 264 | { |
| 265 | int ret; |
| 266 | unsigned long val; |
| 267 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 268 | |
| 269 | ret = kstrtoul(buf, 16, &val); |
| 270 | if (ret) |
| 271 | return ret; |
| 272 | |
| 273 | drvdata->trigger_cntr = val; |
| 274 | return size; |
| 275 | } |
| 276 | static DEVICE_ATTR_RW(trigger_cntr); |
| 277 | |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 278 | static struct attribute *coresight_tmc_attrs[] = { |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 279 | &dev_attr_trigger_cntr.attr, |
| 280 | NULL, |
| 281 | }; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 282 | |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 283 | static const struct attribute_group coresight_tmc_group = { |
| 284 | .attrs = coresight_tmc_attrs, |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 285 | }; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 286 | |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 287 | static const struct attribute_group coresight_tmc_mgmt_group = { |
| 288 | .attrs = coresight_tmc_mgmt_attrs, |
| 289 | .name = "mgmt", |
| 290 | }; |
| 291 | |
| 292 | const struct attribute_group *coresight_tmc_groups[] = { |
| 293 | &coresight_tmc_group, |
| 294 | &coresight_tmc_mgmt_group, |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 295 | NULL, |
| 296 | }; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 297 | |
| 298 | static int tmc_probe(struct amba_device *adev, const struct amba_id *id) |
| 299 | { |
| 300 | int ret = 0; |
| 301 | u32 devid; |
| 302 | void __iomem *base; |
| 303 | struct device *dev = &adev->dev; |
| 304 | struct coresight_platform_data *pdata = NULL; |
| 305 | struct tmc_drvdata *drvdata; |
| 306 | struct resource *res = &adev->res; |
| 307 | struct coresight_desc *desc; |
| 308 | struct device_node *np = adev->dev.of_node; |
| 309 | |
| 310 | if (np) { |
| 311 | pdata = of_get_coresight_platform_data(dev, np); |
| 312 | if (IS_ERR(pdata)) |
| 313 | return PTR_ERR(pdata); |
| 314 | adev->dev.platform_data = pdata; |
| 315 | } |
| 316 | |
| 317 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
| 318 | if (!drvdata) |
| 319 | return -ENOMEM; |
| 320 | |
| 321 | drvdata->dev = &adev->dev; |
| 322 | dev_set_drvdata(dev, drvdata); |
| 323 | |
| 324 | /* Validity for the resource is already checked by the AMBA core */ |
| 325 | base = devm_ioremap_resource(dev, res); |
| 326 | if (IS_ERR(base)) |
| 327 | return PTR_ERR(base); |
| 328 | |
| 329 | drvdata->base = base; |
| 330 | |
| 331 | spin_lock_init(&drvdata->spinlock); |
| 332 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 333 | devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); |
| 334 | drvdata->config_type = BMVAL(devid, 6, 7); |
Mathieu Poirier | 4f1ff3d | 2016-05-03 11:33:57 -0600 | [diff] [blame^] | 335 | drvdata->memwidth = tmc_get_memwidth(devid); |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 336 | |
| 337 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { |
| 338 | if (np) |
| 339 | ret = of_property_read_u32(np, |
| 340 | "arm,buffer-size", |
| 341 | &drvdata->size); |
| 342 | if (ret) |
| 343 | drvdata->size = SZ_1M; |
| 344 | } else { |
| 345 | drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; |
| 346 | } |
| 347 | |
Linus Walleij | 32398ef | 2015-05-19 10:55:13 -0600 | [diff] [blame] | 348 | pm_runtime_put(&adev->dev); |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 349 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 350 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); |
| 351 | if (!desc) { |
| 352 | ret = -ENOMEM; |
| 353 | goto err_devm_kzalloc; |
| 354 | } |
| 355 | |
| 356 | desc->pdata = pdata; |
| 357 | desc->dev = dev; |
| 358 | desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; |
Mathieu Poirier | 7d83d17 | 2016-05-03 11:33:43 -0600 | [diff] [blame] | 359 | desc->groups = coresight_tmc_groups; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 360 | |
| 361 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { |
| 362 | desc->type = CORESIGHT_DEV_TYPE_SINK; |
| 363 | desc->ops = &tmc_etb_cs_ops; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 364 | } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { |
| 365 | desc->type = CORESIGHT_DEV_TYPE_SINK; |
| 366 | desc->ops = &tmc_etr_cs_ops; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 367 | } else { |
| 368 | desc->type = CORESIGHT_DEV_TYPE_LINKSINK; |
| 369 | desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; |
| 370 | desc->ops = &tmc_etf_cs_ops; |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 371 | } |
| 372 | |
| 373 | drvdata->csdev = coresight_register(desc); |
| 374 | if (IS_ERR(drvdata->csdev)) { |
| 375 | ret = PTR_ERR(drvdata->csdev); |
| 376 | goto err_devm_kzalloc; |
| 377 | } |
| 378 | |
| 379 | drvdata->miscdev.name = pdata->name; |
| 380 | drvdata->miscdev.minor = MISC_DYNAMIC_MINOR; |
| 381 | drvdata->miscdev.fops = &tmc_fops; |
| 382 | ret = misc_register(&drvdata->miscdev); |
| 383 | if (ret) |
| 384 | goto err_misc_register; |
| 385 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 386 | return 0; |
| 387 | |
| 388 | err_misc_register: |
| 389 | coresight_unregister(drvdata->csdev); |
| 390 | err_devm_kzalloc: |
| 391 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) |
| 392 | dma_free_coherent(dev, drvdata->size, |
Eric Long | 6139059 | 2016-02-17 17:51:44 -0700 | [diff] [blame] | 393 | drvdata->vaddr, drvdata->paddr); |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 394 | return ret; |
| 395 | } |
| 396 | |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 397 | static struct amba_id tmc_ids[] = { |
| 398 | { |
| 399 | .id = 0x0003b961, |
| 400 | .mask = 0x0003ffff, |
| 401 | }, |
| 402 | { 0, 0}, |
| 403 | }; |
| 404 | |
| 405 | static struct amba_driver tmc_driver = { |
| 406 | .drv = { |
| 407 | .name = "coresight-tmc", |
| 408 | .owner = THIS_MODULE, |
Mathieu Poirier | b15f0fb | 2016-02-02 14:14:00 -0700 | [diff] [blame] | 409 | .suppress_bind_attrs = true, |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 410 | }, |
| 411 | .probe = tmc_probe, |
Pratik Patel | bc4bf7f | 2014-11-03 11:07:36 -0700 | [diff] [blame] | 412 | .id_table = tmc_ids, |
| 413 | }; |
Paul Gortmaker | 941943c | 2016-02-17 17:52:03 -0700 | [diff] [blame] | 414 | builtin_amba_driver(tmc_driver); |