0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/acpi.h>
0009 #include <linux/amba/bus.h>
0010 #include <linux/kernel.h>
0011 #include <linux/device.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/io.h>
0014 #include <linux/err.h>
0015 #include <linux/slab.h>
0016 #include <linux/pm_runtime.h>
0017 #include <linux/property.h>
0018 #include <linux/clk.h>
0019 #include <linux/of.h>
0020 #include <linux/coresight.h>
0021
0022 #include "coresight-priv.h"
0023
0024 #define REPLICATOR_IDFILTER0 0x000
0025 #define REPLICATOR_IDFILTER1 0x004
0026
0027 DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 struct replicator_drvdata {
0039 void __iomem *base;
0040 struct clk *atclk;
0041 struct coresight_device *csdev;
0042 spinlock_t spinlock;
0043 bool check_idfilter_val;
0044 };
0045
0046 static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
0047 {
0048 struct coresight_device *csdev = drvdata->csdev;
0049
0050 CS_UNLOCK(drvdata->base);
0051
0052 if (!coresight_claim_device_unlocked(csdev)) {
0053 writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
0054 writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
0055 coresight_disclaim_device_unlocked(csdev);
0056 }
0057
0058 CS_LOCK(drvdata->base);
0059 }
0060
0061
0062
0063
0064 static inline void replicator_reset(struct replicator_drvdata *drvdata)
0065 {
0066 if (drvdata->base)
0067 dynamic_replicator_reset(drvdata);
0068 }
0069
0070 static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
0071 int inport, int outport)
0072 {
0073 int rc = 0;
0074 u32 id0val, id1val;
0075 struct coresight_device *csdev = drvdata->csdev;
0076
0077 CS_UNLOCK(drvdata->base);
0078
0079 id0val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0);
0080 id1val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1);
0081
0082
0083
0084
0085
0086 if (drvdata->check_idfilter_val && id0val == 0x0 && id1val == 0x0)
0087 id0val = id1val = 0xff;
0088
0089 if (id0val == 0xff && id1val == 0xff)
0090 rc = coresight_claim_device_unlocked(csdev);
0091
0092 if (!rc) {
0093 switch (outport) {
0094 case 0:
0095 id0val = 0x0;
0096 break;
0097 case 1:
0098 id1val = 0x0;
0099 break;
0100 default:
0101 WARN_ON(1);
0102 rc = -EINVAL;
0103 }
0104 }
0105
0106
0107 if (!rc) {
0108 writel_relaxed(id0val, drvdata->base + REPLICATOR_IDFILTER0);
0109 writel_relaxed(id1val, drvdata->base + REPLICATOR_IDFILTER1);
0110 }
0111
0112 CS_LOCK(drvdata->base);
0113
0114 return rc;
0115 }
0116
0117 static int replicator_enable(struct coresight_device *csdev, int inport,
0118 int outport)
0119 {
0120 int rc = 0;
0121 struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
0122 unsigned long flags;
0123 bool first_enable = false;
0124
0125 spin_lock_irqsave(&drvdata->spinlock, flags);
0126 if (atomic_read(&csdev->refcnt[outport]) == 0) {
0127 if (drvdata->base)
0128 rc = dynamic_replicator_enable(drvdata, inport,
0129 outport);
0130 if (!rc)
0131 first_enable = true;
0132 }
0133 if (!rc)
0134 atomic_inc(&csdev->refcnt[outport]);
0135 spin_unlock_irqrestore(&drvdata->spinlock, flags);
0136
0137 if (first_enable)
0138 dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
0139 return rc;
0140 }
0141
0142 static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,
0143 int inport, int outport)
0144 {
0145 u32 reg;
0146 struct coresight_device *csdev = drvdata->csdev;
0147
0148 switch (outport) {
0149 case 0:
0150 reg = REPLICATOR_IDFILTER0;
0151 break;
0152 case 1:
0153 reg = REPLICATOR_IDFILTER1;
0154 break;
0155 default:
0156 WARN_ON(1);
0157 return;
0158 }
0159
0160 CS_UNLOCK(drvdata->base);
0161
0162
0163 writel_relaxed(0xff, drvdata->base + reg);
0164
0165 if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
0166 (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
0167 coresight_disclaim_device_unlocked(csdev);
0168 CS_LOCK(drvdata->base);
0169 }
0170
0171 static void replicator_disable(struct coresight_device *csdev, int inport,
0172 int outport)
0173 {
0174 struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
0175 unsigned long flags;
0176 bool last_disable = false;
0177
0178 spin_lock_irqsave(&drvdata->spinlock, flags);
0179 if (atomic_dec_return(&csdev->refcnt[outport]) == 0) {
0180 if (drvdata->base)
0181 dynamic_replicator_disable(drvdata, inport, outport);
0182 last_disable = true;
0183 }
0184 spin_unlock_irqrestore(&drvdata->spinlock, flags);
0185
0186 if (last_disable)
0187 dev_dbg(&csdev->dev, "REPLICATOR disabled\n");
0188 }
0189
0190 static const struct coresight_ops_link replicator_link_ops = {
0191 .enable = replicator_enable,
0192 .disable = replicator_disable,
0193 };
0194
0195 static const struct coresight_ops replicator_cs_ops = {
0196 .link_ops = &replicator_link_ops,
0197 };
0198
0199 #define coresight_replicator_reg(name, offset) \
0200 coresight_simple_reg32(struct replicator_drvdata, name, offset)
0201
0202 coresight_replicator_reg(idfilter0, REPLICATOR_IDFILTER0);
0203 coresight_replicator_reg(idfilter1, REPLICATOR_IDFILTER1);
0204
0205 static struct attribute *replicator_mgmt_attrs[] = {
0206 &dev_attr_idfilter0.attr,
0207 &dev_attr_idfilter1.attr,
0208 NULL,
0209 };
0210
0211 static const struct attribute_group replicator_mgmt_group = {
0212 .attrs = replicator_mgmt_attrs,
0213 .name = "mgmt",
0214 };
0215
0216 static const struct attribute_group *replicator_groups[] = {
0217 &replicator_mgmt_group,
0218 NULL,
0219 };
0220
0221 static int replicator_probe(struct device *dev, struct resource *res)
0222 {
0223 int ret = 0;
0224 struct coresight_platform_data *pdata = NULL;
0225 struct replicator_drvdata *drvdata;
0226 struct coresight_desc desc = { 0 };
0227 void __iomem *base;
0228
0229 if (is_of_node(dev_fwnode(dev)) &&
0230 of_device_is_compatible(dev->of_node, "arm,coresight-replicator"))
0231 dev_warn_once(dev,
0232 "Uses OBSOLETE CoreSight replicator binding\n");
0233
0234 desc.name = coresight_alloc_device_name(&replicator_devs, dev);
0235 if (!desc.name)
0236 return -ENOMEM;
0237
0238 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
0239 if (!drvdata)
0240 return -ENOMEM;
0241
0242 drvdata->atclk = devm_clk_get(dev, "atclk");
0243 if (!IS_ERR(drvdata->atclk)) {
0244 ret = clk_prepare_enable(drvdata->atclk);
0245 if (ret)
0246 return ret;
0247 }
0248
0249
0250
0251
0252
0253 if (res) {
0254 base = devm_ioremap_resource(dev, res);
0255 if (IS_ERR(base)) {
0256 ret = PTR_ERR(base);
0257 goto out_disable_clk;
0258 }
0259 drvdata->base = base;
0260 desc.groups = replicator_groups;
0261 desc.access = CSDEV_ACCESS_IOMEM(base);
0262 }
0263
0264 if (fwnode_property_present(dev_fwnode(dev),
0265 "qcom,replicator-loses-context"))
0266 drvdata->check_idfilter_val = true;
0267
0268 dev_set_drvdata(dev, drvdata);
0269
0270 pdata = coresight_get_platform_data(dev);
0271 if (IS_ERR(pdata)) {
0272 ret = PTR_ERR(pdata);
0273 goto out_disable_clk;
0274 }
0275 dev->platform_data = pdata;
0276
0277 spin_lock_init(&drvdata->spinlock);
0278 desc.type = CORESIGHT_DEV_TYPE_LINK;
0279 desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
0280 desc.ops = &replicator_cs_ops;
0281 desc.pdata = dev->platform_data;
0282 desc.dev = dev;
0283
0284 drvdata->csdev = coresight_register(&desc);
0285 if (IS_ERR(drvdata->csdev)) {
0286 ret = PTR_ERR(drvdata->csdev);
0287 goto out_disable_clk;
0288 }
0289
0290 replicator_reset(drvdata);
0291 pm_runtime_put(dev);
0292
0293 out_disable_clk:
0294 if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
0295 clk_disable_unprepare(drvdata->atclk);
0296 return ret;
0297 }
0298
0299 static int replicator_remove(struct device *dev)
0300 {
0301 struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
0302
0303 coresight_unregister(drvdata->csdev);
0304 return 0;
0305 }
0306
0307 static int static_replicator_probe(struct platform_device *pdev)
0308 {
0309 int ret;
0310
0311 pm_runtime_get_noresume(&pdev->dev);
0312 pm_runtime_set_active(&pdev->dev);
0313 pm_runtime_enable(&pdev->dev);
0314
0315
0316 ret = replicator_probe(&pdev->dev, NULL);
0317
0318 if (ret) {
0319 pm_runtime_put_noidle(&pdev->dev);
0320 pm_runtime_disable(&pdev->dev);
0321 }
0322
0323 return ret;
0324 }
0325
0326 static int static_replicator_remove(struct platform_device *pdev)
0327 {
0328 replicator_remove(&pdev->dev);
0329 pm_runtime_disable(&pdev->dev);
0330 return 0;
0331 }
0332
0333 #ifdef CONFIG_PM
0334 static int replicator_runtime_suspend(struct device *dev)
0335 {
0336 struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
0337
0338 if (drvdata && !IS_ERR(drvdata->atclk))
0339 clk_disable_unprepare(drvdata->atclk);
0340
0341 return 0;
0342 }
0343
0344 static int replicator_runtime_resume(struct device *dev)
0345 {
0346 struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
0347
0348 if (drvdata && !IS_ERR(drvdata->atclk))
0349 clk_prepare_enable(drvdata->atclk);
0350
0351 return 0;
0352 }
0353 #endif
0354
0355 static const struct dev_pm_ops replicator_dev_pm_ops = {
0356 SET_RUNTIME_PM_OPS(replicator_runtime_suspend,
0357 replicator_runtime_resume, NULL)
0358 };
0359
0360 static const struct of_device_id static_replicator_match[] = {
0361 {.compatible = "arm,coresight-replicator"},
0362 {.compatible = "arm,coresight-static-replicator"},
0363 {}
0364 };
0365
0366 MODULE_DEVICE_TABLE(of, static_replicator_match);
0367
0368 #ifdef CONFIG_ACPI
0369 static const struct acpi_device_id static_replicator_acpi_ids[] = {
0370 {"ARMHC985", 0},
0371 {}
0372 };
0373
0374 MODULE_DEVICE_TABLE(acpi, static_replicator_acpi_ids);
0375 #endif
0376
0377 static struct platform_driver static_replicator_driver = {
0378 .probe = static_replicator_probe,
0379 .remove = static_replicator_remove,
0380 .driver = {
0381 .name = "coresight-static-replicator",
0382
0383 .of_match_table = of_match_ptr(static_replicator_match),
0384 .acpi_match_table = ACPI_PTR(static_replicator_acpi_ids),
0385 .pm = &replicator_dev_pm_ops,
0386 .suppress_bind_attrs = true,
0387 },
0388 };
0389
0390 static int dynamic_replicator_probe(struct amba_device *adev,
0391 const struct amba_id *id)
0392 {
0393 return replicator_probe(&adev->dev, &adev->res);
0394 }
0395
0396 static void dynamic_replicator_remove(struct amba_device *adev)
0397 {
0398 replicator_remove(&adev->dev);
0399 }
0400
0401 static const struct amba_id dynamic_replicator_ids[] = {
0402 CS_AMBA_ID(0x000bb909),
0403 CS_AMBA_ID(0x000bb9ec),
0404 {},
0405 };
0406
0407 MODULE_DEVICE_TABLE(amba, dynamic_replicator_ids);
0408
0409 static struct amba_driver dynamic_replicator_driver = {
0410 .drv = {
0411 .name = "coresight-dynamic-replicator",
0412 .pm = &replicator_dev_pm_ops,
0413 .owner = THIS_MODULE,
0414 .suppress_bind_attrs = true,
0415 },
0416 .probe = dynamic_replicator_probe,
0417 .remove = dynamic_replicator_remove,
0418 .id_table = dynamic_replicator_ids,
0419 };
0420
0421 static int __init replicator_init(void)
0422 {
0423 int ret;
0424
0425 ret = platform_driver_register(&static_replicator_driver);
0426 if (ret) {
0427 pr_info("Error registering platform driver\n");
0428 return ret;
0429 }
0430
0431 ret = amba_driver_register(&dynamic_replicator_driver);
0432 if (ret) {
0433 pr_info("Error registering amba driver\n");
0434 platform_driver_unregister(&static_replicator_driver);
0435 }
0436
0437 return ret;
0438 }
0439
0440 static void __exit replicator_exit(void)
0441 {
0442 platform_driver_unregister(&static_replicator_driver);
0443 amba_driver_unregister(&dynamic_replicator_driver);
0444 }
0445
0446 module_init(replicator_init);
0447 module_exit(replicator_exit);
0448
0449 MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
0450 MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
0451 MODULE_DESCRIPTION("Arm CoreSight Replicator Driver");
0452 MODULE_LICENSE("GPL v2");