EDAC, fsl_ddr: Add support for little endian
authorYork Sun <york.sun@nxp.com>
Tue, 9 Aug 2016 21:55:43 +0000 (14:55 -0700)
committerBorislav Petkov <bp@suse.de>
Thu, 1 Sep 2016 08:28:02 +0000 (10:28 +0200)
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>
Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt [deleted file]
drivers/edac/fsl_ddr_edac.c

diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt
new file mode 100644 (file)
index 0000000..dde6d83
--- /dev/null
@@ -0,0 +1,29 @@
+Freescale DDR memory controller
+
+Properties:
+
+- compatible   : Should include "fsl,chip-memory-controller" where
+                 chip is the processor (bsc9132, mpc8572 etc.), or
+                 "fsl,qoriq-memory-controller".
+- reg          : Address and size of DDR controller registers
+- interrupts   : Error interrupt of DDR controller
+- little-endian        : Specifies little-endian access to registers
+                 If omitted, big-endian will be used.
+
+Example 1:
+
+       memory-controller@2000 {
+               compatible = "fsl,bsc9132-memory-controller";
+               reg = <0x2000 0x1000>;
+               interrupts = <16 2 1 8>;
+       };
+
+
+Example 2:
+
+       ddr1: memory-controller@8000 {
+               compatible = "fsl,qoriq-memory-controller-v4.7",
+                               "fsl,qoriq-memory-controller";
+               reg = <0x8000 0x1000>;
+               interrupts = <16 2 1 23>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
deleted file mode 100644 (file)
index f87856f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Freescale DDR memory controller
-
-Properties:
-
-- compatible   : Should include "fsl,chip-memory-controller" where
-                 chip is the processor (bsc9132, mpc8572 etc.), or
-                 "fsl,qoriq-memory-controller".
-- reg          : Address and size of DDR controller registers
-- interrupts   : Error interrupt of DDR controller
-
-Example 1:
-
-       memory-controller@2000 {
-               compatible = "fsl,bsc9132-memory-controller";
-               reg = <0x2000 0x1000>;
-               interrupts = <16 2 1 8>;
-       };
-
-
-Example 2:
-
-       ddr1: memory-controller@8000 {
-               compatible = "fsl,qoriq-memory-controller-v4.7",
-                               "fsl,qoriq-memory-controller";
-               reg = <0x8000 0x1000>;
-               interrupts = <16 2 1 23>;
-       };
index 46b00e15e44288e5467d6b9bfb3d82a4e89af986..6d4dd84a9d4865f0b8865e69dd40f6d8ca1e52a0 100644 (file)
@@ -13,7 +13,6 @@
  * the terms of the GNU General Public License version 2. This program
  * is licensed "as is" without any warranty of any kind, whether express
  * or implied.
- *
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -37,6 +36,20 @@ static int edac_mc_idx;
 
 static u32 orig_ddr_err_disable;
 static u32 orig_ddr_err_sbe;
+static bool little_endian;
+
+static inline u32 ddr_in32(void __iomem *addr)
+{
+       return little_endian ? ioread32(addr) : ioread32be(addr);
+}
+
+static inline void ddr_out32(void __iomem *addr, u32 value)
+{
+       if (little_endian)
+               iowrite32(value, addr);
+       else
+               iowrite32be(value, addr);
+}
 
 /************************ MC SYSFS parts ***********************************/
 
@@ -49,8 +62,7 @@ static ssize_t fsl_mc_inject_data_hi_show(struct device *dev,
        struct mem_ctl_info *mci = to_mci(dev);
        struct fsl_mc_pdata *pdata = mci->pvt_info;
        return sprintf(data, "0x%08x",
-                      in_be32(pdata->mc_vbase +
-                              FSL_MC_DATA_ERR_INJECT_HI));
+                      ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI));
 }
 
 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,
        struct mem_ctl_info *mci = to_mci(dev);
        struct fsl_mc_pdata *pdata = mci->pvt_info;
        return sprintf(data, "0x%08x",
-                      in_be32(pdata->mc_vbase +
-                              FSL_MC_DATA_ERR_INJECT_LO));
+                      ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO));
 }
 
 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,
        struct mem_ctl_info *mci = to_mci(dev);
        struct fsl_mc_pdata *pdata = mci->pvt_info;
        return sprintf(data, "0x%08x",
-                      in_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT));
+                      ddr_in32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT));
 }
 
 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,
        struct mem_ctl_info *mci = to_mci(dev);
        struct fsl_mc_pdata *pdata = mci->pvt_info;
        if (isdigit(*data)) {
-               out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI,
-                        simple_strtoul(data, NULL, 0));
+               ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI,
+                         simple_strtoul(data, NULL, 0));
                return count;
        }
        return 0;
@@ -95,8 +106,8 @@ static ssize_t fsl_mc_inject_data_lo_store(struct device *dev,
        struct mem_ctl_info *mci = to_mci(dev);
        struct fsl_mc_pdata *pdata = mci->pvt_info;
        if (isdigit(*data)) {
-               out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO,
-                        simple_strtoul(data, NULL, 0));
+               ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO,
+                         simple_strtoul(data, NULL, 0));
                return count;
        }
        return 0;
@@ -109,8 +120,8 @@ static ssize_t fsl_mc_inject_ctrl_store(struct device *dev,
        struct mem_ctl_info *mci = to_mci(dev);
        struct fsl_mc_pdata *pdata = mci->pvt_info;
        if (isdigit(*data)) {
-               out_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT,
-                        simple_strtoul(data, NULL, 0));
+               ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT,
+                         simple_strtoul(data, NULL, 0));
                return count;
        }
        return 0;
@@ -256,7 +267,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci)
        int bad_data_bit;
        int bad_ecc_bit;
 
-       err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT);
+       err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT);
        if (!err_detect)
                return;
 
@@ -265,23 +276,23 @@ static void fsl_mc_check(struct mem_ctl_info *mci)
 
        /* no more processing if not ECC bit errors */
        if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) {
-               out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect);
+               ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect);
                return;
        }
 
-       syndrome = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC);
+       syndrome = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC);
 
        /* Mask off appropriate bits of syndrome based on bus width */
-       bus_width = (in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) &
-                       DSC_DBW_MASK) ? 32 : 64;
+       bus_width = (ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) &
+                    DSC_DBW_MASK) ? 32 : 64;
        if (bus_width == 64)
                syndrome &= 0xff;
        else
                syndrome &= 0xffff;
 
        err_addr = make64(
-               in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS),
-               in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS));
+               ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS),
+               ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS));
        pfn = err_addr >> PAGE_SHIFT;
 
        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)
                        break;
        }
 
-       cap_high = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI);
-       cap_low = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO);
+       cap_high = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI);
+       cap_low = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO);
 
        /*
         * Analyze single-bit errors on 64-bit wide buses
@@ -337,7 +348,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci)
                                     row_index, 0, -1,
                                     mci->ctl_name, "");
 
-       out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect);
+       ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect);
 }
 
 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)
        struct fsl_mc_pdata *pdata = mci->pvt_info;
        u32 err_detect;
 
-       err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT);
+       err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT);
        if (!err_detect)
                return IRQ_NONE;
 
@@ -366,7 +377,7 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci)
        u32 cs_bnds;
        int index;
 
-       sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG);
+       sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG);
 
        sdtype = sdram_ctl & DSC_SDTYPE_MASK;
        if (sdram_ctl & DSC_RD_EN) {
@@ -414,8 +425,8 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci)
                csrow = mci->csrows[index];
                dimm = csrow->channels[0]->dimm;
 
-               cs_bnds = in_be32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 +
-                                 (index * FSL_MC_CS_BNDS_OFS));
+               cs_bnds = ddr_in32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 +
+                                  (index * FSL_MC_CS_BNDS_OFS));
 
                start = (cs_bnds & 0xffff0000) >> 16;
                end   = (cs_bnds & 0x0000ffff);
@@ -474,6 +485,12 @@ int fsl_mc_err_probe(struct platform_device *op)
        mci->ctl_name = pdata->name;
        mci->dev_name = pdata->name;
 
+       /*
+        * Get the endianness of DDR controller registers.
+        * Default is big endian.
+        */
+       little_endian = of_property_read_bool(op->dev.of_node, "little-endian");
+
        res = of_address_to_resource(op->dev.of_node, 0, &r);
        if (res) {
                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)
                goto err;
        }
 
-       sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG);
+       sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG);
        if (!(sdram_ctl & DSC_ECC_EN)) {
                /* no ECC */
                pr_warn("%s: No ECC DIMMs discovered\n", __func__);
@@ -523,12 +540,11 @@ int fsl_mc_err_probe(struct platform_device *op)
        fsl_ddr_init_csrows(mci);
 
        /* store the original error disable bits */
-       orig_ddr_err_disable =
-           in_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE);
-       out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0);
+       orig_ddr_err_disable = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DISABLE);
+       ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0);
 
        /* clear all error bits */
-       out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0);
+       ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0);
 
        if (edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups)) {
                edac_dbg(3, "failed edac_mc_add_mc()\n");
@@ -536,15 +552,15 @@ int fsl_mc_err_probe(struct platform_device *op)
        }
 
        if (edac_op_state == EDAC_OPSTATE_INT) {
-               out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN,
-                        DDR_EIE_MBEE | DDR_EIE_SBEE);
+               ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN,
+                         DDR_EIE_MBEE | DDR_EIE_SBEE);
 
                /* store the original error management threshold */
-               orig_ddr_err_sbe = in_be32(pdata->mc_vbase +
-                                          FSL_MC_ERR_SBE) & 0xff0000;
+               orig_ddr_err_sbe = ddr_in32(pdata->mc_vbase +
+                                           FSL_MC_ERR_SBE) & 0xff0000;
 
                /* set threshold to 1 error per interrupt */
-               out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000);
+               ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000);
 
                /* register interrupts */
                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)
        edac_dbg(0, "\n");
 
        if (edac_op_state == EDAC_OPSTATE_INT) {
-               out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0);
                irq_dispose_mapping(pdata->irq);
+               ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0);
        }
 
-       out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE,
-                orig_ddr_err_disable);
-       out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe);
+       ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE,
+                 orig_ddr_err_disable);
+       ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe);
 
        edac_mc_del_mc(&op->dev);
        edac_mc_free(mci);