1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. 4 * 5 * Description: CoreSight Replicator driver 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/amba/bus.h> 10 #include <linux/kernel.h> 11 #include <linux/device.h> 12 #include <linux/platform_device.h> 13 #include <linux/io.h> 14 #include <linux/err.h> 15 #include <linux/slab.h> 16 #include <linux/pm_runtime.h> 17 #include <linux/clk.h> 18 #include <linux/of.h> 19 #include <linux/coresight.h> 20 21 #include "coresight-priv.h" 22 23 #define REPLICATOR_IDFILTER0 0x000 24 #define REPLICATOR_IDFILTER1 0x004 25 26 DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); 27 28 /** 29 * struct replicator_drvdata - specifics associated to a replicator component 30 * @base: memory mapped base address for this component. Also indicates 31 * whether this one is programmable or not. 32 * @atclk: optional clock for the core parts of the replicator. 33 * @csdev: component vitals needed by the framework 34 * @spinlock: serialize enable/disable operations. 35 */ 36 struct replicator_drvdata { 37 void __iomem *base; 38 struct clk *atclk; 39 struct coresight_device *csdev; 40 spinlock_t spinlock; 41 }; 42 43 static void dynamic_replicator_reset(struct replicator_drvdata *drvdata) 44 { 45 CS_UNLOCK(drvdata->base); 46 47 if (!coresight_claim_device_unlocked(drvdata->base)) { 48 writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0); 49 writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1); 50 coresight_disclaim_device_unlocked(drvdata->base); 51 } 52 53 CS_LOCK(drvdata->base); 54 } 55 56 /* 57 * replicator_reset : Reset the replicator configuration to sane values. 58 */ 59 static inline void replicator_reset(struct replicator_drvdata *drvdata) 60 { 61 if (drvdata->base) 62 dynamic_replicator_reset(drvdata); 63 } 64 65 static int dynamic_replicator_enable(struct replicator_drvdata *drvdata, 66 int inport, int outport) 67 { 68 int rc = 0; 69 u32 reg; 70 71 switch (outport) { 72 case 0: 73 reg = REPLICATOR_IDFILTER0; 74 break; 75 case 1: 76 reg = REPLICATOR_IDFILTER1; 77 break; 78 default: 79 WARN_ON(1); 80 return -EINVAL; 81 } 82 83 CS_UNLOCK(drvdata->base); 84 85 if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) && 86 (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff)) 87 rc = coresight_claim_device_unlocked(drvdata->base); 88 89 /* Ensure that the outport is enabled. */ 90 if (!rc) 91 writel_relaxed(0x00, drvdata->base + reg); 92 CS_LOCK(drvdata->base); 93 94 return rc; 95 } 96 97 static int replicator_enable(struct coresight_device *csdev, int inport, 98 int outport) 99 { 100 int rc = 0; 101 struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 102 unsigned long flags; 103 bool first_enable = false; 104 105 spin_lock_irqsave(&drvdata->spinlock, flags); 106 if (atomic_read(&csdev->refcnt[outport]) == 0) { 107 if (drvdata->base) 108 rc = dynamic_replicator_enable(drvdata, inport, 109 outport); 110 if (!rc) 111 first_enable = true; 112 } 113 if (!rc) 114 atomic_inc(&csdev->refcnt[outport]); 115 spin_unlock_irqrestore(&drvdata->spinlock, flags); 116 117 if (first_enable) 118 dev_dbg(&csdev->dev, "REPLICATOR enabled\n"); 119 return rc; 120 } 121 122 static void dynamic_replicator_disable(struct replicator_drvdata *drvdata, 123 int inport, int outport) 124 { 125 u32 reg; 126 127 switch (outport) { 128 case 0: 129 reg = REPLICATOR_IDFILTER0; 130 break; 131 case 1: 132 reg = REPLICATOR_IDFILTER1; 133 break; 134 default: 135 WARN_ON(1); 136 return; 137 } 138 139 CS_UNLOCK(drvdata->base); 140 141 /* disable the flow of ATB data through port */ 142 writel_relaxed(0xff, drvdata->base + reg); 143 144 if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) && 145 (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff)) 146 coresight_disclaim_device_unlocked(drvdata->base); 147 CS_LOCK(drvdata->base); 148 } 149 150 static void replicator_disable(struct coresight_device *csdev, int inport, 151 int outport) 152 { 153 struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 154 unsigned long flags; 155 bool last_disable = false; 156 157 spin_lock_irqsave(&drvdata->spinlock, flags); 158 if (atomic_dec_return(&csdev->refcnt[outport]) == 0) { 159 if (drvdata->base) 160 dynamic_replicator_disable(drvdata, inport, outport); 161 last_disable = true; 162 } 163 spin_unlock_irqrestore(&drvdata->spinlock, flags); 164 165 if (last_disable) 166 dev_dbg(&csdev->dev, "REPLICATOR disabled\n"); 167 } 168 169 static const struct coresight_ops_link replicator_link_ops = { 170 .enable = replicator_enable, 171 .disable = replicator_disable, 172 }; 173 174 static const struct coresight_ops replicator_cs_ops = { 175 .link_ops = &replicator_link_ops, 176 }; 177 178 #define coresight_replicator_reg(name, offset) \ 179 coresight_simple_reg32(struct replicator_drvdata, name, offset) 180 181 coresight_replicator_reg(idfilter0, REPLICATOR_IDFILTER0); 182 coresight_replicator_reg(idfilter1, REPLICATOR_IDFILTER1); 183 184 static struct attribute *replicator_mgmt_attrs[] = { 185 &dev_attr_idfilter0.attr, 186 &dev_attr_idfilter1.attr, 187 NULL, 188 }; 189 190 static const struct attribute_group replicator_mgmt_group = { 191 .attrs = replicator_mgmt_attrs, 192 .name = "mgmt", 193 }; 194 195 static const struct attribute_group *replicator_groups[] = { 196 &replicator_mgmt_group, 197 NULL, 198 }; 199 200 static int replicator_probe(struct device *dev, struct resource *res) 201 { 202 int ret = 0; 203 struct coresight_platform_data *pdata = NULL; 204 struct replicator_drvdata *drvdata; 205 struct coresight_desc desc = { 0 }; 206 void __iomem *base; 207 208 if (is_of_node(dev_fwnode(dev)) && 209 of_device_is_compatible(dev->of_node, "arm,coresight-replicator")) 210 dev_warn_once(dev, 211 "Uses OBSOLETE CoreSight replicator binding\n"); 212 213 desc.name = coresight_alloc_device_name(&replicator_devs, dev); 214 if (!desc.name) 215 return -ENOMEM; 216 217 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); 218 if (!drvdata) 219 return -ENOMEM; 220 221 drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ 222 if (!IS_ERR(drvdata->atclk)) { 223 ret = clk_prepare_enable(drvdata->atclk); 224 if (ret) 225 return ret; 226 } 227 228 /* 229 * Map the device base for dynamic-replicator, which has been 230 * validated by AMBA core 231 */ 232 if (res) { 233 base = devm_ioremap_resource(dev, res); 234 if (IS_ERR(base)) { 235 ret = PTR_ERR(base); 236 goto out_disable_clk; 237 } 238 drvdata->base = base; 239 desc.groups = replicator_groups; 240 } 241 242 dev_set_drvdata(dev, drvdata); 243 244 pdata = coresight_get_platform_data(dev); 245 if (IS_ERR(pdata)) { 246 ret = PTR_ERR(pdata); 247 goto out_disable_clk; 248 } 249 dev->platform_data = pdata; 250 251 spin_lock_init(&drvdata->spinlock); 252 desc.type = CORESIGHT_DEV_TYPE_LINK; 253 desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; 254 desc.ops = &replicator_cs_ops; 255 desc.pdata = dev->platform_data; 256 desc.dev = dev; 257 258 drvdata->csdev = coresight_register(&desc); 259 if (IS_ERR(drvdata->csdev)) { 260 ret = PTR_ERR(drvdata->csdev); 261 goto out_disable_clk; 262 } 263 264 replicator_reset(drvdata); 265 pm_runtime_put(dev); 266 267 out_disable_clk: 268 if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) 269 clk_disable_unprepare(drvdata->atclk); 270 return ret; 271 } 272 273 static int static_replicator_probe(struct platform_device *pdev) 274 { 275 int ret; 276 277 pm_runtime_get_noresume(&pdev->dev); 278 pm_runtime_set_active(&pdev->dev); 279 pm_runtime_enable(&pdev->dev); 280 281 /* Static replicators do not have programming base */ 282 ret = replicator_probe(&pdev->dev, NULL); 283 284 if (ret) { 285 pm_runtime_put_noidle(&pdev->dev); 286 pm_runtime_disable(&pdev->dev); 287 } 288 289 return ret; 290 } 291 292 #ifdef CONFIG_PM 293 static int replicator_runtime_suspend(struct device *dev) 294 { 295 struct replicator_drvdata *drvdata = dev_get_drvdata(dev); 296 297 if (drvdata && !IS_ERR(drvdata->atclk)) 298 clk_disable_unprepare(drvdata->atclk); 299 300 return 0; 301 } 302 303 static int replicator_runtime_resume(struct device *dev) 304 { 305 struct replicator_drvdata *drvdata = dev_get_drvdata(dev); 306 307 if (drvdata && !IS_ERR(drvdata->atclk)) 308 clk_prepare_enable(drvdata->atclk); 309 310 return 0; 311 } 312 #endif 313 314 static const struct dev_pm_ops replicator_dev_pm_ops = { 315 SET_RUNTIME_PM_OPS(replicator_runtime_suspend, 316 replicator_runtime_resume, NULL) 317 }; 318 319 static const struct of_device_id static_replicator_match[] = { 320 {.compatible = "arm,coresight-replicator"}, 321 {.compatible = "arm,coresight-static-replicator"}, 322 {} 323 }; 324 325 #ifdef CONFIG_ACPI 326 static const struct acpi_device_id static_replicator_acpi_ids[] = { 327 {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */ 328 {} 329 }; 330 #endif 331 332 static struct platform_driver static_replicator_driver = { 333 .probe = static_replicator_probe, 334 .driver = { 335 .name = "coresight-static-replicator", 336 .of_match_table = of_match_ptr(static_replicator_match), 337 .acpi_match_table = ACPI_PTR(static_replicator_acpi_ids), 338 .pm = &replicator_dev_pm_ops, 339 .suppress_bind_attrs = true, 340 }, 341 }; 342 builtin_platform_driver(static_replicator_driver); 343 344 static int dynamic_replicator_probe(struct amba_device *adev, 345 const struct amba_id *id) 346 { 347 return replicator_probe(&adev->dev, &adev->res); 348 } 349 350 static const struct amba_id dynamic_replicator_ids[] = { 351 { 352 .id = 0x000bb909, 353 .mask = 0x000fffff, 354 }, 355 { 356 /* Coresight SoC-600 */ 357 .id = 0x000bb9ec, 358 .mask = 0x000fffff, 359 }, 360 { 0, 0 }, 361 }; 362 363 static struct amba_driver dynamic_replicator_driver = { 364 .drv = { 365 .name = "coresight-dynamic-replicator", 366 .pm = &replicator_dev_pm_ops, 367 .suppress_bind_attrs = true, 368 }, 369 .probe = dynamic_replicator_probe, 370 .id_table = dynamic_replicator_ids, 371 }; 372 builtin_amba_driver(dynamic_replicator_driver); 373