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 pr_warn_once("Uses OBSOLETE CoreSight replicator binding\n"); 188 189 desc.name = coresight_alloc_device_name(&replicator_devs, dev); 190 if (!desc.name) 191 return -ENOMEM; 192 193 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); 194 if (!drvdata) 195 return -ENOMEM; 196 197 drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ 198 if (!IS_ERR(drvdata->atclk)) { 199 ret = clk_prepare_enable(drvdata->atclk); 200 if (ret) 201 return ret; 202 } 203 204 /* 205 * Map the device base for dynamic-replicator, which has been 206 * validated by AMBA core 207 */ 208 if (res) { 209 base = devm_ioremap_resource(dev, res); 210 if (IS_ERR(base)) { 211 ret = PTR_ERR(base); 212 goto out_disable_clk; 213 } 214 drvdata->base = base; 215 desc.groups = replicator_groups; 216 } 217 218 dev_set_drvdata(dev, drvdata); 219 220 pdata = coresight_get_platform_data(dev); 221 if (IS_ERR(pdata)) { 222 ret = PTR_ERR(pdata); 223 goto out_disable_clk; 224 } 225 dev->platform_data = pdata; 226 227 desc.type = CORESIGHT_DEV_TYPE_LINK; 228 desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; 229 desc.ops = &replicator_cs_ops; 230 desc.pdata = dev->platform_data; 231 desc.dev = dev; 232 233 drvdata->csdev = coresight_register(&desc); 234 if (IS_ERR(drvdata->csdev)) { 235 ret = PTR_ERR(drvdata->csdev); 236 goto out_disable_clk; 237 } 238 239 replicator_reset(drvdata); 240 pm_runtime_put(dev); 241 242 out_disable_clk: 243 if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) 244 clk_disable_unprepare(drvdata->atclk); 245 return ret; 246 } 247 248 static int static_replicator_probe(struct platform_device *pdev) 249 { 250 int ret; 251 252 pm_runtime_get_noresume(&pdev->dev); 253 pm_runtime_set_active(&pdev->dev); 254 pm_runtime_enable(&pdev->dev); 255 256 /* Static replicators do not have programming base */ 257 ret = replicator_probe(&pdev->dev, NULL); 258 259 if (ret) { 260 pm_runtime_put_noidle(&pdev->dev); 261 pm_runtime_disable(&pdev->dev); 262 } 263 264 return ret; 265 } 266 267 #ifdef CONFIG_PM 268 static int replicator_runtime_suspend(struct device *dev) 269 { 270 struct replicator_drvdata *drvdata = dev_get_drvdata(dev); 271 272 if (drvdata && !IS_ERR(drvdata->atclk)) 273 clk_disable_unprepare(drvdata->atclk); 274 275 return 0; 276 } 277 278 static int replicator_runtime_resume(struct device *dev) 279 { 280 struct replicator_drvdata *drvdata = dev_get_drvdata(dev); 281 282 if (drvdata && !IS_ERR(drvdata->atclk)) 283 clk_prepare_enable(drvdata->atclk); 284 285 return 0; 286 } 287 #endif 288 289 static const struct dev_pm_ops replicator_dev_pm_ops = { 290 SET_RUNTIME_PM_OPS(replicator_runtime_suspend, 291 replicator_runtime_resume, NULL) 292 }; 293 294 static const struct of_device_id static_replicator_match[] = { 295 {.compatible = "arm,coresight-replicator"}, 296 {.compatible = "arm,coresight-static-replicator"}, 297 {} 298 }; 299 300 #ifdef CONFIG_ACPI 301 static const struct acpi_device_id static_replicator_acpi_ids[] = { 302 {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */ 303 {} 304 }; 305 #endif 306 307 static struct platform_driver static_replicator_driver = { 308 .probe = static_replicator_probe, 309 .driver = { 310 .name = "coresight-static-replicator", 311 .of_match_table = of_match_ptr(static_replicator_match), 312 .acpi_match_table = ACPI_PTR(static_replicator_acpi_ids), 313 .pm = &replicator_dev_pm_ops, 314 .suppress_bind_attrs = true, 315 }, 316 }; 317 builtin_platform_driver(static_replicator_driver); 318 319 static int dynamic_replicator_probe(struct amba_device *adev, 320 const struct amba_id *id) 321 { 322 return replicator_probe(&adev->dev, &adev->res); 323 } 324 325 static const struct amba_id dynamic_replicator_ids[] = { 326 { 327 .id = 0x000bb909, 328 .mask = 0x000fffff, 329 }, 330 { 331 /* Coresight SoC-600 */ 332 .id = 0x000bb9ec, 333 .mask = 0x000fffff, 334 }, 335 { 0, 0 }, 336 }; 337 338 static struct amba_driver dynamic_replicator_driver = { 339 .drv = { 340 .name = "coresight-dynamic-replicator", 341 .pm = &replicator_dev_pm_ops, 342 .suppress_bind_attrs = true, 343 }, 344 .probe = dynamic_replicator_probe, 345 .id_table = dynamic_replicator_ids, 346 }; 347 builtin_amba_driver(dynamic_replicator_driver); 348