101101/* DDR ECC Quirks */
102102#define DDR_ECC_INTR_SUPPORT BIT(0)
103103#define DDR_ECC_DATA_POISON_SUPPORT BIT(1)
104+ #define DDR_ECC_INTR_SELF_CLEAR BIT(2)
104105
105106/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */
106107/* ECC Configuration Registers */
171172#define DDR_QOS_IRQ_EN_OFST 0x20208
172173#define DDR_QOS_IRQ_DB_OFST 0x2020C
173174
175+ /* DDR QOS Interrupt register definitions */
176+ #define DDR_UE_MASK BIT(9)
177+ #define DDR_CE_MASK BIT(8)
178+
174179/* ECC Corrected Error Register Mask and Shifts*/
175180#define ECC_CEADDR0_RW_MASK 0x3FFFF
176181#define ECC_CEADDR0_RNK_MASK BIT(24)
@@ -533,10 +538,16 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
533538 priv = mci -> pvt_info ;
534539 p_data = priv -> p_data ;
535540
536- regval = readl (priv -> baseaddr + DDR_QOS_IRQ_STAT_OFST );
537- regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK );
538- if (!(regval & ECC_CE_UE_INTR_MASK ))
539- return IRQ_NONE ;
541+ /*
542+ * v3.0 of the controller has the ce/ue bits cleared automatically,
543+ * so this condition does not apply.
544+ */
545+ if (!(priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR )) {
546+ regval = readl (priv -> baseaddr + DDR_QOS_IRQ_STAT_OFST );
547+ regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK );
548+ if (!(regval & ECC_CE_UE_INTR_MASK ))
549+ return IRQ_NONE ;
550+ }
540551
541552 status = p_data -> get_error_info (priv );
542553 if (status )
@@ -548,7 +559,9 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
548559
549560 edac_dbg (3 , "Total error count CE %d UE %d\n" ,
550561 priv -> ce_cnt , priv -> ue_cnt );
551- writel (regval , priv -> baseaddr + DDR_QOS_IRQ_STAT_OFST );
562+ /* v3.0 of the controller does not have this register */
563+ if (!(priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR ))
564+ writel (regval , priv -> baseaddr + DDR_QOS_IRQ_STAT_OFST );
552565 return IRQ_HANDLED ;
553566}
554567
@@ -834,8 +847,13 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
834847static void enable_intr (struct synps_edac_priv * priv )
835848{
836849 /* Enable UE/CE Interrupts */
837- writel (DDR_QOSUE_MASK | DDR_QOSCE_MASK ,
838- priv -> baseaddr + DDR_QOS_IRQ_EN_OFST );
850+ if (priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR )
851+ writel (DDR_UE_MASK | DDR_CE_MASK ,
852+ priv -> baseaddr + ECC_CLR_OFST );
853+ else
854+ writel (DDR_QOSUE_MASK | DDR_QOSCE_MASK ,
855+ priv -> baseaddr + DDR_QOS_IRQ_EN_OFST );
856+
839857}
840858
841859static void disable_intr (struct synps_edac_priv * priv )
@@ -890,6 +908,19 @@ static const struct synps_platform_data zynqmp_edac_def = {
890908 ),
891909};
892910
911+ static const struct synps_platform_data synopsys_edac_def = {
912+ .get_error_info = zynqmp_get_error_info ,
913+ .get_mtype = zynqmp_get_mtype ,
914+ .get_dtype = zynqmp_get_dtype ,
915+ .get_ecc_state = zynqmp_get_ecc_state ,
916+ .quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_INTR_SELF_CLEAR
917+ #ifdef CONFIG_EDAC_DEBUG
918+ | DDR_ECC_DATA_POISON_SUPPORT
919+ #endif
920+ ),
921+ };
922+
923+
893924static const struct of_device_id synps_edac_match [] = {
894925 {
895926 .compatible = "xlnx,zynq-ddrc-a05" ,
@@ -899,6 +930,10 @@ static const struct of_device_id synps_edac_match[] = {
899930 .compatible = "xlnx,zynqmp-ddrc-2.40a" ,
900931 .data = (void * )& zynqmp_edac_def
901932 },
933+ {
934+ .compatible = "snps,ddrc-3.80a" ,
935+ .data = (void * )& synopsys_edac_def
936+ },
902937 {
903938 /* end of table */
904939 }
0 commit comments