2018-03-28 18:46:15 +03:00
// SPDX-License-Identifier: GPL-2.0
2015-09-22 15:47:19 +03:00
/*
* Intel ( R ) Trace Hub PTI output driver
*
2016-11-11 12:07:25 +02:00
* Copyright ( C ) 2014 - 2016 Intel Corporation .
2015-09-22 15:47:19 +03:00
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/types.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/sizes.h>
# include <linux/printk.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/io.h>
# include "intel_th.h"
# include "pti.h"
struct pti_device {
void __iomem * base ;
struct intel_th_device * thdev ;
unsigned int mode ;
unsigned int freeclk ;
unsigned int clkdiv ;
unsigned int patgen ;
2016-11-11 12:07:25 +02:00
unsigned int lpp_dest_mask ;
unsigned int lpp_dest ;
2015-09-22 15:47:19 +03:00
} ;
/* map PTI widths to MODE settings of PTI_CTL register */
static const unsigned int pti_mode [ ] = {
0 , 4 , 8 , 0 , 12 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
} ;
static int pti_width_mode ( unsigned int width )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( pti_mode ) ; i + + )
if ( pti_mode [ i ] = = width )
return i ;
return - EINVAL ;
}
static ssize_t mode_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
return scnprintf ( buf , PAGE_SIZE , " %d \n " , pti_mode [ pti - > mode ] ) ;
}
static ssize_t mode_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t size )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
unsigned long val ;
int ret ;
ret = kstrtoul ( buf , 10 , & val ) ;
if ( ret )
return ret ;
ret = pti_width_mode ( val ) ;
if ( ret < 0 )
return ret ;
pti - > mode = ret ;
return size ;
}
static DEVICE_ATTR_RW ( mode ) ;
static ssize_t
freerunning_clock_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
return scnprintf ( buf , PAGE_SIZE , " %d \n " , pti - > freeclk ) ;
}
static ssize_t
freerunning_clock_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t size )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
unsigned long val ;
int ret ;
ret = kstrtoul ( buf , 10 , & val ) ;
if ( ret )
return ret ;
pti - > freeclk = ! ! val ;
return size ;
}
static DEVICE_ATTR_RW ( freerunning_clock ) ;
static ssize_t
clock_divider_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
return scnprintf ( buf , PAGE_SIZE , " %d \n " , 1u < < pti - > clkdiv ) ;
}
static ssize_t
clock_divider_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t size )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
unsigned long val ;
int ret ;
ret = kstrtoul ( buf , 10 , & val ) ;
if ( ret )
return ret ;
if ( ! is_power_of_2 ( val ) | | val > 8 | | ! val )
return - EINVAL ;
pti - > clkdiv = val ;
return size ;
}
static DEVICE_ATTR_RW ( clock_divider ) ;
static struct attribute * pti_output_attrs [ ] = {
& dev_attr_mode . attr ,
& dev_attr_freerunning_clock . attr ,
& dev_attr_clock_divider . attr ,
NULL ,
} ;
2021-04-14 20:12:48 +03:00
static const struct attribute_group pti_output_group = {
2015-09-22 15:47:19 +03:00
. attrs = pti_output_attrs ,
} ;
static int intel_th_pti_activate ( struct intel_th_device * thdev )
{
struct pti_device * pti = dev_get_drvdata ( & thdev - > dev ) ;
u32 ctl = PTI_EN ;
if ( pti - > patgen )
ctl | = pti - > patgen < < __ffs ( PTI_PATGENMODE ) ;
if ( pti - > freeclk )
ctl | = PTI_FCEN ;
ctl | = pti - > mode < < __ffs ( PTI_MODE ) ;
ctl | = pti - > clkdiv < < __ffs ( PTI_CLKDIV ) ;
2016-11-11 12:07:25 +02:00
ctl | = pti - > lpp_dest < < __ffs ( LPP_DEST ) ;
2015-09-22 15:47:19 +03:00
iowrite32 ( ctl , pti - > base + REG_PTI_CTL ) ;
intel_th_trace_enable ( thdev ) ;
return 0 ;
}
static void intel_th_pti_deactivate ( struct intel_th_device * thdev )
{
struct pti_device * pti = dev_get_drvdata ( & thdev - > dev ) ;
intel_th_trace_disable ( thdev ) ;
iowrite32 ( 0 , pti - > base + REG_PTI_CTL ) ;
}
static void read_hw_config ( struct pti_device * pti )
{
u32 ctl = ioread32 ( pti - > base + REG_PTI_CTL ) ;
pti - > mode = ( ctl & PTI_MODE ) > > __ffs ( PTI_MODE ) ;
pti - > clkdiv = ( ctl & PTI_CLKDIV ) > > __ffs ( PTI_CLKDIV ) ;
pti - > freeclk = ! ! ( ctl & PTI_FCEN ) ;
if ( ! pti_mode [ pti - > mode ] )
pti - > mode = pti_width_mode ( 4 ) ;
if ( ! pti - > clkdiv )
pti - > clkdiv = 1 ;
2016-11-11 12:07:25 +02:00
if ( pti - > thdev - > output . type = = GTH_LPP ) {
if ( ctl & LPP_PTIPRESENT )
pti - > lpp_dest_mask | = LPP_DEST_PTI ;
if ( ctl & LPP_BSSBPRESENT )
pti - > lpp_dest_mask | = LPP_DEST_EXI ;
if ( ctl & LPP_DEST )
pti - > lpp_dest = 1 ;
}
2015-09-22 15:47:19 +03:00
}
static int intel_th_pti_probe ( struct intel_th_device * thdev )
{
struct device * dev = & thdev - > dev ;
struct resource * res ;
struct pti_device * pti ;
void __iomem * base ;
res = intel_th_device_get_resource ( thdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - ENODEV ;
base = devm_ioremap ( dev , res - > start , resource_size ( res ) ) ;
2015-10-16 17:09:13 +03:00
if ( ! base )
return - ENOMEM ;
2015-09-22 15:47:19 +03:00
pti = devm_kzalloc ( dev , sizeof ( * pti ) , GFP_KERNEL ) ;
if ( ! pti )
return - ENOMEM ;
pti - > thdev = thdev ;
pti - > base = base ;
read_hw_config ( pti ) ;
dev_set_drvdata ( dev , pti ) ;
return 0 ;
}
static void intel_th_pti_remove ( struct intel_th_device * thdev )
{
}
static struct intel_th_driver intel_th_pti_driver = {
. probe = intel_th_pti_probe ,
. remove = intel_th_pti_remove ,
. activate = intel_th_pti_activate ,
. deactivate = intel_th_pti_deactivate ,
2016-03-04 19:55:10 +02:00
. attr_group = & pti_output_group ,
2015-09-22 15:47:19 +03:00
. driver = {
. name = " pti " ,
. owner = THIS_MODULE ,
} ,
} ;
2016-11-11 12:07:25 +02:00
static const char * const lpp_dest_str [ ] = { " pti " , " exi " } ;
static ssize_t lpp_dest_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
ssize_t ret = 0 ;
int i ;
for ( i = ARRAY_SIZE ( lpp_dest_str ) - 1 ; i > = 0 ; i - - ) {
const char * fmt = pti - > lpp_dest = = i ? " [%s] " : " %s " ;
if ( ! ( pti - > lpp_dest_mask & BIT ( i ) ) )
continue ;
ret + = scnprintf ( buf + ret , PAGE_SIZE - ret ,
fmt , lpp_dest_str [ i ] ) ;
}
if ( ret )
buf [ ret - 1 ] = ' \n ' ;
return ret ;
}
static ssize_t lpp_dest_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t size )
{
struct pti_device * pti = dev_get_drvdata ( dev ) ;
int i ;
2018-05-04 22:19:25 +03:00
i = sysfs_match_string ( lpp_dest_str , buf ) ;
if ( i < 0 )
return i ;
2016-11-11 12:07:25 +02:00
2018-05-04 22:19:25 +03:00
if ( ! ( pti - > lpp_dest_mask & BIT ( i ) ) )
return - EINVAL ;
2016-11-11 12:07:25 +02:00
2018-05-04 22:19:25 +03:00
pti - > lpp_dest = i ;
return size ;
2016-11-11 12:07:25 +02:00
}
static DEVICE_ATTR_RW ( lpp_dest ) ;
static struct attribute * lpp_output_attrs [ ] = {
& dev_attr_mode . attr ,
& dev_attr_freerunning_clock . attr ,
& dev_attr_clock_divider . attr ,
& dev_attr_lpp_dest . attr ,
NULL ,
} ;
2021-04-14 20:12:48 +03:00
static const struct attribute_group lpp_output_group = {
2016-11-11 12:07:25 +02:00
. attrs = lpp_output_attrs ,
} ;
static struct intel_th_driver intel_th_lpp_driver = {
. probe = intel_th_pti_probe ,
. remove = intel_th_pti_remove ,
. activate = intel_th_pti_activate ,
. deactivate = intel_th_pti_deactivate ,
. attr_group = & lpp_output_group ,
. driver = {
. name = " lpp " ,
. owner = THIS_MODULE ,
} ,
} ;
static int __init intel_th_pti_lpp_init ( void )
{
int err ;
err = intel_th_driver_register ( & intel_th_pti_driver ) ;
if ( err )
return err ;
err = intel_th_driver_register ( & intel_th_lpp_driver ) ;
if ( err ) {
intel_th_driver_unregister ( & intel_th_pti_driver ) ;
return err ;
}
return 0 ;
}
module_init ( intel_th_pti_lpp_init ) ;
static void __exit intel_th_pti_lpp_exit ( void )
{
intel_th_driver_unregister ( & intel_th_pti_driver ) ;
intel_th_driver_unregister ( & intel_th_lpp_driver ) ;
}
module_exit ( intel_th_pti_lpp_exit ) ;
2015-09-22 15:47:19 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2016-11-11 12:07:25 +02:00
MODULE_DESCRIPTION ( " Intel(R) Trace Hub PTI/LPP output driver " ) ;
2015-09-22 15:47:19 +03:00
MODULE_AUTHOR ( " Alexander Shishkin <alexander.shishkin@linux.intel.com> " ) ;