2015-01-06 20:43:47 +03:00
/*
* Synopsys DDR ECC Driver
* This driver is based on ppc4xx_edac . c drivers
*
* Copyright ( C ) 2012 - 2014 Xilinx , Inc .
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details
*/
# include <linux/edac.h>
# include <linux/module.h>
# include <linux/platform_device.h>
2016-10-29 20:16:34 +03:00
# include "edac_module.h"
2015-01-06 20:43:47 +03:00
/* Number of cs_rows needed per memory controller */
2018-10-04 18:35:19 +03:00
# define SYNPS_EDAC_NR_CSROWS 1
2015-01-06 20:43:47 +03:00
/* Number of channels per memory controller */
2018-10-04 18:35:19 +03:00
# define SYNPS_EDAC_NR_CHANS 1
2015-01-06 20:43:47 +03:00
/* Granularity of reported error in bytes */
2018-10-04 18:35:19 +03:00
# define SYNPS_EDAC_ERR_GRAIN 1
2015-01-06 20:43:47 +03:00
2018-10-04 18:35:19 +03:00
# define SYNPS_EDAC_MSG_SIZE 256
2015-01-06 20:43:47 +03:00
2018-10-04 18:35:19 +03:00
# define SYNPS_EDAC_MOD_STRING "synps_edac"
# define SYNPS_EDAC_MOD_VER "1"
2015-01-06 20:43:47 +03:00
/* Synopsys DDR memory controller registers that are relevant to ECC */
2018-10-04 18:35:19 +03:00
# define CTRL_OFST 0x0
# define T_ZQ_OFST 0xA4
2015-01-06 20:43:47 +03:00
/* ECC control register */
2018-10-04 18:35:19 +03:00
# define ECC_CTRL_OFST 0xC4
2015-01-06 20:43:47 +03:00
/* ECC log register */
2018-10-04 18:35:19 +03:00
# define CE_LOG_OFST 0xC8
2015-01-06 20:43:47 +03:00
/* ECC address register */
2018-10-04 18:35:19 +03:00
# define CE_ADDR_OFST 0xCC
2015-01-06 20:43:47 +03:00
/* ECC data[31:0] register */
2018-10-04 18:35:19 +03:00
# define CE_DATA_31_0_OFST 0xD0
2015-01-06 20:43:47 +03:00
/* Uncorrectable error info registers */
2018-10-04 18:35:19 +03:00
# define UE_LOG_OFST 0xDC
# define UE_ADDR_OFST 0xE0
# define UE_DATA_31_0_OFST 0xE4
2015-01-06 20:43:47 +03:00
2018-10-04 18:35:19 +03:00
# define STAT_OFST 0xF0
# define SCRUB_OFST 0xF4
2015-01-06 20:43:47 +03:00
/* Control register bit field definitions */
2018-10-04 18:35:19 +03:00
# define CTRL_BW_MASK 0xC
# define CTRL_BW_SHIFT 2
2015-01-06 20:43:47 +03:00
2018-10-04 18:35:19 +03:00
# define DDRCTL_WDTH_16 1
# define DDRCTL_WDTH_32 0
2015-01-06 20:43:47 +03:00
/* ZQ register bit field definitions */
2018-10-04 18:35:19 +03:00
# define T_ZQ_DDRMODE_MASK 0x2
2015-01-06 20:43:47 +03:00
/* ECC control register bit field definitions */
2018-10-04 18:35:19 +03:00
# define ECC_CTRL_CLR_CE_ERR 0x2
# define ECC_CTRL_CLR_UE_ERR 0x1
2015-01-06 20:43:47 +03:00
/* ECC correctable/uncorrectable error log register definitions */
2018-10-04 18:35:19 +03:00
# define LOG_VALID 0x1
# define CE_LOG_BITPOS_MASK 0xFE
# define CE_LOG_BITPOS_SHIFT 1
2015-01-06 20:43:47 +03:00
/* ECC correctable/uncorrectable error address register definitions */
2018-10-04 18:35:19 +03:00
# define ADDR_COL_MASK 0xFFF
# define ADDR_ROW_MASK 0xFFFF000
# define ADDR_ROW_SHIFT 12
# define ADDR_BANK_MASK 0x70000000
# define ADDR_BANK_SHIFT 28
2015-01-06 20:43:47 +03:00
/* ECC statistic register definitions */
2018-10-04 18:35:19 +03:00
# define STAT_UECNT_MASK 0xFF
# define STAT_CECNT_MASK 0xFF00
# define STAT_CECNT_SHIFT 8
2015-01-06 20:43:47 +03:00
/* ECC scrub register definitions */
2018-10-04 18:35:19 +03:00
# define SCRUB_MODE_MASK 0x7
# define SCRUB_MODE_SECDED 0x4
2015-01-06 20:43:47 +03:00
/**
2018-10-04 18:35:21 +03:00
* struct ecc_error_info - ECC error log information .
* @ row : Row number .
* @ col : Column number .
* @ bank : Bank number .
* @ bitpos : Bit position .
* @ data : Data causing the error .
2015-01-06 20:43:47 +03:00
*/
struct ecc_error_info {
u32 row ;
u32 col ;
u32 bank ;
u32 bitpos ;
u32 data ;
} ;
/**
2018-10-04 18:35:21 +03:00
* struct synps_ecc_status - ECC status information to report .
* @ ce_cnt : Correctable error count .
* @ ue_cnt : Uncorrectable error count .
* @ ceinfo : Correctable error log information .
* @ ueinfo : Uncorrectable error log information .
2015-01-06 20:43:47 +03:00
*/
struct synps_ecc_status {
u32 ce_cnt ;
u32 ue_cnt ;
struct ecc_error_info ceinfo ;
struct ecc_error_info ueinfo ;
} ;
/**
2018-10-04 18:35:21 +03:00
* struct synps_edac_priv - DDR memory controller private instance data .
* @ baseaddr : Base address of the DDR controller .
* @ message : Buffer for framing the event specific info .
* @ stat : ECC status information .
* @ ce_cnt : Correctable Error count .
* @ ue_cnt : Uncorrectable Error count .
2015-01-06 20:43:47 +03:00
*/
struct synps_edac_priv {
void __iomem * baseaddr ;
char message [ SYNPS_EDAC_MSG_SIZE ] ;
struct synps_ecc_status stat ;
u32 ce_cnt ;
u32 ue_cnt ;
} ;
/**
2018-10-04 18:35:21 +03:00
* get_error_info - Get the current ECC error info .
* @ base : Base address of the DDR memory controller .
* @ p : Synopsys ECC status structure .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Return : one if there is no error otherwise zero .
2015-01-06 20:43:47 +03:00
*/
2018-10-04 18:35:20 +03:00
static int get_error_info ( void __iomem * base , struct synps_ecc_status * p )
2015-01-06 20:43:47 +03:00
{
u32 regval , clearval = 0 ;
regval = readl ( base + STAT_OFST ) ;
if ( ! regval )
return 1 ;
p - > ce_cnt = ( regval & STAT_CECNT_MASK ) > > STAT_CECNT_SHIFT ;
p - > ue_cnt = regval & STAT_UECNT_MASK ;
regval = readl ( base + CE_LOG_OFST ) ;
if ( ! ( p - > ce_cnt & & ( regval & LOG_VALID ) ) )
goto ue_err ;
p - > ceinfo . bitpos = ( regval & CE_LOG_BITPOS_MASK ) > > CE_LOG_BITPOS_SHIFT ;
regval = readl ( base + CE_ADDR_OFST ) ;
p - > ceinfo . row = ( regval & ADDR_ROW_MASK ) > > ADDR_ROW_SHIFT ;
p - > ceinfo . col = regval & ADDR_COL_MASK ;
p - > ceinfo . bank = ( regval & ADDR_BANK_MASK ) > > ADDR_BANK_SHIFT ;
p - > ceinfo . data = readl ( base + CE_DATA_31_0_OFST ) ;
2018-10-04 18:35:19 +03:00
edac_dbg ( 3 , " CE bit position: %d data: %d \n " , p - > ceinfo . bitpos ,
2015-01-06 20:43:47 +03:00
p - > ceinfo . data ) ;
clearval = ECC_CTRL_CLR_CE_ERR ;
ue_err :
regval = readl ( base + UE_LOG_OFST ) ;
if ( ! ( p - > ue_cnt & & ( regval & LOG_VALID ) ) )
goto out ;
regval = readl ( base + UE_ADDR_OFST ) ;
p - > ueinfo . row = ( regval & ADDR_ROW_MASK ) > > ADDR_ROW_SHIFT ;
p - > ueinfo . col = regval & ADDR_COL_MASK ;
p - > ueinfo . bank = ( regval & ADDR_BANK_MASK ) > > ADDR_BANK_SHIFT ;
p - > ueinfo . data = readl ( base + UE_DATA_31_0_OFST ) ;
clearval | = ECC_CTRL_CLR_UE_ERR ;
out :
writel ( clearval , base + ECC_CTRL_OFST ) ;
writel ( 0x0 , base + ECC_CTRL_OFST ) ;
return 0 ;
}
/**
2018-10-04 18:35:21 +03:00
* handle_error - Handle Correctable and Uncorrectable errors .
* @ mci : EDAC memory controller instance .
* @ p : Synopsys ECC status structure .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Handles ECC correctable and uncorrectable errors .
2015-01-06 20:43:47 +03:00
*/
2018-10-04 18:35:20 +03:00
static void handle_error ( struct mem_ctl_info * mci , struct synps_ecc_status * p )
2015-01-06 20:43:47 +03:00
{
struct synps_edac_priv * priv = mci - > pvt_info ;
struct ecc_error_info * pinf ;
if ( p - > ce_cnt ) {
pinf = & p - > ceinfo ;
snprintf ( priv - > message , SYNPS_EDAC_MSG_SIZE ,
" DDR ECC error type :%s Row %d Bank %d Col %d " ,
" CE " , pinf - > row , pinf - > bank , pinf - > col ) ;
edac_mc_handle_error ( HW_EVENT_ERR_CORRECTED , mci ,
p - > ce_cnt , 0 , 0 , 0 , 0 , 0 , - 1 ,
priv - > message , " " ) ;
}
if ( p - > ue_cnt ) {
pinf = & p - > ueinfo ;
snprintf ( priv - > message , SYNPS_EDAC_MSG_SIZE ,
" DDR ECC error type :%s Row %d Bank %d Col %d " ,
" UE " , pinf - > row , pinf - > bank , pinf - > col ) ;
edac_mc_handle_error ( HW_EVENT_ERR_UNCORRECTED , mci ,
p - > ue_cnt , 0 , 0 , 0 , 0 , 0 , - 1 ,
priv - > message , " " ) ;
}
memset ( p , 0 , sizeof ( * p ) ) ;
}
/**
2018-10-04 18:35:21 +03:00
* check_errors - Check controller for ECC errors .
* @ mci : EDAC memory controller instance .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Check and post ECC errors . Called by the polling thread .
2015-01-06 20:43:47 +03:00
*/
2018-10-04 18:35:20 +03:00
static void check_errors ( struct mem_ctl_info * mci )
2015-01-06 20:43:47 +03:00
{
struct synps_edac_priv * priv = mci - > pvt_info ;
int status ;
2018-10-04 18:35:20 +03:00
status = get_error_info ( priv - > baseaddr , & priv - > stat ) ;
2015-01-06 20:43:47 +03:00
if ( status )
return ;
priv - > ce_cnt + = priv - > stat . ce_cnt ;
priv - > ue_cnt + = priv - > stat . ue_cnt ;
2018-10-04 18:35:20 +03:00
handle_error ( mci , & priv - > stat ) ;
2015-01-06 20:43:47 +03:00
2018-10-04 18:35:19 +03:00
edac_dbg ( 3 , " Total error count CE %d UE %d \n " ,
2015-01-06 20:43:47 +03:00
priv - > ce_cnt , priv - > ue_cnt ) ;
}
/**
2018-10-04 18:35:21 +03:00
* get_dtype - Return the controller memory width .
* @ base : DDR memory controller base address .
2015-01-06 20:43:47 +03:00
*
* Get the EDAC device type width appropriate for the current controller
* configuration .
*
* Return : a device type width enumeration .
*/
2018-10-04 18:35:20 +03:00
static enum dev_type get_dtype ( const void __iomem * base )
2015-01-06 20:43:47 +03:00
{
enum dev_type dt ;
u32 width ;
width = readl ( base + CTRL_OFST ) ;
width = ( width & CTRL_BW_MASK ) > > CTRL_BW_SHIFT ;
switch ( width ) {
case DDRCTL_WDTH_16 :
dt = DEV_X2 ;
break ;
case DDRCTL_WDTH_32 :
dt = DEV_X4 ;
break ;
default :
dt = DEV_UNKNOWN ;
}
return dt ;
}
/**
2018-10-04 18:35:21 +03:00
* get_ecc_state - Return the controller ECC enable / disable status .
* @ base : DDR memory controller base address .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Get the ECC enable / disable status of the controller .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Return : true if enabled , otherwise false .
2015-01-06 20:43:47 +03:00
*/
2018-10-04 18:35:20 +03:00
static bool get_ecc_state ( void __iomem * base )
2015-01-06 20:43:47 +03:00
{
2018-10-04 18:35:19 +03:00
bool state = false ;
2015-01-06 20:43:47 +03:00
enum dev_type dt ;
u32 ecctype ;
2018-10-04 18:35:20 +03:00
dt = get_dtype ( base ) ;
2015-01-06 20:43:47 +03:00
if ( dt = = DEV_UNKNOWN )
return state ;
ecctype = readl ( base + SCRUB_OFST ) & SCRUB_MODE_MASK ;
if ( ( ecctype = = SCRUB_MODE_SECDED ) & & ( dt = = DEV_X2 ) )
state = true ;
return state ;
}
/**
2018-10-04 18:35:21 +03:00
* get_memsize - Read the size of the attached memory device .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Return : the memory size in bytes .
2015-01-06 20:43:47 +03:00
*/
2018-10-04 18:35:20 +03:00
static u32 get_memsize ( void )
2015-01-06 20:43:47 +03:00
{
struct sysinfo inf ;
si_meminfo ( & inf ) ;
return inf . totalram * inf . mem_unit ;
}
/**
2018-10-04 18:35:21 +03:00
* get_mtype - Return the controller memory type .
* @ base : Synopsys ECC status structure .
2015-01-06 20:43:47 +03:00
*
* Get the EDAC memory type appropriate for the current controller
* configuration .
*
* Return : a memory type enumeration .
*/
2018-10-04 18:35:20 +03:00
static enum mem_type get_mtype ( const void __iomem * base )
2015-01-06 20:43:47 +03:00
{
enum mem_type mt ;
u32 memtype ;
memtype = readl ( base + T_ZQ_OFST ) ;
if ( memtype & T_ZQ_DDRMODE_MASK )
mt = MEM_DDR3 ;
else
mt = MEM_DDR2 ;
return mt ;
}
/**
2018-10-04 18:35:21 +03:00
* init_csrows - Initialize the csrow data .
* @ mci : EDAC memory controller instance .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Initialize the chip select rows associated with the EDAC memory
* controller instance .
2015-01-06 20:43:47 +03:00
*
* Return : Unconditionally 0.
*/
2018-10-04 18:35:20 +03:00
static int init_csrows ( struct mem_ctl_info * mci )
2015-01-06 20:43:47 +03:00
{
2018-10-04 18:35:19 +03:00
struct synps_edac_priv * priv = mci - > pvt_info ;
2015-01-06 20:43:47 +03:00
struct csrow_info * csi ;
struct dimm_info * dimm ;
2018-10-04 18:35:19 +03:00
u32 size , row ;
int j ;
2015-01-06 20:43:47 +03:00
for ( row = 0 ; row < mci - > nr_csrows ; row + + ) {
csi = mci - > csrows [ row ] ;
2018-10-04 18:35:20 +03:00
size = get_memsize ( ) ;
2015-01-06 20:43:47 +03:00
for ( j = 0 ; j < csi - > nr_channels ; j + + ) {
2018-10-04 18:35:19 +03:00
dimm = csi - > channels [ j ] - > dimm ;
dimm - > edac_mode = EDAC_FLAG_SECDED ;
2018-10-04 18:35:20 +03:00
dimm - > mtype = get_mtype ( priv - > baseaddr ) ;
2018-10-04 18:35:19 +03:00
dimm - > nr_pages = ( size > > PAGE_SHIFT ) / csi - > nr_channels ;
dimm - > grain = SYNPS_EDAC_ERR_GRAIN ;
2018-10-04 18:35:20 +03:00
dimm - > dtype = get_dtype ( priv - > baseaddr ) ;
2015-01-06 20:43:47 +03:00
}
}
return 0 ;
}
/**
2018-10-04 18:35:21 +03:00
* mc_init - Initialize one driver instance .
* @ mci : EDAC memory controller instance .
* @ pdev : platform device .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Perform initialization of the EDAC memory controller instance and
2015-01-06 20:43:47 +03:00
* related driver - private data associated with the memory controller the
* instance is bound to .
*
* Return : Always zero .
*/
2018-10-04 18:35:20 +03:00
static int mc_init ( struct mem_ctl_info * mci , struct platform_device * pdev )
2015-01-06 20:43:47 +03:00
{
int status ;
struct synps_edac_priv * priv ;
mci - > pdev = & pdev - > dev ;
priv = mci - > pvt_info ;
platform_set_drvdata ( pdev , mci ) ;
/* Initialize controller capabilities and configuration */
mci - > mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2 ;
mci - > edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED ;
mci - > scrub_cap = SCRUB_HW_SRC ;
mci - > scrub_mode = SCRUB_NONE ;
mci - > edac_cap = EDAC_FLAG_SECDED ;
mci - > ctl_name = " synps_ddr_controller " ;
mci - > dev_name = SYNPS_EDAC_MOD_STRING ;
mci - > mod_name = SYNPS_EDAC_MOD_VER ;
edac_op_state = EDAC_OPSTATE_POLL ;
2018-10-04 18:35:20 +03:00
mci - > edac_check = check_errors ;
2015-01-06 20:43:47 +03:00
mci - > ctl_page_to_phys = NULL ;
2018-10-04 18:35:20 +03:00
status = init_csrows ( mci ) ;
2015-01-06 20:43:47 +03:00
return status ;
}
/**
2018-10-04 18:35:21 +03:00
* mc_probe - Check controller and bind driver .
* @ pdev : platform device .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:21 +03:00
* Probe a specific controller instance for binding with the driver .
2015-01-06 20:43:47 +03:00
*
* Return : 0 if the controller instance was successfully bound to the
* driver ; otherwise , < 0 on error .
*/
2018-10-04 18:35:20 +03:00
static int mc_probe ( struct platform_device * pdev )
2015-01-06 20:43:47 +03:00
{
struct edac_mc_layer layers [ 2 ] ;
struct synps_edac_priv * priv ;
2018-10-04 18:35:19 +03:00
struct mem_ctl_info * mci ;
2015-01-06 20:43:47 +03:00
void __iomem * baseaddr ;
2018-10-04 18:35:19 +03:00
struct resource * res ;
int rc ;
2015-01-06 20:43:47 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
baseaddr = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( baseaddr ) )
return PTR_ERR ( baseaddr ) ;
2018-10-04 18:35:20 +03:00
if ( ! get_ecc_state ( baseaddr ) ) {
2015-01-06 20:43:47 +03:00
edac_printk ( KERN_INFO , EDAC_MC , " ECC not enabled \n " ) ;
return - ENXIO ;
}
layers [ 0 ] . type = EDAC_MC_LAYER_CHIP_SELECT ;
layers [ 0 ] . size = SYNPS_EDAC_NR_CSROWS ;
layers [ 0 ] . is_virt_csrow = true ;
layers [ 1 ] . type = EDAC_MC_LAYER_CHANNEL ;
layers [ 1 ] . size = SYNPS_EDAC_NR_CHANS ;
layers [ 1 ] . is_virt_csrow = false ;
mci = edac_mc_alloc ( 0 , ARRAY_SIZE ( layers ) , layers ,
sizeof ( struct synps_edac_priv ) ) ;
if ( ! mci ) {
edac_printk ( KERN_ERR , EDAC_MC ,
" Failed memory allocation for mc instance \n " ) ;
return - ENOMEM ;
}
priv = mci - > pvt_info ;
priv - > baseaddr = baseaddr ;
2018-10-04 18:35:20 +03:00
rc = mc_init ( mci , pdev ) ;
2015-01-06 20:43:47 +03:00
if ( rc ) {
edac_printk ( KERN_ERR , EDAC_MC ,
" Failed to initialize instance \n " ) ;
goto free_edac_mc ;
}
rc = edac_mc_add_mc ( mci ) ;
if ( rc ) {
edac_printk ( KERN_ERR , EDAC_MC ,
" Failed to register with EDAC core \n " ) ;
goto free_edac_mc ;
}
/*
* Start capturing the correctable and uncorrectable errors . A write of
* 0 starts the counters .
*/
writel ( 0x0 , baseaddr + ECC_CTRL_OFST ) ;
return rc ;
free_edac_mc :
edac_mc_free ( mci ) ;
return rc ;
}
/**
2018-10-04 18:35:21 +03:00
* mc_remove - Unbind driver from controller .
* @ pdev : Platform device .
2015-01-06 20:43:47 +03:00
*
* Return : Unconditionally 0
*/
2018-10-04 18:35:20 +03:00
static int mc_remove ( struct platform_device * pdev )
2015-01-06 20:43:47 +03:00
{
struct mem_ctl_info * mci = platform_get_drvdata ( pdev ) ;
edac_mc_del_mc ( & pdev - > dev ) ;
edac_mc_free ( mci ) ;
return 0 ;
}
2015-03-16 22:54:41 +03:00
static const struct of_device_id synps_edac_match [ ] = {
2015-01-06 20:43:47 +03:00
{ . compatible = " xlnx,zynq-ddrc-a05 " , } ,
{ /* end of table */ }
} ;
MODULE_DEVICE_TABLE ( of , synps_edac_match ) ;
static struct platform_driver synps_edac_mc_driver = {
. driver = {
. name = " synopsys-edac " ,
. of_match_table = synps_edac_match ,
} ,
2018-10-04 18:35:20 +03:00
. probe = mc_probe ,
. remove = mc_remove ,
2015-01-06 20:43:47 +03:00
} ;
module_platform_driver ( synps_edac_mc_driver ) ;
MODULE_AUTHOR ( " Xilinx Inc " ) ;
MODULE_DESCRIPTION ( " Synopsys DDR ECC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;