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