From 9f17bb73d5a32b948901d2f9e0056e35f584500c Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Tue, 27 Oct 2020 18:30:17 +0800 Subject: [PATCH] coresight: Add snapshot of Coresight Fuse driver Add snapshot for coresight fuse driver from msm-3.18 commit cf126d1be1a("ANDROID: sdcardfs: Add option to not link obb"). Make necessary change to adopt coresight framework change. Change-Id: If0c677c9e7cb33c2c1656fb458649f0b4c069a00 Signed-off-by: Yuanfang Zhang --- drivers/hwtracing/coresight/Kconfig | 9 + drivers/hwtracing/coresight/Makefile | 1 + drivers/hwtracing/coresight/coresight-cti.c | 3 + drivers/hwtracing/coresight/coresight-fuse.c | 400 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 11 + drivers/hwtracing/coresight/coresight-tpdm.c | 3 + 6 files changed, 427 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-fuse.c diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 9027e747cc0a..9699778ed5b5 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -229,4 +229,13 @@ config CORESIGHT_OST This is primarily intended to be used as a layer on top of underlying physical byte transport mechanisms.The additional header can be used to provide more information. + +config CORESIGHT_FUSE + bool "CoreSight FUSE framework" + help + This driver provides support for CoreSight Fuse state checks that + other CoreSight drivers can query to determine existence of + Hardware functionality they support. Drivers can then take necessary + actions like failing the probe if the Hardware they manage is + functionally disabled. endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 057ad4ffe43e..01ad6fe5315c 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_CORESIGHT_TPDA) += coresight-tpda.o obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o +obj-$(CONFIG_CORESIGHT_FUSE) += coresight-fuse.o obj-$(CONFIG_CORESIGHT_REMOTE_ETM) += coresight-remote-etm.o obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o apss_tgu.o diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 7f5c159e3809..c6b0fba32673 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -1535,6 +1535,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) struct coresight_desc desc = { 0 }; struct device_node *cpu_node; + if (coresight_fuse_access_disabled()) + return -EPERM; + desc.name = coresight_alloc_device_name(&cti_devs, dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-fuse.c b/drivers/hwtracing/coresight/coresight-fuse.c new file mode 100644 index 000000000000..8c7238000c46 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-fuse.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2016, 2020, The Linux Foundation. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coresight-priv.h" + +#define fuse_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) +#define fuse_readl(drvdata, off) __raw_readl(drvdata->base + off) + +#define OEM_CONFIG0 (0x000) +#define OEM_CONFIG1 (0x004) +#define OEM_CONFIG2 (0x008) +#define FEATURE_CONFIG2 (0x000) + +#define CORESIGHT_FUSE_VERSION_V1 "arm,coresight-fuse" +#define CORESIGHT_FUSE_VERSION_V2 "arm,coresight-fuse-v2" +#define CORESIGHT_FUSE_VERSION_V3 "arm,coresight-fuse-v3" + +/* CoreSight FUSE V1 */ +#define ALL_DEBUG_DISABLE BIT(21) +#define APPS_DBGEN_DISABLE BIT(0) +#define APPS_NIDEN_DISABLE BIT(1) +#define APPS_SPIDEN_DISABLE BIT(2) +#define APPS_SPNIDEN_DISABLE BIT(3) +#define DAP_DBGEN_DISABLE BIT(4) +#define DAP_NIDEN_DISABLE BIT(5) +#define DAP_SPIDEN_DISABLE BIT(6) +#define DAP_SPNIDEN_DISABLE BIT(7) +#define DAP_DEVICEEN_DISABLE BIT(8) + +/* CoreSight FUSE V2 */ +#define ALL_DEBUG_DISABLE_V2 BIT(0) +#define APPS_DBGEN_DISABLE_V2 BIT(10) +#define APPS_NIDEN_DISABLE_V2 BIT(11) +#define APPS_SPIDEN_DISABLE_V2 BIT(12) +#define APPS_SPNIDEN_DISABLE_V2 BIT(13) +#define DAP_DBGEN_DISABLE_V2 BIT(14) +#define DAP_NIDEN_DISABLE_V2 BIT(15) +#define DAP_SPIDEN_DISABLE_V2 BIT(16) +#define DAP_SPNIDEN_DISABLE_V2 BIT(17) +#define DAP_DEVICEEN_DISABLE_V2 BIT(18) + +/* CoreSight FUSE V3 */ +#define ALL_DEBUG_DISABLE_V3 BIT(29) +#define APPS_DBGEN_DISABLE_V3 BIT(8) +#define APPS_NIDEN_DISABLE_V3 BIT(21) +#define APPS_SPIDEN_DISABLE_V3 BIT(5) +#define APPS_SPNIDEN_DISABLE_V3 BIT(31) +#define DAP_DBGEN_DISABLE_V3 BIT(10) +#define DAP_NIDEN_DISABLE_V3 BIT(23) +#define DAP_SPIDEN_DISABLE_V3 BIT(7) +#define DAP_SPNIDEN_DISABLE_V3 BIT(1) +#define DAP_DEVICEEN_DISABLE_V3 BIT(7) + +#define QPDI_SPMI_DISABLE BIT(2) +#define NIDNT_DISABLE BIT(27) + +struct fuse_nidnt { + void __iomem *base; +}; + +struct fuse_qpdi { + void __iomem *base; +}; + +struct fuse_drvdata { + void __iomem *base; + struct fuse_nidnt *fuse_nidnt; + struct fuse_qpdi *qpdi; + struct device *dev; + struct coresight_device *csdev; + bool fuse_v2; + bool fuse_v3; +}; + +static struct fuse_drvdata *fusedrvdata; + +bool coresight_fuse_nidnt_access_disabled(void) +{ + struct fuse_drvdata *drvdata = fusedrvdata; + uint32_t nidnt_fuse; + bool ret; + + if (!drvdata || !drvdata->fuse_nidnt) + return false; + + nidnt_fuse = fuse_readl(drvdata->fuse_nidnt, 0); + + dev_dbg(drvdata->dev, "nidnt_fuse: %lx\n", (unsigned long)nidnt_fuse); + + if (nidnt_fuse & NIDNT_DISABLE) + ret = true; + else + ret = false; + + if (ret) + dev_dbg(drvdata->dev, "coresight nidnt fuse disabled\n"); + + return ret; +} +EXPORT_SYMBOL(coresight_fuse_nidnt_access_disabled); + +bool coresight_fuse_access_disabled(void) +{ + struct fuse_drvdata *drvdata = fusedrvdata; + uint32_t config0, config1, config2; + bool ret = false; + + if (!drvdata) + return false; + + config0 = fuse_readl(drvdata, OEM_CONFIG0); + config1 = fuse_readl(drvdata, OEM_CONFIG1); + + dev_dbg(drvdata->dev, "config0: %lx\n", (unsigned long)config0); + dev_dbg(drvdata->dev, "config1: %lx\n", (unsigned long)config1); + + if (drvdata->fuse_v3) { + config2 = fuse_readl(drvdata, OEM_CONFIG2); + dev_dbg(drvdata->dev, "config2: %lx\n", (unsigned long)config2); + } + + if (drvdata->fuse_v2) { + if (config1 & ALL_DEBUG_DISABLE_V2) + ret = true; + else if (config1 & DAP_DBGEN_DISABLE_V2) + ret = true; + else if (config1 & DAP_NIDEN_DISABLE_V2) + ret = true; + else if (config1 & DAP_SPIDEN_DISABLE_V2) + ret = true; + else if (config1 & DAP_SPNIDEN_DISABLE_V2) + ret = true; + else if (config1 & DAP_DEVICEEN_DISABLE_V2) + ret = true; + } else if (drvdata->fuse_v3) { + if (config0 & ALL_DEBUG_DISABLE_V3) + ret = true; + else if (config1 & DAP_DBGEN_DISABLE_V3) + ret = true; + else if (config1 & DAP_NIDEN_DISABLE_V3) + ret = true; + else if (config2 & DAP_SPIDEN_DISABLE_V3) + ret = true; + else if (config2 & DAP_SPNIDEN_DISABLE_V3) + ret = true; + else if (config1 & DAP_DEVICEEN_DISABLE_V3) + ret = true; + } else { + if (config0 & ALL_DEBUG_DISABLE) + ret = true; + else if (config1 & DAP_DBGEN_DISABLE) + ret = true; + else if (config1 & DAP_NIDEN_DISABLE) + ret = true; + else if (config1 & DAP_SPIDEN_DISABLE) + ret = true; + else if (config1 & DAP_SPNIDEN_DISABLE) + ret = true; + else if (config1 & DAP_DEVICEEN_DISABLE) + ret = true; + } + + if (ret) + dev_dbg(drvdata->dev, "coresight fuse disabled\n"); + + return ret; +} +EXPORT_SYMBOL(coresight_fuse_access_disabled); + +bool coresight_fuse_apps_access_disabled(void) +{ + struct fuse_drvdata *drvdata = fusedrvdata; + uint32_t config0, config1, config2; + bool ret = false; + + if (!drvdata) + return false; + + config0 = fuse_readl(drvdata, OEM_CONFIG0); + config1 = fuse_readl(drvdata, OEM_CONFIG1); + + dev_dbg(drvdata->dev, "apps config0: %lx\n", (unsigned long)config0); + dev_dbg(drvdata->dev, "apps config1: %lx\n", (unsigned long)config1); + + if (drvdata->fuse_v3) { + config2 = fuse_readl(drvdata, OEM_CONFIG2); + dev_dbg(drvdata->dev, "apps config2: %lx\n", + (unsigned long)config2); + } + + if (drvdata->fuse_v2) { + if (config1 & ALL_DEBUG_DISABLE_V2) + ret = true; + else if (config1 & APPS_DBGEN_DISABLE_V2) + ret = true; + else if (config1 & APPS_NIDEN_DISABLE_V2) + ret = true; + else if (config1 & APPS_SPIDEN_DISABLE_V2) + ret = true; + else if (config1 & APPS_SPNIDEN_DISABLE_V2) + ret = true; + else if (config1 & DAP_DEVICEEN_DISABLE_V2) + ret = true; + } else if (drvdata->fuse_v3) { + if (config0 & ALL_DEBUG_DISABLE_V3) + ret = true; + else if (config1 & APPS_DBGEN_DISABLE_V3) + ret = true; + else if (config1 & APPS_NIDEN_DISABLE_V3) + ret = true; + else if (config2 & APPS_SPIDEN_DISABLE_V3) + ret = true; + else if (config1 & APPS_SPNIDEN_DISABLE_V3) + ret = true; + else if (config1 & DAP_DEVICEEN_DISABLE_V3) + ret = true; + } else { + if (config0 & ALL_DEBUG_DISABLE) + ret = true; + else if (config1 & APPS_DBGEN_DISABLE) + ret = true; + else if (config1 & APPS_NIDEN_DISABLE) + ret = true; + else if (config1 & APPS_SPIDEN_DISABLE) + ret = true; + else if (config1 & APPS_SPNIDEN_DISABLE) + ret = true; + else if (config1 & DAP_DEVICEEN_DISABLE) + ret = true; + } + + if (ret) + dev_dbg(drvdata->dev, "apps fuse disabled\n"); + + return ret; +} +EXPORT_SYMBOL(coresight_fuse_apps_access_disabled); + +bool coresight_fuse_qpdi_access_disabled(void) +{ + struct fuse_drvdata *drvdata = fusedrvdata; + uint32_t config; + + if (!drvdata || !drvdata->qpdi) + return false; + + config = fuse_readl(drvdata->qpdi, FEATURE_CONFIG2); + + dev_dbg(drvdata->dev, "qpdi config: %lx\n", (unsigned long)config); + + if (config & QPDI_SPMI_DISABLE) { + dev_dbg(drvdata->dev, "qpdi fuse disabled\n"); + return true; + } else { + return false; + } +} +EXPORT_SYMBOL(coresight_fuse_qpdi_access_disabled); + +static const struct of_device_id fuse_match[] = { + {.compatible = CORESIGHT_FUSE_VERSION_V1 }, + {.compatible = CORESIGHT_FUSE_VERSION_V2 }, + {.compatible = CORESIGHT_FUSE_VERSION_V3 }, + {} +}; + +static int fuse_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct coresight_platform_data *pdata; + struct fuse_drvdata *drvdata; + struct resource *res; + struct coresight_desc desc = { 0 }; + const struct of_device_id *match; + + pdata = coresight_get_platform_data(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + pdev->dev.platform_data = pdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &pdev->dev; + platform_set_drvdata(pdev, drvdata); + + + match = of_match_device(fuse_match, dev); + if (!match) + return -EINVAL; + + if (!strcmp(match->compatible, CORESIGHT_FUSE_VERSION_V2)) + drvdata->fuse_v2 = true; + else if (!strcmp(match->compatible, CORESIGHT_FUSE_VERSION_V3)) + drvdata->fuse_v3 = true; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fuse-base"); + if (!res) + return -ENODEV; + + drvdata->base = devm_ioremap(dev, res->start, resource_size(res)); + if (!drvdata->base) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "qpdi-fuse-base"); + if (res) { + drvdata->qpdi = devm_kzalloc(dev, sizeof(*drvdata->qpdi), + GFP_KERNEL); + if (!drvdata->qpdi) + return -ENOMEM; + + drvdata->qpdi->base = devm_ioremap(dev, res->start, + resource_size(res)); + if (!drvdata->qpdi->base) + return -ENOMEM; + } else { + dev_info(dev, "QPDI fuse not specified\n"); + } + + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, + "nidnt-fuse-base"); + if (res) { + drvdata->fuse_nidnt = devm_kzalloc(dev, + sizeof(*drvdata->fuse_nidnt), + GFP_KERNEL); + if (!drvdata->fuse_nidnt) + return -ENOMEM; + + drvdata->fuse_nidnt->base = devm_ioremap(dev, res->start, + resource_size(res)); + if (!drvdata->fuse_nidnt->base) + return -ENOMEM; + } + + if (of_property_read_string(dev->of_node, "coresight-name", &desc.name)) + desc.name = "coresight-fuse"; + + desc.type = CORESIGHT_DEV_TYPE_NONE; + desc.pdata = pdev->dev.platform_data; + desc.dev = &pdev->dev; + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); + + /* Store the driver data pointer for use in exported functions */ + fusedrvdata = drvdata; + + dev_info(dev, "Fuse initialized\n"); + return 0; +} + +static int fuse_remove(struct platform_device *pdev) +{ + struct fuse_drvdata *drvdata = platform_get_drvdata(pdev); + + coresight_unregister(drvdata->csdev); + return 0; +} + +static struct platform_driver fuse_driver = { + .probe = fuse_probe, + .remove = fuse_remove, + .driver = { + .name = "coresight-fuse", + .of_match_table = fuse_match, + }, +}; + +static int __init fuse_init(void) +{ + return platform_driver_register(&fuse_driver); +} +module_init(fuse_init); + +static void __exit fuse_exit(void) +{ + platform_driver_unregister(&fuse_driver); +} +module_exit(fuse_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CoreSight Fuse driver"); diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 616610278d85..0dc97ff18086 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,17 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif +#ifdef CONFIG_CORESIGHT_FUSE +extern bool coresight_fuse_access_disabled(void); +extern bool coresight_fuse_apps_access_disabled(void); +extern bool coresight_fuse_qpdi_access_disabled(void); +extern bool coresight_fuse_nidnt_access_disabled(void); +#else +static inline bool coresight_fuse_access_disabled(void) { return false; } +static inline bool coresight_fuse_apps_access_disabled(void) { return false; } +static inline bool coresight_fuse_qpdi_access_disabled(void) { return false; } +static inline bool coresight_fuse_nidnt_access_disabled(void) { return false; } +#endif /* * Macros and inline functions to handle CoreSight UCI data and driver * private data in AMBA ID table entries, and extract data values. diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 1e2f4a603437..3aa67c98cde8 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -4152,6 +4152,9 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) uint32_t version; u32 dump_state = 0; + if (coresight_fuse_access_disabled()) + return -EPERM; + desc.name = coresight_alloc_device_name(&tpdm_devs, dev); if (!desc.name) return -ENOMEM;