ARM: dts: add 'dr_mode' property to hsotg devices for exynos boards
[linux/fpc-iii.git] / drivers / memory / fsl-corenet-cf.c
blobfc7ab5a3561e708f24d448209df8d8b980ed6f53
1 /*
2 * CoreNet Coherency Fabric error reporting
4 * Copyright 2014 Freescale Semiconductor Inc.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
12 #include <linux/interrupt.h>
13 #include <linux/io.h>
14 #include <linux/irq.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_address.h>
18 #include <linux/of_device.h>
19 #include <linux/of_irq.h>
20 #include <linux/platform_device.h>
22 enum ccf_version {
23 CCF1,
24 CCF2,
27 struct ccf_info {
28 enum ccf_version version;
29 int err_reg_offs;
32 static const struct ccf_info ccf1_info = {
33 .version = CCF1,
34 .err_reg_offs = 0xa00,
37 static const struct ccf_info ccf2_info = {
38 .version = CCF2,
39 .err_reg_offs = 0xe40,
42 static const struct of_device_id ccf_matches[] = {
44 .compatible = "fsl,corenet1-cf",
45 .data = &ccf1_info,
48 .compatible = "fsl,corenet2-cf",
49 .data = &ccf2_info,
54 struct ccf_err_regs {
55 u32 errdet; /* 0x00 Error Detect Register */
56 /* 0x04 Error Enable (ccf1)/Disable (ccf2) Register */
57 u32 errdis;
58 /* 0x08 Error Interrupt Enable Register (ccf2 only) */
59 u32 errinten;
60 u32 cecar; /* 0x0c Error Capture Attribute Register */
61 u32 cecaddrh; /* 0x10 Error Capture Address High */
62 u32 cecaddrl; /* 0x14 Error Capture Address Low */
63 u32 cecar2; /* 0x18 Error Capture Attribute Register 2 */
66 /* LAE/CV also valid for errdis and errinten */
67 #define ERRDET_LAE (1 << 0) /* Local Access Error */
68 #define ERRDET_CV (1 << 1) /* Coherency Violation */
69 #define ERRDET_CTYPE_SHIFT 26 /* Capture Type (ccf2 only) */
70 #define ERRDET_CTYPE_MASK (0x1f << ERRDET_CTYPE_SHIFT)
71 #define ERRDET_CAP (1 << 31) /* Capture Valid (ccf2 only) */
73 #define CECAR_VAL (1 << 0) /* Valid (ccf1 only) */
74 #define CECAR_UVT (1 << 15) /* Unavailable target ID (ccf1) */
75 #define CECAR_SRCID_SHIFT_CCF1 24
76 #define CECAR_SRCID_MASK_CCF1 (0xff << CECAR_SRCID_SHIFT_CCF1)
77 #define CECAR_SRCID_SHIFT_CCF2 18
78 #define CECAR_SRCID_MASK_CCF2 (0xff << CECAR_SRCID_SHIFT_CCF2)
80 #define CECADDRH_ADDRH 0xff
82 struct ccf_private {
83 const struct ccf_info *info;
84 struct device *dev;
85 void __iomem *regs;
86 struct ccf_err_regs __iomem *err_regs;
89 static irqreturn_t ccf_irq(int irq, void *dev_id)
91 struct ccf_private *ccf = dev_id;
92 static DEFINE_RATELIMIT_STATE(ratelimit, DEFAULT_RATELIMIT_INTERVAL,
93 DEFAULT_RATELIMIT_BURST);
94 u32 errdet, cecar, cecar2;
95 u64 addr;
96 u32 src_id;
97 bool uvt = false;
98 bool cap_valid = false;
100 errdet = ioread32be(&ccf->err_regs->errdet);
101 cecar = ioread32be(&ccf->err_regs->cecar);
102 cecar2 = ioread32be(&ccf->err_regs->cecar2);
103 addr = ioread32be(&ccf->err_regs->cecaddrl);
104 addr |= ((u64)(ioread32be(&ccf->err_regs->cecaddrh) &
105 CECADDRH_ADDRH)) << 32;
107 if (!__ratelimit(&ratelimit))
108 goto out;
110 switch (ccf->info->version) {
111 case CCF1:
112 if (cecar & CECAR_VAL) {
113 if (cecar & CECAR_UVT)
114 uvt = true;
116 src_id = (cecar & CECAR_SRCID_MASK_CCF1) >>
117 CECAR_SRCID_SHIFT_CCF1;
118 cap_valid = true;
121 break;
122 case CCF2:
123 if (errdet & ERRDET_CAP) {
124 src_id = (cecar & CECAR_SRCID_MASK_CCF2) >>
125 CECAR_SRCID_SHIFT_CCF2;
126 cap_valid = true;
129 break;
132 dev_crit(ccf->dev, "errdet 0x%08x cecar 0x%08x cecar2 0x%08x\n",
133 errdet, cecar, cecar2);
135 if (errdet & ERRDET_LAE) {
136 if (uvt)
137 dev_crit(ccf->dev, "LAW Unavailable Target ID\n");
138 else
139 dev_crit(ccf->dev, "Local Access Window Error\n");
142 if (errdet & ERRDET_CV)
143 dev_crit(ccf->dev, "Coherency Violation\n");
145 if (cap_valid) {
146 dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n",
147 addr, src_id);
150 out:
151 iowrite32be(errdet, &ccf->err_regs->errdet);
152 return errdet ? IRQ_HANDLED : IRQ_NONE;
155 static int ccf_probe(struct platform_device *pdev)
157 struct ccf_private *ccf;
158 struct resource *r;
159 const struct of_device_id *match;
160 int ret, irq;
162 match = of_match_device(ccf_matches, &pdev->dev);
163 if (WARN_ON(!match))
164 return -ENODEV;
166 ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL);
167 if (!ccf)
168 return -ENOMEM;
170 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
171 if (!r) {
172 dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
173 return -ENXIO;
176 ccf->regs = devm_ioremap_resource(&pdev->dev, r);
177 if (IS_ERR(ccf->regs)) {
178 dev_err(&pdev->dev, "%s: can't map mem resource\n", __func__);
179 return PTR_ERR(ccf->regs);
182 ccf->dev = &pdev->dev;
183 ccf->info = match->data;
184 ccf->err_regs = ccf->regs + ccf->info->err_reg_offs;
186 dev_set_drvdata(&pdev->dev, ccf);
188 irq = platform_get_irq(pdev, 0);
189 if (!irq) {
190 dev_err(&pdev->dev, "%s: no irq\n", __func__);
191 return -ENXIO;
194 ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
195 if (ret) {
196 dev_err(&pdev->dev, "%s: can't request irq\n", __func__);
197 return ret;
200 switch (ccf->info->version) {
201 case CCF1:
202 /* On CCF1 this register enables rather than disables. */
203 iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errdis);
204 break;
206 case CCF2:
207 iowrite32be(0, &ccf->err_regs->errdis);
208 iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errinten);
209 break;
212 return 0;
215 static int ccf_remove(struct platform_device *pdev)
217 struct ccf_private *ccf = dev_get_drvdata(&pdev->dev);
219 switch (ccf->info->version) {
220 case CCF1:
221 iowrite32be(0, &ccf->err_regs->errdis);
222 break;
224 case CCF2:
226 * We clear errdis on ccf1 because that's the only way to
227 * disable interrupts, but on ccf2 there's no need to disable
228 * detection.
230 iowrite32be(0, &ccf->err_regs->errinten);
231 break;
234 return 0;
237 static struct platform_driver ccf_driver = {
238 .driver = {
239 .name = KBUILD_MODNAME,
240 .of_match_table = ccf_matches,
242 .probe = ccf_probe,
243 .remove = ccf_remove,
246 module_platform_driver(ccf_driver);
248 MODULE_LICENSE("GPL");
249 MODULE_AUTHOR("Freescale Semiconductor");
250 MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting");