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