1/*
2 * Marvell MV64x60 Memory Controller kernel module for PPC platforms
3 *
4 * Author: Dave Jiang <djiang@mvista.com>
5 *
6 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/io.h>
17#include <linux/edac.h>
18#include <linux/gfp.h>
19
20#include "edac_module.h"
21#include "mv64x60_edac.h"
22
23static const char *mv64x60_ctl_name = "MV64x60";
24static int edac_dev_idx;
25static int edac_pci_idx;
26static int edac_mc_idx;
27
28/*********************** PCI err device **********************************/
29#ifdef CONFIG_PCI
30static void mv64x60_pci_check(struct edac_pci_ctl_info *pci)
31{
32	struct mv64x60_pci_pdata *pdata = pci->pvt_info;
33	u32 cause;
34
35	cause = readl(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
36	if (!cause)
37		return;
38
39	printk(KERN_ERR "Error in PCI %d Interface\n", pdata->pci_hose);
40	printk(KERN_ERR "Cause register: 0x%08x\n", cause);
41	printk(KERN_ERR "Address Low: 0x%08x\n",
42	       readl(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_LO));
43	printk(KERN_ERR "Address High: 0x%08x\n",
44	       readl(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_HI));
45	printk(KERN_ERR "Attribute: 0x%08x\n",
46	       readl(pdata->pci_vbase + MV64X60_PCI_ERROR_ATTR));
47	printk(KERN_ERR "Command: 0x%08x\n",
48	       readl(pdata->pci_vbase + MV64X60_PCI_ERROR_CMD));
49	writel(~cause, pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
50
51	if (cause & MV64X60_PCI_PE_MASK)
52		edac_pci_handle_pe(pci, pci->ctl_name);
53
54	if (!(cause & MV64X60_PCI_PE_MASK))
55		edac_pci_handle_npe(pci, pci->ctl_name);
56}
57
58static irqreturn_t mv64x60_pci_isr(int irq, void *dev_id)
59{
60	struct edac_pci_ctl_info *pci = dev_id;
61	struct mv64x60_pci_pdata *pdata = pci->pvt_info;
62	u32 val;
63
64	val = readl(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
65	if (!val)
66		return IRQ_NONE;
67
68	mv64x60_pci_check(pci);
69
70	return IRQ_HANDLED;
71}
72
73/*
74 * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of
75 * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as
76 * well.  IOW, don't set bit 0.
77 */
78
79/* Erratum FEr PCI-#16: clear bit 0 of PCI SERRn Mask reg. */
80static int __init mv64x60_pci_fixup(struct platform_device *pdev)
81{
82	struct resource *r;
83	void __iomem *pci_serr;
84
85	r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
86	if (!r) {
87		printk(KERN_ERR "%s: Unable to get resource for "
88		       "PCI err regs\n", __func__);
89		return -ENOENT;
90	}
91
92	pci_serr = ioremap(r->start, resource_size(r));
93	if (!pci_serr)
94		return -ENOMEM;
95
96	writel(readl(pci_serr) & ~0x1, pci_serr);
97	iounmap(pci_serr);
98
99	return 0;
100}
101
102static int mv64x60_pci_err_probe(struct platform_device *pdev)
103{
104	struct edac_pci_ctl_info *pci;
105	struct mv64x60_pci_pdata *pdata;
106	struct resource *r;
107	int res = 0;
108
109	if (!devres_open_group(&pdev->dev, mv64x60_pci_err_probe, GFP_KERNEL))
110		return -ENOMEM;
111
112	pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mv64x60_pci_err");
113	if (!pci)
114		return -ENOMEM;
115
116	pdata = pci->pvt_info;
117
118	pdata->pci_hose = pdev->id;
119	pdata->name = "mv64x60_pci_err";
120	platform_set_drvdata(pdev, pci);
121	pci->dev = &pdev->dev;
122	pci->dev_name = dev_name(&pdev->dev);
123	pci->mod_name = EDAC_MOD_STR;
124	pci->ctl_name = pdata->name;
125
126	if (edac_op_state == EDAC_OPSTATE_POLL)
127		pci->edac_check = mv64x60_pci_check;
128
129	pdata->edac_idx = edac_pci_idx++;
130
131	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
132	if (!r) {
133		printk(KERN_ERR "%s: Unable to get resource for "
134		       "PCI err regs\n", __func__);
135		res = -ENOENT;
136		goto err;
137	}
138
139	if (!devm_request_mem_region(&pdev->dev,
140				     r->start,
141				     resource_size(r),
142				     pdata->name)) {
143		printk(KERN_ERR "%s: Error while requesting mem region\n",
144		       __func__);
145		res = -EBUSY;
146		goto err;
147	}
148
149	pdata->pci_vbase = devm_ioremap(&pdev->dev,
150					r->start,
151					resource_size(r));
152	if (!pdata->pci_vbase) {
153		printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
154		res = -ENOMEM;
155		goto err;
156	}
157
158	res = mv64x60_pci_fixup(pdev);
159	if (res < 0) {
160		printk(KERN_ERR "%s: PCI fixup failed\n", __func__);
161		goto err;
162	}
163
164	writel(0, pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
165	writel(0, pdata->pci_vbase + MV64X60_PCI_ERROR_MASK);
166	writel(MV64X60_PCIx_ERR_MASK_VAL,
167		  pdata->pci_vbase + MV64X60_PCI_ERROR_MASK);
168
169	if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
170		edac_dbg(3, "failed edac_pci_add_device()\n");
171		goto err;
172	}
173
174	if (edac_op_state == EDAC_OPSTATE_INT) {
175		pdata->irq = platform_get_irq(pdev, 0);
176		res = devm_request_irq(&pdev->dev,
177				       pdata->irq,
178				       mv64x60_pci_isr,
179				       0,
180				       "[EDAC] PCI err",
181				       pci);
182		if (res < 0) {
183			printk(KERN_ERR "%s: Unable to request irq %d for "
184			       "MV64x60 PCI ERR\n", __func__, pdata->irq);
185			res = -ENODEV;
186			goto err2;
187		}
188		printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n",
189		       pdata->irq);
190	}
191
192	devres_remove_group(&pdev->dev, mv64x60_pci_err_probe);
193
194	/* get this far and it's successful */
195	edac_dbg(3, "success\n");
196
197	return 0;
198
199err2:
200	edac_pci_del_device(&pdev->dev);
201err:
202	edac_pci_free_ctl_info(pci);
203	devres_release_group(&pdev->dev, mv64x60_pci_err_probe);
204	return res;
205}
206
207static int mv64x60_pci_err_remove(struct platform_device *pdev)
208{
209	struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
210
211	edac_dbg(0, "\n");
212
213	edac_pci_del_device(&pdev->dev);
214
215	edac_pci_free_ctl_info(pci);
216
217	return 0;
218}
219
220static struct platform_driver mv64x60_pci_err_driver = {
221	.probe = mv64x60_pci_err_probe,
222	.remove = mv64x60_pci_err_remove,
223	.driver = {
224		   .name = "mv64x60_pci_err",
225	}
226};
227
228#endif /* CONFIG_PCI */
229
230/*********************** SRAM err device **********************************/
231static void mv64x60_sram_check(struct edac_device_ctl_info *edac_dev)
232{
233	struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
234	u32 cause;
235
236	cause = readl(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
237	if (!cause)
238		return;
239
240	printk(KERN_ERR "Error in internal SRAM\n");
241	printk(KERN_ERR "Cause register: 0x%08x\n", cause);
242	printk(KERN_ERR "Address Low: 0x%08x\n",
243	       readl(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_LO));
244	printk(KERN_ERR "Address High: 0x%08x\n",
245	       readl(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_HI));
246	printk(KERN_ERR "Data Low: 0x%08x\n",
247	       readl(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_LO));
248	printk(KERN_ERR "Data High: 0x%08x\n",
249	       readl(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_HI));
250	printk(KERN_ERR "Parity: 0x%08x\n",
251	       readl(pdata->sram_vbase + MV64X60_SRAM_ERR_PARITY));
252	writel(0, pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
253
254	edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
255}
256
257static irqreturn_t mv64x60_sram_isr(int irq, void *dev_id)
258{
259	struct edac_device_ctl_info *edac_dev = dev_id;
260	struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
261	u32 cause;
262
263	cause = readl(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
264	if (!cause)
265		return IRQ_NONE;
266
267	mv64x60_sram_check(edac_dev);
268
269	return IRQ_HANDLED;
270}
271
272static int mv64x60_sram_err_probe(struct platform_device *pdev)
273{
274	struct edac_device_ctl_info *edac_dev;
275	struct mv64x60_sram_pdata *pdata;
276	struct resource *r;
277	int res = 0;
278
279	if (!devres_open_group(&pdev->dev, mv64x60_sram_err_probe, GFP_KERNEL))
280		return -ENOMEM;
281
282	edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
283					      "sram", 1, NULL, 0, 0, NULL, 0,
284					      edac_dev_idx);
285	if (!edac_dev) {
286		devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
287		return -ENOMEM;
288	}
289
290	pdata = edac_dev->pvt_info;
291	pdata->name = "mv64x60_sram_err";
292	edac_dev->dev = &pdev->dev;
293	platform_set_drvdata(pdev, edac_dev);
294	edac_dev->dev_name = dev_name(&pdev->dev);
295
296	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
297	if (!r) {
298		printk(KERN_ERR "%s: Unable to get resource for "
299		       "SRAM err regs\n", __func__);
300		res = -ENOENT;
301		goto err;
302	}
303
304	if (!devm_request_mem_region(&pdev->dev,
305				     r->start,
306				     resource_size(r),
307				     pdata->name)) {
308		printk(KERN_ERR "%s: Error while request mem region\n",
309		       __func__);
310		res = -EBUSY;
311		goto err;
312	}
313
314	pdata->sram_vbase = devm_ioremap(&pdev->dev,
315					 r->start,
316					 resource_size(r));
317	if (!pdata->sram_vbase) {
318		printk(KERN_ERR "%s: Unable to setup SRAM err regs\n",
319		       __func__);
320		res = -ENOMEM;
321		goto err;
322	}
323
324	/* setup SRAM err registers */
325	writel(0, pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
326
327	edac_dev->mod_name = EDAC_MOD_STR;
328	edac_dev->ctl_name = pdata->name;
329
330	if (edac_op_state == EDAC_OPSTATE_POLL)
331		edac_dev->edac_check = mv64x60_sram_check;
332
333	pdata->edac_idx = edac_dev_idx++;
334
335	if (edac_device_add_device(edac_dev) > 0) {
336		edac_dbg(3, "failed edac_device_add_device()\n");
337		goto err;
338	}
339
340	if (edac_op_state == EDAC_OPSTATE_INT) {
341		pdata->irq = platform_get_irq(pdev, 0);
342		res = devm_request_irq(&pdev->dev,
343				       pdata->irq,
344				       mv64x60_sram_isr,
345				       0,
346				       "[EDAC] SRAM err",
347				       edac_dev);
348		if (res < 0) {
349			printk(KERN_ERR
350			       "%s: Unable to request irq %d for "
351			       "MV64x60 SRAM ERR\n", __func__, pdata->irq);
352			res = -ENODEV;
353			goto err2;
354		}
355
356		printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for SRAM Err\n",
357		       pdata->irq);
358	}
359
360	devres_remove_group(&pdev->dev, mv64x60_sram_err_probe);
361
362	/* get this far and it's successful */
363	edac_dbg(3, "success\n");
364
365	return 0;
366
367err2:
368	edac_device_del_device(&pdev->dev);
369err:
370	devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
371	edac_device_free_ctl_info(edac_dev);
372	return res;
373}
374
375static int mv64x60_sram_err_remove(struct platform_device *pdev)
376{
377	struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
378
379	edac_dbg(0, "\n");
380
381	edac_device_del_device(&pdev->dev);
382	edac_device_free_ctl_info(edac_dev);
383
384	return 0;
385}
386
387static struct platform_driver mv64x60_sram_err_driver = {
388	.probe = mv64x60_sram_err_probe,
389	.remove = mv64x60_sram_err_remove,
390	.driver = {
391		   .name = "mv64x60_sram_err",
392	}
393};
394
395/*********************** CPU err device **********************************/
396static void mv64x60_cpu_check(struct edac_device_ctl_info *edac_dev)
397{
398	struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
399	u32 cause;
400
401	cause = readl(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
402	    MV64x60_CPU_CAUSE_MASK;
403	if (!cause)
404		return;
405
406	printk(KERN_ERR "Error on CPU interface\n");
407	printk(KERN_ERR "Cause register: 0x%08x\n", cause);
408	printk(KERN_ERR "Address Low: 0x%08x\n",
409	       readl(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_LO));
410	printk(KERN_ERR "Address High: 0x%08x\n",
411	       readl(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_HI));
412	printk(KERN_ERR "Data Low: 0x%08x\n",
413	       readl(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_LO));
414	printk(KERN_ERR "Data High: 0x%08x\n",
415	       readl(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_HI));
416	printk(KERN_ERR "Parity: 0x%08x\n",
417	       readl(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_PARITY));
418	writel(0, pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE);
419
420	edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
421}
422
423static irqreturn_t mv64x60_cpu_isr(int irq, void *dev_id)
424{
425	struct edac_device_ctl_info *edac_dev = dev_id;
426	struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
427	u32 cause;
428
429	cause = readl(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
430	    MV64x60_CPU_CAUSE_MASK;
431	if (!cause)
432		return IRQ_NONE;
433
434	mv64x60_cpu_check(edac_dev);
435
436	return IRQ_HANDLED;
437}
438
439static int mv64x60_cpu_err_probe(struct platform_device *pdev)
440{
441	struct edac_device_ctl_info *edac_dev;
442	struct resource *r;
443	struct mv64x60_cpu_pdata *pdata;
444	int res = 0;
445
446	if (!devres_open_group(&pdev->dev, mv64x60_cpu_err_probe, GFP_KERNEL))
447		return -ENOMEM;
448
449	edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
450					      "cpu", 1, NULL, 0, 0, NULL, 0,
451					      edac_dev_idx);
452	if (!edac_dev) {
453		devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
454		return -ENOMEM;
455	}
456
457	pdata = edac_dev->pvt_info;
458	pdata->name = "mv64x60_cpu_err";
459	edac_dev->dev = &pdev->dev;
460	platform_set_drvdata(pdev, edac_dev);
461	edac_dev->dev_name = dev_name(&pdev->dev);
462
463	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
464	if (!r) {
465		printk(KERN_ERR "%s: Unable to get resource for "
466		       "CPU err regs\n", __func__);
467		res = -ENOENT;
468		goto err;
469	}
470
471	if (!devm_request_mem_region(&pdev->dev,
472				     r->start,
473				     resource_size(r),
474				     pdata->name)) {
475		printk(KERN_ERR "%s: Error while requesting mem region\n",
476		       __func__);
477		res = -EBUSY;
478		goto err;
479	}
480
481	pdata->cpu_vbase[0] = devm_ioremap(&pdev->dev,
482					   r->start,
483					   resource_size(r));
484	if (!pdata->cpu_vbase[0]) {
485		printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
486		res = -ENOMEM;
487		goto err;
488	}
489
490	r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
491	if (!r) {
492		printk(KERN_ERR "%s: Unable to get resource for "
493		       "CPU err regs\n", __func__);
494		res = -ENOENT;
495		goto err;
496	}
497
498	if (!devm_request_mem_region(&pdev->dev,
499				     r->start,
500				     resource_size(r),
501				     pdata->name)) {
502		printk(KERN_ERR "%s: Error while requesting mem region\n",
503		       __func__);
504		res = -EBUSY;
505		goto err;
506	}
507
508	pdata->cpu_vbase[1] = devm_ioremap(&pdev->dev,
509					   r->start,
510					   resource_size(r));
511	if (!pdata->cpu_vbase[1]) {
512		printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
513		res = -ENOMEM;
514		goto err;
515	}
516
517	/* setup CPU err registers */
518	writel(0, pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE);
519	writel(0, pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK);
520	writel(0x000000ff, pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK);
521
522	edac_dev->mod_name = EDAC_MOD_STR;
523	edac_dev->ctl_name = pdata->name;
524	if (edac_op_state == EDAC_OPSTATE_POLL)
525		edac_dev->edac_check = mv64x60_cpu_check;
526
527	pdata->edac_idx = edac_dev_idx++;
528
529	if (edac_device_add_device(edac_dev) > 0) {
530		edac_dbg(3, "failed edac_device_add_device()\n");
531		goto err;
532	}
533
534	if (edac_op_state == EDAC_OPSTATE_INT) {
535		pdata->irq = platform_get_irq(pdev, 0);
536		res = devm_request_irq(&pdev->dev,
537				       pdata->irq,
538				       mv64x60_cpu_isr,
539				       0,
540				       "[EDAC] CPU err",
541				       edac_dev);
542		if (res < 0) {
543			printk(KERN_ERR
544			       "%s: Unable to request irq %d for MV64x60 "
545			       "CPU ERR\n", __func__, pdata->irq);
546			res = -ENODEV;
547			goto err2;
548		}
549
550		printk(KERN_INFO EDAC_MOD_STR
551		       " acquired irq %d for CPU Err\n", pdata->irq);
552	}
553
554	devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe);
555
556	/* get this far and it's successful */
557	edac_dbg(3, "success\n");
558
559	return 0;
560
561err2:
562	edac_device_del_device(&pdev->dev);
563err:
564	devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
565	edac_device_free_ctl_info(edac_dev);
566	return res;
567}
568
569static int mv64x60_cpu_err_remove(struct platform_device *pdev)
570{
571	struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
572
573	edac_dbg(0, "\n");
574
575	edac_device_del_device(&pdev->dev);
576	edac_device_free_ctl_info(edac_dev);
577	return 0;
578}
579
580static struct platform_driver mv64x60_cpu_err_driver = {
581	.probe = mv64x60_cpu_err_probe,
582	.remove = mv64x60_cpu_err_remove,
583	.driver = {
584		   .name = "mv64x60_cpu_err",
585	}
586};
587
588/*********************** DRAM err device **********************************/
589
590static void mv64x60_mc_check(struct mem_ctl_info *mci)
591{
592	struct mv64x60_mc_pdata *pdata = mci->pvt_info;
593	u32 reg;
594	u32 err_addr;
595	u32 sdram_ecc;
596	u32 comp_ecc;
597	u32 syndrome;
598
599	reg = readl(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
600	if (!reg)
601		return;
602
603	err_addr = reg & ~0x3;
604	sdram_ecc = readl(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_RCVD);
605	comp_ecc = readl(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CALC);
606	syndrome = sdram_ecc ^ comp_ecc;
607
608	/* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */
609	if (!(reg & 0x1))
610		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
611				     err_addr >> PAGE_SHIFT,
612				     err_addr & PAGE_MASK, syndrome,
613				     0, 0, -1,
614				     mci->ctl_name, "");
615	else	/* 2 bit error, UE */
616		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
617				     err_addr >> PAGE_SHIFT,
618				     err_addr & PAGE_MASK, 0,
619				     0, 0, -1,
620				     mci->ctl_name, "");
621
622	/* clear the error */
623	writel(0, pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
624}
625
626static irqreturn_t mv64x60_mc_isr(int irq, void *dev_id)
627{
628	struct mem_ctl_info *mci = dev_id;
629	struct mv64x60_mc_pdata *pdata = mci->pvt_info;
630	u32 reg;
631
632	reg = readl(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
633	if (!reg)
634		return IRQ_NONE;
635
636	/* writing 0's to the ECC err addr in check function clears irq */
637	mv64x60_mc_check(mci);
638
639	return IRQ_HANDLED;
640}
641
642static void get_total_mem(struct mv64x60_mc_pdata *pdata)
643{
644	struct device_node *np = NULL;
645	const unsigned int *reg;
646
647	np = of_find_node_by_type(NULL, "memory");
648	if (!np)
649		return;
650
651	reg = of_get_property(np, "reg", NULL);
652
653	pdata->total_mem = reg[1];
654}
655
656static void mv64x60_init_csrows(struct mem_ctl_info *mci,
657				struct mv64x60_mc_pdata *pdata)
658{
659	struct csrow_info *csrow;
660	struct dimm_info *dimm;
661
662	u32 devtype;
663	u32 ctl;
664
665	get_total_mem(pdata);
666
667	ctl = readl(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
668
669	csrow = mci->csrows[0];
670	dimm = csrow->channels[0]->dimm;
671
672	dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
673	dimm->grain = 8;
674
675	dimm->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
676
677	devtype = (ctl >> 20) & 0x3;
678	switch (devtype) {
679	case 0x0:
680		dimm->dtype = DEV_X32;
681		break;
682	case 0x2:		/* could be X8 too, but no way to tell */
683		dimm->dtype = DEV_X16;
684		break;
685	case 0x3:
686		dimm->dtype = DEV_X4;
687		break;
688	default:
689		dimm->dtype = DEV_UNKNOWN;
690		break;
691	}
692
693	dimm->edac_mode = EDAC_SECDED;
694}
695
696static int mv64x60_mc_err_probe(struct platform_device *pdev)
697{
698	struct mem_ctl_info *mci;
699	struct edac_mc_layer layers[2];
700	struct mv64x60_mc_pdata *pdata;
701	struct resource *r;
702	u32 ctl;
703	int res = 0;
704
705	if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL))
706		return -ENOMEM;
707
708	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
709	layers[0].size = 1;
710	layers[0].is_virt_csrow = true;
711	layers[1].type = EDAC_MC_LAYER_CHANNEL;
712	layers[1].size = 1;
713	layers[1].is_virt_csrow = false;
714	mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers,
715			    sizeof(struct mv64x60_mc_pdata));
716	if (!mci) {
717		printk(KERN_ERR "%s: No memory for CPU err\n", __func__);
718		devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
719		return -ENOMEM;
720	}
721
722	pdata = mci->pvt_info;
723	mci->pdev = &pdev->dev;
724	platform_set_drvdata(pdev, mci);
725	pdata->name = "mv64x60_mc_err";
726	mci->dev_name = dev_name(&pdev->dev);
727	pdata->edac_idx = edac_mc_idx++;
728
729	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
730	if (!r) {
731		printk(KERN_ERR "%s: Unable to get resource for "
732		       "MC err regs\n", __func__);
733		res = -ENOENT;
734		goto err;
735	}
736
737	if (!devm_request_mem_region(&pdev->dev,
738				     r->start,
739				     resource_size(r),
740				     pdata->name)) {
741		printk(KERN_ERR "%s: Error while requesting mem region\n",
742		       __func__);
743		res = -EBUSY;
744		goto err;
745	}
746
747	pdata->mc_vbase = devm_ioremap(&pdev->dev,
748				       r->start,
749				       resource_size(r));
750	if (!pdata->mc_vbase) {
751		printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__);
752		res = -ENOMEM;
753		goto err;
754	}
755
756	ctl = readl(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
757	if (!(ctl & MV64X60_SDRAM_ECC)) {
758		/* Non-ECC RAM? */
759		printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
760		res = -ENODEV;
761		goto err;
762	}
763
764	edac_dbg(3, "init mci\n");
765	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
766	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
767	mci->edac_cap = EDAC_FLAG_SECDED;
768	mci->mod_name = EDAC_MOD_STR;
769	mci->ctl_name = mv64x60_ctl_name;
770
771	if (edac_op_state == EDAC_OPSTATE_POLL)
772		mci->edac_check = mv64x60_mc_check;
773
774	mci->ctl_page_to_phys = NULL;
775
776	mci->scrub_mode = SCRUB_SW_SRC;
777
778	mv64x60_init_csrows(mci, pdata);
779
780	/* setup MC registers */
781	writel(0, pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
782	ctl = readl(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL);
783	ctl = (ctl & 0xff00ffff) | 0x10000;
784	writel(ctl, pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL);
785
786	res = edac_mc_add_mc(mci);
787	if (res) {
788		edac_dbg(3, "failed edac_mc_add_mc()\n");
789		goto err;
790	}
791
792	if (edac_op_state == EDAC_OPSTATE_INT) {
793		/* acquire interrupt that reports errors */
794		pdata->irq = platform_get_irq(pdev, 0);
795		res = devm_request_irq(&pdev->dev,
796				       pdata->irq,
797				       mv64x60_mc_isr,
798				       0,
799				       "[EDAC] MC err",
800				       mci);
801		if (res < 0) {
802			printk(KERN_ERR "%s: Unable to request irq %d for "
803			       "MV64x60 DRAM ERR\n", __func__, pdata->irq);
804			res = -ENODEV;
805			goto err2;
806		}
807
808		printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC Err\n",
809		       pdata->irq);
810	}
811
812	/* get this far and it's successful */
813	edac_dbg(3, "success\n");
814
815	return 0;
816
817err2:
818	edac_mc_del_mc(&pdev->dev);
819err:
820	devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
821	edac_mc_free(mci);
822	return res;
823}
824
825static int mv64x60_mc_err_remove(struct platform_device *pdev)
826{
827	struct mem_ctl_info *mci = platform_get_drvdata(pdev);
828
829	edac_dbg(0, "\n");
830
831	edac_mc_del_mc(&pdev->dev);
832	edac_mc_free(mci);
833	return 0;
834}
835
836static struct platform_driver mv64x60_mc_err_driver = {
837	.probe = mv64x60_mc_err_probe,
838	.remove = mv64x60_mc_err_remove,
839	.driver = {
840		   .name = "mv64x60_mc_err",
841	}
842};
843
844static struct platform_driver * const drivers[] = {
845	&mv64x60_mc_err_driver,
846	&mv64x60_cpu_err_driver,
847	&mv64x60_sram_err_driver,
848#ifdef CONFIG_PCI
849	&mv64x60_pci_err_driver,
850#endif
851};
852
853static int __init mv64x60_edac_init(void)
854{
855
856	printk(KERN_INFO "Marvell MV64x60 EDAC driver " MV64x60_REVISION "\n");
857	printk(KERN_INFO "\t(C) 2006-2007 MontaVista Software\n");
858
859	/* make sure error reporting method is sane */
860	switch (edac_op_state) {
861	case EDAC_OPSTATE_POLL:
862	case EDAC_OPSTATE_INT:
863		break;
864	default:
865		edac_op_state = EDAC_OPSTATE_INT;
866		break;
867	}
868
869	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
870}
871module_init(mv64x60_edac_init);
872
873static void __exit mv64x60_edac_exit(void)
874{
875	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
876}
877module_exit(mv64x60_edac_exit);
878
879MODULE_LICENSE("GPL");
880MODULE_AUTHOR("Montavista Software, Inc.");
881module_param(edac_op_state, int, 0444);
882MODULE_PARM_DESC(edac_op_state,
883		 "EDAC Error Reporting state: 0=Poll, 2=Interrupt");
884