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>
2018-10-04 18:35:23 +03:00
# include <linux/of.h>
# include <linux/of_device.h>
2015-01-06 20:43:47 +03:00
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-25 09:06:58 +03:00
/* DDR ECC Quirks */
# define DDR_ECC_INTR_SUPPORT BIT(0)
# define DDR_ECC_DATA_POISON_SUPPORT BIT(1)
/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */
/* ECC Configuration Registers */
# define ECC_CFG0_OFST 0x70
# define ECC_CFG1_OFST 0x74
/* ECC Status Register */
# define ECC_STAT_OFST 0x78
/* ECC Clear Register */
# define ECC_CLR_OFST 0x7C
/* ECC Error count Register */
# define ECC_ERRCNT_OFST 0x80
/* ECC Corrected Error Address Register */
# define ECC_CEADDR0_OFST 0x84
# define ECC_CEADDR1_OFST 0x88
/* ECC Syndrome Registers */
# define ECC_CSYND0_OFST 0x8C
# define ECC_CSYND1_OFST 0x90
# define ECC_CSYND2_OFST 0x94
/* ECC Bit Mask0 Address Register */
# define ECC_BITMASK0_OFST 0x98
# define ECC_BITMASK1_OFST 0x9C
# define ECC_BITMASK2_OFST 0xA0
/* ECC UnCorrected Error Address Register */
# define ECC_UEADDR0_OFST 0xA4
# define ECC_UEADDR1_OFST 0xA8
/* ECC Syndrome Registers */
# define ECC_UESYND0_OFST 0xAC
# define ECC_UESYND1_OFST 0xB0
# define ECC_UESYND2_OFST 0xB4
/* ECC Poison Address Reg */
# define ECC_POISON0_OFST 0xB8
# define ECC_POISON1_OFST 0xBC
# define ECC_ADDRMAP0_OFFSET 0x200
/* Control register bitfield definitions */
# define ECC_CTRL_BUSWIDTH_MASK 0x3000
# define ECC_CTRL_BUSWIDTH_SHIFT 12
# define ECC_CTRL_CLR_CE_ERRCNT BIT(2)
# define ECC_CTRL_CLR_UE_ERRCNT BIT(3)
/* DDR Control Register width definitions */
# define DDRCTL_EWDTH_16 2
# define DDRCTL_EWDTH_32 1
# define DDRCTL_EWDTH_64 0
/* ECC status register definitions */
# define ECC_STAT_UECNT_MASK 0xF0000
# define ECC_STAT_UECNT_SHIFT 16
# define ECC_STAT_CECNT_MASK 0xF00
# define ECC_STAT_CECNT_SHIFT 8
# define ECC_STAT_BITNUM_MASK 0x7F
/* DDR QOS Interrupt register definitions */
# define DDR_QOS_IRQ_STAT_OFST 0x20200
# define DDR_QOSUE_MASK 0x4
# define DDR_QOSCE_MASK 0x2
# define ECC_CE_UE_INTR_MASK 0x6
# define DDR_QOS_IRQ_EN_OFST 0x20208
# define DDR_QOS_IRQ_DB_OFST 0x2020C
/* ECC Corrected Error Register Mask and Shifts*/
# define ECC_CEADDR0_RW_MASK 0x3FFFF
# define ECC_CEADDR0_RNK_MASK BIT(24)
# define ECC_CEADDR1_BNKGRP_MASK 0x3000000
# define ECC_CEADDR1_BNKNR_MASK 0x70000
# define ECC_CEADDR1_BLKNR_MASK 0xFFF
# define ECC_CEADDR1_BNKGRP_SHIFT 24
# define ECC_CEADDR1_BNKNR_SHIFT 16
/* ECC Poison register shifts */
# define ECC_POISON0_RANK_SHIFT 24
# define ECC_POISON0_RANK_MASK BIT(24)
# define ECC_POISON0_COLUMN_SHIFT 0
# define ECC_POISON0_COLUMN_MASK 0xFFF
# define ECC_POISON1_BG_SHIFT 28
# define ECC_POISON1_BG_MASK 0x30000000
# define ECC_POISON1_BANKNR_SHIFT 24
# define ECC_POISON1_BANKNR_MASK 0x7000000
# define ECC_POISON1_ROW_SHIFT 0
# define ECC_POISON1_ROW_MASK 0x3FFFF
/* DDR Memory type defines */
# define MEM_TYPE_DDR3 0x1
# define MEM_TYPE_LPDDR3 0x8
# define MEM_TYPE_DDR2 0x4
# define MEM_TYPE_DDR4 0x10
# define MEM_TYPE_LPDDR4 0x20
/* DDRC Software control register */
# define DDRC_SWCTL 0x320
/* DDRC ECC CE & UE poison mask */
# define ECC_CEPOISON_MASK 0x3
# define ECC_UEPOISON_MASK 0x1
/* DDRC Device config masks */
# define DDRC_MSTR_CFG_MASK 0xC0000000
# define DDRC_MSTR_CFG_SHIFT 30
# define DDRC_MSTR_CFG_X4_MASK 0x0
# define DDRC_MSTR_CFG_X8_MASK 0x1
# define DDRC_MSTR_CFG_X16_MASK 0x2
# define DDRC_MSTR_CFG_X32_MASK 0x3
# define DDR_MAX_ROW_SHIFT 18
# define DDR_MAX_COL_SHIFT 14
# define DDR_MAX_BANK_SHIFT 3
# define DDR_MAX_BANKGRP_SHIFT 2
# define ROW_MAX_VAL_MASK 0xF
# define COL_MAX_VAL_MASK 0xF
# define BANK_MAX_VAL_MASK 0x1F
# define BANKGRP_MAX_VAL_MASK 0x1F
# define RANK_MAX_VAL_MASK 0x1F
# define ROW_B0_BASE 6
# define ROW_B1_BASE 7
# define ROW_B2_BASE 8
# define ROW_B3_BASE 9
# define ROW_B4_BASE 10
# define ROW_B5_BASE 11
# define ROW_B6_BASE 12
# define ROW_B7_BASE 13
# define ROW_B8_BASE 14
# define ROW_B9_BASE 15
# define ROW_B10_BASE 16
# define ROW_B11_BASE 17
# define ROW_B12_BASE 18
# define ROW_B13_BASE 19
# define ROW_B14_BASE 20
# define ROW_B15_BASE 21
# define ROW_B16_BASE 22
# define ROW_B17_BASE 23
# define COL_B2_BASE 2
# define COL_B3_BASE 3
# define COL_B4_BASE 4
# define COL_B5_BASE 5
# define COL_B6_BASE 6
# define COL_B7_BASE 7
# define COL_B8_BASE 8
# define COL_B9_BASE 9
# define COL_B10_BASE 10
# define COL_B11_BASE 11
# define COL_B12_BASE 12
# define COL_B13_BASE 13
# define BANK_B0_BASE 2
# define BANK_B1_BASE 3
# define BANK_B2_BASE 4
# define BANKGRP_B0_BASE 2
# define BANKGRP_B1_BASE 3
# define RANK_B0_BASE 6
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 .
2018-10-04 18:35:23 +03:00
* @ p_data : Platform data .
2018-10-04 18:35:21 +03:00
* @ 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 ;
2018-10-04 18:35:23 +03:00
const struct synps_platform_data * p_data ;
2015-01-06 20:43:47 +03:00
u32 ce_cnt ;
u32 ue_cnt ;
} ;
/**
2018-10-04 18:35:23 +03:00
* struct synps_platform_data - synps platform data structure .
* @ get_error_info : Get EDAC error info .
* @ get_mtype : Get mtype .
* @ get_dtype : Get dtype .
* @ get_ecc_state : Get ECC state .
* @ quirks : To differentiate IPs .
*/
struct synps_platform_data {
int ( * get_error_info ) ( struct synps_edac_priv * priv ) ;
enum mem_type ( * get_mtype ) ( const void __iomem * base ) ;
enum dev_type ( * get_dtype ) ( const void __iomem * base ) ;
bool ( * get_ecc_state ) ( void __iomem * base ) ;
int quirks ;
} ;
/**
* zynq_get_error_info - Get the current ECC error info .
* @ priv : DDR memory controller private instance data .
2015-01-06 20:43:47 +03:00
*
2018-10-04 18:35:23 +03:00
* Return : one if there is no error , otherwise zero .
2015-01-06 20:43:47 +03:00
*/
2018-10-04 18:35:23 +03:00
static int zynq_get_error_info ( struct synps_edac_priv * priv )
2015-01-06 20:43:47 +03:00
{
2018-10-04 18:35:23 +03:00
struct synps_ecc_status * p ;
2015-01-06 20:43:47 +03:00
u32 regval , clearval = 0 ;
2018-10-04 18:35:23 +03:00
void __iomem * base ;
base = priv - > baseaddr ;
p = & priv - > stat ;
2015-01-06 20:43:47 +03:00
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 ;
2018-10-04 18:35:23 +03:00
const struct synps_platform_data * p_data = priv - > p_data ;
2015-01-06 20:43:47 +03:00
int status ;
2018-10-04 18:35:23 +03:00
status = p_data - > get_error_info ( priv ) ;
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:23 +03:00
* zynq_get_dtype - Return the controller memory width .
2018-10-04 18:35:21 +03:00
* @ 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:23 +03:00
static enum dev_type zynq_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:23 +03:00
* zynq_get_ecc_state - Return the controller ECC enable / disable status .
2018-10-04 18:35:21 +03:00
* @ 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:23 +03:00
static bool zynq_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:23 +03:00
dt = zynq_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:23 +03:00
* zynq_get_mtype - Return the controller memory type .
2018-10-04 18:35:21 +03:00
* @ 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:23 +03:00
static enum mem_type zynq_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
*/
2018-10-04 18:35:22 +03:00
static void 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 ;
2018-10-04 18:35:23 +03:00
const struct synps_platform_data * p_data ;
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
2018-10-04 18:35:23 +03:00
p_data = priv - > p_data ;
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:23 +03:00
dimm - > mtype = p_data - > 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:23 +03:00
dimm - > dtype = p_data - > get_dtype ( priv - > baseaddr ) ;
2015-01-06 20:43:47 +03:00
}
}
}
/**
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 .
*/
2018-10-04 18:35:22 +03:00
static void mc_init ( struct mem_ctl_info * mci , struct platform_device * pdev )
2015-01-06 20:43:47 +03:00
{
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:22 +03:00
init_csrows ( mci ) ;
2015-01-06 20:43:47 +03:00
}
2018-10-04 18:35:23 +03:00
static const struct synps_platform_data zynq_edac_def = {
. get_error_info = zynq_get_error_info ,
. get_mtype = zynq_get_mtype ,
. get_dtype = zynq_get_dtype ,
. get_ecc_state = zynq_get_ecc_state ,
. quirks = 0 ,
} ;
static const struct of_device_id synps_edac_match [ ] = {
{ . compatible = " xlnx,zynq-ddrc-a05 " , . data = ( void * ) & zynq_edac_def } ,
{ /* end of table */ }
} ;
MODULE_DEVICE_TABLE ( of , synps_edac_match ) ;
2015-01-06 20:43:47 +03:00
/**
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
{
2018-10-04 18:35:23 +03:00
const struct synps_platform_data * p_data ;
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:23 +03:00
p_data = of_device_get_match_data ( & pdev - > dev ) ;
2018-10-25 09:06:56 +03:00
if ( ! p_data )
return - ENODEV ;
2018-10-04 18:35:23 +03:00
if ( ! p_data - > 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:23 +03:00
priv - > p_data = p_data ;
2018-10-04 18:35:22 +03:00
mc_init ( mci , pdev ) ;
2015-01-06 20:43:47 +03:00
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 ;
}
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 " ) ;