101
101
/* DDR ECC Quirks */
102
102
#define DDR_ECC_INTR_SUPPORT BIT(0)
103
103
#define DDR_ECC_DATA_POISON_SUPPORT BIT(1)
104
+ #define DDR_ECC_INTR_SELF_CLEAR BIT(2)
104
105
105
106
/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */
106
107
/* ECC Configuration Registers */
171
172
#define DDR_QOS_IRQ_EN_OFST 0x20208
172
173
#define DDR_QOS_IRQ_DB_OFST 0x2020C
173
174
175
+ /* DDR QOS Interrupt register definitions */
176
+ #define DDR_UE_MASK BIT(9)
177
+ #define DDR_CE_MASK BIT(8)
178
+
174
179
/* ECC Corrected Error Register Mask and Shifts*/
175
180
#define ECC_CEADDR0_RW_MASK 0x3FFFF
176
181
#define ECC_CEADDR0_RNK_MASK BIT(24)
@@ -533,10 +538,16 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
533
538
priv = mci -> pvt_info ;
534
539
p_data = priv -> p_data ;
535
540
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
+ }
540
551
541
552
status = p_data -> get_error_info (priv );
542
553
if (status )
@@ -548,7 +559,9 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
548
559
549
560
edac_dbg (3 , "Total error count CE %d UE %d\n" ,
550
561
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 );
552
565
return IRQ_HANDLED ;
553
566
}
554
567
@@ -834,8 +847,13 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
834
847
static void enable_intr (struct synps_edac_priv * priv )
835
848
{
836
849
/* 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
+
839
857
}
840
858
841
859
static void disable_intr (struct synps_edac_priv * priv )
@@ -890,6 +908,19 @@ static const struct synps_platform_data zynqmp_edac_def = {
890
908
),
891
909
};
892
910
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
+
893
924
static const struct of_device_id synps_edac_match [] = {
894
925
{
895
926
.compatible = "xlnx,zynq-ddrc-a05" ,
@@ -899,6 +930,10 @@ static const struct of_device_id synps_edac_match[] = {
899
930
.compatible = "xlnx,zynqmp-ddrc-2.40a" ,
900
931
.data = (void * )& zynqmp_edac_def
901
932
},
933
+ {
934
+ .compatible = "snps,ddrc-3.80a" ,
935
+ .data = (void * )& synopsys_edac_def
936
+ },
902
937
{
903
938
/* end of table */
904
939
}
0 commit comments