Skip to content

Commit

Permalink
EDAC/synopsys: Add support for version 3 of the Synopsys EDAC DDR
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Dinh Nguyen authored and suryasaimadhu committed Nov 20, 2021
1 parent bd1d6da commit f7824de
Showing 1 changed file with 42 additions and 7 deletions.
49 changes: 42 additions & 7 deletions drivers/edac/synopsys_edac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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",
Expand All @@ -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 */
}
Expand Down

0 comments on commit f7824de

Please sign in to comment.