xref: /OK3568_Linux_fs/kernel/drivers/edac/synopsys_edac.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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