2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-10-31 17:45:35 +03:00
/*
* TI da8xx master peripheral priority driver
*
* Copyright ( C ) 2016 BayLibre SAS
*
* Author :
2016-12-19 12:58:11 +03:00
* Bartosz Golaszewski < bgolaszewski @ baylibre . com >
2016-10-31 17:45:35 +03:00
*/
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/io.h>
# include <linux/regmap.h>
/*
* REVISIT : Linux doesn ' t have a good framework for the kind of performance
* knobs this driver controls . We can ' t use device tree properties as it deals
* with hardware configuration rather than description . We also don ' t want to
* commit to maintaining some random sysfs attributes .
*
* For now we just hardcode the register values for the boards that need
* some changes ( as is the case for the LCD controller on da850 - lcdk - the
* first board we support here ) . When linux gets an appropriate framework ,
* we ' ll easily convert the driver to it .
*/
# define DA8XX_MSTPRI0_OFFSET 0
# define DA8XX_MSTPRI1_OFFSET 4
# define DA8XX_MSTPRI2_OFFSET 8
enum {
DA8XX_MSTPRI_ARM_I = 0 ,
DA8XX_MSTPRI_ARM_D ,
DA8XX_MSTPRI_UPP ,
DA8XX_MSTPRI_SATA ,
DA8XX_MSTPRI_PRU0 ,
DA8XX_MSTPRI_PRU1 ,
DA8XX_MSTPRI_EDMA30TC0 ,
DA8XX_MSTPRI_EDMA30TC1 ,
DA8XX_MSTPRI_EDMA31TC0 ,
DA8XX_MSTPRI_VPIF_DMA_0 ,
DA8XX_MSTPRI_VPIF_DMA_1 ,
DA8XX_MSTPRI_EMAC ,
DA8XX_MSTPRI_USB0CFG ,
DA8XX_MSTPRI_USB0CDMA ,
DA8XX_MSTPRI_UHPI ,
DA8XX_MSTPRI_USB1 ,
DA8XX_MSTPRI_LCDC ,
} ;
struct da8xx_mstpri_descr {
int reg ;
int shift ;
int mask ;
} ;
static const struct da8xx_mstpri_descr da8xx_mstpri_priority_list [ ] = {
[ DA8XX_MSTPRI_ARM_I ] = {
. reg = DA8XX_MSTPRI0_OFFSET ,
. shift = 0 ,
. mask = 0x0000000f ,
} ,
[ DA8XX_MSTPRI_ARM_D ] = {
. reg = DA8XX_MSTPRI0_OFFSET ,
. shift = 4 ,
. mask = 0x000000f0 ,
} ,
[ DA8XX_MSTPRI_UPP ] = {
. reg = DA8XX_MSTPRI0_OFFSET ,
. shift = 16 ,
. mask = 0x000f0000 ,
} ,
[ DA8XX_MSTPRI_SATA ] = {
. reg = DA8XX_MSTPRI0_OFFSET ,
. shift = 20 ,
. mask = 0x00f00000 ,
} ,
[ DA8XX_MSTPRI_PRU0 ] = {
. reg = DA8XX_MSTPRI1_OFFSET ,
. shift = 0 ,
. mask = 0x0000000f ,
} ,
[ DA8XX_MSTPRI_PRU1 ] = {
. reg = DA8XX_MSTPRI1_OFFSET ,
. shift = 4 ,
. mask = 0x000000f0 ,
} ,
[ DA8XX_MSTPRI_EDMA30TC0 ] = {
. reg = DA8XX_MSTPRI1_OFFSET ,
. shift = 8 ,
. mask = 0x00000f00 ,
} ,
[ DA8XX_MSTPRI_EDMA30TC1 ] = {
. reg = DA8XX_MSTPRI1_OFFSET ,
. shift = 12 ,
. mask = 0x0000f000 ,
} ,
[ DA8XX_MSTPRI_EDMA31TC0 ] = {
. reg = DA8XX_MSTPRI1_OFFSET ,
. shift = 16 ,
. mask = 0x000f0000 ,
} ,
[ DA8XX_MSTPRI_VPIF_DMA_0 ] = {
. reg = DA8XX_MSTPRI1_OFFSET ,
. shift = 24 ,
. mask = 0x0f000000 ,
} ,
[ DA8XX_MSTPRI_VPIF_DMA_1 ] = {
. reg = DA8XX_MSTPRI1_OFFSET ,
. shift = 28 ,
. mask = 0xf0000000 ,
} ,
[ DA8XX_MSTPRI_EMAC ] = {
. reg = DA8XX_MSTPRI2_OFFSET ,
. shift = 0 ,
. mask = 0x0000000f ,
} ,
[ DA8XX_MSTPRI_USB0CFG ] = {
. reg = DA8XX_MSTPRI2_OFFSET ,
. shift = 8 ,
. mask = 0x00000f00 ,
} ,
[ DA8XX_MSTPRI_USB0CDMA ] = {
. reg = DA8XX_MSTPRI2_OFFSET ,
. shift = 12 ,
. mask = 0x0000f000 ,
} ,
[ DA8XX_MSTPRI_UHPI ] = {
. reg = DA8XX_MSTPRI2_OFFSET ,
. shift = 20 ,
. mask = 0x00f00000 ,
} ,
[ DA8XX_MSTPRI_USB1 ] = {
. reg = DA8XX_MSTPRI2_OFFSET ,
. shift = 24 ,
. mask = 0x0f000000 ,
} ,
[ DA8XX_MSTPRI_LCDC ] = {
. reg = DA8XX_MSTPRI2_OFFSET ,
. shift = 28 ,
. mask = 0xf0000000 ,
} ,
} ;
struct da8xx_mstpri_priority {
int which ;
u32 val ;
} ;
struct da8xx_mstpri_board_priorities {
const char * board ;
const struct da8xx_mstpri_priority * priorities ;
size_t numprio ;
} ;
/*
* Default memory settings of da850 do not meet the throughput / latency
* requirements of tilcdc . This results in the image displayed being
* incorrect and the following warning being displayed by the LCDC
* drm driver :
*
* tilcdc da8xx_lcdc .0 : tilcdc_crtc_irq ( 0x00000020 ) : FIFO underfow
*/
static const struct da8xx_mstpri_priority da850_lcdk_priorities [ ] = {
{
. which = DA8XX_MSTPRI_LCDC ,
. val = 0 ,
} ,
{
. which = DA8XX_MSTPRI_EDMA30TC1 ,
. val = 0 ,
} ,
{
. which = DA8XX_MSTPRI_EDMA30TC0 ,
. val = 1 ,
} ,
} ;
static const struct da8xx_mstpri_board_priorities da8xx_mstpri_board_confs [ ] = {
{
. board = " ti,da850-lcdk " ,
. priorities = da850_lcdk_priorities ,
. numprio = ARRAY_SIZE ( da850_lcdk_priorities ) ,
} ,
} ;
static const struct da8xx_mstpri_board_priorities *
da8xx_mstpri_get_board_prio ( void )
{
const struct da8xx_mstpri_board_priorities * board_prio ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( da8xx_mstpri_board_confs ) ; i + + ) {
board_prio = & da8xx_mstpri_board_confs [ i ] ;
if ( of_machine_is_compatible ( board_prio - > board ) )
return board_prio ;
}
return NULL ;
}
static int da8xx_mstpri_probe ( struct platform_device * pdev )
{
const struct da8xx_mstpri_board_priorities * prio_list ;
const struct da8xx_mstpri_descr * prio_descr ;
const struct da8xx_mstpri_priority * prio ;
struct device * dev = & pdev - > dev ;
struct resource * res ;
void __iomem * mstpri ;
u32 reg ;
int i ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
mstpri = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( mstpri ) ) {
dev_err ( dev , " unable to map MSTPRI registers \n " ) ;
return PTR_ERR ( mstpri ) ;
}
prio_list = da8xx_mstpri_get_board_prio ( ) ;
if ( ! prio_list ) {
2016-11-23 16:39:59 +03:00
dev_err ( dev , " no master priorities defined for this board \n " ) ;
2016-10-31 17:45:35 +03:00
return - EINVAL ;
}
for ( i = 0 ; i < prio_list - > numprio ; i + + ) {
prio = & prio_list - > priorities [ i ] ;
prio_descr = & da8xx_mstpri_priority_list [ prio - > which ] ;
if ( prio_descr - > reg + sizeof ( u32 ) > resource_size ( res ) ) {
dev_warn ( dev , " register offset out of range \n " ) ;
continue ;
}
reg = readl ( mstpri + prio_descr - > reg ) ;
reg & = ~ prio_descr - > mask ;
reg | = prio - > val < < prio_descr - > shift ;
writel ( reg , mstpri + prio_descr - > reg ) ;
}
return 0 ;
}
static const struct of_device_id da8xx_mstpri_of_match [ ] = {
{ . compatible = " ti,da850-mstpri " , } ,
{ } ,
} ;
static struct platform_driver da8xx_mstpri_driver = {
. probe = da8xx_mstpri_probe ,
. driver = {
. name = " da8xx-mstpri " ,
. of_match_table = da8xx_mstpri_of_match ,
} ,
} ;
module_platform_driver ( da8xx_mstpri_driver ) ;
MODULE_AUTHOR ( " Bartosz Golaszewski <bgolaszewski@baylibre.com> " ) ;
MODULE_DESCRIPTION ( " TI da8xx master peripheral priority driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;