1*b3c71626SMao Jinlong // SPDX-License-Identifier: GPL-2.0 2*b3c71626SMao Jinlong /* 3*b3c71626SMao Jinlong * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 4*b3c71626SMao Jinlong */ 5*b3c71626SMao Jinlong 6*b3c71626SMao Jinlong #include <linux/amba/bus.h> 7*b3c71626SMao Jinlong #include <linux/bitmap.h> 8*b3c71626SMao Jinlong #include <linux/coresight.h> 9*b3c71626SMao Jinlong #include <linux/coresight-pmu.h> 10*b3c71626SMao Jinlong #include <linux/device.h> 11*b3c71626SMao Jinlong #include <linux/err.h> 12*b3c71626SMao Jinlong #include <linux/fs.h> 13*b3c71626SMao Jinlong #include <linux/io.h> 14*b3c71626SMao Jinlong #include <linux/kernel.h> 15*b3c71626SMao Jinlong #include <linux/module.h> 16*b3c71626SMao Jinlong #include <linux/of.h> 17*b3c71626SMao Jinlong 18*b3c71626SMao Jinlong #include "coresight-priv.h" 19*b3c71626SMao Jinlong #include "coresight-tpdm.h" 20*b3c71626SMao Jinlong 21*b3c71626SMao Jinlong DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm"); 22*b3c71626SMao Jinlong 23*b3c71626SMao Jinlong /* TPDM enable operations */ 24*b3c71626SMao Jinlong static int tpdm_enable(struct coresight_device *csdev, 25*b3c71626SMao Jinlong struct perf_event *event, u32 mode) 26*b3c71626SMao Jinlong { 27*b3c71626SMao Jinlong struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 28*b3c71626SMao Jinlong 29*b3c71626SMao Jinlong spin_lock(&drvdata->spinlock); 30*b3c71626SMao Jinlong if (drvdata->enable) { 31*b3c71626SMao Jinlong spin_unlock(&drvdata->spinlock); 32*b3c71626SMao Jinlong return -EBUSY; 33*b3c71626SMao Jinlong } 34*b3c71626SMao Jinlong 35*b3c71626SMao Jinlong drvdata->enable = true; 36*b3c71626SMao Jinlong spin_unlock(&drvdata->spinlock); 37*b3c71626SMao Jinlong 38*b3c71626SMao Jinlong dev_dbg(drvdata->dev, "TPDM tracing enabled\n"); 39*b3c71626SMao Jinlong return 0; 40*b3c71626SMao Jinlong } 41*b3c71626SMao Jinlong 42*b3c71626SMao Jinlong /* TPDM disable operations */ 43*b3c71626SMao Jinlong static void tpdm_disable(struct coresight_device *csdev, 44*b3c71626SMao Jinlong struct perf_event *event) 45*b3c71626SMao Jinlong { 46*b3c71626SMao Jinlong struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 47*b3c71626SMao Jinlong 48*b3c71626SMao Jinlong spin_lock(&drvdata->spinlock); 49*b3c71626SMao Jinlong if (!drvdata->enable) { 50*b3c71626SMao Jinlong spin_unlock(&drvdata->spinlock); 51*b3c71626SMao Jinlong return; 52*b3c71626SMao Jinlong } 53*b3c71626SMao Jinlong 54*b3c71626SMao Jinlong drvdata->enable = false; 55*b3c71626SMao Jinlong spin_unlock(&drvdata->spinlock); 56*b3c71626SMao Jinlong 57*b3c71626SMao Jinlong dev_dbg(drvdata->dev, "TPDM tracing disabled\n"); 58*b3c71626SMao Jinlong } 59*b3c71626SMao Jinlong 60*b3c71626SMao Jinlong static const struct coresight_ops_source tpdm_source_ops = { 61*b3c71626SMao Jinlong .enable = tpdm_enable, 62*b3c71626SMao Jinlong .disable = tpdm_disable, 63*b3c71626SMao Jinlong }; 64*b3c71626SMao Jinlong 65*b3c71626SMao Jinlong static const struct coresight_ops tpdm_cs_ops = { 66*b3c71626SMao Jinlong .source_ops = &tpdm_source_ops, 67*b3c71626SMao Jinlong }; 68*b3c71626SMao Jinlong 69*b3c71626SMao Jinlong static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) 70*b3c71626SMao Jinlong { 71*b3c71626SMao Jinlong void __iomem *base; 72*b3c71626SMao Jinlong struct device *dev = &adev->dev; 73*b3c71626SMao Jinlong struct coresight_platform_data *pdata; 74*b3c71626SMao Jinlong struct tpdm_drvdata *drvdata; 75*b3c71626SMao Jinlong struct coresight_desc desc = { 0 }; 76*b3c71626SMao Jinlong 77*b3c71626SMao Jinlong pdata = coresight_get_platform_data(dev); 78*b3c71626SMao Jinlong if (IS_ERR(pdata)) 79*b3c71626SMao Jinlong return PTR_ERR(pdata); 80*b3c71626SMao Jinlong adev->dev.platform_data = pdata; 81*b3c71626SMao Jinlong 82*b3c71626SMao Jinlong /* driver data*/ 83*b3c71626SMao Jinlong drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); 84*b3c71626SMao Jinlong if (!drvdata) 85*b3c71626SMao Jinlong return -ENOMEM; 86*b3c71626SMao Jinlong drvdata->dev = &adev->dev; 87*b3c71626SMao Jinlong dev_set_drvdata(dev, drvdata); 88*b3c71626SMao Jinlong 89*b3c71626SMao Jinlong base = devm_ioremap_resource(dev, &adev->res); 90*b3c71626SMao Jinlong if (IS_ERR(base)) 91*b3c71626SMao Jinlong return PTR_ERR(base); 92*b3c71626SMao Jinlong 93*b3c71626SMao Jinlong drvdata->base = base; 94*b3c71626SMao Jinlong 95*b3c71626SMao Jinlong /* Set up coresight component description */ 96*b3c71626SMao Jinlong desc.name = coresight_alloc_device_name(&tpdm_devs, dev); 97*b3c71626SMao Jinlong if (!desc.name) 98*b3c71626SMao Jinlong return -ENOMEM; 99*b3c71626SMao Jinlong desc.type = CORESIGHT_DEV_TYPE_SOURCE; 100*b3c71626SMao Jinlong desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS; 101*b3c71626SMao Jinlong desc.ops = &tpdm_cs_ops; 102*b3c71626SMao Jinlong desc.pdata = adev->dev.platform_data; 103*b3c71626SMao Jinlong desc.dev = &adev->dev; 104*b3c71626SMao Jinlong desc.access = CSDEV_ACCESS_IOMEM(base); 105*b3c71626SMao Jinlong drvdata->csdev = coresight_register(&desc); 106*b3c71626SMao Jinlong if (IS_ERR(drvdata->csdev)) 107*b3c71626SMao Jinlong return PTR_ERR(drvdata->csdev); 108*b3c71626SMao Jinlong 109*b3c71626SMao Jinlong spin_lock_init(&drvdata->spinlock); 110*b3c71626SMao Jinlong /* Decrease pm refcount when probe is done.*/ 111*b3c71626SMao Jinlong pm_runtime_put(&adev->dev); 112*b3c71626SMao Jinlong 113*b3c71626SMao Jinlong return 0; 114*b3c71626SMao Jinlong } 115*b3c71626SMao Jinlong 116*b3c71626SMao Jinlong static void __exit tpdm_remove(struct amba_device *adev) 117*b3c71626SMao Jinlong { 118*b3c71626SMao Jinlong struct tpdm_drvdata *drvdata = dev_get_drvdata(&adev->dev); 119*b3c71626SMao Jinlong 120*b3c71626SMao Jinlong coresight_unregister(drvdata->csdev); 121*b3c71626SMao Jinlong } 122*b3c71626SMao Jinlong 123*b3c71626SMao Jinlong /* 124*b3c71626SMao Jinlong * Different TPDM has different periph id. 125*b3c71626SMao Jinlong * The difference is 0-7 bits' value. So ignore 0-7 bits. 126*b3c71626SMao Jinlong */ 127*b3c71626SMao Jinlong static struct amba_id tpdm_ids[] = { 128*b3c71626SMao Jinlong { 129*b3c71626SMao Jinlong .id = 0x000f0e00, 130*b3c71626SMao Jinlong .mask = 0x000fff00, 131*b3c71626SMao Jinlong }, 132*b3c71626SMao Jinlong { 0, 0}, 133*b3c71626SMao Jinlong }; 134*b3c71626SMao Jinlong 135*b3c71626SMao Jinlong static struct amba_driver tpdm_driver = { 136*b3c71626SMao Jinlong .drv = { 137*b3c71626SMao Jinlong .name = "coresight-tpdm", 138*b3c71626SMao Jinlong .owner = THIS_MODULE, 139*b3c71626SMao Jinlong .suppress_bind_attrs = true, 140*b3c71626SMao Jinlong }, 141*b3c71626SMao Jinlong .probe = tpdm_probe, 142*b3c71626SMao Jinlong .id_table = tpdm_ids, 143*b3c71626SMao Jinlong .remove = tpdm_remove, 144*b3c71626SMao Jinlong }; 145*b3c71626SMao Jinlong 146*b3c71626SMao Jinlong module_amba_driver(tpdm_driver); 147*b3c71626SMao Jinlong 148*b3c71626SMao Jinlong MODULE_LICENSE("GPL"); 149*b3c71626SMao Jinlong MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Monitor driver"); 150