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 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); 193 if (!drvdata) 194 return -ENOMEM; 195 196 drvdata->dev = dev; 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 desc.type = CORESIGHT_DEV_TYPE_LINK; 221 desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; 222 desc.ops = &replicator_cs_ops; 223 desc.pdata = dev->platform_data; 224 desc.dev = dev; 225 drvdata->csdev = coresight_register(&desc); 226 if (IS_ERR(drvdata->csdev)) { 227 ret = PTR_ERR(drvdata->csdev); 228 goto out_disable_clk; 229 } 230 231 replicator_reset(drvdata); 232 pm_runtime_put(dev); 233 234 out_disable_clk: 235 if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) 236 clk_disable_unprepare(drvdata->atclk); 237 return ret; 238 } 239 240 static int static_replicator_probe(struct platform_device *pdev) 241 { 242 int ret; 243 244 pm_runtime_get_noresume(&pdev->dev); 245 pm_runtime_set_active(&pdev->dev); 246 pm_runtime_enable(&pdev->dev); 247 248 /* Static replicators do not have programming base */ 249 ret = replicator_probe(&pdev->dev, NULL); 250 251 if (ret) { 252 pm_runtime_put_noidle(&pdev->dev); 253 pm_runtime_disable(&pdev->dev); 254 } 255 256 return ret; 257 } 258 259 #ifdef CONFIG_PM 260 static int replicator_runtime_suspend(struct device *dev) 261 { 262 struct replicator_drvdata *drvdata = dev_get_drvdata(dev); 263 264 if (drvdata && !IS_ERR(drvdata->atclk)) 265 clk_disable_unprepare(drvdata->atclk); 266 267 return 0; 268 } 269 270 static int replicator_runtime_resume(struct device *dev) 271 { 272 struct replicator_drvdata *drvdata = dev_get_drvdata(dev); 273 274 if (drvdata && !IS_ERR(drvdata->atclk)) 275 clk_prepare_enable(drvdata->atclk); 276 277 return 0; 278 } 279 #endif 280 281 static const struct dev_pm_ops replicator_dev_pm_ops = { 282 SET_RUNTIME_PM_OPS(replicator_runtime_suspend, 283 replicator_runtime_resume, NULL) 284 }; 285 286 static const struct of_device_id static_replicator_match[] = { 287 {.compatible = "arm,coresight-replicator"}, 288 {} 289 }; 290 291 static struct platform_driver static_replicator_driver = { 292 .probe = static_replicator_probe, 293 .driver = { 294 .name = "coresight-replicator", 295 .of_match_table = static_replicator_match, 296 .pm = &replicator_dev_pm_ops, 297 .suppress_bind_attrs = true, 298 }, 299 }; 300 builtin_platform_driver(static_replicator_driver); 301 302 static int dynamic_replicator_probe(struct amba_device *adev, 303 const struct amba_id *id) 304 { 305 return replicator_probe(&adev->dev, &adev->res); 306 } 307 308 static const struct amba_id dynamic_replicator_ids[] = { 309 { 310 .id = 0x000bb909, 311 .mask = 0x000fffff, 312 }, 313 { 314 /* Coresight SoC-600 */ 315 .id = 0x000bb9ec, 316 .mask = 0x000fffff, 317 }, 318 { 0, 0 }, 319 }; 320 321 static struct amba_driver dynamic_replicator_driver = { 322 .drv = { 323 .name = "coresight-dynamic-replicator", 324 .pm = &replicator_dev_pm_ops, 325 .suppress_bind_attrs = true, 326 }, 327 .probe = dynamic_replicator_probe, 328 .id_table = dynamic_replicator_ids, 329 }; 330 builtin_amba_driver(dynamic_replicator_driver); 331