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