blob: a625a68345a3d52d5ce045866923a6263d3d315a [file] [log] [blame]
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +05301/*
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>
25
Mauro Carvalho Chehab78d88e82016-10-29 15:16:34 -020026#include "edac_module.h"
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053027
28/* Number of cs_rows needed per memory controller */
Manish Narani1b51adc2018-10-04 21:05:19 +053029#define SYNPS_EDAC_NR_CSROWS 1
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053030
31/* Number of channels per memory controller */
Manish Narani1b51adc2018-10-04 21:05:19 +053032#define SYNPS_EDAC_NR_CHANS 1
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053033
34/* Granularity of reported error in bytes */
Manish Narani1b51adc2018-10-04 21:05:19 +053035#define SYNPS_EDAC_ERR_GRAIN 1
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053036
Manish Narani1b51adc2018-10-04 21:05:19 +053037#define SYNPS_EDAC_MSG_SIZE 256
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053038
Manish Narani1b51adc2018-10-04 21:05:19 +053039#define SYNPS_EDAC_MOD_STRING "synps_edac"
40#define SYNPS_EDAC_MOD_VER "1"
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053041
42/* Synopsys DDR memory controller registers that are relevant to ECC */
Manish Narani1b51adc2018-10-04 21:05:19 +053043#define CTRL_OFST 0x0
44#define T_ZQ_OFST 0xA4
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053045
46/* ECC control register */
Manish Narani1b51adc2018-10-04 21:05:19 +053047#define ECC_CTRL_OFST 0xC4
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053048/* ECC log register */
Manish Narani1b51adc2018-10-04 21:05:19 +053049#define CE_LOG_OFST 0xC8
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053050/* ECC address register */
Manish Narani1b51adc2018-10-04 21:05:19 +053051#define CE_ADDR_OFST 0xCC
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053052/* ECC data[31:0] register */
Manish Narani1b51adc2018-10-04 21:05:19 +053053#define CE_DATA_31_0_OFST 0xD0
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053054
55/* Uncorrectable error info registers */
Manish Narani1b51adc2018-10-04 21:05:19 +053056#define UE_LOG_OFST 0xDC
57#define UE_ADDR_OFST 0xE0
58#define UE_DATA_31_0_OFST 0xE4
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053059
Manish Narani1b51adc2018-10-04 21:05:19 +053060#define STAT_OFST 0xF0
61#define SCRUB_OFST 0xF4
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053062
63/* Control register bit field definitions */
Manish Narani1b51adc2018-10-04 21:05:19 +053064#define CTRL_BW_MASK 0xC
65#define CTRL_BW_SHIFT 2
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053066
Manish Narani1b51adc2018-10-04 21:05:19 +053067#define DDRCTL_WDTH_16 1
68#define DDRCTL_WDTH_32 0
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053069
70/* ZQ register bit field definitions */
Manish Narani1b51adc2018-10-04 21:05:19 +053071#define T_ZQ_DDRMODE_MASK 0x2
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053072
73/* ECC control register bit field definitions */
Manish Narani1b51adc2018-10-04 21:05:19 +053074#define ECC_CTRL_CLR_CE_ERR 0x2
75#define ECC_CTRL_CLR_UE_ERR 0x1
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053076
77/* ECC correctable/uncorrectable error log register definitions */
Manish Narani1b51adc2018-10-04 21:05:19 +053078#define LOG_VALID 0x1
79#define CE_LOG_BITPOS_MASK 0xFE
80#define CE_LOG_BITPOS_SHIFT 1
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053081
82/* ECC correctable/uncorrectable error address register definitions */
Manish Narani1b51adc2018-10-04 21:05:19 +053083#define ADDR_COL_MASK 0xFFF
84#define ADDR_ROW_MASK 0xFFFF000
85#define ADDR_ROW_SHIFT 12
86#define ADDR_BANK_MASK 0x70000000
87#define ADDR_BANK_SHIFT 28
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053088
89/* ECC statistic register definitions */
Manish Narani1b51adc2018-10-04 21:05:19 +053090#define STAT_UECNT_MASK 0xFF
91#define STAT_CECNT_MASK 0xFF00
92#define STAT_CECNT_SHIFT 8
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053093
94/* ECC scrub register definitions */
Manish Narani1b51adc2018-10-04 21:05:19 +053095#define SCRUB_MODE_MASK 0x7
96#define SCRUB_MODE_SECDED 0x4
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +053097
98/**
Manish Narani225af742018-10-04 21:05:21 +053099 * struct ecc_error_info - ECC error log information.
100 * @row: Row number.
101 * @col: Column number.
102 * @bank: Bank number.
103 * @bitpos: Bit position.
104 * @data: Data causing the error.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530105 */
106struct ecc_error_info {
107 u32 row;
108 u32 col;
109 u32 bank;
110 u32 bitpos;
111 u32 data;
112};
113
114/**
Manish Narani225af742018-10-04 21:05:21 +0530115 * struct synps_ecc_status - ECC status information to report.
116 * @ce_cnt: Correctable error count.
117 * @ue_cnt: Uncorrectable error count.
118 * @ceinfo: Correctable error log information.
119 * @ueinfo: Uncorrectable error log information.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530120 */
121struct synps_ecc_status {
122 u32 ce_cnt;
123 u32 ue_cnt;
124 struct ecc_error_info ceinfo;
125 struct ecc_error_info ueinfo;
126};
127
128/**
Manish Narani225af742018-10-04 21:05:21 +0530129 * struct synps_edac_priv - DDR memory controller private instance data.
130 * @baseaddr: Base address of the DDR controller.
131 * @message: Buffer for framing the event specific info.
132 * @stat: ECC status information.
133 * @ce_cnt: Correctable Error count.
134 * @ue_cnt: Uncorrectable Error count.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530135 */
136struct synps_edac_priv {
137 void __iomem *baseaddr;
138 char message[SYNPS_EDAC_MSG_SIZE];
139 struct synps_ecc_status stat;
140 u32 ce_cnt;
141 u32 ue_cnt;
142};
143
144/**
Manish Narani225af742018-10-04 21:05:21 +0530145 * get_error_info - Get the current ECC error info.
146 * @base: Base address of the DDR memory controller.
147 * @p: Synopsys ECC status structure.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530148 *
Manish Narani225af742018-10-04 21:05:21 +0530149 * Return: one if there is no error otherwise zero.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530150 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530151static int get_error_info(void __iomem *base, struct synps_ecc_status *p)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530152{
153 u32 regval, clearval = 0;
154
155 regval = readl(base + STAT_OFST);
156 if (!regval)
157 return 1;
158
159 p->ce_cnt = (regval & STAT_CECNT_MASK) >> STAT_CECNT_SHIFT;
160 p->ue_cnt = regval & STAT_UECNT_MASK;
161
162 regval = readl(base + CE_LOG_OFST);
163 if (!(p->ce_cnt && (regval & LOG_VALID)))
164 goto ue_err;
165
166 p->ceinfo.bitpos = (regval & CE_LOG_BITPOS_MASK) >> CE_LOG_BITPOS_SHIFT;
167 regval = readl(base + CE_ADDR_OFST);
168 p->ceinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
169 p->ceinfo.col = regval & ADDR_COL_MASK;
170 p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
171 p->ceinfo.data = readl(base + CE_DATA_31_0_OFST);
Manish Narani1b51adc2018-10-04 21:05:19 +0530172 edac_dbg(3, "CE bit position: %d data: %d\n", p->ceinfo.bitpos,
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530173 p->ceinfo.data);
174 clearval = ECC_CTRL_CLR_CE_ERR;
175
176ue_err:
177 regval = readl(base + UE_LOG_OFST);
178 if (!(p->ue_cnt && (regval & LOG_VALID)))
179 goto out;
180
181 regval = readl(base + UE_ADDR_OFST);
182 p->ueinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
183 p->ueinfo.col = regval & ADDR_COL_MASK;
184 p->ueinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
185 p->ueinfo.data = readl(base + UE_DATA_31_0_OFST);
186 clearval |= ECC_CTRL_CLR_UE_ERR;
187
188out:
189 writel(clearval, base + ECC_CTRL_OFST);
190 writel(0x0, base + ECC_CTRL_OFST);
191
192 return 0;
193}
194
195/**
Manish Narani225af742018-10-04 21:05:21 +0530196 * handle_error - Handle Correctable and Uncorrectable errors.
197 * @mci: EDAC memory controller instance.
198 * @p: Synopsys ECC status structure.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530199 *
Manish Narani225af742018-10-04 21:05:21 +0530200 * Handles ECC correctable and uncorrectable errors.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530201 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530202static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530203{
204 struct synps_edac_priv *priv = mci->pvt_info;
205 struct ecc_error_info *pinf;
206
207 if (p->ce_cnt) {
208 pinf = &p->ceinfo;
209 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
210 "DDR ECC error type :%s Row %d Bank %d Col %d ",
211 "CE", pinf->row, pinf->bank, pinf->col);
212 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
213 p->ce_cnt, 0, 0, 0, 0, 0, -1,
214 priv->message, "");
215 }
216
217 if (p->ue_cnt) {
218 pinf = &p->ueinfo;
219 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
220 "DDR ECC error type :%s Row %d Bank %d Col %d ",
221 "UE", pinf->row, pinf->bank, pinf->col);
222 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
223 p->ue_cnt, 0, 0, 0, 0, 0, -1,
224 priv->message, "");
225 }
226
227 memset(p, 0, sizeof(*p));
228}
229
230/**
Manish Narani225af742018-10-04 21:05:21 +0530231 * check_errors - Check controller for ECC errors.
232 * @mci: EDAC memory controller instance.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530233 *
Manish Narani225af742018-10-04 21:05:21 +0530234 * Check and post ECC errors. Called by the polling thread.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530235 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530236static void check_errors(struct mem_ctl_info *mci)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530237{
238 struct synps_edac_priv *priv = mci->pvt_info;
239 int status;
240
Manish Naranibb894bc2018-10-04 21:05:20 +0530241 status = get_error_info(priv->baseaddr, &priv->stat);
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530242 if (status)
243 return;
244
245 priv->ce_cnt += priv->stat.ce_cnt;
246 priv->ue_cnt += priv->stat.ue_cnt;
Manish Naranibb894bc2018-10-04 21:05:20 +0530247 handle_error(mci, &priv->stat);
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530248
Manish Narani1b51adc2018-10-04 21:05:19 +0530249 edac_dbg(3, "Total error count CE %d UE %d\n",
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530250 priv->ce_cnt, priv->ue_cnt);
251}
252
253/**
Manish Narani225af742018-10-04 21:05:21 +0530254 * get_dtype - Return the controller memory width.
255 * @base: DDR memory controller base address.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530256 *
257 * Get the EDAC device type width appropriate for the current controller
258 * configuration.
259 *
260 * Return: a device type width enumeration.
261 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530262static enum dev_type get_dtype(const void __iomem *base)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530263{
264 enum dev_type dt;
265 u32 width;
266
267 width = readl(base + CTRL_OFST);
268 width = (width & CTRL_BW_MASK) >> CTRL_BW_SHIFT;
269
270 switch (width) {
271 case DDRCTL_WDTH_16:
272 dt = DEV_X2;
273 break;
274 case DDRCTL_WDTH_32:
275 dt = DEV_X4;
276 break;
277 default:
278 dt = DEV_UNKNOWN;
279 }
280
281 return dt;
282}
283
284/**
Manish Narani225af742018-10-04 21:05:21 +0530285 * get_ecc_state - Return the controller ECC enable/disable status.
286 * @base: DDR memory controller base address.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530287 *
Manish Narani225af742018-10-04 21:05:21 +0530288 * Get the ECC enable/disable status of the controller.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530289 *
Manish Narani225af742018-10-04 21:05:21 +0530290 * Return: true if enabled, otherwise false.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530291 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530292static bool get_ecc_state(void __iomem *base)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530293{
Manish Narani1b51adc2018-10-04 21:05:19 +0530294 bool state = false;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530295 enum dev_type dt;
296 u32 ecctype;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530297
Manish Naranibb894bc2018-10-04 21:05:20 +0530298 dt = get_dtype(base);
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530299 if (dt == DEV_UNKNOWN)
300 return state;
301
302 ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK;
303 if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2))
304 state = true;
305
306 return state;
307}
308
309/**
Manish Narani225af742018-10-04 21:05:21 +0530310 * get_memsize - Read the size of the attached memory device.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530311 *
Manish Narani225af742018-10-04 21:05:21 +0530312 * Return: the memory size in bytes.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530313 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530314static u32 get_memsize(void)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530315{
316 struct sysinfo inf;
317
318 si_meminfo(&inf);
319
320 return inf.totalram * inf.mem_unit;
321}
322
323/**
Manish Narani225af742018-10-04 21:05:21 +0530324 * get_mtype - Return the controller memory type.
325 * @base: Synopsys ECC status structure.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530326 *
327 * Get the EDAC memory type appropriate for the current controller
328 * configuration.
329 *
330 * Return: a memory type enumeration.
331 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530332static enum mem_type get_mtype(const void __iomem *base)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530333{
334 enum mem_type mt;
335 u32 memtype;
336
337 memtype = readl(base + T_ZQ_OFST);
338
339 if (memtype & T_ZQ_DDRMODE_MASK)
340 mt = MEM_DDR3;
341 else
342 mt = MEM_DDR2;
343
344 return mt;
345}
346
347/**
Manish Narani225af742018-10-04 21:05:21 +0530348 * init_csrows - Initialize the csrow data.
349 * @mci: EDAC memory controller instance.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530350 *
Manish Narani225af742018-10-04 21:05:21 +0530351 * Initialize the chip select rows associated with the EDAC memory
352 * controller instance.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530353 */
Manish Naranifa9f6b92018-10-04 21:05:22 +0530354static void init_csrows(struct mem_ctl_info *mci)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530355{
Manish Narani1b51adc2018-10-04 21:05:19 +0530356 struct synps_edac_priv *priv = mci->pvt_info;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530357 struct csrow_info *csi;
358 struct dimm_info *dimm;
Manish Narani1b51adc2018-10-04 21:05:19 +0530359 u32 size, row;
360 int j;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530361
362 for (row = 0; row < mci->nr_csrows; row++) {
363 csi = mci->csrows[row];
Manish Naranibb894bc2018-10-04 21:05:20 +0530364 size = get_memsize();
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530365
366 for (j = 0; j < csi->nr_channels; j++) {
Manish Narani1b51adc2018-10-04 21:05:19 +0530367 dimm = csi->channels[j]->dimm;
368 dimm->edac_mode = EDAC_FLAG_SECDED;
Manish Naranibb894bc2018-10-04 21:05:20 +0530369 dimm->mtype = get_mtype(priv->baseaddr);
Manish Narani1b51adc2018-10-04 21:05:19 +0530370 dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels;
371 dimm->grain = SYNPS_EDAC_ERR_GRAIN;
Manish Naranibb894bc2018-10-04 21:05:20 +0530372 dimm->dtype = get_dtype(priv->baseaddr);
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530373 }
374 }
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530375}
376
377/**
Manish Narani225af742018-10-04 21:05:21 +0530378 * mc_init - Initialize one driver instance.
379 * @mci: EDAC memory controller instance.
380 * @pdev: platform device.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530381 *
Manish Narani225af742018-10-04 21:05:21 +0530382 * Perform initialization of the EDAC memory controller instance and
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530383 * related driver-private data associated with the memory controller the
384 * instance is bound to.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530385 */
Manish Naranifa9f6b92018-10-04 21:05:22 +0530386static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530387{
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530388 struct synps_edac_priv *priv;
389
390 mci->pdev = &pdev->dev;
391 priv = mci->pvt_info;
392 platform_set_drvdata(pdev, mci);
393
394 /* Initialize controller capabilities and configuration */
395 mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
396 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
397 mci->scrub_cap = SCRUB_HW_SRC;
398 mci->scrub_mode = SCRUB_NONE;
399
400 mci->edac_cap = EDAC_FLAG_SECDED;
401 mci->ctl_name = "synps_ddr_controller";
402 mci->dev_name = SYNPS_EDAC_MOD_STRING;
403 mci->mod_name = SYNPS_EDAC_MOD_VER;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530404
405 edac_op_state = EDAC_OPSTATE_POLL;
Manish Naranibb894bc2018-10-04 21:05:20 +0530406 mci->edac_check = check_errors;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530407 mci->ctl_page_to_phys = NULL;
408
Manish Naranifa9f6b92018-10-04 21:05:22 +0530409 init_csrows(mci);
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530410}
411
412/**
Manish Narani225af742018-10-04 21:05:21 +0530413 * mc_probe - Check controller and bind driver.
414 * @pdev: platform device.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530415 *
Manish Narani225af742018-10-04 21:05:21 +0530416 * Probe a specific controller instance for binding with the driver.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530417 *
418 * Return: 0 if the controller instance was successfully bound to the
419 * driver; otherwise, < 0 on error.
420 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530421static int mc_probe(struct platform_device *pdev)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530422{
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530423 struct edac_mc_layer layers[2];
424 struct synps_edac_priv *priv;
Manish Narani1b51adc2018-10-04 21:05:19 +0530425 struct mem_ctl_info *mci;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530426 void __iomem *baseaddr;
Manish Narani1b51adc2018-10-04 21:05:19 +0530427 struct resource *res;
428 int rc;
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530429
430 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
431 baseaddr = devm_ioremap_resource(&pdev->dev, res);
432 if (IS_ERR(baseaddr))
433 return PTR_ERR(baseaddr);
434
Manish Naranibb894bc2018-10-04 21:05:20 +0530435 if (!get_ecc_state(baseaddr)) {
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530436 edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
437 return -ENXIO;
438 }
439
440 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
441 layers[0].size = SYNPS_EDAC_NR_CSROWS;
442 layers[0].is_virt_csrow = true;
443 layers[1].type = EDAC_MC_LAYER_CHANNEL;
444 layers[1].size = SYNPS_EDAC_NR_CHANS;
445 layers[1].is_virt_csrow = false;
446
447 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
448 sizeof(struct synps_edac_priv));
449 if (!mci) {
450 edac_printk(KERN_ERR, EDAC_MC,
451 "Failed memory allocation for mc instance\n");
452 return -ENOMEM;
453 }
454
455 priv = mci->pvt_info;
456 priv->baseaddr = baseaddr;
Manish Naranifa9f6b92018-10-04 21:05:22 +0530457 mc_init(mci, pdev);
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530458
459 rc = edac_mc_add_mc(mci);
460 if (rc) {
461 edac_printk(KERN_ERR, EDAC_MC,
462 "Failed to register with EDAC core\n");
463 goto free_edac_mc;
464 }
465
466 /*
467 * Start capturing the correctable and uncorrectable errors. A write of
468 * 0 starts the counters.
469 */
470 writel(0x0, baseaddr + ECC_CTRL_OFST);
471 return rc;
472
473free_edac_mc:
474 edac_mc_free(mci);
475
476 return rc;
477}
478
479/**
Manish Narani225af742018-10-04 21:05:21 +0530480 * mc_remove - Unbind driver from controller.
481 * @pdev: Platform device.
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530482 *
483 * Return: Unconditionally 0
484 */
Manish Naranibb894bc2018-10-04 21:05:20 +0530485static int mc_remove(struct platform_device *pdev)
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530486{
487 struct mem_ctl_info *mci = platform_get_drvdata(pdev);
488
489 edac_mc_del_mc(&pdev->dev);
490 edac_mc_free(mci);
491
492 return 0;
493}
494
Fabian Frederick1afaa052015-03-16 20:54:41 +0100495static const struct of_device_id synps_edac_match[] = {
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530496 { .compatible = "xlnx,zynq-ddrc-a05", },
497 { /* end of table */ }
498};
499
500MODULE_DEVICE_TABLE(of, synps_edac_match);
501
502static struct platform_driver synps_edac_mc_driver = {
503 .driver = {
504 .name = "synopsys-edac",
505 .of_match_table = synps_edac_match,
506 },
Manish Naranibb894bc2018-10-04 21:05:20 +0530507 .probe = mc_probe,
508 .remove = mc_remove,
Punnaiah Choudary Kalluriae9b56e32015-01-06 23:13:47 +0530509};
510
511module_platform_driver(synps_edac_mc_driver);
512
513MODULE_AUTHOR("Xilinx Inc");
514MODULE_DESCRIPTION("Synopsys DDR ECC driver");
515MODULE_LICENSE("GPL v2");