2018-12-06 18:17:34 +05:30
// SPDX-License-Identifier: GPL-2.0
/*
* ARM PL353 SMC driver
*
* Copyright ( C ) 2012 - 2018 Xilinx , Inc
* Author : Punnaiah Choudary Kalluri < punnaiah @ xilinx . com >
* Author : Naga Sureshkumar Relli < nagasure @ xilinx . com >
*/
# include <linux/clk.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/pl353-smc.h>
# include <linux/amba/bus.h>
/* Register definitions */
# define PL353_SMC_MEMC_STATUS_OFFS 0 /* Controller status reg, RO */
# define PL353_SMC_CFG_CLR_OFFS 0xC /* Clear config reg, WO */
# define PL353_SMC_DIRECT_CMD_OFFS 0x10 /* Direct command reg, WO */
# define PL353_SMC_SET_CYCLES_OFFS 0x14 /* Set cycles register, WO */
# define PL353_SMC_SET_OPMODE_OFFS 0x18 /* Set opmode register, WO */
# define PL353_SMC_ECC_STATUS_OFFS 0x400 /* ECC status register */
# define PL353_SMC_ECC_MEMCFG_OFFS 0x404 /* ECC mem config reg */
# define PL353_SMC_ECC_MEMCMD1_OFFS 0x408 /* ECC mem cmd1 reg */
# define PL353_SMC_ECC_MEMCMD2_OFFS 0x40C /* ECC mem cmd2 reg */
# define PL353_SMC_ECC_VALUE0_OFFS 0x418 /* ECC value 0 reg */
/* Controller status register specific constants */
# define PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT 6
/* Clear configuration register specific constants */
# define PL353_SMC_CFG_CLR_INT_CLR_1 0x10
# define PL353_SMC_CFG_CLR_ECC_INT_DIS_1 0x40
# define PL353_SMC_CFG_CLR_INT_DIS_1 0x2
# define PL353_SMC_CFG_CLR_DEFAULT_MASK (PL353_SMC_CFG_CLR_INT_CLR_1 | \
PL353_SMC_CFG_CLR_ECC_INT_DIS_1 | \
PL353_SMC_CFG_CLR_INT_DIS_1 )
/* Set cycles register specific constants */
# define PL353_SMC_SET_CYCLES_T0_MASK 0xF
# define PL353_SMC_SET_CYCLES_T0_SHIFT 0
# define PL353_SMC_SET_CYCLES_T1_MASK 0xF
# define PL353_SMC_SET_CYCLES_T1_SHIFT 4
# define PL353_SMC_SET_CYCLES_T2_MASK 0x7
# define PL353_SMC_SET_CYCLES_T2_SHIFT 8
# define PL353_SMC_SET_CYCLES_T3_MASK 0x7
# define PL353_SMC_SET_CYCLES_T3_SHIFT 11
# define PL353_SMC_SET_CYCLES_T4_MASK 0x7
# define PL353_SMC_SET_CYCLES_T4_SHIFT 14
# define PL353_SMC_SET_CYCLES_T5_MASK 0x7
# define PL353_SMC_SET_CYCLES_T5_SHIFT 17
# define PL353_SMC_SET_CYCLES_T6_MASK 0xF
# define PL353_SMC_SET_CYCLES_T6_SHIFT 20
/* ECC status register specific constants */
# define PL353_SMC_ECC_STATUS_BUSY BIT(6)
# define PL353_SMC_ECC_REG_SIZE_OFFS 4
/* ECC memory config register specific constants */
# define PL353_SMC_ECC_MEMCFG_MODE_MASK 0xC
# define PL353_SMC_ECC_MEMCFG_MODE_SHIFT 2
2021-03-31 11:10:56 +08:00
# define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK 0x3
2018-12-06 18:17:34 +05:30
# define PL353_SMC_DC_UPT_NAND_REGS ((4 << 23) | /* CS: NAND chip */ \
( 2 < < 21 ) ) /* UpdateRegs operation */
# define PL353_NAND_ECC_CMD1 ((0x80) | /* Write command */ \
( 0 < < 8 ) | /* Read command */ \
( 0x30 < < 16 ) | /* Read End command */ \
( 1 < < 24 ) ) /* Read End command calid */
# define PL353_NAND_ECC_CMD2 ((0x85) | /* Write col change cmd */ \
( 5 < < 8 ) | /* Read col change cmd */ \
( 0xE0 < < 16 ) | /* Read col change end cmd */ \
( 1 < < 24 ) ) /* Read col change end cmd valid */
# define PL353_NAND_ECC_BUSY_TIMEOUT (1 * HZ)
/**
* struct pl353_smc_data - Private smc driver structure
* @ memclk : Pointer to the peripheral clock
* @ aclk : Pointer to the APER clock
*/
struct pl353_smc_data {
struct clk * memclk ;
struct clk * aclk ;
} ;
/* SMC virtual register base */
static void __iomem * pl353_smc_base ;
/**
* pl353_smc_set_buswidth - Set memory buswidth
* @ bw : Memory buswidth ( 8 | 16 )
* Return : 0 on success or negative errno .
*/
int pl353_smc_set_buswidth ( unsigned int bw )
{
if ( bw ! = PL353_SMC_MEM_WIDTH_8 & & bw ! = PL353_SMC_MEM_WIDTH_16 )
return - EINVAL ;
writel ( bw , pl353_smc_base + PL353_SMC_SET_OPMODE_OFFS ) ;
writel ( PL353_SMC_DC_UPT_NAND_REGS , pl353_smc_base +
PL353_SMC_DIRECT_CMD_OFFS ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_set_buswidth ) ;
/**
* pl353_smc_set_cycles - Set memory timing parameters
* @ timings : NAND controller timing parameters
*
* Sets NAND chip specific timing parameters .
*/
void pl353_smc_set_cycles ( u32 timings [ ] )
{
/*
* Set write pulse timing . This one is easy to extract :
*
* NWE_PULSE = tWP
*/
timings [ 0 ] & = PL353_SMC_SET_CYCLES_T0_MASK ;
timings [ 1 ] = ( timings [ 1 ] & PL353_SMC_SET_CYCLES_T1_MASK ) < <
PL353_SMC_SET_CYCLES_T1_SHIFT ;
timings [ 2 ] = ( timings [ 2 ] & PL353_SMC_SET_CYCLES_T2_MASK ) < <
PL353_SMC_SET_CYCLES_T2_SHIFT ;
timings [ 3 ] = ( timings [ 3 ] & PL353_SMC_SET_CYCLES_T3_MASK ) < <
PL353_SMC_SET_CYCLES_T3_SHIFT ;
timings [ 4 ] = ( timings [ 4 ] & PL353_SMC_SET_CYCLES_T4_MASK ) < <
PL353_SMC_SET_CYCLES_T4_SHIFT ;
timings [ 5 ] = ( timings [ 5 ] & PL353_SMC_SET_CYCLES_T5_MASK ) < <
PL353_SMC_SET_CYCLES_T5_SHIFT ;
timings [ 6 ] = ( timings [ 6 ] & PL353_SMC_SET_CYCLES_T6_MASK ) < <
PL353_SMC_SET_CYCLES_T6_SHIFT ;
timings [ 0 ] | = timings [ 1 ] | timings [ 2 ] | timings [ 3 ] |
timings [ 4 ] | timings [ 5 ] | timings [ 6 ] ;
writel ( timings [ 0 ] , pl353_smc_base + PL353_SMC_SET_CYCLES_OFFS ) ;
writel ( PL353_SMC_DC_UPT_NAND_REGS , pl353_smc_base +
PL353_SMC_DIRECT_CMD_OFFS ) ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_set_cycles ) ;
/**
* pl353_smc_ecc_is_busy - Read ecc busy flag
* Return : the ecc_status bit from the ecc_status register . 1 = busy , 0 = idle
*/
bool pl353_smc_ecc_is_busy ( void )
{
return ( ( readl ( pl353_smc_base + PL353_SMC_ECC_STATUS_OFFS ) &
PL353_SMC_ECC_STATUS_BUSY ) = = PL353_SMC_ECC_STATUS_BUSY ) ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_ecc_is_busy ) ;
/**
* pl353_smc_get_ecc_val - Read ecc_valueN registers
* @ ecc_reg : Index of the ecc_value reg ( 0. .3 )
* Return : the content of the requested ecc_value register .
*
* There are four valid ecc_value registers . The argument is truncated to stay
* within this valid boundary .
*/
u32 pl353_smc_get_ecc_val ( int ecc_reg )
{
u32 addr , reg ;
addr = PL353_SMC_ECC_VALUE0_OFFS +
( ecc_reg * PL353_SMC_ECC_REG_SIZE_OFFS ) ;
reg = readl ( pl353_smc_base + addr ) ;
return reg ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_get_ecc_val ) ;
/**
* pl353_smc_get_nand_int_status_raw - Get NAND interrupt status bit
* Return : the raw_int_status1 bit from the memc_status register
*/
int pl353_smc_get_nand_int_status_raw ( void )
{
u32 reg ;
reg = readl ( pl353_smc_base + PL353_SMC_MEMC_STATUS_OFFS ) ;
reg > > = PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT ;
reg & = 1 ;
return reg ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_get_nand_int_status_raw ) ;
/**
* pl353_smc_clr_nand_int - Clear NAND interrupt
*/
void pl353_smc_clr_nand_int ( void )
{
writel ( PL353_SMC_CFG_CLR_INT_CLR_1 ,
pl353_smc_base + PL353_SMC_CFG_CLR_OFFS ) ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_clr_nand_int ) ;
/**
* pl353_smc_set_ecc_mode - Set SMC ECC mode
* @ mode : ECC mode ( BYPASS , APB , MEM )
* Return : 0 on success or negative errno .
*/
int pl353_smc_set_ecc_mode ( enum pl353_smc_ecc_mode mode )
{
u32 reg ;
int ret = 0 ;
switch ( mode ) {
case PL353_SMC_ECCMODE_BYPASS :
case PL353_SMC_ECCMODE_APB :
case PL353_SMC_ECCMODE_MEM :
reg = readl ( pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS ) ;
reg & = ~ PL353_SMC_ECC_MEMCFG_MODE_MASK ;
reg | = mode < < PL353_SMC_ECC_MEMCFG_MODE_SHIFT ;
writel ( reg , pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS ) ;
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_set_ecc_mode ) ;
/**
* pl353_smc_set_ecc_pg_size - Set SMC ECC page size
* @ pg_sz : ECC page size
* Return : 0 on success or negative errno .
*/
int pl353_smc_set_ecc_pg_size ( unsigned int pg_sz )
{
u32 reg , sz ;
switch ( pg_sz ) {
case 0 :
sz = 0 ;
break ;
case SZ_512 :
sz = 1 ;
break ;
case SZ_1K :
sz = 2 ;
break ;
case SZ_2K :
sz = 3 ;
break ;
default :
return - EINVAL ;
}
reg = readl ( pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS ) ;
reg & = ~ PL353_SMC_ECC_MEMCFG_PGSIZE_MASK ;
reg | = sz ;
writel ( reg , pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( pl353_smc_set_ecc_pg_size ) ;
static int __maybe_unused pl353_smc_suspend ( struct device * dev )
{
struct pl353_smc_data * pl353_smc = dev_get_drvdata ( dev ) ;
clk_disable ( pl353_smc - > memclk ) ;
clk_disable ( pl353_smc - > aclk ) ;
return 0 ;
}
static int __maybe_unused pl353_smc_resume ( struct device * dev )
{
int ret ;
struct pl353_smc_data * pl353_smc = dev_get_drvdata ( dev ) ;
ret = clk_enable ( pl353_smc - > aclk ) ;
if ( ret ) {
dev_err ( dev , " Cannot enable axi domain clock. \n " ) ;
return ret ;
}
ret = clk_enable ( pl353_smc - > memclk ) ;
if ( ret ) {
dev_err ( dev , " Cannot enable memory clock. \n " ) ;
clk_disable ( pl353_smc - > aclk ) ;
return ret ;
}
return ret ;
}
static struct amba_driver pl353_smc_driver ;
static SIMPLE_DEV_PM_OPS ( pl353_smc_dev_pm_ops , pl353_smc_suspend ,
pl353_smc_resume ) ;
/**
* pl353_smc_init_nand_interface - Initialize the NAND interface
* @ adev : Pointer to the amba_device struct
* @ nand_node : Pointer to the pl353_nand device_node struct
*/
static void pl353_smc_init_nand_interface ( struct amba_device * adev ,
struct device_node * nand_node )
{
unsigned long timeout ;
pl353_smc_set_buswidth ( PL353_SMC_MEM_WIDTH_8 ) ;
writel ( PL353_SMC_CFG_CLR_INT_CLR_1 ,
pl353_smc_base + PL353_SMC_CFG_CLR_OFFS ) ;
writel ( PL353_SMC_DC_UPT_NAND_REGS , pl353_smc_base +
PL353_SMC_DIRECT_CMD_OFFS ) ;
timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT ;
/* Wait till the ECC operation is complete */
do {
if ( pl353_smc_ecc_is_busy ( ) )
cpu_relax ( ) ;
else
break ;
} while ( ! time_after_eq ( jiffies , timeout ) ) ;
if ( time_after_eq ( jiffies , timeout ) )
return ;
writel ( PL353_NAND_ECC_CMD1 ,
pl353_smc_base + PL353_SMC_ECC_MEMCMD1_OFFS ) ;
writel ( PL353_NAND_ECC_CMD2 ,
pl353_smc_base + PL353_SMC_ECC_MEMCMD2_OFFS ) ;
}
static const struct of_device_id pl353_smc_supported_children [ ] = {
{
. compatible = " cfi-flash "
} ,
{
. compatible = " arm,pl353-nand-r2p1 " ,
. data = pl353_smc_init_nand_interface
} ,
{ }
} ;
static int pl353_smc_probe ( struct amba_device * adev , const struct amba_id * id )
{
struct pl353_smc_data * pl353_smc ;
struct device_node * child ;
struct resource * res ;
int err ;
struct device_node * of_node = adev - > dev . of_node ;
static void ( * init ) ( struct amba_device * adev ,
struct device_node * nand_node ) ;
const struct of_device_id * match = NULL ;
pl353_smc = devm_kzalloc ( & adev - > dev , sizeof ( * pl353_smc ) , GFP_KERNEL ) ;
if ( ! pl353_smc )
return - ENOMEM ;
/* Get the NAND controller virtual address */
res = & adev - > res ;
pl353_smc_base = devm_ioremap_resource ( & adev - > dev , res ) ;
if ( IS_ERR ( pl353_smc_base ) )
return PTR_ERR ( pl353_smc_base ) ;
pl353_smc - > aclk = devm_clk_get ( & adev - > dev , " apb_pclk " ) ;
if ( IS_ERR ( pl353_smc - > aclk ) ) {
dev_err ( & adev - > dev , " aclk clock not found. \n " ) ;
return PTR_ERR ( pl353_smc - > aclk ) ;
}
pl353_smc - > memclk = devm_clk_get ( & adev - > dev , " memclk " ) ;
if ( IS_ERR ( pl353_smc - > memclk ) ) {
dev_err ( & adev - > dev , " memclk clock not found. \n " ) ;
return PTR_ERR ( pl353_smc - > memclk ) ;
}
err = clk_prepare_enable ( pl353_smc - > aclk ) ;
if ( err ) {
dev_err ( & adev - > dev , " Unable to enable AXI clock. \n " ) ;
return err ;
}
err = clk_prepare_enable ( pl353_smc - > memclk ) ;
if ( err ) {
dev_err ( & adev - > dev , " Unable to enable memory clock. \n " ) ;
goto out_clk_dis_aper ;
}
amba_set_drvdata ( adev , pl353_smc ) ;
/* clear interrupts */
writel ( PL353_SMC_CFG_CLR_DEFAULT_MASK ,
pl353_smc_base + PL353_SMC_CFG_CLR_OFFS ) ;
/* Find compatible children. Only a single child is supported */
for_each_available_child_of_node ( of_node , child ) {
match = of_match_node ( pl353_smc_supported_children , child ) ;
if ( ! match ) {
dev_warn ( & adev - > dev , " unsupported child node \n " ) ;
continue ;
}
break ;
}
if ( ! match ) {
dev_err ( & adev - > dev , " no matching children \n " ) ;
goto out_clk_disable ;
}
init = match - > data ;
if ( init )
init ( adev , child ) ;
of_platform_device_create ( child , NULL , & adev - > dev ) ;
return 0 ;
out_clk_disable :
clk_disable_unprepare ( pl353_smc - > memclk ) ;
out_clk_dis_aper :
clk_disable_unprepare ( pl353_smc - > aclk ) ;
return err ;
}
2021-01-26 17:58:34 +01:00
static void pl353_smc_remove ( struct amba_device * adev )
2018-12-06 18:17:34 +05:30
{
struct pl353_smc_data * pl353_smc = amba_get_drvdata ( adev ) ;
clk_disable_unprepare ( pl353_smc - > memclk ) ;
clk_disable_unprepare ( pl353_smc - > aclk ) ;
}
static const struct amba_id pl353_ids [ ] = {
{
. id = 0x00041353 ,
. mask = 0x000fffff ,
} ,
{ 0 , 0 } ,
} ;
MODULE_DEVICE_TABLE ( amba , pl353_ids ) ;
static struct amba_driver pl353_smc_driver = {
. drv = {
. owner = THIS_MODULE ,
. name = " pl353-smc " ,
. pm = & pl353_smc_dev_pm_ops ,
} ,
. id_table = pl353_ids ,
. probe = pl353_smc_probe ,
. remove = pl353_smc_remove ,
} ;
module_amba_driver ( pl353_smc_driver ) ;
MODULE_AUTHOR ( " Xilinx, Inc. " ) ;
MODULE_DESCRIPTION ( " ARM PL353 SMC Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;