brintos

brintos / linux-shallow public Read only

0
0
Text · 11.3 KiB · 3e55be9 Raw
456 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.4 *5 * Description: CoreSight Replicator driver6 */7 8#include <linux/acpi.h>9#include <linux/amba/bus.h>10#include <linux/kernel.h>11#include <linux/device.h>12#include <linux/platform_device.h>13#include <linux/io.h>14#include <linux/err.h>15#include <linux/slab.h>16#include <linux/pm_runtime.h>17#include <linux/property.h>18#include <linux/clk.h>19#include <linux/of.h>20#include <linux/coresight.h>21 22#include "coresight-priv.h"23 24#define REPLICATOR_IDFILTER0		0x00025#define REPLICATOR_IDFILTER1		0x00426 27DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");28 29/**30 * struct replicator_drvdata - specifics associated to a replicator component31 * @base:	memory mapped base address for this component. Also indicates32 *		whether this one is programmable or not.33 * @atclk:	optional clock for the core parts of the replicator.34 * @pclk:	APB clock if present, otherwise NULL35 * @csdev:	component vitals needed by the framework36 * @spinlock:	serialize enable/disable operations.37 * @check_idfilter_val: check if the context is lost upon clock removal.38 */39struct replicator_drvdata {40	void __iomem		*base;41	struct clk		*atclk;42	struct clk		*pclk;43	struct coresight_device	*csdev;44	spinlock_t		spinlock;45	bool			check_idfilter_val;46};47 48static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)49{50	struct coresight_device *csdev = drvdata->csdev;51 52	CS_UNLOCK(drvdata->base);53 54	if (!coresight_claim_device_unlocked(csdev)) {55		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);56		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);57		coresight_disclaim_device_unlocked(csdev);58	}59 60	CS_LOCK(drvdata->base);61}62 63/*64 * replicator_reset : Reset the replicator configuration to sane values.65 */66static inline void replicator_reset(struct replicator_drvdata *drvdata)67{68	if (drvdata->base)69		dynamic_replicator_reset(drvdata);70}71 72static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,73				     int inport, int outport)74{75	int rc = 0;76	u32 id0val, id1val;77	struct coresight_device *csdev = drvdata->csdev;78 79	CS_UNLOCK(drvdata->base);80 81	id0val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0);82	id1val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1);83 84	/*85	 * Some replicator designs lose context when AMBA clocks are removed,86	 * so have a check for this.87	 */88	if (drvdata->check_idfilter_val && id0val == 0x0 && id1val == 0x0)89		id0val = id1val = 0xff;90 91	if (id0val == 0xff && id1val == 0xff)92		rc = coresight_claim_device_unlocked(csdev);93 94	if (!rc) {95		switch (outport) {96		case 0:97			id0val = 0x0;98			break;99		case 1:100			id1val = 0x0;101			break;102		default:103			WARN_ON(1);104			rc = -EINVAL;105		}106	}107 108	/* Ensure that the outport is enabled. */109	if (!rc) {110		writel_relaxed(id0val, drvdata->base + REPLICATOR_IDFILTER0);111		writel_relaxed(id1val, drvdata->base + REPLICATOR_IDFILTER1);112	}113 114	CS_LOCK(drvdata->base);115 116	return rc;117}118 119static int replicator_enable(struct coresight_device *csdev,120			     struct coresight_connection *in,121			     struct coresight_connection *out)122{123	int rc = 0;124	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);125	unsigned long flags;126	bool first_enable = false;127 128	spin_lock_irqsave(&drvdata->spinlock, flags);129	if (atomic_read(&out->src_refcnt) == 0) {130		if (drvdata->base)131			rc = dynamic_replicator_enable(drvdata, in->dest_port,132						       out->src_port);133		if (!rc)134			first_enable = true;135	}136	if (!rc)137		atomic_inc(&out->src_refcnt);138	spin_unlock_irqrestore(&drvdata->spinlock, flags);139 140	if (first_enable)141		dev_dbg(&csdev->dev, "REPLICATOR enabled\n");142	return rc;143}144 145static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,146				       int inport, int outport)147{148	u32 reg;149	struct coresight_device *csdev = drvdata->csdev;150 151	switch (outport) {152	case 0:153		reg = REPLICATOR_IDFILTER0;154		break;155	case 1:156		reg = REPLICATOR_IDFILTER1;157		break;158	default:159		WARN_ON(1);160		return;161	}162 163	CS_UNLOCK(drvdata->base);164 165	/* disable the flow of ATB data through port */166	writel_relaxed(0xff, drvdata->base + reg);167 168	if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&169	    (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))170		coresight_disclaim_device_unlocked(csdev);171	CS_LOCK(drvdata->base);172}173 174static void replicator_disable(struct coresight_device *csdev,175			       struct coresight_connection *in,176			       struct coresight_connection *out)177{178	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);179	unsigned long flags;180	bool last_disable = false;181 182	spin_lock_irqsave(&drvdata->spinlock, flags);183	if (atomic_dec_return(&out->src_refcnt) == 0) {184		if (drvdata->base)185			dynamic_replicator_disable(drvdata, in->dest_port,186						   out->src_port);187		last_disable = true;188	}189	spin_unlock_irqrestore(&drvdata->spinlock, flags);190 191	if (last_disable)192		dev_dbg(&csdev->dev, "REPLICATOR disabled\n");193}194 195static const struct coresight_ops_link replicator_link_ops = {196	.enable		= replicator_enable,197	.disable	= replicator_disable,198};199 200static const struct coresight_ops replicator_cs_ops = {201	.link_ops	= &replicator_link_ops,202};203 204static struct attribute *replicator_mgmt_attrs[] = {205	coresight_simple_reg32(idfilter0, REPLICATOR_IDFILTER0),206	coresight_simple_reg32(idfilter1, REPLICATOR_IDFILTER1),207	NULL,208};209 210static const struct attribute_group replicator_mgmt_group = {211	.attrs = replicator_mgmt_attrs,212	.name = "mgmt",213};214 215static const struct attribute_group *replicator_groups[] = {216	&replicator_mgmt_group,217	NULL,218};219 220static int replicator_probe(struct device *dev, struct resource *res)221{222	int ret = 0;223	struct coresight_platform_data *pdata = NULL;224	struct replicator_drvdata *drvdata;225	struct coresight_desc desc = { 0 };226	void __iomem *base;227 228	if (is_of_node(dev_fwnode(dev)) &&229	    of_device_is_compatible(dev->of_node, "arm,coresight-replicator"))230		dev_warn_once(dev,231			      "Uses OBSOLETE CoreSight replicator binding\n");232 233	desc.name = coresight_alloc_device_name(&replicator_devs, dev);234	if (!desc.name)235		return -ENOMEM;236 237	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);238	if (!drvdata)239		return -ENOMEM;240 241	drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */242	if (!IS_ERR(drvdata->atclk)) {243		ret = clk_prepare_enable(drvdata->atclk);244		if (ret)245			return ret;246	}247 248	drvdata->pclk = coresight_get_enable_apb_pclk(dev);249	if (IS_ERR(drvdata->pclk))250		return -ENODEV;251 252	/*253	 * Map the device base for dynamic-replicator, which has been254	 * validated by AMBA core255	 */256	if (res) {257		base = devm_ioremap_resource(dev, res);258		if (IS_ERR(base)) {259			ret = PTR_ERR(base);260			goto out_disable_clk;261		}262		drvdata->base = base;263		desc.groups = replicator_groups;264		desc.access = CSDEV_ACCESS_IOMEM(base);265	}266 267	if (fwnode_property_present(dev_fwnode(dev),268				    "qcom,replicator-loses-context"))269		drvdata->check_idfilter_val = true;270 271	dev_set_drvdata(dev, drvdata);272 273	pdata = coresight_get_platform_data(dev);274	if (IS_ERR(pdata)) {275		ret = PTR_ERR(pdata);276		goto out_disable_clk;277	}278	dev->platform_data = pdata;279 280	spin_lock_init(&drvdata->spinlock);281	desc.type = CORESIGHT_DEV_TYPE_LINK;282	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;283	desc.ops = &replicator_cs_ops;284	desc.pdata = dev->platform_data;285	desc.dev = dev;286 287	drvdata->csdev = coresight_register(&desc);288	if (IS_ERR(drvdata->csdev)) {289		ret = PTR_ERR(drvdata->csdev);290		goto out_disable_clk;291	}292 293	replicator_reset(drvdata);294 295out_disable_clk:296	if (ret && !IS_ERR_OR_NULL(drvdata->atclk))297		clk_disable_unprepare(drvdata->atclk);298	if (ret && !IS_ERR_OR_NULL(drvdata->pclk))299		clk_disable_unprepare(drvdata->pclk);300	return ret;301}302 303static int replicator_remove(struct device *dev)304{305	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);306 307	coresight_unregister(drvdata->csdev);308	return 0;309}310 311static int replicator_platform_probe(struct platform_device *pdev)312{313	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);314	int ret;315 316	pm_runtime_get_noresume(&pdev->dev);317	pm_runtime_set_active(&pdev->dev);318	pm_runtime_enable(&pdev->dev);319 320	ret = replicator_probe(&pdev->dev, res);321	pm_runtime_put(&pdev->dev);322	if (ret)323		pm_runtime_disable(&pdev->dev);324 325	return ret;326}327 328static void replicator_platform_remove(struct platform_device *pdev)329{330	struct replicator_drvdata *drvdata = dev_get_drvdata(&pdev->dev);331 332	if (WARN_ON(!drvdata))333		return;334 335	replicator_remove(&pdev->dev);336	pm_runtime_disable(&pdev->dev);337	if (!IS_ERR_OR_NULL(drvdata->pclk))338		clk_put(drvdata->pclk);339}340 341#ifdef CONFIG_PM342static int replicator_runtime_suspend(struct device *dev)343{344	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);345 346	if (drvdata && !IS_ERR(drvdata->atclk))347		clk_disable_unprepare(drvdata->atclk);348 349	if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))350		clk_disable_unprepare(drvdata->pclk);351	return 0;352}353 354static int replicator_runtime_resume(struct device *dev)355{356	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);357 358	if (drvdata && !IS_ERR(drvdata->atclk))359		clk_prepare_enable(drvdata->atclk);360 361	if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))362		clk_prepare_enable(drvdata->pclk);363	return 0;364}365#endif366 367static const struct dev_pm_ops replicator_dev_pm_ops = {368	SET_RUNTIME_PM_OPS(replicator_runtime_suspend,369			   replicator_runtime_resume, NULL)370};371 372static const struct of_device_id replicator_match[] = {373	{.compatible = "arm,coresight-replicator"},374	{.compatible = "arm,coresight-static-replicator"},375	{}376};377 378MODULE_DEVICE_TABLE(of, replicator_match);379 380#ifdef CONFIG_ACPI381static const struct acpi_device_id replicator_acpi_ids[] = {382	{"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */383	{"ARMHC98D", 0, 0, 0}, /* ARM CoreSight Dynamic Replicator */384	{}385};386 387MODULE_DEVICE_TABLE(acpi, replicator_acpi_ids);388#endif389 390static struct platform_driver replicator_driver = {391	.probe          = replicator_platform_probe,392	.remove_new     = replicator_platform_remove,393	.driver         = {394		.name   = "coresight-replicator",395		/* THIS_MODULE is taken care of by platform_driver_register() */396		.of_match_table = of_match_ptr(replicator_match),397		.acpi_match_table = ACPI_PTR(replicator_acpi_ids),398		.pm	= &replicator_dev_pm_ops,399		.suppress_bind_attrs = true,400	},401};402 403static int dynamic_replicator_probe(struct amba_device *adev,404				    const struct amba_id *id)405{406	int ret;407 408	ret = replicator_probe(&adev->dev, &adev->res);409	if (!ret)410		pm_runtime_put(&adev->dev);411 412	return ret;413}414 415static void dynamic_replicator_remove(struct amba_device *adev)416{417	replicator_remove(&adev->dev);418}419 420static const struct amba_id dynamic_replicator_ids[] = {421	CS_AMBA_ID(0x000bb909),422	CS_AMBA_ID(0x000bb9ec),		/* Coresight SoC-600 */423	{},424};425 426MODULE_DEVICE_TABLE(amba, dynamic_replicator_ids);427 428static struct amba_driver dynamic_replicator_driver = {429	.drv = {430		.name	= "coresight-dynamic-replicator",431		.pm	= &replicator_dev_pm_ops,432		.suppress_bind_attrs = true,433	},434	.probe		= dynamic_replicator_probe,435	.remove         = dynamic_replicator_remove,436	.id_table	= dynamic_replicator_ids,437};438 439static int __init replicator_init(void)440{441	return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver);442}443 444static void __exit replicator_exit(void)445{446	coresight_remove_driver(&dynamic_replicator_driver, &replicator_driver);447}448 449module_init(replicator_init);450module_exit(replicator_exit);451 452MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");453MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");454MODULE_DESCRIPTION("Arm CoreSight Replicator Driver");455MODULE_LICENSE("GPL v2");456