Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
0004  *
0005  * Description: CoreSight Replicator driver
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  * struct replicator_drvdata - specifics associated to a replicator component
0031  * @base:   memory mapped base address for this component. Also indicates
0032  *      whether this one is programmable or not.
0033  * @atclk:  optional clock for the core parts of the replicator.
0034  * @csdev:  component vitals needed by the framework
0035  * @spinlock:   serialize enable/disable operations.
0036  * @check_idfilter_val: check if the context is lost upon clock removal.
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  * replicator_reset : Reset the replicator configuration to sane values.
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      * Some replicator designs lose context when AMBA clocks are removed,
0084      * so have a check for this.
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     /* Ensure that the outport is enabled. */
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     /* disable the flow of ATB data through port */
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"); /* optional */
0243     if (!IS_ERR(drvdata->atclk)) {
0244         ret = clk_prepare_enable(drvdata->atclk);
0245         if (ret)
0246             return ret;
0247     }
0248 
0249     /*
0250      * Map the device base for dynamic-replicator, which has been
0251      * validated by AMBA core
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     /* Static replicators do not have programming base */
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}, /* ARM CoreSight Static Replicator */
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         /* THIS_MODULE is taken care of by platform_driver_register() */
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),     /* Coresight SoC-600 */
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");