diff options
author | York Sun <york.sun@nxp.com> | 2016-08-09 17:55:43 -0400 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2016-09-01 04:28:02 -0400 |
commit | 339fdff14c1ed34acc9c3368e01b56f80692cf83 (patch) | |
tree | 390b7ae614e13a47f61dfda06939d6b1923b938b | |
parent | 4e2c3252d2426cd05286e38650365f215571d3c6 (diff) |
EDAC, fsl_ddr: Add support for little endian
Get endianness from device tree. Both big endian and little endian are
supported. Default to big endian for backwards compatibility to MPC85xx.
Signed-off-by: York Sun <york.sun@nxp.com>
Acked-by: Rob Herring <robh+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: linux-edac <linux-edac@vger.kernel.org>
Cc: morbidrsa@gmail.com
Cc: oss@buserror.net
Cc: stuart.yoder@nxp.com
Link: http://lkml.kernel.org/r/1470779760-16483-7-git-send-email-york.sun@nxp.com
Signed-off-by: Borislav Petkov <bp@suse.de>
-rw-r--r-- | Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt (renamed from Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt) | 2 | ||||
-rw-r--r-- | drivers/edac/fsl_ddr_edac.c | 96 |
2 files changed, 58 insertions, 40 deletions
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt index f87856faf1ab..dde6d837083a 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt +++ b/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt | |||
@@ -7,6 +7,8 @@ Properties: | |||
7 | "fsl,qoriq-memory-controller". | 7 | "fsl,qoriq-memory-controller". |
8 | - reg : Address and size of DDR controller registers | 8 | - reg : Address and size of DDR controller registers |
9 | - interrupts : Error interrupt of DDR controller | 9 | - interrupts : Error interrupt of DDR controller |
10 | - little-endian : Specifies little-endian access to registers | ||
11 | If omitted, big-endian will be used. | ||
10 | 12 | ||
11 | Example 1: | 13 | Example 1: |
12 | 14 | ||
diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 46b00e15e442..6d4dd84a9d48 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c | |||
@@ -13,7 +13,6 @@ | |||
13 | * the terms of the GNU General Public License version 2. This program | 13 | * the terms of the GNU General Public License version 2. This program |
14 | * is licensed "as is" without any warranty of any kind, whether express | 14 | * is licensed "as is" without any warranty of any kind, whether express |
15 | * or implied. | 15 | * or implied. |
16 | * | ||
17 | */ | 16 | */ |
18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
19 | #include <linux/init.h> | 18 | #include <linux/init.h> |
@@ -37,6 +36,20 @@ static int edac_mc_idx; | |||
37 | 36 | ||
38 | static u32 orig_ddr_err_disable; | 37 | static u32 orig_ddr_err_disable; |
39 | static u32 orig_ddr_err_sbe; | 38 | static u32 orig_ddr_err_sbe; |
39 | static bool little_endian; | ||
40 | |||
41 | static inline u32 ddr_in32(void __iomem *addr) | ||
42 | { | ||
43 | return little_endian ? ioread32(addr) : ioread32be(addr); | ||
44 | } | ||
45 | |||
46 | static inline void ddr_out32(void __iomem *addr, u32 value) | ||
47 | { | ||
48 | if (little_endian) | ||
49 | iowrite32(value, addr); | ||
50 | else | ||
51 | iowrite32be(value, addr); | ||
52 | } | ||
40 | 53 | ||
41 | /************************ MC SYSFS parts ***********************************/ | 54 | /************************ MC SYSFS parts ***********************************/ |
42 | 55 | ||
@@ -49,8 +62,7 @@ static ssize_t fsl_mc_inject_data_hi_show(struct device *dev, | |||
49 | struct mem_ctl_info *mci = to_mci(dev); | 62 | struct mem_ctl_info *mci = to_mci(dev); |
50 | struct fsl_mc_pdata *pdata = mci->pvt_info; | 63 | struct fsl_mc_pdata *pdata = mci->pvt_info; |
51 | return sprintf(data, "0x%08x", | 64 | return sprintf(data, "0x%08x", |
52 | in_be32(pdata->mc_vbase + | 65 | ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI)); |
53 | FSL_MC_DATA_ERR_INJECT_HI)); | ||
54 | } | 66 | } |
55 | 67 | ||
56 | static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, | 68 | static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, |
@@ -60,8 +72,7 @@ static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, | |||
60 | struct mem_ctl_info *mci = to_mci(dev); | 72 | struct mem_ctl_info *mci = to_mci(dev); |
61 | struct fsl_mc_pdata *pdata = mci->pvt_info; | 73 | struct fsl_mc_pdata *pdata = mci->pvt_info; |
62 | return sprintf(data, "0x%08x", | 74 | return sprintf(data, "0x%08x", |
63 | in_be32(pdata->mc_vbase + | 75 | ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO)); |
64 | FSL_MC_DATA_ERR_INJECT_LO)); | ||
65 | } | 76 | } |
66 | 77 | ||
67 | static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, | 78 | static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, |
@@ -71,7 +82,7 @@ static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, | |||
71 | struct mem_ctl_info *mci = to_mci(dev); | 82 | struct mem_ctl_info *mci = to_mci(dev); |
72 | struct fsl_mc_pdata *pdata = mci->pvt_info; | 83 | struct fsl_mc_pdata *pdata = mci->pvt_info; |
73 | return sprintf(data, "0x%08x", | 84 | return sprintf(data, "0x%08x", |
74 | in_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); | 85 | ddr_in32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); |
75 | } | 86 | } |
76 | 87 | ||
77 | static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, | 88 | static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, |
@@ -81,8 +92,8 @@ static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, | |||
81 | struct mem_ctl_info *mci = to_mci(dev); | 92 | struct mem_ctl_info *mci = to_mci(dev); |
82 | struct fsl_mc_pdata *pdata = mci->pvt_info; | 93 | struct fsl_mc_pdata *pdata = mci->pvt_info; |
83 | if (isdigit(*data)) { | 94 | if (isdigit(*data)) { |
84 | out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, | 95 | ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, |
85 | simple_strtoul(data, NULL, 0)); | 96 | simple_strtoul(data, NULL, 0)); |
86 | return count; | 97 | return count; |
87 | } | 98 | } |
88 | return 0; | 99 | return 0; |
@@ -95,8 +106,8 @@ static ssize_t fsl_mc_inject_data_lo_store(struct device *dev, | |||
95 | struct mem_ctl_info *mci = to_mci(dev); | 106 | struct mem_ctl_info *mci = to_mci(dev); |
96 | struct fsl_mc_pdata *pdata = mci->pvt_info; | 107 | struct fsl_mc_pdata *pdata = mci->pvt_info; |
97 | if (isdigit(*data)) { | 108 | if (isdigit(*data)) { |
98 | out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, | 109 | ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, |
99 | simple_strtoul(data, NULL, 0)); | 110 | simple_strtoul(data, NULL, 0)); |
100 | return count; | 111 | return count; |
101 | } | 112 | } |
102 | return 0; | 113 | return 0; |
@@ -109,8 +120,8 @@ static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, | |||
109 | struct mem_ctl_info *mci = to_mci(dev); | 120 | struct mem_ctl_info *mci = to_mci(dev); |
110 | struct fsl_mc_pdata *pdata = mci->pvt_info; | 121 | struct fsl_mc_pdata *pdata = mci->pvt_info; |
111 | if (isdigit(*data)) { | 122 | if (isdigit(*data)) { |
112 | out_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, | 123 | ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, |
113 | simple_strtoul(data, NULL, 0)); | 124 | simple_strtoul(data, NULL, 0)); |
114 | return count; | 125 | return count; |
115 | } | 126 | } |
116 | return 0; | 127 | return 0; |
@@ -256,7 +267,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci) | |||
256 | int bad_data_bit; | 267 | int bad_data_bit; |
257 | int bad_ecc_bit; | 268 | int bad_ecc_bit; |
258 | 269 | ||
259 | err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT); | 270 | err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); |
260 | if (!err_detect) | 271 | if (!err_detect) |
261 | return; | 272 | return; |
262 | 273 | ||
@@ -265,23 +276,23 @@ static void fsl_mc_check(struct mem_ctl_info *mci) | |||
265 | 276 | ||
266 | /* no more processing if not ECC bit errors */ | 277 | /* no more processing if not ECC bit errors */ |
267 | if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { | 278 | if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { |
268 | out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); | 279 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); |
269 | return; | 280 | return; |
270 | } | 281 | } |
271 | 282 | ||
272 | syndrome = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); | 283 | syndrome = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); |
273 | 284 | ||
274 | /* Mask off appropriate bits of syndrome based on bus width */ | 285 | /* Mask off appropriate bits of syndrome based on bus width */ |
275 | bus_width = (in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & | 286 | bus_width = (ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & |
276 | DSC_DBW_MASK) ? 32 : 64; | 287 | DSC_DBW_MASK) ? 32 : 64; |
277 | if (bus_width == 64) | 288 | if (bus_width == 64) |
278 | syndrome &= 0xff; | 289 | syndrome &= 0xff; |
279 | else | 290 | else |
280 | syndrome &= 0xffff; | 291 | syndrome &= 0xffff; |
281 | 292 | ||
282 | err_addr = make64( | 293 | err_addr = make64( |
283 | in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), | 294 | ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), |
284 | in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); | 295 | ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); |
285 | pfn = err_addr >> PAGE_SHIFT; | 296 | pfn = err_addr >> PAGE_SHIFT; |
286 | 297 | ||
287 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { | 298 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { |
@@ -290,8 +301,8 @@ static void fsl_mc_check(struct mem_ctl_info *mci) | |||
290 | break; | 301 | break; |
291 | } | 302 | } |
292 | 303 | ||
293 | cap_high = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); | 304 | cap_high = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); |
294 | cap_low = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); | 305 | cap_low = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); |
295 | 306 | ||
296 | /* | 307 | /* |
297 | * Analyze single-bit errors on 64-bit wide buses | 308 | * Analyze single-bit errors on 64-bit wide buses |
@@ -337,7 +348,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci) | |||
337 | row_index, 0, -1, | 348 | row_index, 0, -1, |
338 | mci->ctl_name, ""); | 349 | mci->ctl_name, ""); |
339 | 350 | ||
340 | out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); | 351 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); |
341 | } | 352 | } |
342 | 353 | ||
343 | static irqreturn_t fsl_mc_isr(int irq, void *dev_id) | 354 | static irqreturn_t fsl_mc_isr(int irq, void *dev_id) |
@@ -346,7 +357,7 @@ static irqreturn_t fsl_mc_isr(int irq, void *dev_id) | |||
346 | struct fsl_mc_pdata *pdata = mci->pvt_info; | 357 | struct fsl_mc_pdata *pdata = mci->pvt_info; |
347 | u32 err_detect; | 358 | u32 err_detect; |
348 | 359 | ||
349 | err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT); | 360 | err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); |
350 | if (!err_detect) | 361 | if (!err_detect) |
351 | return IRQ_NONE; | 362 | return IRQ_NONE; |
352 | 363 | ||
@@ -366,7 +377,7 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) | |||
366 | u32 cs_bnds; | 377 | u32 cs_bnds; |
367 | int index; | 378 | int index; |
368 | 379 | ||
369 | sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); | 380 | sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); |
370 | 381 | ||
371 | sdtype = sdram_ctl & DSC_SDTYPE_MASK; | 382 | sdtype = sdram_ctl & DSC_SDTYPE_MASK; |
372 | if (sdram_ctl & DSC_RD_EN) { | 383 | if (sdram_ctl & DSC_RD_EN) { |
@@ -414,8 +425,8 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) | |||
414 | csrow = mci->csrows[index]; | 425 | csrow = mci->csrows[index]; |
415 | dimm = csrow->channels[0]->dimm; | 426 | dimm = csrow->channels[0]->dimm; |
416 | 427 | ||
417 | cs_bnds = in_be32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + | 428 | cs_bnds = ddr_in32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + |
418 | (index * FSL_MC_CS_BNDS_OFS)); | 429 | (index * FSL_MC_CS_BNDS_OFS)); |
419 | 430 | ||
420 | start = (cs_bnds & 0xffff0000) >> 16; | 431 | start = (cs_bnds & 0xffff0000) >> 16; |
421 | end = (cs_bnds & 0x0000ffff); | 432 | end = (cs_bnds & 0x0000ffff); |
@@ -474,6 +485,12 @@ int fsl_mc_err_probe(struct platform_device *op) | |||
474 | mci->ctl_name = pdata->name; | 485 | mci->ctl_name = pdata->name; |
475 | mci->dev_name = pdata->name; | 486 | mci->dev_name = pdata->name; |
476 | 487 | ||
488 | /* | ||
489 | * Get the endianness of DDR controller registers. | ||
490 | * Default is big endian. | ||
491 | */ | ||
492 | little_endian = of_property_read_bool(op->dev.of_node, "little-endian"); | ||
493 | |||
477 | res = of_address_to_resource(op->dev.of_node, 0, &r); | 494 | res = of_address_to_resource(op->dev.of_node, 0, &r); |
478 | if (res) { | 495 | if (res) { |
479 | pr_err("%s: Unable to get resource for MC err regs\n", | 496 | pr_err("%s: Unable to get resource for MC err regs\n", |
@@ -496,7 +513,7 @@ int fsl_mc_err_probe(struct platform_device *op) | |||
496 | goto err; | 513 | goto err; |
497 | } | 514 | } |
498 | 515 | ||
499 | sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); | 516 | sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); |
500 | if (!(sdram_ctl & DSC_ECC_EN)) { | 517 | if (!(sdram_ctl & DSC_ECC_EN)) { |
501 | /* no ECC */ | 518 | /* no ECC */ |
502 | pr_warn("%s: No ECC DIMMs discovered\n", __func__); | 519 | pr_warn("%s: No ECC DIMMs discovered\n", __func__); |
@@ -523,12 +540,11 @@ int fsl_mc_err_probe(struct platform_device *op) | |||
523 | fsl_ddr_init_csrows(mci); | 540 | fsl_ddr_init_csrows(mci); |
524 | 541 | ||
525 | /* store the original error disable bits */ | 542 | /* store the original error disable bits */ |
526 | orig_ddr_err_disable = | 543 | orig_ddr_err_disable = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); |
527 | in_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); | 544 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); |
528 | out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); | ||
529 | 545 | ||
530 | /* clear all error bits */ | 546 | /* clear all error bits */ |
531 | out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); | 547 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); |
532 | 548 | ||
533 | if (edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups)) { | 549 | if (edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups)) { |
534 | edac_dbg(3, "failed edac_mc_add_mc()\n"); | 550 | edac_dbg(3, "failed edac_mc_add_mc()\n"); |
@@ -536,15 +552,15 @@ int fsl_mc_err_probe(struct platform_device *op) | |||
536 | } | 552 | } |
537 | 553 | ||
538 | if (edac_op_state == EDAC_OPSTATE_INT) { | 554 | if (edac_op_state == EDAC_OPSTATE_INT) { |
539 | out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, | 555 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, |
540 | DDR_EIE_MBEE | DDR_EIE_SBEE); | 556 | DDR_EIE_MBEE | DDR_EIE_SBEE); |
541 | 557 | ||
542 | /* store the original error management threshold */ | 558 | /* store the original error management threshold */ |
543 | orig_ddr_err_sbe = in_be32(pdata->mc_vbase + | 559 | orig_ddr_err_sbe = ddr_in32(pdata->mc_vbase + |
544 | FSL_MC_ERR_SBE) & 0xff0000; | 560 | FSL_MC_ERR_SBE) & 0xff0000; |
545 | 561 | ||
546 | /* set threshold to 1 error per interrupt */ | 562 | /* set threshold to 1 error per interrupt */ |
547 | out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); | 563 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); |
548 | 564 | ||
549 | /* register interrupts */ | 565 | /* register interrupts */ |
550 | pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); | 566 | pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); |
@@ -586,13 +602,13 @@ int fsl_mc_err_remove(struct platform_device *op) | |||
586 | edac_dbg(0, "\n"); | 602 | edac_dbg(0, "\n"); |
587 | 603 | ||
588 | if (edac_op_state == EDAC_OPSTATE_INT) { | 604 | if (edac_op_state == EDAC_OPSTATE_INT) { |
589 | out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); | ||
590 | irq_dispose_mapping(pdata->irq); | 605 | irq_dispose_mapping(pdata->irq); |
606 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); | ||
591 | } | 607 | } |
592 | 608 | ||
593 | out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, | 609 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, |
594 | orig_ddr_err_disable); | 610 | orig_ddr_err_disable); |
595 | out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); | 611 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); |
596 | 612 | ||
597 | edac_mc_del_mc(&op->dev); | 613 | edac_mc_del_mc(&op->dev); |
598 | edac_mc_free(mci); | 614 | edac_mc_free(mci); |