]>
Commit | Line | Data |
---|---|---|
ae9b56e3 PCK |
1 | /* |
2 | * Synopsys DDR ECC Driver | |
3 | * This driver is based on ppc4xx_edac.c drivers | |
4 | * | |
5 | * Copyright (C) 2012 - 2014 Xilinx, Inc. | |
6 | * | |
7 | * This program is free software: you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation, either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * This file is subject to the terms and conditions of the GNU General Public | |
18 | * License. See the file "COPYING" in the main directory of this archive | |
19 | * for more details | |
20 | */ | |
21 | ||
22 | #include <linux/edac.h> | |
23 | #include <linux/module.h> | |
24 | #include <linux/platform_device.h> | |
3d02a897 MN |
25 | #include <linux/of.h> |
26 | #include <linux/of_device.h> | |
ae9b56e3 | 27 | |
78d88e8a | 28 | #include "edac_module.h" |
ae9b56e3 PCK |
29 | |
30 | /* Number of cs_rows needed per memory controller */ | |
1b51adc6 | 31 | #define SYNPS_EDAC_NR_CSROWS 1 |
ae9b56e3 PCK |
32 | |
33 | /* Number of channels per memory controller */ | |
1b51adc6 | 34 | #define SYNPS_EDAC_NR_CHANS 1 |
ae9b56e3 PCK |
35 | |
36 | /* Granularity of reported error in bytes */ | |
1b51adc6 | 37 | #define SYNPS_EDAC_ERR_GRAIN 1 |
ae9b56e3 | 38 | |
1b51adc6 | 39 | #define SYNPS_EDAC_MSG_SIZE 256 |
ae9b56e3 | 40 | |
1b51adc6 MN |
41 | #define SYNPS_EDAC_MOD_STRING "synps_edac" |
42 | #define SYNPS_EDAC_MOD_VER "1" | |
ae9b56e3 PCK |
43 | |
44 | /* Synopsys DDR memory controller registers that are relevant to ECC */ | |
1b51adc6 MN |
45 | #define CTRL_OFST 0x0 |
46 | #define T_ZQ_OFST 0xA4 | |
ae9b56e3 PCK |
47 | |
48 | /* ECC control register */ | |
1b51adc6 | 49 | #define ECC_CTRL_OFST 0xC4 |
ae9b56e3 | 50 | /* ECC log register */ |
1b51adc6 | 51 | #define CE_LOG_OFST 0xC8 |
ae9b56e3 | 52 | /* ECC address register */ |
1b51adc6 | 53 | #define CE_ADDR_OFST 0xCC |
ae9b56e3 | 54 | /* ECC data[31:0] register */ |
1b51adc6 | 55 | #define CE_DATA_31_0_OFST 0xD0 |
ae9b56e3 PCK |
56 | |
57 | /* Uncorrectable error info registers */ | |
1b51adc6 MN |
58 | #define UE_LOG_OFST 0xDC |
59 | #define UE_ADDR_OFST 0xE0 | |
60 | #define UE_DATA_31_0_OFST 0xE4 | |
ae9b56e3 | 61 | |
1b51adc6 MN |
62 | #define STAT_OFST 0xF0 |
63 | #define SCRUB_OFST 0xF4 | |
ae9b56e3 PCK |
64 | |
65 | /* Control register bit field definitions */ | |
1b51adc6 MN |
66 | #define CTRL_BW_MASK 0xC |
67 | #define CTRL_BW_SHIFT 2 | |
ae9b56e3 | 68 | |
1b51adc6 MN |
69 | #define DDRCTL_WDTH_16 1 |
70 | #define DDRCTL_WDTH_32 0 | |
ae9b56e3 PCK |
71 | |
72 | /* ZQ register bit field definitions */ | |
1b51adc6 | 73 | #define T_ZQ_DDRMODE_MASK 0x2 |
ae9b56e3 PCK |
74 | |
75 | /* ECC control register bit field definitions */ | |
1b51adc6 MN |
76 | #define ECC_CTRL_CLR_CE_ERR 0x2 |
77 | #define ECC_CTRL_CLR_UE_ERR 0x1 | |
ae9b56e3 PCK |
78 | |
79 | /* ECC correctable/uncorrectable error log register definitions */ | |
1b51adc6 MN |
80 | #define LOG_VALID 0x1 |
81 | #define CE_LOG_BITPOS_MASK 0xFE | |
82 | #define CE_LOG_BITPOS_SHIFT 1 | |
ae9b56e3 PCK |
83 | |
84 | /* ECC correctable/uncorrectable error address register definitions */ | |
1b51adc6 MN |
85 | #define ADDR_COL_MASK 0xFFF |
86 | #define ADDR_ROW_MASK 0xFFFF000 | |
87 | #define ADDR_ROW_SHIFT 12 | |
88 | #define ADDR_BANK_MASK 0x70000000 | |
89 | #define ADDR_BANK_SHIFT 28 | |
ae9b56e3 PCK |
90 | |
91 | /* ECC statistic register definitions */ | |
1b51adc6 MN |
92 | #define STAT_UECNT_MASK 0xFF |
93 | #define STAT_CECNT_MASK 0xFF00 | |
94 | #define STAT_CECNT_SHIFT 8 | |
ae9b56e3 PCK |
95 | |
96 | /* ECC scrub register definitions */ | |
1b51adc6 MN |
97 | #define SCRUB_MODE_MASK 0x7 |
98 | #define SCRUB_MODE_SECDED 0x4 | |
ae9b56e3 | 99 | |
e926ae57 MN |
100 | /* DDR ECC Quirks */ |
101 | #define DDR_ECC_INTR_SUPPORT BIT(0) | |
102 | #define DDR_ECC_DATA_POISON_SUPPORT BIT(1) | |
103 | ||
104 | /* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ | |
105 | /* ECC Configuration Registers */ | |
106 | #define ECC_CFG0_OFST 0x70 | |
107 | #define ECC_CFG1_OFST 0x74 | |
108 | ||
109 | /* ECC Status Register */ | |
110 | #define ECC_STAT_OFST 0x78 | |
111 | ||
112 | /* ECC Clear Register */ | |
113 | #define ECC_CLR_OFST 0x7C | |
114 | ||
115 | /* ECC Error count Register */ | |
116 | #define ECC_ERRCNT_OFST 0x80 | |
117 | ||
118 | /* ECC Corrected Error Address Register */ | |
119 | #define ECC_CEADDR0_OFST 0x84 | |
120 | #define ECC_CEADDR1_OFST 0x88 | |
121 | ||
122 | /* ECC Syndrome Registers */ | |
123 | #define ECC_CSYND0_OFST 0x8C | |
124 | #define ECC_CSYND1_OFST 0x90 | |
125 | #define ECC_CSYND2_OFST 0x94 | |
126 | ||
127 | /* ECC Bit Mask0 Address Register */ | |
128 | #define ECC_BITMASK0_OFST 0x98 | |
129 | #define ECC_BITMASK1_OFST 0x9C | |
130 | #define ECC_BITMASK2_OFST 0xA0 | |
131 | ||
132 | /* ECC UnCorrected Error Address Register */ | |
133 | #define ECC_UEADDR0_OFST 0xA4 | |
134 | #define ECC_UEADDR1_OFST 0xA8 | |
135 | ||
136 | /* ECC Syndrome Registers */ | |
137 | #define ECC_UESYND0_OFST 0xAC | |
138 | #define ECC_UESYND1_OFST 0xB0 | |
139 | #define ECC_UESYND2_OFST 0xB4 | |
140 | ||
141 | /* ECC Poison Address Reg */ | |
142 | #define ECC_POISON0_OFST 0xB8 | |
143 | #define ECC_POISON1_OFST 0xBC | |
144 | ||
145 | #define ECC_ADDRMAP0_OFFSET 0x200 | |
146 | ||
147 | /* Control register bitfield definitions */ | |
148 | #define ECC_CTRL_BUSWIDTH_MASK 0x3000 | |
149 | #define ECC_CTRL_BUSWIDTH_SHIFT 12 | |
150 | #define ECC_CTRL_CLR_CE_ERRCNT BIT(2) | |
151 | #define ECC_CTRL_CLR_UE_ERRCNT BIT(3) | |
152 | ||
153 | /* DDR Control Register width definitions */ | |
154 | #define DDRCTL_EWDTH_16 2 | |
155 | #define DDRCTL_EWDTH_32 1 | |
156 | #define DDRCTL_EWDTH_64 0 | |
157 | ||
158 | /* ECC status register definitions */ | |
159 | #define ECC_STAT_UECNT_MASK 0xF0000 | |
160 | #define ECC_STAT_UECNT_SHIFT 16 | |
161 | #define ECC_STAT_CECNT_MASK 0xF00 | |
162 | #define ECC_STAT_CECNT_SHIFT 8 | |
163 | #define ECC_STAT_BITNUM_MASK 0x7F | |
164 | ||
165 | /* DDR QOS Interrupt register definitions */ | |
166 | #define DDR_QOS_IRQ_STAT_OFST 0x20200 | |
167 | #define DDR_QOSUE_MASK 0x4 | |
168 | #define DDR_QOSCE_MASK 0x2 | |
169 | #define ECC_CE_UE_INTR_MASK 0x6 | |
170 | #define DDR_QOS_IRQ_EN_OFST 0x20208 | |
171 | #define DDR_QOS_IRQ_DB_OFST 0x2020C | |
172 | ||
173 | /* ECC Corrected Error Register Mask and Shifts*/ | |
174 | #define ECC_CEADDR0_RW_MASK 0x3FFFF | |
175 | #define ECC_CEADDR0_RNK_MASK BIT(24) | |
176 | #define ECC_CEADDR1_BNKGRP_MASK 0x3000000 | |
177 | #define ECC_CEADDR1_BNKNR_MASK 0x70000 | |
178 | #define ECC_CEADDR1_BLKNR_MASK 0xFFF | |
179 | #define ECC_CEADDR1_BNKGRP_SHIFT 24 | |
180 | #define ECC_CEADDR1_BNKNR_SHIFT 16 | |
181 | ||
182 | /* ECC Poison register shifts */ | |
183 | #define ECC_POISON0_RANK_SHIFT 24 | |
184 | #define ECC_POISON0_RANK_MASK BIT(24) | |
185 | #define ECC_POISON0_COLUMN_SHIFT 0 | |
186 | #define ECC_POISON0_COLUMN_MASK 0xFFF | |
187 | #define ECC_POISON1_BG_SHIFT 28 | |
188 | #define ECC_POISON1_BG_MASK 0x30000000 | |
189 | #define ECC_POISON1_BANKNR_SHIFT 24 | |
190 | #define ECC_POISON1_BANKNR_MASK 0x7000000 | |
191 | #define ECC_POISON1_ROW_SHIFT 0 | |
192 | #define ECC_POISON1_ROW_MASK 0x3FFFF | |
193 | ||
194 | /* DDR Memory type defines */ | |
195 | #define MEM_TYPE_DDR3 0x1 | |
196 | #define MEM_TYPE_LPDDR3 0x8 | |
197 | #define MEM_TYPE_DDR2 0x4 | |
198 | #define MEM_TYPE_DDR4 0x10 | |
199 | #define MEM_TYPE_LPDDR4 0x20 | |
200 | ||
201 | /* DDRC Software control register */ | |
202 | #define DDRC_SWCTL 0x320 | |
203 | ||
204 | /* DDRC ECC CE & UE poison mask */ | |
205 | #define ECC_CEPOISON_MASK 0x3 | |
206 | #define ECC_UEPOISON_MASK 0x1 | |
207 | ||
208 | /* DDRC Device config masks */ | |
209 | #define DDRC_MSTR_CFG_MASK 0xC0000000 | |
210 | #define DDRC_MSTR_CFG_SHIFT 30 | |
211 | #define DDRC_MSTR_CFG_X4_MASK 0x0 | |
212 | #define DDRC_MSTR_CFG_X8_MASK 0x1 | |
213 | #define DDRC_MSTR_CFG_X16_MASK 0x2 | |
214 | #define DDRC_MSTR_CFG_X32_MASK 0x3 | |
215 | ||
216 | #define DDR_MAX_ROW_SHIFT 18 | |
217 | #define DDR_MAX_COL_SHIFT 14 | |
218 | #define DDR_MAX_BANK_SHIFT 3 | |
219 | #define DDR_MAX_BANKGRP_SHIFT 2 | |
220 | ||
221 | #define ROW_MAX_VAL_MASK 0xF | |
222 | #define COL_MAX_VAL_MASK 0xF | |
223 | #define BANK_MAX_VAL_MASK 0x1F | |
224 | #define BANKGRP_MAX_VAL_MASK 0x1F | |
225 | #define RANK_MAX_VAL_MASK 0x1F | |
226 | ||
227 | #define ROW_B0_BASE 6 | |
228 | #define ROW_B1_BASE 7 | |
229 | #define ROW_B2_BASE 8 | |
230 | #define ROW_B3_BASE 9 | |
231 | #define ROW_B4_BASE 10 | |
232 | #define ROW_B5_BASE 11 | |
233 | #define ROW_B6_BASE 12 | |
234 | #define ROW_B7_BASE 13 | |
235 | #define ROW_B8_BASE 14 | |
236 | #define ROW_B9_BASE 15 | |
237 | #define ROW_B10_BASE 16 | |
238 | #define ROW_B11_BASE 17 | |
239 | #define ROW_B12_BASE 18 | |
240 | #define ROW_B13_BASE 19 | |
241 | #define ROW_B14_BASE 20 | |
242 | #define ROW_B15_BASE 21 | |
243 | #define ROW_B16_BASE 22 | |
244 | #define ROW_B17_BASE 23 | |
245 | ||
246 | #define COL_B2_BASE 2 | |
247 | #define COL_B3_BASE 3 | |
248 | #define COL_B4_BASE 4 | |
249 | #define COL_B5_BASE 5 | |
250 | #define COL_B6_BASE 6 | |
251 | #define COL_B7_BASE 7 | |
252 | #define COL_B8_BASE 8 | |
253 | #define COL_B9_BASE 9 | |
254 | #define COL_B10_BASE 10 | |
255 | #define COL_B11_BASE 11 | |
256 | #define COL_B12_BASE 12 | |
257 | #define COL_B13_BASE 13 | |
258 | ||
259 | #define BANK_B0_BASE 2 | |
260 | #define BANK_B1_BASE 3 | |
261 | #define BANK_B2_BASE 4 | |
262 | ||
263 | #define BANKGRP_B0_BASE 2 | |
264 | #define BANKGRP_B1_BASE 3 | |
265 | ||
266 | #define RANK_B0_BASE 6 | |
267 | ||
ae9b56e3 | 268 | /** |
225af74d MN |
269 | * struct ecc_error_info - ECC error log information. |
270 | * @row: Row number. | |
271 | * @col: Column number. | |
272 | * @bank: Bank number. | |
273 | * @bitpos: Bit position. | |
274 | * @data: Data causing the error. | |
ae9b56e3 PCK |
275 | */ |
276 | struct ecc_error_info { | |
277 | u32 row; | |
278 | u32 col; | |
279 | u32 bank; | |
280 | u32 bitpos; | |
281 | u32 data; | |
282 | }; | |
283 | ||
284 | /** | |
225af74d MN |
285 | * struct synps_ecc_status - ECC status information to report. |
286 | * @ce_cnt: Correctable error count. | |
287 | * @ue_cnt: Uncorrectable error count. | |
288 | * @ceinfo: Correctable error log information. | |
289 | * @ueinfo: Uncorrectable error log information. | |
ae9b56e3 PCK |
290 | */ |
291 | struct synps_ecc_status { | |
292 | u32 ce_cnt; | |
293 | u32 ue_cnt; | |
294 | struct ecc_error_info ceinfo; | |
295 | struct ecc_error_info ueinfo; | |
296 | }; | |
297 | ||
298 | /** | |
225af74d MN |
299 | * struct synps_edac_priv - DDR memory controller private instance data. |
300 | * @baseaddr: Base address of the DDR controller. | |
301 | * @message: Buffer for framing the event specific info. | |
302 | * @stat: ECC status information. | |
3d02a897 | 303 | * @p_data: Platform data. |
225af74d MN |
304 | * @ce_cnt: Correctable Error count. |
305 | * @ue_cnt: Uncorrectable Error count. | |
ae9b56e3 PCK |
306 | */ |
307 | struct synps_edac_priv { | |
308 | void __iomem *baseaddr; | |
309 | char message[SYNPS_EDAC_MSG_SIZE]; | |
310 | struct synps_ecc_status stat; | |
3d02a897 | 311 | const struct synps_platform_data *p_data; |
ae9b56e3 PCK |
312 | u32 ce_cnt; |
313 | u32 ue_cnt; | |
314 | }; | |
315 | ||
316 | /** | |
3d02a897 MN |
317 | * struct synps_platform_data - synps platform data structure. |
318 | * @get_error_info: Get EDAC error info. | |
319 | * @get_mtype: Get mtype. | |
320 | * @get_dtype: Get dtype. | |
321 | * @get_ecc_state: Get ECC state. | |
322 | * @quirks: To differentiate IPs. | |
323 | */ | |
324 | struct synps_platform_data { | |
325 | int (*get_error_info)(struct synps_edac_priv *priv); | |
326 | enum mem_type (*get_mtype)(const void __iomem *base); | |
327 | enum dev_type (*get_dtype)(const void __iomem *base); | |
328 | bool (*get_ecc_state)(void __iomem *base); | |
329 | int quirks; | |
330 | }; | |
331 | ||
332 | /** | |
333 | * zynq_get_error_info - Get the current ECC error info. | |
334 | * @priv: DDR memory controller private instance data. | |
ae9b56e3 | 335 | * |
3d02a897 | 336 | * Return: one if there is no error, otherwise zero. |
ae9b56e3 | 337 | */ |
3d02a897 | 338 | static int zynq_get_error_info(struct synps_edac_priv *priv) |
ae9b56e3 | 339 | { |
3d02a897 | 340 | struct synps_ecc_status *p; |
ae9b56e3 | 341 | u32 regval, clearval = 0; |
3d02a897 MN |
342 | void __iomem *base; |
343 | ||
344 | base = priv->baseaddr; | |
345 | p = &priv->stat; | |
ae9b56e3 PCK |
346 | |
347 | regval = readl(base + STAT_OFST); | |
348 | if (!regval) | |
349 | return 1; | |
350 | ||
351 | p->ce_cnt = (regval & STAT_CECNT_MASK) >> STAT_CECNT_SHIFT; | |
352 | p->ue_cnt = regval & STAT_UECNT_MASK; | |
353 | ||
354 | regval = readl(base + CE_LOG_OFST); | |
355 | if (!(p->ce_cnt && (regval & LOG_VALID))) | |
356 | goto ue_err; | |
357 | ||
358 | p->ceinfo.bitpos = (regval & CE_LOG_BITPOS_MASK) >> CE_LOG_BITPOS_SHIFT; | |
359 | regval = readl(base + CE_ADDR_OFST); | |
360 | p->ceinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT; | |
361 | p->ceinfo.col = regval & ADDR_COL_MASK; | |
362 | p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; | |
363 | p->ceinfo.data = readl(base + CE_DATA_31_0_OFST); | |
1b51adc6 | 364 | edac_dbg(3, "CE bit position: %d data: %d\n", p->ceinfo.bitpos, |
ae9b56e3 PCK |
365 | p->ceinfo.data); |
366 | clearval = ECC_CTRL_CLR_CE_ERR; | |
367 | ||
368 | ue_err: | |
369 | regval = readl(base + UE_LOG_OFST); | |
370 | if (!(p->ue_cnt && (regval & LOG_VALID))) | |
371 | goto out; | |
372 | ||
373 | regval = readl(base + UE_ADDR_OFST); | |
374 | p->ueinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT; | |
375 | p->ueinfo.col = regval & ADDR_COL_MASK; | |
376 | p->ueinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; | |
377 | p->ueinfo.data = readl(base + UE_DATA_31_0_OFST); | |
378 | clearval |= ECC_CTRL_CLR_UE_ERR; | |
379 | ||
380 | out: | |
381 | writel(clearval, base + ECC_CTRL_OFST); | |
382 | writel(0x0, base + ECC_CTRL_OFST); | |
383 | ||
384 | return 0; | |
385 | } | |
386 | ||
387 | /** | |
225af74d MN |
388 | * handle_error - Handle Correctable and Uncorrectable errors. |
389 | * @mci: EDAC memory controller instance. | |
390 | * @p: Synopsys ECC status structure. | |
ae9b56e3 | 391 | * |
225af74d | 392 | * Handles ECC correctable and uncorrectable errors. |
ae9b56e3 | 393 | */ |
bb894bc4 | 394 | static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) |
ae9b56e3 PCK |
395 | { |
396 | struct synps_edac_priv *priv = mci->pvt_info; | |
397 | struct ecc_error_info *pinf; | |
398 | ||
399 | if (p->ce_cnt) { | |
400 | pinf = &p->ceinfo; | |
401 | snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, | |
402 | "DDR ECC error type :%s Row %d Bank %d Col %d ", | |
403 | "CE", pinf->row, pinf->bank, pinf->col); | |
404 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, | |
405 | p->ce_cnt, 0, 0, 0, 0, 0, -1, | |
406 | priv->message, ""); | |
407 | } | |
408 | ||
409 | if (p->ue_cnt) { | |
410 | pinf = &p->ueinfo; | |
411 | snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, | |
412 | "DDR ECC error type :%s Row %d Bank %d Col %d ", | |
413 | "UE", pinf->row, pinf->bank, pinf->col); | |
414 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, | |
415 | p->ue_cnt, 0, 0, 0, 0, 0, -1, | |
416 | priv->message, ""); | |
417 | } | |
418 | ||
419 | memset(p, 0, sizeof(*p)); | |
420 | } | |
421 | ||
422 | /** | |
225af74d MN |
423 | * check_errors - Check controller for ECC errors. |
424 | * @mci: EDAC memory controller instance. | |
ae9b56e3 | 425 | * |
225af74d | 426 | * Check and post ECC errors. Called by the polling thread. |
ae9b56e3 | 427 | */ |
bb894bc4 | 428 | static void check_errors(struct mem_ctl_info *mci) |
ae9b56e3 PCK |
429 | { |
430 | struct synps_edac_priv *priv = mci->pvt_info; | |
3d02a897 | 431 | const struct synps_platform_data *p_data = priv->p_data; |
ae9b56e3 PCK |
432 | int status; |
433 | ||
3d02a897 | 434 | status = p_data->get_error_info(priv); |
ae9b56e3 PCK |
435 | if (status) |
436 | return; | |
437 | ||
438 | priv->ce_cnt += priv->stat.ce_cnt; | |
439 | priv->ue_cnt += priv->stat.ue_cnt; | |
bb894bc4 | 440 | handle_error(mci, &priv->stat); |
ae9b56e3 | 441 | |
1b51adc6 | 442 | edac_dbg(3, "Total error count CE %d UE %d\n", |
ae9b56e3 PCK |
443 | priv->ce_cnt, priv->ue_cnt); |
444 | } | |
445 | ||
446 | /** | |
3d02a897 | 447 | * zynq_get_dtype - Return the controller memory width. |
225af74d | 448 | * @base: DDR memory controller base address. |
ae9b56e3 PCK |
449 | * |
450 | * Get the EDAC device type width appropriate for the current controller | |
451 | * configuration. | |
452 | * | |
453 | * Return: a device type width enumeration. | |
454 | */ | |
3d02a897 | 455 | static enum dev_type zynq_get_dtype(const void __iomem *base) |
ae9b56e3 PCK |
456 | { |
457 | enum dev_type dt; | |
458 | u32 width; | |
459 | ||
460 | width = readl(base + CTRL_OFST); | |
461 | width = (width & CTRL_BW_MASK) >> CTRL_BW_SHIFT; | |
462 | ||
463 | switch (width) { | |
464 | case DDRCTL_WDTH_16: | |
465 | dt = DEV_X2; | |
466 | break; | |
467 | case DDRCTL_WDTH_32: | |
468 | dt = DEV_X4; | |
469 | break; | |
470 | default: | |
471 | dt = DEV_UNKNOWN; | |
472 | } | |
473 | ||
474 | return dt; | |
475 | } | |
476 | ||
477 | /** | |
3d02a897 | 478 | * zynq_get_ecc_state - Return the controller ECC enable/disable status. |
225af74d | 479 | * @base: DDR memory controller base address. |
ae9b56e3 | 480 | * |
225af74d | 481 | * Get the ECC enable/disable status of the controller. |
ae9b56e3 | 482 | * |
225af74d | 483 | * Return: true if enabled, otherwise false. |
ae9b56e3 | 484 | */ |
3d02a897 | 485 | static bool zynq_get_ecc_state(void __iomem *base) |
ae9b56e3 | 486 | { |
1b51adc6 | 487 | bool state = false; |
ae9b56e3 PCK |
488 | enum dev_type dt; |
489 | u32 ecctype; | |
ae9b56e3 | 490 | |
3d02a897 | 491 | dt = zynq_get_dtype(base); |
ae9b56e3 PCK |
492 | if (dt == DEV_UNKNOWN) |
493 | return state; | |
494 | ||
495 | ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK; | |
496 | if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2)) | |
497 | state = true; | |
498 | ||
499 | return state; | |
500 | } | |
501 | ||
502 | /** | |
225af74d | 503 | * get_memsize - Read the size of the attached memory device. |
ae9b56e3 | 504 | * |
225af74d | 505 | * Return: the memory size in bytes. |
ae9b56e3 | 506 | */ |
bb894bc4 | 507 | static u32 get_memsize(void) |
ae9b56e3 PCK |
508 | { |
509 | struct sysinfo inf; | |
510 | ||
511 | si_meminfo(&inf); | |
512 | ||
513 | return inf.totalram * inf.mem_unit; | |
514 | } | |
515 | ||
516 | /** | |
3d02a897 | 517 | * zynq_get_mtype - Return the controller memory type. |
225af74d | 518 | * @base: Synopsys ECC status structure. |
ae9b56e3 PCK |
519 | * |
520 | * Get the EDAC memory type appropriate for the current controller | |
521 | * configuration. | |
522 | * | |
523 | * Return: a memory type enumeration. | |
524 | */ | |
3d02a897 | 525 | static enum mem_type zynq_get_mtype(const void __iomem *base) |
ae9b56e3 PCK |
526 | { |
527 | enum mem_type mt; | |
528 | u32 memtype; | |
529 | ||
530 | memtype = readl(base + T_ZQ_OFST); | |
531 | ||
532 | if (memtype & T_ZQ_DDRMODE_MASK) | |
533 | mt = MEM_DDR3; | |
534 | else | |
535 | mt = MEM_DDR2; | |
536 | ||
537 | return mt; | |
538 | } | |
539 | ||
540 | /** | |
225af74d MN |
541 | * init_csrows - Initialize the csrow data. |
542 | * @mci: EDAC memory controller instance. | |
ae9b56e3 | 543 | * |
225af74d MN |
544 | * Initialize the chip select rows associated with the EDAC memory |
545 | * controller instance. | |
ae9b56e3 | 546 | */ |
fa9f6b9e | 547 | static void init_csrows(struct mem_ctl_info *mci) |
ae9b56e3 | 548 | { |
1b51adc6 | 549 | struct synps_edac_priv *priv = mci->pvt_info; |
3d02a897 | 550 | const struct synps_platform_data *p_data; |
ae9b56e3 PCK |
551 | struct csrow_info *csi; |
552 | struct dimm_info *dimm; | |
1b51adc6 MN |
553 | u32 size, row; |
554 | int j; | |
ae9b56e3 | 555 | |
3d02a897 MN |
556 | p_data = priv->p_data; |
557 | ||
ae9b56e3 PCK |
558 | for (row = 0; row < mci->nr_csrows; row++) { |
559 | csi = mci->csrows[row]; | |
bb894bc4 | 560 | size = get_memsize(); |
ae9b56e3 PCK |
561 | |
562 | for (j = 0; j < csi->nr_channels; j++) { | |
1b51adc6 MN |
563 | dimm = csi->channels[j]->dimm; |
564 | dimm->edac_mode = EDAC_FLAG_SECDED; | |
3d02a897 | 565 | dimm->mtype = p_data->get_mtype(priv->baseaddr); |
1b51adc6 MN |
566 | dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; |
567 | dimm->grain = SYNPS_EDAC_ERR_GRAIN; | |
3d02a897 | 568 | dimm->dtype = p_data->get_dtype(priv->baseaddr); |
ae9b56e3 PCK |
569 | } |
570 | } | |
ae9b56e3 PCK |
571 | } |
572 | ||
573 | /** | |
225af74d MN |
574 | * mc_init - Initialize one driver instance. |
575 | * @mci: EDAC memory controller instance. | |
576 | * @pdev: platform device. | |
ae9b56e3 | 577 | * |
225af74d | 578 | * Perform initialization of the EDAC memory controller instance and |
ae9b56e3 PCK |
579 | * related driver-private data associated with the memory controller the |
580 | * instance is bound to. | |
ae9b56e3 | 581 | */ |
fa9f6b9e | 582 | static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev) |
ae9b56e3 | 583 | { |
ae9b56e3 PCK |
584 | struct synps_edac_priv *priv; |
585 | ||
586 | mci->pdev = &pdev->dev; | |
587 | priv = mci->pvt_info; | |
588 | platform_set_drvdata(pdev, mci); | |
589 | ||
590 | /* Initialize controller capabilities and configuration */ | |
591 | mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2; | |
592 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | |
593 | mci->scrub_cap = SCRUB_HW_SRC; | |
594 | mci->scrub_mode = SCRUB_NONE; | |
595 | ||
596 | mci->edac_cap = EDAC_FLAG_SECDED; | |
597 | mci->ctl_name = "synps_ddr_controller"; | |
598 | mci->dev_name = SYNPS_EDAC_MOD_STRING; | |
599 | mci->mod_name = SYNPS_EDAC_MOD_VER; | |
ae9b56e3 PCK |
600 | |
601 | edac_op_state = EDAC_OPSTATE_POLL; | |
bb894bc4 | 602 | mci->edac_check = check_errors; |
ae9b56e3 PCK |
603 | mci->ctl_page_to_phys = NULL; |
604 | ||
fa9f6b9e | 605 | init_csrows(mci); |
ae9b56e3 PCK |
606 | } |
607 | ||
3d02a897 MN |
608 | static const struct synps_platform_data zynq_edac_def = { |
609 | .get_error_info = zynq_get_error_info, | |
610 | .get_mtype = zynq_get_mtype, | |
611 | .get_dtype = zynq_get_dtype, | |
612 | .get_ecc_state = zynq_get_ecc_state, | |
613 | .quirks = 0, | |
614 | }; | |
615 | ||
616 | static const struct of_device_id synps_edac_match[] = { | |
617 | { .compatible = "xlnx,zynq-ddrc-a05", .data = (void *)&zynq_edac_def }, | |
618 | { /* end of table */ } | |
619 | }; | |
620 | ||
621 | MODULE_DEVICE_TABLE(of, synps_edac_match); | |
622 | ||
ae9b56e3 | 623 | /** |
225af74d MN |
624 | * mc_probe - Check controller and bind driver. |
625 | * @pdev: platform device. | |
ae9b56e3 | 626 | * |
225af74d | 627 | * Probe a specific controller instance for binding with the driver. |
ae9b56e3 PCK |
628 | * |
629 | * Return: 0 if the controller instance was successfully bound to the | |
630 | * driver; otherwise, < 0 on error. | |
631 | */ | |
bb894bc4 | 632 | static int mc_probe(struct platform_device *pdev) |
ae9b56e3 | 633 | { |
3d02a897 | 634 | const struct synps_platform_data *p_data; |
ae9b56e3 PCK |
635 | struct edac_mc_layer layers[2]; |
636 | struct synps_edac_priv *priv; | |
1b51adc6 | 637 | struct mem_ctl_info *mci; |
ae9b56e3 | 638 | void __iomem *baseaddr; |
1b51adc6 MN |
639 | struct resource *res; |
640 | int rc; | |
ae9b56e3 PCK |
641 | |
642 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
643 | baseaddr = devm_ioremap_resource(&pdev->dev, res); | |
644 | if (IS_ERR(baseaddr)) | |
645 | return PTR_ERR(baseaddr); | |
646 | ||
3d02a897 | 647 | p_data = of_device_get_match_data(&pdev->dev); |
84de0b49 MN |
648 | if (!p_data) |
649 | return -ENODEV; | |
650 | ||
3d02a897 | 651 | if (!p_data->get_ecc_state(baseaddr)) { |
ae9b56e3 PCK |
652 | edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); |
653 | return -ENXIO; | |
654 | } | |
655 | ||
656 | layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; | |
657 | layers[0].size = SYNPS_EDAC_NR_CSROWS; | |
658 | layers[0].is_virt_csrow = true; | |
659 | layers[1].type = EDAC_MC_LAYER_CHANNEL; | |
660 | layers[1].size = SYNPS_EDAC_NR_CHANS; | |
661 | layers[1].is_virt_csrow = false; | |
662 | ||
663 | mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, | |
664 | sizeof(struct synps_edac_priv)); | |
665 | if (!mci) { | |
666 | edac_printk(KERN_ERR, EDAC_MC, | |
667 | "Failed memory allocation for mc instance\n"); | |
668 | return -ENOMEM; | |
669 | } | |
670 | ||
671 | priv = mci->pvt_info; | |
672 | priv->baseaddr = baseaddr; | |
3d02a897 MN |
673 | priv->p_data = p_data; |
674 | ||
fa9f6b9e | 675 | mc_init(mci, pdev); |
ae9b56e3 PCK |
676 | |
677 | rc = edac_mc_add_mc(mci); | |
678 | if (rc) { | |
679 | edac_printk(KERN_ERR, EDAC_MC, | |
680 | "Failed to register with EDAC core\n"); | |
681 | goto free_edac_mc; | |
682 | } | |
683 | ||
684 | /* | |
685 | * Start capturing the correctable and uncorrectable errors. A write of | |
686 | * 0 starts the counters. | |
687 | */ | |
688 | writel(0x0, baseaddr + ECC_CTRL_OFST); | |
689 | return rc; | |
690 | ||
691 | free_edac_mc: | |
692 | edac_mc_free(mci); | |
693 | ||
694 | return rc; | |
695 | } | |
696 | ||
697 | /** | |
225af74d MN |
698 | * mc_remove - Unbind driver from controller. |
699 | * @pdev: Platform device. | |
ae9b56e3 PCK |
700 | * |
701 | * Return: Unconditionally 0 | |
702 | */ | |
bb894bc4 | 703 | static int mc_remove(struct platform_device *pdev) |
ae9b56e3 PCK |
704 | { |
705 | struct mem_ctl_info *mci = platform_get_drvdata(pdev); | |
706 | ||
707 | edac_mc_del_mc(&pdev->dev); | |
708 | edac_mc_free(mci); | |
709 | ||
710 | return 0; | |
711 | } | |
712 | ||
ae9b56e3 PCK |
713 | static struct platform_driver synps_edac_mc_driver = { |
714 | .driver = { | |
715 | .name = "synopsys-edac", | |
716 | .of_match_table = synps_edac_match, | |
717 | }, | |
bb894bc4 MN |
718 | .probe = mc_probe, |
719 | .remove = mc_remove, | |
ae9b56e3 PCK |
720 | }; |
721 | ||
722 | module_platform_driver(synps_edac_mc_driver); | |
723 | ||
724 | MODULE_AUTHOR("Xilinx Inc"); | |
725 | MODULE_DESCRIPTION("Synopsys DDR ECC driver"); | |
726 | MODULE_LICENSE("GPL v2"); |