EDAC/synopsys: Add support for version 3 of the Synopsys EDAC DDR
Add support for version 3.80a of the Synopsys DDR controller. This version of the controller has the following differences: - UE/CE are auto cleared - Interrupts are supported by default Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Michal Simek <michal.simek@xilinx.com> Link: https://lkml.kernel.org/r/20211012190709.1504152-2-dinguyen@kernel.org
This commit is contained in:
Родитель
bd1d6da17c
Коммит
f7824ded41
|
@ -101,6 +101,7 @@
|
|||
/* DDR ECC Quirks */
|
||||
#define DDR_ECC_INTR_SUPPORT BIT(0)
|
||||
#define DDR_ECC_DATA_POISON_SUPPORT BIT(1)
|
||||
#define DDR_ECC_INTR_SELF_CLEAR BIT(2)
|
||||
|
||||
/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */
|
||||
/* ECC Configuration Registers */
|
||||
|
@ -171,6 +172,10 @@
|
|||
#define DDR_QOS_IRQ_EN_OFST 0x20208
|
||||
#define DDR_QOS_IRQ_DB_OFST 0x2020C
|
||||
|
||||
/* DDR QOS Interrupt register definitions */
|
||||
#define DDR_UE_MASK BIT(9)
|
||||
#define DDR_CE_MASK BIT(8)
|
||||
|
||||
/* ECC Corrected Error Register Mask and Shifts*/
|
||||
#define ECC_CEADDR0_RW_MASK 0x3FFFF
|
||||
#define ECC_CEADDR0_RNK_MASK BIT(24)
|
||||
|
@ -533,10 +538,16 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
|
|||
priv = mci->pvt_info;
|
||||
p_data = priv->p_data;
|
||||
|
||||
regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
|
||||
regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK);
|
||||
if (!(regval & ECC_CE_UE_INTR_MASK))
|
||||
return IRQ_NONE;
|
||||
/*
|
||||
* v3.0 of the controller has the ce/ue bits cleared automatically,
|
||||
* so this condition does not apply.
|
||||
*/
|
||||
if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)) {
|
||||
regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
|
||||
regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK);
|
||||
if (!(regval & ECC_CE_UE_INTR_MASK))
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
status = p_data->get_error_info(priv);
|
||||
if (status)
|
||||
|
@ -548,7 +559,9 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
|
|||
|
||||
edac_dbg(3, "Total error count CE %d UE %d\n",
|
||||
priv->ce_cnt, priv->ue_cnt);
|
||||
writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
|
||||
/* v3.0 of the controller does not have this register */
|
||||
if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR))
|
||||
writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -834,8 +847,13 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
|
|||
static void enable_intr(struct synps_edac_priv *priv)
|
||||
{
|
||||
/* Enable UE/CE Interrupts */
|
||||
writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
|
||||
priv->baseaddr + DDR_QOS_IRQ_EN_OFST);
|
||||
if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)
|
||||
writel(DDR_UE_MASK | DDR_CE_MASK,
|
||||
priv->baseaddr + ECC_CLR_OFST);
|
||||
else
|
||||
writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
|
||||
priv->baseaddr + DDR_QOS_IRQ_EN_OFST);
|
||||
|
||||
}
|
||||
|
||||
static void disable_intr(struct synps_edac_priv *priv)
|
||||
|
@ -890,6 +908,19 @@ static const struct synps_platform_data zynqmp_edac_def = {
|
|||
),
|
||||
};
|
||||
|
||||
static const struct synps_platform_data synopsys_edac_def = {
|
||||
.get_error_info = zynqmp_get_error_info,
|
||||
.get_mtype = zynqmp_get_mtype,
|
||||
.get_dtype = zynqmp_get_dtype,
|
||||
.get_ecc_state = zynqmp_get_ecc_state,
|
||||
.quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_INTR_SELF_CLEAR
|
||||
#ifdef CONFIG_EDAC_DEBUG
|
||||
| DDR_ECC_DATA_POISON_SUPPORT
|
||||
#endif
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
static const struct of_device_id synps_edac_match[] = {
|
||||
{
|
||||
.compatible = "xlnx,zynq-ddrc-a05",
|
||||
|
@ -899,6 +930,10 @@ static const struct of_device_id synps_edac_match[] = {
|
|||
.compatible = "xlnx,zynqmp-ddrc-2.40a",
|
||||
.data = (void *)&zynqmp_edac_def
|
||||
},
|
||||
{
|
||||
.compatible = "snps,ddrc-3.80a",
|
||||
.data = (void *)&synopsys_edac_def
|
||||
},
|
||||
{
|
||||
/* end of table */
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче