335 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.4 *5 * Description: CoreSight Trace Port Interface Unit driver6 */7 8#include <linux/acpi.h>9#include <linux/amba/bus.h>10#include <linux/atomic.h>11#include <linux/clk.h>12#include <linux/coresight.h>13#include <linux/device.h>14#include <linux/err.h>15#include <linux/init.h>16#include <linux/io.h>17#include <linux/kernel.h>18#include <linux/platform_device.h>19#include <linux/pm_runtime.h>20#include <linux/slab.h>21 22#include "coresight-priv.h"23 24#define TPIU_SUPP_PORTSZ 0x00025#define TPIU_CURR_PORTSZ 0x00426#define TPIU_SUPP_TRIGMODES 0x10027#define TPIU_TRIG_CNTRVAL 0x10428#define TPIU_TRIG_MULT 0x10829#define TPIU_SUPP_TESTPATM 0x20030#define TPIU_CURR_TESTPATM 0x20431#define TPIU_TEST_PATREPCNTR 0x20832#define TPIU_FFSR 0x30033#define TPIU_FFCR 0x30434#define TPIU_FSYNC_CNTR 0x30835#define TPIU_EXTCTL_INPORT 0x40036#define TPIU_EXTCTL_OUTPORT 0x40437#define TPIU_ITTRFLINACK 0xee438#define TPIU_ITTRFLIN 0xee839#define TPIU_ITATBDATA0 0xeec40#define TPIU_ITATBCTR2 0xef041#define TPIU_ITATBCTR1 0xef442#define TPIU_ITATBCTR0 0xef843 44/** register definition **/45/* FFSR - 0x300 */46#define FFSR_FT_STOPPED_BIT 147/* FFCR - 0x304 */48#define FFCR_FON_MAN_BIT 649#define FFCR_FON_MAN BIT(6)50#define FFCR_STOP_FI BIT(12)51 52DEFINE_CORESIGHT_DEVLIST(tpiu_devs, "tpiu");53 54/*55 * @base: memory mapped base address for this component.56 * @atclk: optional clock for the core parts of the TPIU.57 * @pclk: APB clock if present, otherwise NULL58 * @csdev: component vitals needed by the framework.59 */60struct tpiu_drvdata {61 void __iomem *base;62 struct clk *atclk;63 struct clk *pclk;64 struct coresight_device *csdev;65 spinlock_t spinlock;66};67 68static void tpiu_enable_hw(struct csdev_access *csa)69{70 CS_UNLOCK(csa->base);71 72 /* TODO: fill this up */73 74 CS_LOCK(csa->base);75}76 77static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,78 void *__unused)79{80 struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);81 82 guard(spinlock)(&drvdata->spinlock);83 tpiu_enable_hw(&csdev->access);84 csdev->refcnt++;85 dev_dbg(&csdev->dev, "TPIU enabled\n");86 return 0;87}88 89static void tpiu_disable_hw(struct csdev_access *csa)90{91 CS_UNLOCK(csa->base);92 93 /* Clear formatter and stop on flush */94 csdev_access_relaxed_write32(csa, FFCR_STOP_FI, TPIU_FFCR);95 /* Generate manual flush */96 csdev_access_relaxed_write32(csa, FFCR_STOP_FI | FFCR_FON_MAN, TPIU_FFCR);97 /* Wait for flush to complete */98 coresight_timeout(csa, TPIU_FFCR, FFCR_FON_MAN_BIT, 0);99 /* Wait for formatter to stop */100 coresight_timeout(csa, TPIU_FFSR, FFSR_FT_STOPPED_BIT, 1);101 102 CS_LOCK(csa->base);103}104 105static int tpiu_disable(struct coresight_device *csdev)106{107 struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);108 109 guard(spinlock)(&drvdata->spinlock);110 csdev->refcnt--;111 if (csdev->refcnt)112 return -EBUSY;113 114 tpiu_disable_hw(&csdev->access);115 116 dev_dbg(&csdev->dev, "TPIU disabled\n");117 return 0;118}119 120static const struct coresight_ops_sink tpiu_sink_ops = {121 .enable = tpiu_enable,122 .disable = tpiu_disable,123};124 125static const struct coresight_ops tpiu_cs_ops = {126 .sink_ops = &tpiu_sink_ops,127};128 129static int __tpiu_probe(struct device *dev, struct resource *res)130{131 int ret;132 void __iomem *base;133 struct coresight_platform_data *pdata = NULL;134 struct tpiu_drvdata *drvdata;135 struct coresight_desc desc = { 0 };136 137 desc.name = coresight_alloc_device_name(&tpiu_devs, dev);138 if (!desc.name)139 return -ENOMEM;140 141 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);142 if (!drvdata)143 return -ENOMEM;144 145 spin_lock_init(&drvdata->spinlock);146 147 drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */148 if (!IS_ERR(drvdata->atclk)) {149 ret = clk_prepare_enable(drvdata->atclk);150 if (ret)151 return ret;152 }153 154 drvdata->pclk = coresight_get_enable_apb_pclk(dev);155 if (IS_ERR(drvdata->pclk))156 return -ENODEV;157 dev_set_drvdata(dev, drvdata);158 159 /* Validity for the resource is already checked by the AMBA core */160 base = devm_ioremap_resource(dev, res);161 if (IS_ERR(base))162 return PTR_ERR(base);163 164 drvdata->base = base;165 desc.access = CSDEV_ACCESS_IOMEM(base);166 167 /* Disable tpiu to support older devices */168 tpiu_disable_hw(&desc.access);169 170 pdata = coresight_get_platform_data(dev);171 if (IS_ERR(pdata))172 return PTR_ERR(pdata);173 dev->platform_data = pdata;174 175 desc.type = CORESIGHT_DEV_TYPE_SINK;176 desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;177 desc.ops = &tpiu_cs_ops;178 desc.pdata = pdata;179 desc.dev = dev;180 drvdata->csdev = coresight_register(&desc);181 182 if (!IS_ERR(drvdata->csdev))183 return 0;184 185 return PTR_ERR(drvdata->csdev);186}187 188static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)189{190 int ret;191 192 ret = __tpiu_probe(&adev->dev, &adev->res);193 if (!ret)194 pm_runtime_put(&adev->dev);195 return ret;196}197 198static void __tpiu_remove(struct device *dev)199{200 struct tpiu_drvdata *drvdata = dev_get_drvdata(dev);201 202 coresight_unregister(drvdata->csdev);203}204 205static void tpiu_remove(struct amba_device *adev)206{207 __tpiu_remove(&adev->dev);208}209 210#ifdef CONFIG_PM211static int tpiu_runtime_suspend(struct device *dev)212{213 struct tpiu_drvdata *drvdata = dev_get_drvdata(dev);214 215 if (drvdata && !IS_ERR(drvdata->atclk))216 clk_disable_unprepare(drvdata->atclk);217 218 if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))219 clk_disable_unprepare(drvdata->pclk);220 return 0;221}222 223static int tpiu_runtime_resume(struct device *dev)224{225 struct tpiu_drvdata *drvdata = dev_get_drvdata(dev);226 227 if (drvdata && !IS_ERR(drvdata->atclk))228 clk_prepare_enable(drvdata->atclk);229 230 if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))231 clk_prepare_enable(drvdata->pclk);232 return 0;233}234#endif235 236static const struct dev_pm_ops tpiu_dev_pm_ops = {237 SET_RUNTIME_PM_OPS(tpiu_runtime_suspend, tpiu_runtime_resume, NULL)238};239 240static const struct amba_id tpiu_ids[] = {241 {242 .id = 0x000bb912,243 .mask = 0x000fffff,244 },245 {246 .id = 0x0004b912,247 .mask = 0x0007ffff,248 },249 {250 /* Coresight SoC-600 */251 .id = 0x000bb9e7,252 .mask = 0x000fffff,253 },254 { 0, 0, NULL },255};256 257MODULE_DEVICE_TABLE(amba, tpiu_ids);258 259static struct amba_driver tpiu_driver = {260 .drv = {261 .name = "coresight-tpiu",262 .pm = &tpiu_dev_pm_ops,263 .suppress_bind_attrs = true,264 },265 .probe = tpiu_probe,266 .remove = tpiu_remove,267 .id_table = tpiu_ids,268};269 270static int tpiu_platform_probe(struct platform_device *pdev)271{272 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);273 int ret;274 275 pm_runtime_get_noresume(&pdev->dev);276 pm_runtime_set_active(&pdev->dev);277 pm_runtime_enable(&pdev->dev);278 279 ret = __tpiu_probe(&pdev->dev, res);280 pm_runtime_put(&pdev->dev);281 if (ret)282 pm_runtime_disable(&pdev->dev);283 284 return ret;285}286 287static void tpiu_platform_remove(struct platform_device *pdev)288{289 struct tpiu_drvdata *drvdata = dev_get_drvdata(&pdev->dev);290 291 if (WARN_ON(!drvdata))292 return;293 294 __tpiu_remove(&pdev->dev);295 pm_runtime_disable(&pdev->dev);296 if (!IS_ERR_OR_NULL(drvdata->pclk))297 clk_put(drvdata->pclk);298}299 300#ifdef CONFIG_ACPI301static const struct acpi_device_id tpiu_acpi_ids[] = {302 {"ARMHC979", 0, 0, 0}, /* ARM CoreSight TPIU */303 {}304};305MODULE_DEVICE_TABLE(acpi, tpiu_acpi_ids);306#endif307 308static struct platform_driver tpiu_platform_driver = {309 .probe = tpiu_platform_probe,310 .remove_new = tpiu_platform_remove,311 .driver = {312 .name = "coresight-tpiu-platform",313 .acpi_match_table = ACPI_PTR(tpiu_acpi_ids),314 .suppress_bind_attrs = true,315 .pm = &tpiu_dev_pm_ops,316 },317};318 319static int __init tpiu_init(void)320{321 return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver);322}323 324static void __exit tpiu_exit(void)325{326 coresight_remove_driver(&tpiu_driver, &tpiu_platform_driver);327}328module_init(tpiu_init);329module_exit(tpiu_exit);330 331MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");332MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");333MODULE_DESCRIPTION("Arm CoreSight TPIU (Trace Port Interface Unit) driver");334MODULE_LICENSE("GPL v2");335