2018-05-09 12:06:04 -06:00
// SPDX-License-Identifier: GPL-2.0
/*
2019-04-25 13:52:45 -06:00
* Copyright ( c ) 2011 - 2015 , The Linux Foundation . All rights reserved .
2016-02-17 17:52:03 -07:00
*
* Description : CoreSight Replicator driver
2014-11-03 11:07:40 -07:00
*/
2019-06-19 13:53:08 -06:00
# include <linux/acpi.h>
2019-04-25 13:52:45 -06:00
# include <linux/amba/bus.h>
2014-11-03 11:07:40 -07:00
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/platform_device.h>
# include <linux/io.h>
# include <linux/err.h>
# include <linux/slab.h>
2015-05-19 10:55:18 -06:00
# include <linux/pm_runtime.h>
2020-07-16 11:57:34 -06:00
# include <linux/property.h>
2014-11-03 11:07:40 -07:00
# include <linux/clk.h>
# include <linux/of.h>
# include <linux/coresight.h>
# include "coresight-priv.h"
2019-04-25 13:52:45 -06:00
# define REPLICATOR_IDFILTER0 0x000
# define REPLICATOR_IDFILTER1 0x004
2019-06-19 13:53:04 -06:00
DEFINE_CORESIGHT_DEVLIST ( replicator_devs , " replicator " ) ;
2014-11-03 11:07:40 -07:00
/**
* struct replicator_drvdata - specifics associated to a replicator component
2019-04-25 13:52:45 -06:00
* @ base : memory mapped base address for this component . Also indicates
* whether this one is programmable or not .
2015-05-19 10:55:18 -06:00
* @ atclk : optional clock for the core parts of the replicator .
2014-11-03 11:07:40 -07:00
* @ csdev : component vitals needed by the framework
2019-11-04 11:12:50 -07:00
* @ spinlock : serialize enable / disable operations .
2020-07-16 11:57:34 -06:00
* @ check_idfilter_val : check if the context is lost upon clock removal .
2014-11-03 11:07:40 -07:00
*/
struct replicator_drvdata {
2019-04-25 13:52:45 -06:00
void __iomem * base ;
2015-05-19 10:55:18 -06:00
struct clk * atclk ;
2014-11-03 11:07:40 -07:00
struct coresight_device * csdev ;
2019-11-04 11:12:50 -07:00
spinlock_t spinlock ;
2020-07-16 11:57:34 -06:00
bool check_idfilter_val ;
2014-11-03 11:07:40 -07:00
} ;
2019-04-25 13:52:45 -06:00
static void dynamic_replicator_reset ( struct replicator_drvdata * drvdata )
{
2021-02-01 11:13:28 -07:00
struct coresight_device * csdev = drvdata - > csdev ;
2019-04-25 13:52:45 -06:00
CS_UNLOCK ( drvdata - > base ) ;
2021-02-01 11:13:28 -07:00
if ( ! coresight_claim_device_unlocked ( csdev ) ) {
2019-04-25 13:52:45 -06:00
writel_relaxed ( 0xff , drvdata - > base + REPLICATOR_IDFILTER0 ) ;
writel_relaxed ( 0xff , drvdata - > base + REPLICATOR_IDFILTER1 ) ;
2021-02-01 11:13:28 -07:00
coresight_disclaim_device_unlocked ( csdev ) ;
2019-04-25 13:52:45 -06:00
}
CS_LOCK ( drvdata - > base ) ;
}
/*
* replicator_reset : Reset the replicator configuration to sane values .
*/
static inline void replicator_reset ( struct replicator_drvdata * drvdata )
{
if ( drvdata - > base )
dynamic_replicator_reset ( drvdata ) ;
}
static int dynamic_replicator_enable ( struct replicator_drvdata * drvdata ,
int inport , int outport )
{
int rc = 0 ;
2020-07-16 11:57:34 -06:00
u32 id0val , id1val ;
2021-02-01 11:13:28 -07:00
struct coresight_device * csdev = drvdata - > csdev ;
2019-04-25 13:52:45 -06:00
CS_UNLOCK ( drvdata - > base ) ;
2020-07-16 11:57:34 -06:00
id0val = readl_relaxed ( drvdata - > base + REPLICATOR_IDFILTER0 ) ;
id1val = readl_relaxed ( drvdata - > base + REPLICATOR_IDFILTER1 ) ;
/*
* Some replicator designs lose context when AMBA clocks are removed ,
* so have a check for this .
*/
if ( drvdata - > check_idfilter_val & & id0val = = 0x0 & & id1val = = 0x0 )
id0val = id1val = 0xff ;
if ( id0val = = 0xff & & id1val = = 0xff )
2021-02-01 11:13:28 -07:00
rc = coresight_claim_device_unlocked ( csdev ) ;
2019-04-25 13:52:45 -06:00
2020-07-16 11:57:34 -06:00
if ( ! rc ) {
switch ( outport ) {
case 0 :
id0val = 0x0 ;
break ;
case 1 :
id1val = 0x0 ;
break ;
default :
WARN_ON ( 1 ) ;
rc = - EINVAL ;
}
}
2019-04-25 13:52:45 -06:00
/* Ensure that the outport is enabled. */
2020-07-16 11:57:34 -06:00
if ( ! rc ) {
writel_relaxed ( id0val , drvdata - > base + REPLICATOR_IDFILTER0 ) ;
writel_relaxed ( id1val , drvdata - > base + REPLICATOR_IDFILTER1 ) ;
}
2019-04-25 13:52:45 -06:00
CS_LOCK ( drvdata - > base ) ;
return rc ;
}
2023-04-25 15:35:37 +01:00
static int replicator_enable ( struct coresight_device * csdev ,
struct coresight_connection * in ,
struct coresight_connection * out )
2014-11-03 11:07:40 -07:00
{
2019-04-25 13:52:45 -06:00
int rc = 0 ;
2014-11-03 11:07:40 -07:00
struct replicator_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
2019-11-04 11:12:50 -07:00
unsigned long flags ;
bool first_enable = false ;
spin_lock_irqsave ( & drvdata - > spinlock , flags ) ;
2023-04-25 15:35:37 +01:00
if ( atomic_read ( & out - > src_refcnt ) = = 0 ) {
2019-11-04 11:12:50 -07:00
if ( drvdata - > base )
2023-04-25 15:35:37 +01:00
rc = dynamic_replicator_enable ( drvdata , in - > dest_port ,
out - > src_port ) ;
2019-11-04 11:12:50 -07:00
if ( ! rc )
first_enable = true ;
}
2019-04-25 13:52:45 -06:00
if ( ! rc )
2023-04-25 15:35:37 +01:00
atomic_inc ( & out - > src_refcnt ) ;
2019-11-04 11:12:50 -07:00
spin_unlock_irqrestore ( & drvdata - > spinlock , flags ) ;
if ( first_enable )
2019-06-19 11:29:11 -06:00
dev_dbg ( & csdev - > dev , " REPLICATOR enabled \n " ) ;
2019-04-25 13:52:45 -06:00
return rc ;
}
static void dynamic_replicator_disable ( struct replicator_drvdata * drvdata ,
int inport , int outport )
{
u32 reg ;
2021-02-01 11:13:28 -07:00
struct coresight_device * csdev = drvdata - > csdev ;
2019-04-25 13:52:45 -06:00
switch ( outport ) {
case 0 :
reg = REPLICATOR_IDFILTER0 ;
break ;
case 1 :
reg = REPLICATOR_IDFILTER1 ;
break ;
default :
WARN_ON ( 1 ) ;
return ;
}
CS_UNLOCK ( drvdata - > base ) ;
/* disable the flow of ATB data through port */
writel_relaxed ( 0xff , drvdata - > base + reg ) ;
if ( ( readl_relaxed ( drvdata - > base + REPLICATOR_IDFILTER0 ) = = 0xff ) & &
( readl_relaxed ( drvdata - > base + REPLICATOR_IDFILTER1 ) = = 0xff ) )
2021-02-01 11:13:28 -07:00
coresight_disclaim_device_unlocked ( csdev ) ;
2019-04-25 13:52:45 -06:00
CS_LOCK ( drvdata - > base ) ;
2014-11-03 11:07:40 -07:00
}
2023-04-25 15:35:37 +01:00
static void replicator_disable ( struct coresight_device * csdev ,
struct coresight_connection * in ,
struct coresight_connection * out )
2014-11-03 11:07:40 -07:00
{
struct replicator_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
2019-11-04 11:12:50 -07:00
unsigned long flags ;
bool last_disable = false ;
spin_lock_irqsave ( & drvdata - > spinlock , flags ) ;
2023-04-25 15:35:37 +01:00
if ( atomic_dec_return ( & out - > src_refcnt ) = = 0 ) {
2019-11-04 11:12:50 -07:00
if ( drvdata - > base )
2023-04-25 15:35:37 +01:00
dynamic_replicator_disable ( drvdata , in - > dest_port ,
out - > src_port ) ;
2019-11-04 11:12:50 -07:00
last_disable = true ;
}
spin_unlock_irqrestore ( & drvdata - > spinlock , flags ) ;
2014-11-03 11:07:40 -07:00
2019-11-04 11:12:50 -07:00
if ( last_disable )
dev_dbg ( & csdev - > dev , " REPLICATOR disabled \n " ) ;
2014-11-03 11:07:40 -07:00
}
static const struct coresight_ops_link replicator_link_ops = {
. enable = replicator_enable ,
. disable = replicator_disable ,
} ;
static const struct coresight_ops replicator_cs_ops = {
. link_ops = & replicator_link_ops ,
} ;
2019-04-25 13:52:45 -06:00
static struct attribute * replicator_mgmt_attrs [ ] = {
2022-08-30 18:26:11 +01:00
coresight_simple_reg32 ( idfilter0 , REPLICATOR_IDFILTER0 ) ,
coresight_simple_reg32 ( idfilter1 , REPLICATOR_IDFILTER1 ) ,
2019-04-25 13:52:45 -06:00
NULL ,
} ;
static const struct attribute_group replicator_mgmt_group = {
. attrs = replicator_mgmt_attrs ,
. name = " mgmt " ,
} ;
static const struct attribute_group * replicator_groups [ ] = {
& replicator_mgmt_group ,
NULL ,
} ;
static int replicator_probe ( struct device * dev , struct resource * res )
2014-11-03 11:07:40 -07:00
{
2019-04-25 13:52:43 -06:00
int ret = 0 ;
2014-11-03 11:07:40 -07:00
struct coresight_platform_data * pdata = NULL ;
struct replicator_drvdata * drvdata ;
2016-08-25 15:19:05 -06:00
struct coresight_desc desc = { 0 } ;
2019-04-25 13:52:45 -06:00
void __iomem * base ;
2014-11-03 11:07:40 -07:00
2019-06-19 13:52:53 -06:00
if ( is_of_node ( dev_fwnode ( dev ) ) & &
of_device_is_compatible ( dev - > of_node , " arm,coresight-replicator " ) )
2019-08-29 14:28:32 -06:00
dev_warn_once ( dev ,
" Uses OBSOLETE CoreSight replicator binding \n " ) ;
2019-05-02 10:54:03 -06:00
2019-06-19 13:53:04 -06:00
desc . name = coresight_alloc_device_name ( & replicator_devs , dev ) ;
if ( ! desc . name )
return - ENOMEM ;
2014-11-03 11:07:40 -07:00
drvdata = devm_kzalloc ( dev , sizeof ( * drvdata ) , GFP_KERNEL ) ;
if ( ! drvdata )
return - ENOMEM ;
2019-04-25 13:52:43 -06:00
drvdata - > atclk = devm_clk_get ( dev , " atclk " ) ; /* optional */
2015-05-19 10:55:18 -06:00
if ( ! IS_ERR ( drvdata - > atclk ) ) {
ret = clk_prepare_enable ( drvdata - > atclk ) ;
if ( ret )
return ret ;
}
2019-04-25 13:52:43 -06:00
2019-04-25 13:52:45 -06:00
/*
* Map the device base for dynamic - replicator , which has been
* validated by AMBA core
*/
if ( res ) {
base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( base ) ) {
ret = PTR_ERR ( base ) ;
goto out_disable_clk ;
}
drvdata - > base = base ;
desc . groups = replicator_groups ;
2021-02-01 11:13:25 -07:00
desc . access = CSDEV_ACCESS_IOMEM ( base ) ;
2019-04-25 13:52:45 -06:00
}
2020-07-16 11:57:34 -06:00
if ( fwnode_property_present ( dev_fwnode ( dev ) ,
" qcom,replicator-loses-context " ) )
drvdata - > check_idfilter_val = true ;
2019-04-25 13:52:43 -06:00
dev_set_drvdata ( dev , drvdata ) ;
2014-11-03 11:07:40 -07:00
2019-06-19 13:53:00 -06:00
pdata = coresight_get_platform_data ( dev ) ;
if ( IS_ERR ( pdata ) ) {
ret = PTR_ERR ( pdata ) ;
goto out_disable_clk ;
}
dev - > platform_data = pdata ;
2019-11-18 11:52:07 -07:00
spin_lock_init ( & drvdata - > spinlock ) ;
2016-08-25 15:19:05 -06:00
desc . type = CORESIGHT_DEV_TYPE_LINK ;
desc . subtype . link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT ;
desc . ops = & replicator_cs_ops ;
2019-04-25 13:52:43 -06:00
desc . pdata = dev - > platform_data ;
desc . dev = dev ;
2019-06-19 13:52:57 -06:00
2016-08-25 15:19:05 -06:00
drvdata - > csdev = coresight_register ( & desc ) ;
2015-05-19 10:55:18 -06:00
if ( IS_ERR ( drvdata - > csdev ) ) {
ret = PTR_ERR ( drvdata - > csdev ) ;
2019-04-25 13:52:43 -06:00
goto out_disable_clk ;
2015-05-19 10:55:18 -06:00
}
2019-04-25 13:52:45 -06:00
replicator_reset ( drvdata ) ;
2019-04-25 13:52:43 -06:00
pm_runtime_put ( dev ) ;
2014-11-03 11:07:40 -07:00
2019-04-25 13:52:43 -06:00
out_disable_clk :
if ( ret & & ! IS_ERR_OR_NULL ( drvdata - > atclk ) )
2015-05-19 10:55:18 -06:00
clk_disable_unprepare ( drvdata - > atclk ) ;
2019-04-25 13:52:43 -06:00
return ret ;
}
2020-12-08 11:26:50 -07:00
static int replicator_remove ( struct device * dev )
2020-09-28 10:35:03 -06:00
{
struct replicator_drvdata * drvdata = dev_get_drvdata ( dev ) ;
coresight_unregister ( drvdata - > csdev ) ;
return 0 ;
}
2019-04-25 13:52:43 -06:00
static int static_replicator_probe ( struct platform_device * pdev )
{
int ret ;
pm_runtime_get_noresume ( & pdev - > dev ) ;
pm_runtime_set_active ( & pdev - > dev ) ;
pm_runtime_enable ( & pdev - > dev ) ;
2019-04-25 13:52:45 -06:00
/* Static replicators do not have programming base */
ret = replicator_probe ( & pdev - > dev , NULL ) ;
2019-04-25 13:52:43 -06:00
if ( ret ) {
pm_runtime_put_noidle ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
}
2015-05-19 10:55:18 -06:00
return ret ;
2014-11-03 11:07:40 -07:00
}
2023-11-16 18:33:05 +01:00
static void static_replicator_remove ( struct platform_device * pdev )
2020-09-28 10:35:03 -06:00
{
replicator_remove ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
}
2015-05-19 10:55:18 -06:00
# ifdef CONFIG_PM
static int replicator_runtime_suspend ( struct device * dev )
{
struct replicator_drvdata * drvdata = dev_get_drvdata ( dev ) ;
if ( drvdata & & ! IS_ERR ( drvdata - > atclk ) )
clk_disable_unprepare ( drvdata - > atclk ) ;
2014-11-03 11:07:40 -07:00
return 0 ;
}
2015-05-19 10:55:18 -06:00
static int replicator_runtime_resume ( struct device * dev )
{
struct replicator_drvdata * drvdata = dev_get_drvdata ( dev ) ;
if ( drvdata & & ! IS_ERR ( drvdata - > atclk ) )
clk_prepare_enable ( drvdata - > atclk ) ;
return 0 ;
}
# endif
static const struct dev_pm_ops replicator_dev_pm_ops = {
SET_RUNTIME_PM_OPS ( replicator_runtime_suspend ,
replicator_runtime_resume , NULL )
} ;
2019-04-25 13:52:43 -06:00
static const struct of_device_id static_replicator_match [ ] = {
2014-11-03 11:07:40 -07:00
{ . compatible = " arm,coresight-replicator " } ,
2019-05-02 10:54:03 -06:00
{ . compatible = " arm,coresight-static-replicator " } ,
2014-11-03 11:07:40 -07:00
{ }
} ;
2020-09-28 10:35:03 -06:00
MODULE_DEVICE_TABLE ( of , static_replicator_match ) ;
2019-06-19 13:53:08 -06:00
# ifdef CONFIG_ACPI
static const struct acpi_device_id static_replicator_acpi_ids [ ] = {
{ " ARMHC985 " , 0 } , /* ARM CoreSight Static Replicator */
2019-06-19 13:53:18 -06:00
{ }
2019-06-19 13:53:08 -06:00
} ;
2020-09-28 10:35:03 -06:00
MODULE_DEVICE_TABLE ( acpi , static_replicator_acpi_ids ) ;
2019-06-19 13:53:08 -06:00
# endif
2019-04-25 13:52:43 -06:00
static struct platform_driver static_replicator_driver = {
. probe = static_replicator_probe ,
2023-11-16 18:33:05 +01:00
. remove_new = static_replicator_remove ,
2014-11-03 11:07:40 -07:00
. driver = {
2019-05-02 10:54:03 -06:00
. name = " coresight-static-replicator " ,
2020-11-27 10:52:49 -07:00
/* THIS_MODULE is taken care of by platform_driver_register() */
2019-06-19 13:53:08 -06:00
. of_match_table = of_match_ptr ( static_replicator_match ) ,
. acpi_match_table = ACPI_PTR ( static_replicator_acpi_ids ) ,
2015-05-19 10:55:18 -06:00
. pm = & replicator_dev_pm_ops ,
2016-02-02 14:14:00 -07:00
. suppress_bind_attrs = true ,
2014-11-03 11:07:40 -07:00
} ,
} ;
2019-04-25 13:52:45 -06:00
static int dynamic_replicator_probe ( struct amba_device * adev ,
const struct amba_id * id )
{
return replicator_probe ( & adev - > dev , & adev - > res ) ;
}
2021-01-26 17:58:34 +01:00
static void dynamic_replicator_remove ( struct amba_device * adev )
2020-09-28 10:35:03 -06:00
{
2021-01-26 17:58:34 +01:00
replicator_remove ( & adev - > dev ) ;
2020-09-28 10:35:03 -06:00
}
2019-04-25 13:52:45 -06:00
static const struct amba_id dynamic_replicator_ids [ ] = {
2020-07-16 11:57:30 -06:00
CS_AMBA_ID ( 0x000bb909 ) ,
CS_AMBA_ID ( 0x000bb9ec ) , /* Coresight SoC-600 */
{ } ,
2019-04-25 13:52:45 -06:00
} ;
2020-09-28 10:35:03 -06:00
MODULE_DEVICE_TABLE ( amba , dynamic_replicator_ids ) ;
2019-04-25 13:52:45 -06:00
static struct amba_driver dynamic_replicator_driver = {
. drv = {
. name = " coresight-dynamic-replicator " ,
. pm = & replicator_dev_pm_ops ,
2020-09-28 10:35:03 -06:00
. owner = THIS_MODULE ,
2019-04-25 13:52:45 -06:00
. suppress_bind_attrs = true ,
} ,
. probe = dynamic_replicator_probe ,
2020-09-28 10:35:03 -06:00
. remove = dynamic_replicator_remove ,
2019-04-25 13:52:45 -06:00
. id_table = dynamic_replicator_ids ,
} ;
2020-09-28 10:35:03 -06:00
static int __init replicator_init ( void )
{
int ret ;
ret = platform_driver_register ( & static_replicator_driver ) ;
if ( ret ) {
pr_info ( " Error registering platform driver \n " ) ;
return ret ;
}
ret = amba_driver_register ( & dynamic_replicator_driver ) ;
if ( ret ) {
pr_info ( " Error registering amba driver \n " ) ;
platform_driver_unregister ( & static_replicator_driver ) ;
}
return ret ;
}
static void __exit replicator_exit ( void )
{
platform_driver_unregister ( & static_replicator_driver ) ;
amba_driver_unregister ( & dynamic_replicator_driver ) ;
}
module_init ( replicator_init ) ;
module_exit ( replicator_exit ) ;
MODULE_AUTHOR ( " Pratik Patel <pratikp@codeaurora.org> " ) ;
MODULE_AUTHOR ( " Mathieu Poirier <mathieu.poirier@linaro.org> " ) ;
MODULE_DESCRIPTION ( " Arm CoreSight Replicator Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;