1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/edac.h>
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/interrupt.h>
26#include <linux/of.h>
27
28#include "edac_module.h"
29
30
31#define SYNPS_EDAC_NR_CSROWS 1
32
33
34#define SYNPS_EDAC_NR_CHANS 1
35
36
37#define SYNPS_EDAC_ERR_GRAIN 1
38
39#define SYNPS_EDAC_MSG_SIZE 256
40
41#define SYNPS_EDAC_MOD_STRING "synps_edac"
42#define SYNPS_EDAC_MOD_VER "1"
43
44
45#define CTRL_OFST 0x0
46#define T_ZQ_OFST 0xA4
47
48
49#define ECC_CTRL_OFST 0xC4
50
51#define CE_LOG_OFST 0xC8
52
53#define CE_ADDR_OFST 0xCC
54
55#define CE_DATA_31_0_OFST 0xD0
56
57
58#define UE_LOG_OFST 0xDC
59#define UE_ADDR_OFST 0xE0
60#define UE_DATA_31_0_OFST 0xE4
61
62#define STAT_OFST 0xF0
63#define SCRUB_OFST 0xF4
64
65
66#define CTRL_BW_MASK 0xC
67#define CTRL_BW_SHIFT 2
68
69#define DDRCTL_WDTH_16 1
70#define DDRCTL_WDTH_32 0
71
72
73#define T_ZQ_DDRMODE_MASK 0x2
74
75
76#define ECC_CTRL_CLR_CE_ERR 0x2
77#define ECC_CTRL_CLR_UE_ERR 0x1
78
79
80#define LOG_VALID 0x1
81#define CE_LOG_BITPOS_MASK 0xFE
82#define CE_LOG_BITPOS_SHIFT 1
83
84
85#define ADDR_COL_MASK 0xFFF
86#define ADDR_ROW_MASK 0xFFFF000
87#define ADDR_ROW_SHIFT 12
88#define ADDR_BANK_MASK 0x70000000
89#define ADDR_BANK_SHIFT 28
90
91
92#define STAT_UECNT_MASK 0xFF
93#define STAT_CECNT_MASK 0xFF00
94#define STAT_CECNT_SHIFT 8
95
96
97#define SCRUB_MODE_MASK 0x7
98#define SCRUB_MODE_SECDED 0x4
99
100
101#define DDR_ECC_INTR_SUPPORT BIT(0)
102#define DDR_ECC_DATA_POISON_SUPPORT BIT(1)
103
104
105
106#define ECC_CFG0_OFST 0x70
107#define ECC_CFG1_OFST 0x74
108
109
110#define ECC_STAT_OFST 0x78
111
112
113#define ECC_CLR_OFST 0x7C
114
115
116#define ECC_ERRCNT_OFST 0x80
117
118
119#define ECC_CEADDR0_OFST 0x84
120#define ECC_CEADDR1_OFST 0x88
121
122
123#define ECC_CSYND0_OFST 0x8C
124#define ECC_CSYND1_OFST 0x90
125#define ECC_CSYND2_OFST 0x94
126
127
128#define ECC_BITMASK0_OFST 0x98
129#define ECC_BITMASK1_OFST 0x9C
130#define ECC_BITMASK2_OFST 0xA0
131
132
133#define ECC_UEADDR0_OFST 0xA4
134#define ECC_UEADDR1_OFST 0xA8
135
136
137#define ECC_UESYND0_OFST 0xAC
138#define ECC_UESYND1_OFST 0xB0
139#define ECC_UESYND2_OFST 0xB4
140
141
142#define ECC_POISON0_OFST 0xB8
143#define ECC_POISON1_OFST 0xBC
144
145#define ECC_ADDRMAP0_OFFSET 0x200
146
147
148#define ECC_CTRL_BUSWIDTH_MASK 0x3000
149#define ECC_CTRL_BUSWIDTH_SHIFT 12
150#define ECC_CTRL_CLR_CE_ERRCNT BIT(2)
151#define ECC_CTRL_CLR_UE_ERRCNT BIT(3)
152
153
154#define DDRCTL_EWDTH_16 2
155#define DDRCTL_EWDTH_32 1
156#define DDRCTL_EWDTH_64 0
157
158
159#define ECC_STAT_UECNT_MASK 0xF0000
160#define ECC_STAT_UECNT_SHIFT 16
161#define ECC_STAT_CECNT_MASK 0xF00
162#define ECC_STAT_CECNT_SHIFT 8
163#define ECC_STAT_BITNUM_MASK 0x7F
164
165
166#define DDR_QOS_IRQ_STAT_OFST 0x20200
167#define DDR_QOSUE_MASK 0x4
168#define DDR_QOSCE_MASK 0x2
169#define ECC_CE_UE_INTR_MASK 0x6
170#define DDR_QOS_IRQ_EN_OFST 0x20208
171#define DDR_QOS_IRQ_DB_OFST 0x2020C
172
173
174#define ECC_CEADDR0_RW_MASK 0x3FFFF
175#define ECC_CEADDR0_RNK_MASK BIT(24)
176#define ECC_CEADDR1_BNKGRP_MASK 0x3000000
177#define ECC_CEADDR1_BNKNR_MASK 0x70000
178#define ECC_CEADDR1_BLKNR_MASK 0xFFF
179#define ECC_CEADDR1_BNKGRP_SHIFT 24
180#define ECC_CEADDR1_BNKNR_SHIFT 16
181
182
183#define ECC_POISON0_RANK_SHIFT 24
184#define ECC_POISON1_BANKGRP_SHIFT 28
185#define ECC_POISON1_BANKNR_SHIFT 24
186
187
188#define MEM_TYPE_DDR3 0x1
189#define MEM_TYPE_LPDDR3 0x8
190#define MEM_TYPE_DDR2 0x4
191#define MEM_TYPE_DDR4 0x10
192#define MEM_TYPE_LPDDR4 0x20
193
194
195#define DDRC_SWCTL 0x320
196
197
198#define ECC_CEPOISON_MASK 0x3
199#define ECC_UEPOISON_MASK 0x1
200
201
202#define DDRC_MSTR_DEV_CONFIG_MASK 0xC0000000
203#define DDRC_MSTR_DEV_CONFIG_SHIFT 30
204#define DDRC_MSTR_DEV_CONFIG_X4_MASK 0
205#define DDRC_MSTR_DEV_CONFIG_X8_MASK 1
206#define DDRC_MSTR_DEV_CONFIG_X16_MASK 0x2
207#define DDRC_MSTR_DEV_CONFIG_X32_MASK 0x3
208
209#define DDR_MAX_ROW_SHIFT 18
210#define DDR_MAX_COL_SHIFT 14
211#define DDR_MAX_BANK_SHIFT 3
212#define DDR_MAX_BANKGRP_SHIFT 2
213
214#define ROW_MAX_VAL_MASK 0xF
215#define COL_MAX_VAL_MASK 0xF
216#define BANK_MAX_VAL_MASK 0x1F
217#define BANKGRP_MAX_VAL_MASK 0x1F
218#define RANK_MAX_VAL_MASK 0x1F
219
220#define ROW_B0_BASE 6
221#define ROW_B1_BASE 7
222#define ROW_B2_BASE 8
223#define ROW_B3_BASE 9
224#define ROW_B4_BASE 10
225#define ROW_B5_BASE 11
226#define ROW_B6_BASE 12
227#define ROW_B7_BASE 13
228#define ROW_B8_BASE 14
229#define ROW_B9_BASE 15
230#define ROW_B10_BASE 16
231#define ROW_B11_BASE 17
232#define ROW_B12_BASE 18
233#define ROW_B13_BASE 19
234#define ROW_B14_BASE 20
235#define ROW_B15_BASE 21
236#define ROW_B16_BASE 22
237#define ROW_B17_BASE 23
238
239#define COL_B2_BASE 2
240#define COL_B3_BASE 3
241#define COL_B4_BASE 4
242#define COL_B5_BASE 5
243#define COL_B6_BASE 6
244#define COL_B7_BASE 7
245#define COL_B8_BASE 8
246#define COL_B9_BASE 9
247#define COL_B10_BASE 10
248#define COL_B11_BASE 11
249#define COL_B12_BASE 12
250#define COL_B13_BASE 13
251
252#define BANK_B0_BASE 2
253#define BANK_B1_BASE 3
254#define BANK_B2_BASE 4
255
256#define BANKGRP_B0_BASE 2
257#define BANKGRP_B1_BASE 3
258
259#define RANK_B0_BASE 6
260
261
262
263
264
265
266
267
268
269
270
271struct ecc_error_info {
272 u32 row;
273 u32 col;
274 u32 bank;
275 u32 bitpos;
276 u32 data;
277 u32 bankgrpnr;
278 u32 blknr;
279};
280
281
282
283
284
285
286
287
288struct synps_ecc_status {
289 u32 ce_cnt;
290 u32 ue_cnt;
291 struct ecc_error_info ceinfo;
292 struct ecc_error_info ueinfo;
293};
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310struct synps_edac_priv {
311 void __iomem *baseaddr;
312 char message[SYNPS_EDAC_MSG_SIZE];
313 struct synps_ecc_status stat;
314 const struct synps_platform_data *p_data;
315 u32 ce_cnt;
316 u32 ue_cnt;
317 ulong poison_addr;
318 u32 row_shift[18];
319 u32 col_shift[14];
320 u32 bank_shift[3];
321 u32 bankgrp_shift[2];
322 u32 rank_shift[1];
323};
324
325
326
327
328
329
330
331
332
333struct synps_platform_data {
334 int (*synps_edac_geterror_info)(void __iomem *base,
335 struct synps_ecc_status *p);
336 enum mem_type (*synps_edac_get_mtype)(const void __iomem *base);
337 enum dev_type (*synps_edac_get_dtype)(const void __iomem *base);
338 bool (*synps_edac_get_eccstate)(void __iomem *base);
339 int quirks;
340};
341
342
343
344
345
346
347
348
349
350
351static int synps_edac_geterror_info(void __iomem *base,
352 struct synps_ecc_status *p)
353{
354 u32 regval, clearval = 0;
355
356 regval = readl(base + STAT_OFST);
357 if (!regval)
358 return 1;
359
360 p->ce_cnt = (regval & STAT_CECNT_MASK) >> STAT_CECNT_SHIFT;
361 p->ue_cnt = regval & STAT_UECNT_MASK;
362
363 regval = readl(base + CE_LOG_OFST);
364 if (!(p->ce_cnt && (regval & LOG_VALID)))
365 goto ue_err;
366
367 p->ceinfo.bitpos = (regval & CE_LOG_BITPOS_MASK) >> CE_LOG_BITPOS_SHIFT;
368 regval = readl(base + CE_ADDR_OFST);
369 p->ceinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
370 p->ceinfo.col = regval & ADDR_COL_MASK;
371 p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
372 p->ceinfo.data = readl(base + CE_DATA_31_0_OFST);
373 clearval = ECC_CTRL_CLR_CE_ERR;
374
375ue_err:
376 regval = readl(base + UE_LOG_OFST);
377 if (!(p->ue_cnt && (regval & LOG_VALID)))
378 goto out;
379
380 regval = readl(base + UE_ADDR_OFST);
381 p->ueinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
382 p->ueinfo.col = regval & ADDR_COL_MASK;
383 p->ueinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
384 p->ueinfo.data = readl(base + UE_DATA_31_0_OFST);
385 clearval |= ECC_CTRL_CLR_UE_ERR;
386
387out:
388 writel(clearval, base + ECC_CTRL_OFST);
389 writel(0x0, base + ECC_CTRL_OFST);
390
391 return 0;
392}
393
394
395
396
397
398
399
400
401
402
403static int synps_enh_edac_geterror_info(void __iomem *base,
404 struct synps_ecc_status *p)
405{
406 u32 regval, clearval = 0;
407
408 regval = readl(base + ECC_STAT_OFST);
409 if (!regval)
410 return 1;
411
412 p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT;
413 p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT;
414 p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK);
415
416 regval = readl(base + ECC_CEADDR0_OFST);
417 if (!(p->ce_cnt))
418 goto ue_err;
419
420 p->ceinfo.row = (regval & ECC_CEADDR0_RW_MASK);
421 regval = readl(base + ECC_CEADDR1_OFST);
422 p->ceinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >>
423 ECC_CEADDR1_BNKNR_SHIFT;
424 p->ceinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >>
425 ECC_CEADDR1_BNKGRP_SHIFT;
426 p->ceinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK);
427 p->ceinfo.data = readl(base + ECC_CSYND0_OFST);
428 edac_dbg(2, "ECCCSYN0: 0x%08X ECCCSYN1: 0x%08X ECCCSYN2: 0x%08X\n",
429 readl(base + ECC_CSYND0_OFST), readl(base + ECC_CSYND1_OFST),
430 readl(base + ECC_CSYND2_OFST));
431
432
433ue_err:
434 regval = readl(base + ECC_UEADDR0_OFST);
435 if (!(p->ue_cnt))
436 goto out;
437
438 p->ueinfo.row = (regval & ECC_CEADDR0_RW_MASK);
439 regval = readl(base + ECC_UEADDR1_OFST);
440 p->ueinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >>
441 ECC_CEADDR1_BNKGRP_SHIFT;
442 p->ueinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >>
443 ECC_CEADDR1_BNKNR_SHIFT;
444 p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK);
445 p->ueinfo.data = readl(base + ECC_UESYND0_OFST);
446out:
447 clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT;
448 clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT;
449 writel(clearval, base + ECC_CLR_OFST);
450 writel(0x0, base + ECC_CLR_OFST);
451
452 return 0;
453}
454
455
456
457
458
459
460
461
462static void synps_edac_handle_error(struct mem_ctl_info *mci,
463 struct synps_ecc_status *p)
464{
465 struct synps_edac_priv *priv = mci->pvt_info;
466 struct ecc_error_info *pinf;
467
468 if (p->ce_cnt) {
469 pinf = &p->ceinfo;
470 if (priv->p_data->quirks == 0) {
471 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
472 "DDR ECC error type:%s Row %d Bank %d Col %d ",
473 "CE", pinf->row, pinf->bank, pinf->col);
474 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
475 "Bit Position: %d Data: 0x%08x\n",
476 pinf->bitpos, pinf->data);
477 } else {
478 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
479 "DDR ECC error type:%s Row %d Bank %d Col %d ",
480 "CE", pinf->row, pinf->bank, pinf->col);
481 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
482 "BankGroup Number %d Block Number %d ",
483 pinf->bankgrpnr, pinf->blknr);
484 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
485 "Bit Position: %d Data: 0x%08x\n",
486 pinf->bitpos, pinf->data);
487 }
488
489 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
490 p->ce_cnt, 0, 0, 0, 0, 0, -1,
491 priv->message, "");
492 }
493
494 if (p->ue_cnt) {
495 pinf = &p->ueinfo;
496 if (priv->p_data->quirks == 0)
497 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
498 "DDR ECC error type :%s Row %d Bank %d Col %d ",
499 "UE", pinf->row, pinf->bank, pinf->col);
500 else
501 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
502 "DDR ECC error type :%s Row %d Bank %d Col %d "
503 "BankGroup Number %d Block Number %d",
504 "UE", pinf->row, pinf->bank, pinf->col,
505 pinf->bankgrpnr, pinf->blknr);
506 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
507 p->ue_cnt, 0, 0, 0, 0, 0, -1,
508 priv->message, "");
509 }
510
511 memset(p, 0, sizeof(*p));
512}
513
514
515
516
517
518
519
520
521
522
523
524static irqreturn_t synps_edac_intr_handler(int irq, void *dev_id)
525{
526 struct mem_ctl_info *mci = dev_id;
527 struct synps_edac_priv *priv = mci->pvt_info;
528 int status, regval;
529
530 regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST) &
531 (DDR_QOSCE_MASK | DDR_QOSUE_MASK);
532 if (!(regval & ECC_CE_UE_INTR_MASK))
533 return IRQ_NONE;
534 status = priv->p_data->synps_edac_geterror_info(priv->baseaddr,
535 &priv->stat);
536 if (status)
537 return IRQ_NONE;
538
539 priv->ce_cnt += priv->stat.ce_cnt;
540 priv->ue_cnt += priv->stat.ue_cnt;
541 synps_edac_handle_error(mci, &priv->stat);
542
543 edac_dbg(3, "Total error count ce %d ue %d\n",
544 priv->ce_cnt, priv->ue_cnt);
545 writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
546 return IRQ_HANDLED;
547}
548
549
550
551
552
553
554
555static void synps_edac_check(struct mem_ctl_info *mci)
556{
557 struct synps_edac_priv *priv = mci->pvt_info;
558 int status;
559
560 status = priv->p_data->synps_edac_geterror_info(priv->baseaddr,
561 &priv->stat);
562 if (status)
563 return;
564
565 priv->ce_cnt += priv->stat.ce_cnt;
566 priv->ue_cnt += priv->stat.ue_cnt;
567 synps_edac_handle_error(mci, &priv->stat);
568
569 edac_dbg(3, "Total error count ce %d ue %d\n",
570 priv->ce_cnt, priv->ue_cnt);
571}
572
573
574
575
576
577
578
579
580
581
582static enum dev_type synps_edac_get_dtype(const void __iomem *base)
583{
584 enum dev_type dt;
585 u32 width;
586
587 width = readl(base + CTRL_OFST);
588 width = (width & CTRL_BW_MASK) >> CTRL_BW_SHIFT;
589
590 switch (width) {
591 case DDRCTL_WDTH_16:
592 dt = DEV_X2;
593 break;
594 case DDRCTL_WDTH_32:
595 dt = DEV_X4;
596 break;
597 default:
598 dt = DEV_UNKNOWN;
599 }
600
601 return dt;
602}
603
604
605
606
607
608
609
610
611
612
613static enum dev_type synps_enh_edac_get_dtype(const void __iomem *base)
614{
615 enum dev_type dt;
616 u32 width;
617
618 width = readl(base + CTRL_OFST);
619 width = (width & ECC_CTRL_BUSWIDTH_MASK) >>
620 ECC_CTRL_BUSWIDTH_SHIFT;
621 switch (width) {
622 case DDRCTL_EWDTH_16:
623 dt = DEV_X2;
624 break;
625 case DDRCTL_EWDTH_32:
626 dt = DEV_X4;
627 break;
628 case DDRCTL_EWDTH_64:
629 dt = DEV_X8;
630 break;
631 default:
632 dt = DEV_UNKNOWN;
633 }
634
635 return dt;
636}
637
638
639
640
641
642
643
644
645
646static bool synps_edac_get_eccstate(void __iomem *base)
647{
648 enum dev_type dt;
649 u32 ecctype;
650 bool state = false;
651
652 dt = synps_edac_get_dtype(base);
653 if (dt == DEV_UNKNOWN)
654 return state;
655
656 ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK;
657 if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2))
658 state = true;
659
660 return state;
661}
662
663
664
665
666
667
668
669
670
671static bool synps_enh_edac_get_eccstate(void __iomem *base)
672{
673 enum dev_type dt;
674 u32 ecctype;
675 bool state = false;
676
677 dt = synps_enh_edac_get_dtype(base);
678 if (dt == DEV_UNKNOWN)
679 return state;
680
681 ecctype = readl(base + ECC_CFG0_OFST) & SCRUB_MODE_MASK;
682 if ((ecctype == SCRUB_MODE_SECDED) &&
683 ((dt == DEV_X2) || (dt == DEV_X4) || (dt == DEV_X8)))
684 state = true;
685
686 return state;
687}
688
689
690
691
692
693
694static u32 synps_edac_get_memsize(void)
695{
696 struct sysinfo inf;
697
698 si_meminfo(&inf);
699
700 return inf.totalram * inf.mem_unit;
701}
702
703
704
705
706
707
708
709
710
711
712static enum mem_type synps_edac_get_mtype(const void __iomem *base)
713{
714 enum mem_type mt;
715 u32 memtype;
716
717 memtype = readl(base + T_ZQ_OFST);
718
719 if (memtype & T_ZQ_DDRMODE_MASK)
720 mt = MEM_DDR3;
721 else
722 mt = MEM_DDR2;
723
724 return mt;
725}
726
727
728
729
730
731
732
733
734
735
736static enum mem_type synps_enh_edac_get_mtype(const void __iomem *base)
737{
738 enum mem_type mt;
739 u32 memtype;
740
741 memtype = readl(base + CTRL_OFST);
742
743 mt = MEM_UNKNOWN;
744 if ((memtype & MEM_TYPE_DDR3) || (memtype & MEM_TYPE_LPDDR3))
745 mt = MEM_DDR3;
746 else if (memtype & MEM_TYPE_DDR2)
747 mt = MEM_RDDR2;
748 else if ((memtype & MEM_TYPE_LPDDR4) || (memtype & MEM_TYPE_DDR4))
749 mt = MEM_DDR4;
750
751 return mt;
752}
753
754
755
756
757
758
759
760
761
762
763static int synps_edac_init_csrows(struct mem_ctl_info *mci)
764{
765 struct csrow_info *csi;
766 struct dimm_info *dimm;
767 struct synps_edac_priv *priv = mci->pvt_info;
768 u32 size;
769 int row, j;
770
771 for (row = 0; row < mci->nr_csrows; row++) {
772 csi = mci->csrows[row];
773 size = synps_edac_get_memsize();
774
775 for (j = 0; j < csi->nr_channels; j++) {
776 dimm = csi->channels[j]->dimm;
777 dimm->edac_mode = EDAC_FLAG_SECDED;
778 dimm->mtype = priv->p_data->synps_edac_get_mtype(
779 priv->baseaddr);
780 dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels;
781 dimm->grain = SYNPS_EDAC_ERR_GRAIN;
782 dimm->dtype = priv->p_data->synps_edac_get_dtype(
783 priv->baseaddr);
784 }
785 }
786
787 return 0;
788}
789
790
791
792
793
794
795
796
797
798
799
800
801static int synps_edac_mc_init(struct mem_ctl_info *mci,
802 struct platform_device *pdev)
803{
804 int status;
805 struct synps_edac_priv *priv;
806
807 mci->pdev = &pdev->dev;
808 priv = mci->pvt_info;
809 platform_set_drvdata(pdev, mci);
810
811
812 mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
813 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
814 mci->scrub_cap = SCRUB_HW_SRC;
815 mci->scrub_mode = SCRUB_NONE;
816
817 mci->edac_cap = EDAC_FLAG_SECDED;
818 mci->ctl_name = "synps_ddr_controller";
819 mci->dev_name = SYNPS_EDAC_MOD_STRING;
820 mci->mod_name = SYNPS_EDAC_MOD_VER;
821
822 if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT) {
823 edac_op_state = EDAC_OPSTATE_INT;
824 } else {
825 edac_op_state = EDAC_OPSTATE_POLL;
826 mci->edac_check = synps_edac_check;
827 }
828 mci->ctl_page_to_phys = NULL;
829
830 status = synps_edac_init_csrows(mci);
831
832 return status;
833}
834
835static const struct synps_platform_data zynq_edac_def = {
836 .synps_edac_geterror_info = synps_edac_geterror_info,
837 .synps_edac_get_mtype = synps_edac_get_mtype,
838 .synps_edac_get_dtype = synps_edac_get_dtype,
839 .synps_edac_get_eccstate = synps_edac_get_eccstate,
840 .quirks = 0,
841};
842
843static const struct synps_platform_data zynqmp_enh_edac_def = {
844 .synps_edac_geterror_info = synps_enh_edac_geterror_info,
845 .synps_edac_get_mtype = synps_enh_edac_get_mtype,
846 .synps_edac_get_dtype = synps_enh_edac_get_dtype,
847 .synps_edac_get_eccstate = synps_enh_edac_get_eccstate,
848 .quirks = (DDR_ECC_INTR_SUPPORT |
849 DDR_ECC_DATA_POISON_SUPPORT),
850};
851
852static const struct of_device_id synps_edac_match[] = {
853 { .compatible = "xlnx,zynq-ddrc-a05", .data = (void *)&zynq_edac_def },
854 { .compatible = "xlnx,zynqmp-ddrc-2.40a",
855 .data = (void *)&zynqmp_enh_edac_def},
856 { }
857};
858
859MODULE_DEVICE_TABLE(of, synps_edac_match);
860
861#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
862
863
864
865
866
867
868
869
870static void ddr_poison_setup(struct synps_edac_priv *priv)
871{
872 int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval;
873 int index;
874 ulong hif_addr = 0;
875
876 hif_addr = priv->poison_addr >> 3;
877
878 for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) {
879 if (priv->row_shift[index])
880 row |= (((hif_addr >> priv->row_shift[index]) &
881 BIT(0)) << index);
882 else
883 break;
884 }
885
886 for (index = 0; index < DDR_MAX_COL_SHIFT; index++) {
887 if (priv->col_shift[index] || index < 3)
888 col |= (((hif_addr >> priv->col_shift[index]) &
889 BIT(0)) << index);
890 else
891 break;
892 }
893
894 for (index = 0; index < DDR_MAX_BANK_SHIFT; index++) {
895 if (priv->bank_shift[index])
896 bank |= (((hif_addr >> priv->bank_shift[index]) &
897 BIT(0)) << index);
898 else
899 break;
900 }
901
902 for (index = 0; index < DDR_MAX_BANKGRP_SHIFT; index++) {
903 if (priv->bankgrp_shift[index])
904 bankgrp |= (((hif_addr >> priv->bankgrp_shift[index])
905 & BIT(0)) << index);
906 else
907 break;
908 }
909
910 if (priv->rank_shift[0])
911 rank = (hif_addr >> priv->rank_shift[0]) & BIT(0);
912
913 regval = (rank << ECC_POISON0_RANK_SHIFT) | col;
914 writel(regval, priv->baseaddr + ECC_POISON0_OFST);
915 regval = (bankgrp << ECC_POISON1_BANKGRP_SHIFT) |
916 (bank << ECC_POISON1_BANKNR_SHIFT) | row;
917 writel(regval, priv->baseaddr + ECC_POISON1_OFST);
918}
919
920
921
922
923
924
925
926
927
928
929static ssize_t synps_edac_mc_inject_data_error_show(struct device *dev,
930 struct device_attribute *mattr,
931 char *data)
932{
933 struct mem_ctl_info *mci = to_mci(dev);
934 struct synps_edac_priv *priv = mci->pvt_info;
935
936 return sprintf(data, "Poison0 Addr: 0x%08x\n\rPoison1 Addr: 0x%08x\n\r"
937 "Error injection Address: 0x%lx\n\r",
938 readl(priv->baseaddr + ECC_POISON0_OFST),
939 readl(priv->baseaddr + ECC_POISON1_OFST),
940 priv->poison_addr);
941}
942
943
944
945
946
947
948
949
950
951
952
953
954static ssize_t synps_edac_mc_inject_data_error_store(struct device *dev,
955 struct device_attribute *mattr,
956 const char *data, size_t count)
957{
958 struct mem_ctl_info *mci = to_mci(dev);
959 struct synps_edac_priv *priv = mci->pvt_info;
960
961 if (kstrtoul(data, 0, &priv->poison_addr))
962 return -EINVAL;
963
964 ddr_poison_setup(priv);
965
966 return count;
967}
968
969
970
971
972
973
974
975
976
977
978static ssize_t synps_edac_mc_inject_data_poison_show(struct device *dev,
979 struct device_attribute *mattr,
980 char *data)
981{
982 struct mem_ctl_info *mci = to_mci(dev);
983 struct synps_edac_priv *priv = mci->pvt_info;
984
985 return sprintf(data, "Data Poisoning: %s\n\r",
986 (((readl(priv->baseaddr + ECC_CFG1_OFST)) & 0x3) == 0x3)
987 ? ("Correctable Error") : ("UnCorrectable Error"));
988}
989
990
991
992
993
994
995
996
997
998
999
1000static ssize_t synps_edac_mc_inject_data_poison_store(struct device *dev,
1001 struct device_attribute *mattr,
1002 const char *data, size_t count)
1003{
1004 struct mem_ctl_info *mci = to_mci(dev);
1005 struct synps_edac_priv *priv = mci->pvt_info;
1006
1007 writel(0, priv->baseaddr + DDRC_SWCTL);
1008 if (strncmp(data, "CE", 2) == 0)
1009 writel(ECC_CEPOISON_MASK, priv->baseaddr + ECC_CFG1_OFST);
1010 else
1011 writel(ECC_UEPOISON_MASK, priv->baseaddr + ECC_CFG1_OFST);
1012 writel(1, priv->baseaddr + DDRC_SWCTL);
1013
1014 return count;
1015}
1016
1017static DEVICE_ATTR(inject_data_error, 0644,
1018 synps_edac_mc_inject_data_error_show,
1019 synps_edac_mc_inject_data_error_store);
1020static DEVICE_ATTR(inject_data_poison, 0644,
1021 synps_edac_mc_inject_data_poison_show,
1022 synps_edac_mc_inject_data_poison_store);
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032static int synps_edac_create_sysfs_attributes(struct mem_ctl_info *mci)
1033{
1034 int rc;
1035
1036 rc = device_create_file(&mci->dev, &dev_attr_inject_data_error);
1037 if (rc < 0)
1038 return rc;
1039 rc = device_create_file(&mci->dev, &dev_attr_inject_data_poison);
1040 if (rc < 0)
1041 return rc;
1042 return 0;
1043}
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053static void synps_edac_remove_sysfs_attributes(struct mem_ctl_info *mci)
1054{
1055 device_remove_file(&mci->dev, &dev_attr_inject_data_error);
1056 device_remove_file(&mci->dev, &dev_attr_inject_data_poison);
1057}
1058
1059
1060
1061
1062
1063
1064
1065
1066static void setup_address_map(struct synps_edac_priv *priv)
1067{
1068 u32 addrmap[12], addrmap_row_b2_10;
1069 int index;
1070 u32 width, memtype;
1071
1072 memtype = readl(priv->baseaddr + CTRL_OFST);
1073 width = (memtype & ECC_CTRL_BUSWIDTH_MASK) >> ECC_CTRL_BUSWIDTH_SHIFT;
1074
1075 for (index = 0; index < 12; index++) {
1076 u32 addrmap_offset;
1077
1078 addrmap_offset = ECC_ADDRMAP0_OFFSET + (index * 4);
1079 addrmap[index] = readl(priv->baseaddr + addrmap_offset);
1080 }
1081
1082 priv->row_shift[0] = (addrmap[5] & ROW_MAX_VAL_MASK) + ROW_B0_BASE;
1083 priv->row_shift[1] = ((addrmap[5] >> 8) &
1084 ROW_MAX_VAL_MASK) + ROW_B1_BASE;
1085
1086 addrmap_row_b2_10 = (addrmap[5] >> 16) & ROW_MAX_VAL_MASK;
1087 if (addrmap_row_b2_10 != ROW_MAX_VAL_MASK) {
1088 for (index = 2; index < 11; index++)
1089 priv->row_shift[index] = addrmap_row_b2_10 +
1090 index + ROW_B0_BASE;
1091
1092 } else {
1093 priv->row_shift[2] = (addrmap[9] &
1094 ROW_MAX_VAL_MASK) + ROW_B2_BASE;
1095 priv->row_shift[3] = ((addrmap[9] >> 8) &
1096 ROW_MAX_VAL_MASK) + ROW_B3_BASE;
1097 priv->row_shift[4] = ((addrmap[9] >> 16) &
1098 ROW_MAX_VAL_MASK) + ROW_B4_BASE;
1099 priv->row_shift[5] = ((addrmap[9] >> 24) &
1100 ROW_MAX_VAL_MASK) + ROW_B5_BASE;
1101 priv->row_shift[6] = (addrmap[10] &
1102 ROW_MAX_VAL_MASK) + ROW_B6_BASE;
1103 priv->row_shift[7] = ((addrmap[10] >> 8) &
1104 ROW_MAX_VAL_MASK) + ROW_B7_BASE;
1105 priv->row_shift[8] = ((addrmap[10] >> 16) &
1106 ROW_MAX_VAL_MASK) + ROW_B8_BASE;
1107 priv->row_shift[9] = ((addrmap[10] >> 24) &
1108 ROW_MAX_VAL_MASK) + ROW_B9_BASE;
1109 priv->row_shift[10] = (addrmap[11] &
1110 ROW_MAX_VAL_MASK) + ROW_B10_BASE;
1111 }
1112
1113 priv->row_shift[11] = (((addrmap[5] >> 24) & ROW_MAX_VAL_MASK) ==
1114 ROW_MAX_VAL_MASK) ? 0 : (((addrmap[5] >> 24) &
1115 ROW_MAX_VAL_MASK) + ROW_B11_BASE);
1116 priv->row_shift[12] = ((addrmap[6] & ROW_MAX_VAL_MASK) ==
1117 ROW_MAX_VAL_MASK) ? 0 : ((addrmap[6] &
1118 ROW_MAX_VAL_MASK) + ROW_B12_BASE);
1119 priv->row_shift[13] = (((addrmap[6] >> 8) & ROW_MAX_VAL_MASK) ==
1120 ROW_MAX_VAL_MASK) ? 0 : (((addrmap[6] >> 8) &
1121 ROW_MAX_VAL_MASK) + ROW_B13_BASE);
1122 priv->row_shift[14] = (((addrmap[6] >> 16) & ROW_MAX_VAL_MASK) ==
1123 ROW_MAX_VAL_MASK) ? 0 : (((addrmap[6] >> 16) &
1124 ROW_MAX_VAL_MASK) + ROW_B14_BASE);
1125 priv->row_shift[15] = (((addrmap[6] >> 24) & ROW_MAX_VAL_MASK) ==
1126 ROW_MAX_VAL_MASK) ? 0 : (((addrmap[6] >> 24) &
1127 ROW_MAX_VAL_MASK) + ROW_B15_BASE);
1128 priv->row_shift[16] = ((addrmap[7] & ROW_MAX_VAL_MASK) ==
1129 ROW_MAX_VAL_MASK) ? 0 : ((addrmap[7] &
1130 ROW_MAX_VAL_MASK) + ROW_B16_BASE);
1131 priv->row_shift[17] = (((addrmap[7] >> 8) & ROW_MAX_VAL_MASK) ==
1132 ROW_MAX_VAL_MASK) ? 0 : (((addrmap[7] >> 8) &
1133 ROW_MAX_VAL_MASK) + ROW_B17_BASE);
1134
1135 priv->col_shift[0] = 0;
1136 priv->col_shift[1] = 1;
1137 priv->col_shift[2] = (addrmap[2] & COL_MAX_VAL_MASK) + COL_B2_BASE;
1138 priv->col_shift[3] = ((addrmap[2] >> 8) &
1139 COL_MAX_VAL_MASK) + COL_B3_BASE;
1140 priv->col_shift[4] = (((addrmap[2] >> 16) & COL_MAX_VAL_MASK) ==
1141 COL_MAX_VAL_MASK) ? 0 : (((addrmap[2] >> 16) &
1142 COL_MAX_VAL_MASK) + COL_B4_BASE);
1143 priv->col_shift[5] = (((addrmap[2] >> 24) & COL_MAX_VAL_MASK) ==
1144 COL_MAX_VAL_MASK) ? 0 : (((addrmap[2] >> 24) &
1145 COL_MAX_VAL_MASK) + COL_B5_BASE);
1146 priv->col_shift[6] = ((addrmap[3] & COL_MAX_VAL_MASK) ==
1147 COL_MAX_VAL_MASK) ? 0 : ((addrmap[3] &
1148 COL_MAX_VAL_MASK) + COL_B6_BASE);
1149 priv->col_shift[7] = (((addrmap[3] >> 8) & COL_MAX_VAL_MASK) ==
1150 COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 8) &
1151 COL_MAX_VAL_MASK) + COL_B7_BASE);
1152 priv->col_shift[8] = (((addrmap[3] >> 16) & COL_MAX_VAL_MASK) ==
1153 COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 16) &
1154 COL_MAX_VAL_MASK) + COL_B8_BASE);
1155 priv->col_shift[9] = (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) ==
1156 COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 24) &
1157 COL_MAX_VAL_MASK) + COL_B9_BASE);
1158 if (width == DDRCTL_EWDTH_64) {
1159 if (memtype & MEM_TYPE_LPDDR3) {
1160 priv->col_shift[10] = ((addrmap[4] &
1161 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1162 ((addrmap[4] & COL_MAX_VAL_MASK) +
1163 COL_B10_BASE);
1164 priv->col_shift[11] = (((addrmap[4] >> 8) &
1165 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1166 (((addrmap[4] >> 8) & COL_MAX_VAL_MASK) +
1167 COL_B11_BASE);
1168 } else {
1169 priv->col_shift[11] = ((addrmap[4] &
1170 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1171 ((addrmap[4] & COL_MAX_VAL_MASK) +
1172 COL_B10_BASE);
1173 priv->col_shift[13] = (((addrmap[4] >> 8) &
1174 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1175 (((addrmap[4] >> 8) & COL_MAX_VAL_MASK) +
1176 COL_B11_BASE);
1177 }
1178 } else if (width == DDRCTL_EWDTH_32) {
1179 if (memtype & MEM_TYPE_LPDDR3) {
1180 priv->col_shift[10] = (((addrmap[3] >> 24) &
1181 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1182 (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
1183 COL_B9_BASE);
1184 priv->col_shift[11] = ((addrmap[4] &
1185 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1186 ((addrmap[4] & COL_MAX_VAL_MASK) +
1187 COL_B10_BASE);
1188 } else {
1189 priv->col_shift[11] = (((addrmap[3] >> 24) &
1190 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1191 (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
1192 COL_B9_BASE);
1193 priv->col_shift[13] = ((addrmap[4] &
1194 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1195 ((addrmap[4] & COL_MAX_VAL_MASK) +
1196 COL_B10_BASE);
1197 }
1198 } else {
1199 if (memtype & MEM_TYPE_LPDDR3) {
1200 priv->col_shift[10] = (((addrmap[3] >> 16) &
1201 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1202 (((addrmap[3] >> 16) & COL_MAX_VAL_MASK) +
1203 COL_B8_BASE);
1204 priv->col_shift[11] = (((addrmap[3] >> 24) &
1205 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1206 (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
1207 COL_B9_BASE);
1208 priv->col_shift[13] = ((addrmap[4] &
1209 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1210 ((addrmap[4] & COL_MAX_VAL_MASK) +
1211 COL_B10_BASE);
1212 } else {
1213 priv->col_shift[11] = (((addrmap[3] >> 16) &
1214 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1215 (((addrmap[3] >> 16) & COL_MAX_VAL_MASK) +
1216 COL_B8_BASE);
1217 priv->col_shift[13] = (((addrmap[3] >> 24) &
1218 COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
1219 (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
1220 COL_B9_BASE);
1221 }
1222 }
1223
1224 if (width) {
1225 for (index = 9; index > width; index--) {
1226 priv->col_shift[index] = priv->col_shift[index - width];
1227 priv->col_shift[index - width] = 0;
1228 }
1229 }
1230
1231 priv->bank_shift[0] = (addrmap[1] & BANK_MAX_VAL_MASK) + BANK_B0_BASE;
1232 priv->bank_shift[1] = ((addrmap[1] >> 8) &
1233 BANK_MAX_VAL_MASK) + BANK_B1_BASE;
1234 priv->bank_shift[2] = (((addrmap[1] >> 16) &
1235 BANK_MAX_VAL_MASK) == BANK_MAX_VAL_MASK) ? 0 :
1236 (((addrmap[1] >> 16) & BANK_MAX_VAL_MASK) +
1237 BANK_B2_BASE);
1238
1239 priv->bankgrp_shift[0] = (addrmap[8] &
1240 BANKGRP_MAX_VAL_MASK) + BANKGRP_B0_BASE;
1241 priv->bankgrp_shift[1] = (((addrmap[8] >> 8) & BANKGRP_MAX_VAL_MASK) ==
1242 BANKGRP_MAX_VAL_MASK) ? 0 : (((addrmap[8] >> 8)
1243 & BANKGRP_MAX_VAL_MASK) + BANKGRP_B1_BASE);
1244
1245 priv->rank_shift[0] = ((addrmap[0] & RANK_MAX_VAL_MASK) ==
1246 RANK_MAX_VAL_MASK) ? 0 : ((addrmap[0] &
1247 RANK_MAX_VAL_MASK) + RANK_B0_BASE);
1248}
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259static int synps_edac_mc_probe(struct platform_device *pdev)
1260{
1261 struct mem_ctl_info *mci;
1262 struct edac_mc_layer layers[2];
1263 struct synps_edac_priv *priv;
1264 int rc, irq, status;
1265 struct resource *res;
1266 void __iomem *baseaddr;
1267 const struct of_device_id *match;
1268 const struct synps_platform_data *p_data;
1269
1270 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1271 baseaddr = devm_ioremap_resource(&pdev->dev, res);
1272 if (IS_ERR(baseaddr))
1273 return PTR_ERR(baseaddr);
1274
1275 match = of_match_node(synps_edac_match, pdev->dev.of_node);
1276 if (!match && !match->data) {
1277 dev_err(&pdev->dev, "of_match_node() failed\n");
1278 return -EINVAL;
1279 }
1280
1281 p_data = (struct synps_platform_data *)match->data;
1282 if (!(p_data->synps_edac_get_eccstate(baseaddr))) {
1283 edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
1284 return -ENXIO;
1285 }
1286
1287 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
1288 layers[0].size = SYNPS_EDAC_NR_CSROWS;
1289 layers[0].is_virt_csrow = true;
1290 layers[1].type = EDAC_MC_LAYER_CHANNEL;
1291 layers[1].size = SYNPS_EDAC_NR_CHANS;
1292 layers[1].is_virt_csrow = false;
1293
1294 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
1295 sizeof(struct synps_edac_priv));
1296 if (!mci) {
1297 edac_printk(KERN_ERR, EDAC_MC,
1298 "Failed memory allocation for mc instance\n");
1299 return -ENOMEM;
1300 }
1301
1302 priv = mci->pvt_info;
1303 priv->baseaddr = baseaddr;
1304 priv->p_data = match->data;
1305
1306 rc = synps_edac_mc_init(mci, pdev);
1307 if (rc) {
1308 edac_printk(KERN_ERR, EDAC_MC,
1309 "Failed to initialize instance\n");
1310 goto free_edac_mc;
1311 }
1312
1313 if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT) {
1314 irq = platform_get_irq(pdev, 0);
1315 if (irq < 0) {
1316 edac_printk(KERN_ERR, EDAC_MC,
1317 "No irq %d in DT\n", irq);
1318 return -ENODEV;
1319 }
1320
1321 status = devm_request_irq(&pdev->dev, irq,
1322 synps_edac_intr_handler,
1323 0, dev_name(&pdev->dev), mci);
1324 if (status < 0) {
1325 edac_printk(KERN_ERR, EDAC_MC, "Failed to request Irq\n");
1326 goto free_edac_mc;
1327 }
1328
1329
1330 writel((DDR_QOSUE_MASK | DDR_QOSCE_MASK),
1331 priv->baseaddr + DDR_QOS_IRQ_EN_OFST);
1332 }
1333
1334 rc = edac_mc_add_mc(mci);
1335 if (rc) {
1336 edac_printk(KERN_ERR, EDAC_MC,
1337 "Failed to register with EDAC core\n");
1338 goto free_edac_mc;
1339 }
1340
1341 if (priv->p_data->quirks & DDR_ECC_DATA_POISON_SUPPORT) {
1342 if (synps_edac_create_sysfs_attributes(mci)) {
1343 edac_printk(KERN_ERR, EDAC_MC,
1344 "Failed to create sysfs entries\n");
1345 goto free_edac_mc;
1346 }
1347 }
1348
1349 if (of_device_is_compatible(pdev->dev.of_node,
1350 "xlnx,zynqmp-ddrc-2.40a"))
1351 setup_address_map(priv);
1352
1353
1354
1355
1356
1357 if (!(priv->p_data->quirks & DDR_ECC_INTR_SUPPORT))
1358 writel(0x0, baseaddr + ECC_CTRL_OFST);
1359 return rc;
1360
1361free_edac_mc:
1362 edac_mc_free(mci);
1363
1364 return rc;
1365}
1366
1367
1368
1369
1370
1371
1372
1373static int synps_edac_mc_remove(struct platform_device *pdev)
1374{
1375 struct mem_ctl_info *mci = platform_get_drvdata(pdev);
1376 struct synps_edac_priv *priv;
1377
1378 priv = mci->pvt_info;
1379 if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT)
1380
1381 writel((DDR_QOSUE_MASK | DDR_QOSCE_MASK),
1382 priv->baseaddr + DDR_QOS_IRQ_DB_OFST);
1383 edac_mc_del_mc(&pdev->dev);
1384 if (priv->p_data->quirks & DDR_ECC_DATA_POISON_SUPPORT)
1385 synps_edac_remove_sysfs_attributes(mci);
1386 edac_mc_free(mci);
1387
1388 return 0;
1389}
1390
1391static struct platform_driver synps_edac_mc_driver = {
1392 .driver = {
1393 .name = "synopsys-edac",
1394 .of_match_table = synps_edac_match,
1395 },
1396 .probe = synps_edac_mc_probe,
1397 .remove = synps_edac_mc_remove,
1398};
1399
1400module_platform_driver(synps_edac_mc_driver);
1401
1402MODULE_AUTHOR("Xilinx Inc");
1403MODULE_DESCRIPTION("Synopsys DDR ECC driver");
1404MODULE_LICENSE("GPL v2");
1405