xref: /OK3568_Linux_fs/kernel/drivers/edac/mpc85xx_edac.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Freescale MPC85xx Memory Controller kernel module
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Author: Dave Jiang <djiang@mvista.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
9*4882a593Smuzhiyun  * the terms of the GNU General Public License version 2. This program
10*4882a593Smuzhiyun  * is licensed "as is" without any warranty of any kind, whether express
11*4882a593Smuzhiyun  * or implied.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/ctype.h>
18*4882a593Smuzhiyun #include <linux/io.h>
19*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
20*4882a593Smuzhiyun #include <linux/edac.h>
21*4882a593Smuzhiyun #include <linux/smp.h>
22*4882a593Smuzhiyun #include <linux/gfp.h>
23*4882a593Smuzhiyun #include <linux/fsl/edac.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <linux/of_platform.h>
26*4882a593Smuzhiyun #include <linux/of_device.h>
27*4882a593Smuzhiyun #include "edac_module.h"
28*4882a593Smuzhiyun #include "mpc85xx_edac.h"
29*4882a593Smuzhiyun #include "fsl_ddr_edac.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static int edac_dev_idx;
32*4882a593Smuzhiyun #ifdef CONFIG_PCI
33*4882a593Smuzhiyun static int edac_pci_idx;
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun  * PCI Err defines
38*4882a593Smuzhiyun  */
39*4882a593Smuzhiyun #ifdef CONFIG_PCI
40*4882a593Smuzhiyun static u32 orig_pci_err_cap_dr;
41*4882a593Smuzhiyun static u32 orig_pci_err_en;
42*4882a593Smuzhiyun #endif
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun static u32 orig_l2_err_disable;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /**************************** PCI Err device ***************************/
47*4882a593Smuzhiyun #ifdef CONFIG_PCI
48*4882a593Smuzhiyun 
mpc85xx_pci_check(struct edac_pci_ctl_info * pci)49*4882a593Smuzhiyun static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
52*4882a593Smuzhiyun 	u32 err_detect;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	/* master aborts can happen during PCI config cycles */
57*4882a593Smuzhiyun 	if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
58*4882a593Smuzhiyun 		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
59*4882a593Smuzhiyun 		return;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	pr_err("PCI error(s) detected\n");
63*4882a593Smuzhiyun 	pr_err("PCI/X ERR_DR register: %#08x\n", err_detect);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	pr_err("PCI/X ERR_ATTRIB register: %#08x\n",
66*4882a593Smuzhiyun 	       in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB));
67*4882a593Smuzhiyun 	pr_err("PCI/X ERR_ADDR register: %#08x\n",
68*4882a593Smuzhiyun 	       in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR));
69*4882a593Smuzhiyun 	pr_err("PCI/X ERR_EXT_ADDR register: %#08x\n",
70*4882a593Smuzhiyun 	       in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR));
71*4882a593Smuzhiyun 	pr_err("PCI/X ERR_DL register: %#08x\n",
72*4882a593Smuzhiyun 	       in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL));
73*4882a593Smuzhiyun 	pr_err("PCI/X ERR_DH register: %#08x\n",
74*4882a593Smuzhiyun 	       in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH));
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	/* clear error bits */
77*4882a593Smuzhiyun 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	if (err_detect & PCI_EDE_PERR_MASK)
80*4882a593Smuzhiyun 		edac_pci_handle_pe(pci, pci->ctl_name);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if ((err_detect & ~PCI_EDE_MULTI_ERR) & ~PCI_EDE_PERR_MASK)
83*4882a593Smuzhiyun 		edac_pci_handle_npe(pci, pci->ctl_name);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
mpc85xx_pcie_check(struct edac_pci_ctl_info * pci)86*4882a593Smuzhiyun static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
89*4882a593Smuzhiyun 	u32 err_detect, err_cap_stat;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
92*4882a593Smuzhiyun 	err_cap_stat = in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	pr_err("PCIe error(s) detected\n");
95*4882a593Smuzhiyun 	pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect);
96*4882a593Smuzhiyun 	pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", err_cap_stat);
97*4882a593Smuzhiyun 	pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n",
98*4882a593Smuzhiyun 			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0));
99*4882a593Smuzhiyun 	pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n",
100*4882a593Smuzhiyun 			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R1));
101*4882a593Smuzhiyun 	pr_err("PCIe ERR_CAP_R2 register: 0x%08x\n",
102*4882a593Smuzhiyun 			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R2));
103*4882a593Smuzhiyun 	pr_err("PCIe ERR_CAP_R3 register: 0x%08x\n",
104*4882a593Smuzhiyun 			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R3));
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	/* clear error bits */
107*4882a593Smuzhiyun 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	/* reset error capture */
110*4882a593Smuzhiyun 	out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, err_cap_stat | 0x1);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
mpc85xx_pcie_find_capability(struct device_node * np)113*4882a593Smuzhiyun static int mpc85xx_pcie_find_capability(struct device_node *np)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct pci_controller *hose;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (!np)
118*4882a593Smuzhiyun 		return -EINVAL;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	hose = pci_find_hose_for_OF_device(np);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
mpc85xx_pci_isr(int irq,void * dev_id)125*4882a593Smuzhiyun static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct edac_pci_ctl_info *pci = dev_id;
128*4882a593Smuzhiyun 	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
129*4882a593Smuzhiyun 	u32 err_detect;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if (!err_detect)
134*4882a593Smuzhiyun 		return IRQ_NONE;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	if (pdata->is_pcie)
137*4882a593Smuzhiyun 		mpc85xx_pcie_check(pci);
138*4882a593Smuzhiyun 	else
139*4882a593Smuzhiyun 		mpc85xx_pci_check(pci);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return IRQ_HANDLED;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
mpc85xx_pci_err_probe(struct platform_device * op)144*4882a593Smuzhiyun static int mpc85xx_pci_err_probe(struct platform_device *op)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	struct edac_pci_ctl_info *pci;
147*4882a593Smuzhiyun 	struct mpc85xx_pci_pdata *pdata;
148*4882a593Smuzhiyun 	struct mpc85xx_edac_pci_plat_data *plat_data;
149*4882a593Smuzhiyun 	struct device_node *of_node;
150*4882a593Smuzhiyun 	struct resource r;
151*4882a593Smuzhiyun 	int res = 0;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
154*4882a593Smuzhiyun 		return -ENOMEM;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mpc85xx_pci_err");
157*4882a593Smuzhiyun 	if (!pci)
158*4882a593Smuzhiyun 		return -ENOMEM;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* make sure error reporting method is sane */
161*4882a593Smuzhiyun 	switch (edac_op_state) {
162*4882a593Smuzhiyun 	case EDAC_OPSTATE_POLL:
163*4882a593Smuzhiyun 	case EDAC_OPSTATE_INT:
164*4882a593Smuzhiyun 		break;
165*4882a593Smuzhiyun 	default:
166*4882a593Smuzhiyun 		edac_op_state = EDAC_OPSTATE_INT;
167*4882a593Smuzhiyun 		break;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	pdata = pci->pvt_info;
171*4882a593Smuzhiyun 	pdata->name = "mpc85xx_pci_err";
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	plat_data = op->dev.platform_data;
174*4882a593Smuzhiyun 	if (!plat_data) {
175*4882a593Smuzhiyun 		dev_err(&op->dev, "no platform data");
176*4882a593Smuzhiyun 		res = -ENXIO;
177*4882a593Smuzhiyun 		goto err;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 	of_node = plat_data->of_node;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (mpc85xx_pcie_find_capability(of_node) > 0)
182*4882a593Smuzhiyun 		pdata->is_pcie = true;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	dev_set_drvdata(&op->dev, pci);
185*4882a593Smuzhiyun 	pci->dev = &op->dev;
186*4882a593Smuzhiyun 	pci->mod_name = EDAC_MOD_STR;
187*4882a593Smuzhiyun 	pci->ctl_name = pdata->name;
188*4882a593Smuzhiyun 	pci->dev_name = dev_name(&op->dev);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (edac_op_state == EDAC_OPSTATE_POLL) {
191*4882a593Smuzhiyun 		if (pdata->is_pcie)
192*4882a593Smuzhiyun 			pci->edac_check = mpc85xx_pcie_check;
193*4882a593Smuzhiyun 		else
194*4882a593Smuzhiyun 			pci->edac_check = mpc85xx_pci_check;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	pdata->edac_idx = edac_pci_idx++;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	res = of_address_to_resource(of_node, 0, &r);
200*4882a593Smuzhiyun 	if (res) {
201*4882a593Smuzhiyun 		pr_err("%s: Unable to get resource for PCI err regs\n", __func__);
202*4882a593Smuzhiyun 		goto err;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	/* we only need the error registers */
206*4882a593Smuzhiyun 	r.start += 0xe00;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
209*4882a593Smuzhiyun 					pdata->name)) {
210*4882a593Smuzhiyun 		pr_err("%s: Error while requesting mem region\n", __func__);
211*4882a593Smuzhiyun 		res = -EBUSY;
212*4882a593Smuzhiyun 		goto err;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
216*4882a593Smuzhiyun 	if (!pdata->pci_vbase) {
217*4882a593Smuzhiyun 		pr_err("%s: Unable to setup PCI err regs\n", __func__);
218*4882a593Smuzhiyun 		res = -ENOMEM;
219*4882a593Smuzhiyun 		goto err;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (pdata->is_pcie) {
223*4882a593Smuzhiyun 		orig_pci_err_cap_dr =
224*4882a593Smuzhiyun 		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR);
225*4882a593Smuzhiyun 		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, ~0);
226*4882a593Smuzhiyun 		orig_pci_err_en =
227*4882a593Smuzhiyun 		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
228*4882a593Smuzhiyun 		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, 0);
229*4882a593Smuzhiyun 	} else {
230*4882a593Smuzhiyun 		orig_pci_err_cap_dr =
231*4882a593Smuzhiyun 		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		/* PCI master abort is expected during config cycles */
234*4882a593Smuzhiyun 		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 		orig_pci_err_en =
237*4882a593Smuzhiyun 		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 		/* disable master abort reporting */
240*4882a593Smuzhiyun 		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/* clear error bits */
244*4882a593Smuzhiyun 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/* reset error capture */
247*4882a593Smuzhiyun 	out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, 0x1);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
250*4882a593Smuzhiyun 		edac_dbg(3, "failed edac_pci_add_device()\n");
251*4882a593Smuzhiyun 		goto err;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	if (edac_op_state == EDAC_OPSTATE_INT) {
255*4882a593Smuzhiyun 		pdata->irq = irq_of_parse_and_map(of_node, 0);
256*4882a593Smuzhiyun 		res = devm_request_irq(&op->dev, pdata->irq,
257*4882a593Smuzhiyun 				       mpc85xx_pci_isr,
258*4882a593Smuzhiyun 				       IRQF_SHARED,
259*4882a593Smuzhiyun 				       "[EDAC] PCI err", pci);
260*4882a593Smuzhiyun 		if (res < 0) {
261*4882a593Smuzhiyun 			pr_err("%s: Unable to request irq %d for MPC85xx PCI err\n",
262*4882a593Smuzhiyun 				__func__, pdata->irq);
263*4882a593Smuzhiyun 			irq_dispose_mapping(pdata->irq);
264*4882a593Smuzhiyun 			res = -ENODEV;
265*4882a593Smuzhiyun 			goto err2;
266*4882a593Smuzhiyun 		}
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 		pr_info(EDAC_MOD_STR " acquired irq %d for PCI Err\n",
269*4882a593Smuzhiyun 		       pdata->irq);
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (pdata->is_pcie) {
273*4882a593Smuzhiyun 		/*
274*4882a593Smuzhiyun 		 * Enable all PCIe error interrupt & error detect except invalid
275*4882a593Smuzhiyun 		 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA access interrupt generation
276*4882a593Smuzhiyun 		 * enable bit and invalid PEX_CONFIG_ADDR/PEX_CONFIG_DATA access
277*4882a593Smuzhiyun 		 * detection enable bit. Because PCIe bus code to initialize and
278*4882a593Smuzhiyun 		 * configure these PCIe devices on booting will use some invalid
279*4882a593Smuzhiyun 		 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA, edac driver prints the much
280*4882a593Smuzhiyun 		 * notice information. So disable this detect to fix ugly print.
281*4882a593Smuzhiyun 		 */
282*4882a593Smuzhiyun 		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0
283*4882a593Smuzhiyun 			 & ~PEX_ERR_ICCAIE_EN_BIT);
284*4882a593Smuzhiyun 		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, 0
285*4882a593Smuzhiyun 			 | PEX_ERR_ICCAD_DISR_BIT);
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
289*4882a593Smuzhiyun 	edac_dbg(3, "success\n");
290*4882a593Smuzhiyun 	pr_info(EDAC_MOD_STR " PCI err registered\n");
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	return 0;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun err2:
295*4882a593Smuzhiyun 	edac_pci_del_device(&op->dev);
296*4882a593Smuzhiyun err:
297*4882a593Smuzhiyun 	edac_pci_free_ctl_info(pci);
298*4882a593Smuzhiyun 	devres_release_group(&op->dev, mpc85xx_pci_err_probe);
299*4882a593Smuzhiyun 	return res;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
mpc85xx_pci_err_remove(struct platform_device * op)302*4882a593Smuzhiyun static int mpc85xx_pci_err_remove(struct platform_device *op)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev);
305*4882a593Smuzhiyun 	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	edac_dbg(0, "\n");
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, orig_pci_err_cap_dr);
310*4882a593Smuzhiyun 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	edac_pci_del_device(&op->dev);
313*4882a593Smuzhiyun 	edac_pci_free_ctl_info(pci);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return 0;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun static const struct platform_device_id mpc85xx_pci_err_match[] = {
319*4882a593Smuzhiyun 	{
320*4882a593Smuzhiyun 		.name = "mpc85xx-pci-edac"
321*4882a593Smuzhiyun 	},
322*4882a593Smuzhiyun 	{}
323*4882a593Smuzhiyun };
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun static struct platform_driver mpc85xx_pci_err_driver = {
326*4882a593Smuzhiyun 	.probe = mpc85xx_pci_err_probe,
327*4882a593Smuzhiyun 	.remove = mpc85xx_pci_err_remove,
328*4882a593Smuzhiyun 	.id_table = mpc85xx_pci_err_match,
329*4882a593Smuzhiyun 	.driver = {
330*4882a593Smuzhiyun 		.name = "mpc85xx_pci_err",
331*4882a593Smuzhiyun 		.suppress_bind_attrs = true,
332*4882a593Smuzhiyun 	},
333*4882a593Smuzhiyun };
334*4882a593Smuzhiyun #endif				/* CONFIG_PCI */
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun /**************************** L2 Err device ***************************/
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun /************************ L2 SYSFS parts ***********************************/
339*4882a593Smuzhiyun 
mpc85xx_l2_inject_data_hi_show(struct edac_device_ctl_info * edac_dev,char * data)340*4882a593Smuzhiyun static ssize_t mpc85xx_l2_inject_data_hi_show(struct edac_device_ctl_info
341*4882a593Smuzhiyun 					      *edac_dev, char *data)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
344*4882a593Smuzhiyun 	return sprintf(data, "0x%08x",
345*4882a593Smuzhiyun 		       in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJHI));
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun 
mpc85xx_l2_inject_data_lo_show(struct edac_device_ctl_info * edac_dev,char * data)348*4882a593Smuzhiyun static ssize_t mpc85xx_l2_inject_data_lo_show(struct edac_device_ctl_info
349*4882a593Smuzhiyun 					      *edac_dev, char *data)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
352*4882a593Smuzhiyun 	return sprintf(data, "0x%08x",
353*4882a593Smuzhiyun 		       in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJLO));
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
mpc85xx_l2_inject_ctrl_show(struct edac_device_ctl_info * edac_dev,char * data)356*4882a593Smuzhiyun static ssize_t mpc85xx_l2_inject_ctrl_show(struct edac_device_ctl_info
357*4882a593Smuzhiyun 					   *edac_dev, char *data)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
360*4882a593Smuzhiyun 	return sprintf(data, "0x%08x",
361*4882a593Smuzhiyun 		       in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJCTL));
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
mpc85xx_l2_inject_data_hi_store(struct edac_device_ctl_info * edac_dev,const char * data,size_t count)364*4882a593Smuzhiyun static ssize_t mpc85xx_l2_inject_data_hi_store(struct edac_device_ctl_info
365*4882a593Smuzhiyun 					       *edac_dev, const char *data,
366*4882a593Smuzhiyun 					       size_t count)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
369*4882a593Smuzhiyun 	if (isdigit(*data)) {
370*4882a593Smuzhiyun 		out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJHI,
371*4882a593Smuzhiyun 			 simple_strtoul(data, NULL, 0));
372*4882a593Smuzhiyun 		return count;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 	return 0;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun 
mpc85xx_l2_inject_data_lo_store(struct edac_device_ctl_info * edac_dev,const char * data,size_t count)377*4882a593Smuzhiyun static ssize_t mpc85xx_l2_inject_data_lo_store(struct edac_device_ctl_info
378*4882a593Smuzhiyun 					       *edac_dev, const char *data,
379*4882a593Smuzhiyun 					       size_t count)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
382*4882a593Smuzhiyun 	if (isdigit(*data)) {
383*4882a593Smuzhiyun 		out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJLO,
384*4882a593Smuzhiyun 			 simple_strtoul(data, NULL, 0));
385*4882a593Smuzhiyun 		return count;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 	return 0;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
mpc85xx_l2_inject_ctrl_store(struct edac_device_ctl_info * edac_dev,const char * data,size_t count)390*4882a593Smuzhiyun static ssize_t mpc85xx_l2_inject_ctrl_store(struct edac_device_ctl_info
391*4882a593Smuzhiyun 					    *edac_dev, const char *data,
392*4882a593Smuzhiyun 					    size_t count)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
395*4882a593Smuzhiyun 	if (isdigit(*data)) {
396*4882a593Smuzhiyun 		out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJCTL,
397*4882a593Smuzhiyun 			 simple_strtoul(data, NULL, 0));
398*4882a593Smuzhiyun 		return count;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 	return 0;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun static struct edac_dev_sysfs_attribute mpc85xx_l2_sysfs_attributes[] = {
404*4882a593Smuzhiyun 	{
405*4882a593Smuzhiyun 	 .attr = {
406*4882a593Smuzhiyun 		  .name = "inject_data_hi",
407*4882a593Smuzhiyun 		  .mode = (S_IRUGO | S_IWUSR)
408*4882a593Smuzhiyun 		  },
409*4882a593Smuzhiyun 	 .show = mpc85xx_l2_inject_data_hi_show,
410*4882a593Smuzhiyun 	 .store = mpc85xx_l2_inject_data_hi_store},
411*4882a593Smuzhiyun 	{
412*4882a593Smuzhiyun 	 .attr = {
413*4882a593Smuzhiyun 		  .name = "inject_data_lo",
414*4882a593Smuzhiyun 		  .mode = (S_IRUGO | S_IWUSR)
415*4882a593Smuzhiyun 		  },
416*4882a593Smuzhiyun 	 .show = mpc85xx_l2_inject_data_lo_show,
417*4882a593Smuzhiyun 	 .store = mpc85xx_l2_inject_data_lo_store},
418*4882a593Smuzhiyun 	{
419*4882a593Smuzhiyun 	 .attr = {
420*4882a593Smuzhiyun 		  .name = "inject_ctrl",
421*4882a593Smuzhiyun 		  .mode = (S_IRUGO | S_IWUSR)
422*4882a593Smuzhiyun 		  },
423*4882a593Smuzhiyun 	 .show = mpc85xx_l2_inject_ctrl_show,
424*4882a593Smuzhiyun 	 .store = mpc85xx_l2_inject_ctrl_store},
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	/* End of list */
427*4882a593Smuzhiyun 	{
428*4882a593Smuzhiyun 	 .attr = {.name = NULL}
429*4882a593Smuzhiyun 	 }
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun 
mpc85xx_set_l2_sysfs_attributes(struct edac_device_ctl_info * edac_dev)432*4882a593Smuzhiyun static void mpc85xx_set_l2_sysfs_attributes(struct edac_device_ctl_info
433*4882a593Smuzhiyun 					    *edac_dev)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	edac_dev->sysfs_attributes = mpc85xx_l2_sysfs_attributes;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun /***************************** L2 ops ***********************************/
439*4882a593Smuzhiyun 
mpc85xx_l2_check(struct edac_device_ctl_info * edac_dev)440*4882a593Smuzhiyun static void mpc85xx_l2_check(struct edac_device_ctl_info *edac_dev)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
443*4882a593Smuzhiyun 	u32 err_detect;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	err_detect = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET);
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	if (!(err_detect & L2_EDE_MASK))
448*4882a593Smuzhiyun 		return;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	pr_err("ECC Error in CPU L2 cache\n");
451*4882a593Smuzhiyun 	pr_err("L2 Error Detect Register: 0x%08x\n", err_detect);
452*4882a593Smuzhiyun 	pr_err("L2 Error Capture Data High Register: 0x%08x\n",
453*4882a593Smuzhiyun 	       in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATAHI));
454*4882a593Smuzhiyun 	pr_err("L2 Error Capture Data Lo Register: 0x%08x\n",
455*4882a593Smuzhiyun 	       in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATALO));
456*4882a593Smuzhiyun 	pr_err("L2 Error Syndrome Register: 0x%08x\n",
457*4882a593Smuzhiyun 	       in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTECC));
458*4882a593Smuzhiyun 	pr_err("L2 Error Attributes Capture Register: 0x%08x\n",
459*4882a593Smuzhiyun 	       in_be32(pdata->l2_vbase + MPC85XX_L2_ERRATTR));
460*4882a593Smuzhiyun 	pr_err("L2 Error Address Capture Register: 0x%08x\n",
461*4882a593Smuzhiyun 	       in_be32(pdata->l2_vbase + MPC85XX_L2_ERRADDR));
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/* clear error detect register */
464*4882a593Smuzhiyun 	out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET, err_detect);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	if (err_detect & L2_EDE_CE_MASK)
467*4882a593Smuzhiyun 		edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	if (err_detect & L2_EDE_UE_MASK)
470*4882a593Smuzhiyun 		edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
mpc85xx_l2_isr(int irq,void * dev_id)473*4882a593Smuzhiyun static irqreturn_t mpc85xx_l2_isr(int irq, void *dev_id)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct edac_device_ctl_info *edac_dev = dev_id;
476*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
477*4882a593Smuzhiyun 	u32 err_detect;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	err_detect = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET);
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	if (!(err_detect & L2_EDE_MASK))
482*4882a593Smuzhiyun 		return IRQ_NONE;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	mpc85xx_l2_check(edac_dev);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	return IRQ_HANDLED;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun 
mpc85xx_l2_err_probe(struct platform_device * op)489*4882a593Smuzhiyun static int mpc85xx_l2_err_probe(struct platform_device *op)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	struct edac_device_ctl_info *edac_dev;
492*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata;
493*4882a593Smuzhiyun 	struct resource r;
494*4882a593Smuzhiyun 	int res;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (!devres_open_group(&op->dev, mpc85xx_l2_err_probe, GFP_KERNEL))
497*4882a593Smuzhiyun 		return -ENOMEM;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
500*4882a593Smuzhiyun 					      "cpu", 1, "L", 1, 2, NULL, 0,
501*4882a593Smuzhiyun 					      edac_dev_idx);
502*4882a593Smuzhiyun 	if (!edac_dev) {
503*4882a593Smuzhiyun 		devres_release_group(&op->dev, mpc85xx_l2_err_probe);
504*4882a593Smuzhiyun 		return -ENOMEM;
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	pdata = edac_dev->pvt_info;
508*4882a593Smuzhiyun 	pdata->name = "mpc85xx_l2_err";
509*4882a593Smuzhiyun 	edac_dev->dev = &op->dev;
510*4882a593Smuzhiyun 	dev_set_drvdata(edac_dev->dev, edac_dev);
511*4882a593Smuzhiyun 	edac_dev->ctl_name = pdata->name;
512*4882a593Smuzhiyun 	edac_dev->dev_name = pdata->name;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	res = of_address_to_resource(op->dev.of_node, 0, &r);
515*4882a593Smuzhiyun 	if (res) {
516*4882a593Smuzhiyun 		pr_err("%s: Unable to get resource for L2 err regs\n", __func__);
517*4882a593Smuzhiyun 		goto err;
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	/* we only need the error registers */
521*4882a593Smuzhiyun 	r.start += 0xe00;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
524*4882a593Smuzhiyun 				     pdata->name)) {
525*4882a593Smuzhiyun 		pr_err("%s: Error while requesting mem region\n", __func__);
526*4882a593Smuzhiyun 		res = -EBUSY;
527*4882a593Smuzhiyun 		goto err;
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	pdata->l2_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
531*4882a593Smuzhiyun 	if (!pdata->l2_vbase) {
532*4882a593Smuzhiyun 		pr_err("%s: Unable to setup L2 err regs\n", __func__);
533*4882a593Smuzhiyun 		res = -ENOMEM;
534*4882a593Smuzhiyun 		goto err;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET, ~0);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	orig_l2_err_disable = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	/* clear the err_dis */
542*4882a593Smuzhiyun 	out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS, 0);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	edac_dev->mod_name = EDAC_MOD_STR;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	if (edac_op_state == EDAC_OPSTATE_POLL)
547*4882a593Smuzhiyun 		edac_dev->edac_check = mpc85xx_l2_check;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	mpc85xx_set_l2_sysfs_attributes(edac_dev);
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	pdata->edac_idx = edac_dev_idx++;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	if (edac_device_add_device(edac_dev) > 0) {
554*4882a593Smuzhiyun 		edac_dbg(3, "failed edac_device_add_device()\n");
555*4882a593Smuzhiyun 		goto err;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	if (edac_op_state == EDAC_OPSTATE_INT) {
559*4882a593Smuzhiyun 		pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
560*4882a593Smuzhiyun 		res = devm_request_irq(&op->dev, pdata->irq,
561*4882a593Smuzhiyun 				       mpc85xx_l2_isr, IRQF_SHARED,
562*4882a593Smuzhiyun 				       "[EDAC] L2 err", edac_dev);
563*4882a593Smuzhiyun 		if (res < 0) {
564*4882a593Smuzhiyun 			pr_err("%s: Unable to request irq %d for MPC85xx L2 err\n",
565*4882a593Smuzhiyun 				__func__, pdata->irq);
566*4882a593Smuzhiyun 			irq_dispose_mapping(pdata->irq);
567*4882a593Smuzhiyun 			res = -ENODEV;
568*4882a593Smuzhiyun 			goto err2;
569*4882a593Smuzhiyun 		}
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 		pr_info(EDAC_MOD_STR " acquired irq %d for L2 Err\n", pdata->irq);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 		edac_dev->op_state = OP_RUNNING_INTERRUPT;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 		out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, L2_EIE_MASK);
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	devres_remove_group(&op->dev, mpc85xx_l2_err_probe);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	edac_dbg(3, "success\n");
581*4882a593Smuzhiyun 	pr_info(EDAC_MOD_STR " L2 err registered\n");
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	return 0;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun err2:
586*4882a593Smuzhiyun 	edac_device_del_device(&op->dev);
587*4882a593Smuzhiyun err:
588*4882a593Smuzhiyun 	devres_release_group(&op->dev, mpc85xx_l2_err_probe);
589*4882a593Smuzhiyun 	edac_device_free_ctl_info(edac_dev);
590*4882a593Smuzhiyun 	return res;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun 
mpc85xx_l2_err_remove(struct platform_device * op)593*4882a593Smuzhiyun static int mpc85xx_l2_err_remove(struct platform_device *op)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun 	struct edac_device_ctl_info *edac_dev = dev_get_drvdata(&op->dev);
596*4882a593Smuzhiyun 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	edac_dbg(0, "\n");
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	if (edac_op_state == EDAC_OPSTATE_INT) {
601*4882a593Smuzhiyun 		out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, 0);
602*4882a593Smuzhiyun 		irq_dispose_mapping(pdata->irq);
603*4882a593Smuzhiyun 	}
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS, orig_l2_err_disable);
606*4882a593Smuzhiyun 	edac_device_del_device(&op->dev);
607*4882a593Smuzhiyun 	edac_device_free_ctl_info(edac_dev);
608*4882a593Smuzhiyun 	return 0;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun static const struct of_device_id mpc85xx_l2_err_of_match[] = {
612*4882a593Smuzhiyun /* deprecate the fsl,85.. forms in the future, 2.6.30? */
613*4882a593Smuzhiyun 	{ .compatible = "fsl,8540-l2-cache-controller", },
614*4882a593Smuzhiyun 	{ .compatible = "fsl,8541-l2-cache-controller", },
615*4882a593Smuzhiyun 	{ .compatible = "fsl,8544-l2-cache-controller", },
616*4882a593Smuzhiyun 	{ .compatible = "fsl,8548-l2-cache-controller", },
617*4882a593Smuzhiyun 	{ .compatible = "fsl,8555-l2-cache-controller", },
618*4882a593Smuzhiyun 	{ .compatible = "fsl,8568-l2-cache-controller", },
619*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8536-l2-cache-controller", },
620*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8540-l2-cache-controller", },
621*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8541-l2-cache-controller", },
622*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8544-l2-cache-controller", },
623*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8548-l2-cache-controller", },
624*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8555-l2-cache-controller", },
625*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8560-l2-cache-controller", },
626*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8568-l2-cache-controller", },
627*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8569-l2-cache-controller", },
628*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8572-l2-cache-controller", },
629*4882a593Smuzhiyun 	{ .compatible = "fsl,p1020-l2-cache-controller", },
630*4882a593Smuzhiyun 	{ .compatible = "fsl,p1021-l2-cache-controller", },
631*4882a593Smuzhiyun 	{ .compatible = "fsl,p2020-l2-cache-controller", },
632*4882a593Smuzhiyun 	{ .compatible = "fsl,t2080-l2-cache-controller", },
633*4882a593Smuzhiyun 	{},
634*4882a593Smuzhiyun };
635*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, mpc85xx_l2_err_of_match);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun static struct platform_driver mpc85xx_l2_err_driver = {
638*4882a593Smuzhiyun 	.probe = mpc85xx_l2_err_probe,
639*4882a593Smuzhiyun 	.remove = mpc85xx_l2_err_remove,
640*4882a593Smuzhiyun 	.driver = {
641*4882a593Smuzhiyun 		.name = "mpc85xx_l2_err",
642*4882a593Smuzhiyun 		.of_match_table = mpc85xx_l2_err_of_match,
643*4882a593Smuzhiyun 	},
644*4882a593Smuzhiyun };
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun static const struct of_device_id mpc85xx_mc_err_of_match[] = {
647*4882a593Smuzhiyun /* deprecate the fsl,85.. forms in the future, 2.6.30? */
648*4882a593Smuzhiyun 	{ .compatible = "fsl,8540-memory-controller", },
649*4882a593Smuzhiyun 	{ .compatible = "fsl,8541-memory-controller", },
650*4882a593Smuzhiyun 	{ .compatible = "fsl,8544-memory-controller", },
651*4882a593Smuzhiyun 	{ .compatible = "fsl,8548-memory-controller", },
652*4882a593Smuzhiyun 	{ .compatible = "fsl,8555-memory-controller", },
653*4882a593Smuzhiyun 	{ .compatible = "fsl,8568-memory-controller", },
654*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8536-memory-controller", },
655*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8540-memory-controller", },
656*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8541-memory-controller", },
657*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8544-memory-controller", },
658*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8548-memory-controller", },
659*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8555-memory-controller", },
660*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8560-memory-controller", },
661*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8568-memory-controller", },
662*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8569-memory-controller", },
663*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8572-memory-controller", },
664*4882a593Smuzhiyun 	{ .compatible = "fsl,mpc8349-memory-controller", },
665*4882a593Smuzhiyun 	{ .compatible = "fsl,p1020-memory-controller", },
666*4882a593Smuzhiyun 	{ .compatible = "fsl,p1021-memory-controller", },
667*4882a593Smuzhiyun 	{ .compatible = "fsl,p2020-memory-controller", },
668*4882a593Smuzhiyun 	{ .compatible = "fsl,qoriq-memory-controller", },
669*4882a593Smuzhiyun 	{},
670*4882a593Smuzhiyun };
671*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun static struct platform_driver mpc85xx_mc_err_driver = {
674*4882a593Smuzhiyun 	.probe = fsl_mc_err_probe,
675*4882a593Smuzhiyun 	.remove = fsl_mc_err_remove,
676*4882a593Smuzhiyun 	.driver = {
677*4882a593Smuzhiyun 		.name = "mpc85xx_mc_err",
678*4882a593Smuzhiyun 		.of_match_table = mpc85xx_mc_err_of_match,
679*4882a593Smuzhiyun 	},
680*4882a593Smuzhiyun };
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun static struct platform_driver * const drivers[] = {
683*4882a593Smuzhiyun 	&mpc85xx_mc_err_driver,
684*4882a593Smuzhiyun 	&mpc85xx_l2_err_driver,
685*4882a593Smuzhiyun #ifdef CONFIG_PCI
686*4882a593Smuzhiyun 	&mpc85xx_pci_err_driver,
687*4882a593Smuzhiyun #endif
688*4882a593Smuzhiyun };
689*4882a593Smuzhiyun 
mpc85xx_mc_init(void)690*4882a593Smuzhiyun static int __init mpc85xx_mc_init(void)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	int res = 0;
693*4882a593Smuzhiyun 	u32 __maybe_unused pvr = 0;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	pr_info("Freescale(R) MPC85xx EDAC driver, (C) 2006 Montavista Software\n");
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	/* make sure error reporting method is sane */
698*4882a593Smuzhiyun 	switch (edac_op_state) {
699*4882a593Smuzhiyun 	case EDAC_OPSTATE_POLL:
700*4882a593Smuzhiyun 	case EDAC_OPSTATE_INT:
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun 	default:
703*4882a593Smuzhiyun 		edac_op_state = EDAC_OPSTATE_INT;
704*4882a593Smuzhiyun 		break;
705*4882a593Smuzhiyun 	}
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
708*4882a593Smuzhiyun 	if (res)
709*4882a593Smuzhiyun 		pr_warn(EDAC_MOD_STR "drivers fail to register\n");
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	return 0;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun module_init(mpc85xx_mc_init);
715*4882a593Smuzhiyun 
mpc85xx_mc_exit(void)716*4882a593Smuzhiyun static void __exit mpc85xx_mc_exit(void)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun 	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun module_exit(mpc85xx_mc_exit);
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun MODULE_LICENSE("GPL");
724*4882a593Smuzhiyun MODULE_AUTHOR("Montavista Software, Inc.");
725*4882a593Smuzhiyun module_param(edac_op_state, int, 0444);
726*4882a593Smuzhiyun MODULE_PARM_DESC(edac_op_state,
727*4882a593Smuzhiyun 		 "EDAC Error Reporting state: 0=Poll, 2=Interrupt");
728