From: John Jacques <[email protected]>

The Axxia hardware makes it possible to reset the system without
losing the contents of memory.  This commit adds the ability to
initiate a reset in such a way that memory contents are not
lost.

Cleanup of the DDR Retention feature for Linux 3.10.

Shutdown devices, and disable hotplug before shuting down
the cores.

Signed-off-by: John Jacques <[email protected]>
---
 arch/arm/mach-axxia/Makefile           |    1 +
 arch/arm/mach-axxia/axxia.c            |    3 +
 arch/arm/mach-axxia/ddr_retention.c    |  290 ++++++++++++-------
 arch/arm/mach-axxia/include/mach/ncr.h |   44 +++
 arch/arm/mach-axxia/ncr.c              |  486 ++++++++++++++++++++++++++++++++
 drivers/misc/Kconfig                   |    2 +-
 drivers/misc/lsi-smmon.c               |    2 +-
 drivers/net/ethernet/lsi/lsi_acp_net.c |    9 +-
 8 files changed, 725 insertions(+), 112 deletions(-)
 create mode 100644 arch/arm/mach-axxia/include/mach/ncr.h
 create mode 100644 arch/arm/mach-axxia/ncr.c

diff --git a/arch/arm/mach-axxia/Makefile b/arch/arm/mach-axxia/Makefile
index e49adf1..79053c8 100644
--- a/arch/arm/mach-axxia/Makefile
+++ b/arch/arm/mach-axxia/Makefile
@@ -5,6 +5,7 @@ obj-y                                   += wrappers.o
 obj-y                                  += axxia.o
 obj-y                                  += clock.o
 obj-y                                   += io.o
+obj-y                                  += ncr.o
 obj-y                                  += timers.o
 obj-y                                  += pci.o
 obj-y                                  += ddr_retention.o
diff --git a/arch/arm/mach-axxia/axxia.c b/arch/arm/mach-axxia/axxia.c
index ef87fb2..421b050 100644
--- a/arch/arm/mach-axxia/axxia.c
+++ b/arch/arm/mach-axxia/axxia.c
@@ -49,6 +49,7 @@
 #include <mach/timers.h>
 #include <mach/axxia-gic.h>
 #include <linux/irqchip/arm-gic.h>
+#include <mach/ncr.h>
 #include "axxia.h"
 #include "pci.h"
 #include "i2c.h"
@@ -325,6 +326,8 @@ void __init axxia_dt_init(void)
                             axxia_auxdata_lookup, NULL);
        pm_power_off = NULL; /* TBD */
 
+       ncr_init();
+
        spi_register_board_info(spi_devs, ARRAY_SIZE(spi_devs));
 
        /*
diff --git a/arch/arm/mach-axxia/ddr_retention.c 
b/arch/arm/mach-axxia/ddr_retention.c
index ca426c2..e409774 100644
--- a/arch/arm/mach-axxia/ddr_retention.c
+++ b/arch/arm/mach-axxia/ddr_retention.c
@@ -21,69 +21,124 @@
  */
 
 #include <linux/module.h>
-
-#ifndef CONFIG_ARCH_AXXIA_SIM
-
 #include <linux/cpu.h>
 #include <linux/reboot.h>
 #include <linux/syscore_ops.h>
-
 #include <linux/proc_fs.h>
+#include <linux/delay.h>
 
+#include <linux/of.h>
 #include <asm/io.h>
 #include <asm/cacheflush.h>
-#include <../../../drivers/misc/lsi-ncr.h>
+#include <mach/ncr.h>
 
-static void __iomem *nca_address;
-static void __iomem *apb_base;
-
-static inline void kill_time(int cnt)
-{
-       while (cnt--)
-               ;
-}
+static void __iomem *nca;
+static void __iomem *apb;
+static void __iomem *dickens;
 
 unsigned long ncp_caal_regions_acp55xx[] = {
-       NCP_REGION_ID(0x0b, 0x05),      /* SPPV2   */
-       NCP_REGION_ID(0x0c, 0x05),      /* SED     */
-       NCP_REGION_ID(0x0e, 0x05),      /* DPI_HFA */
-       NCP_REGION_ID(0x14, 0x05),      /* MTM     */
-       NCP_REGION_ID(0x14, 0x0a),      /* MTM2    */
-       NCP_REGION_ID(0x15, 0x00),      /* MME     */
-       NCP_REGION_ID(0x16, 0x05),      /* NCAV2   */
-       NCP_REGION_ID(0x16, 0x10),      /* NCAV22  */
-       NCP_REGION_ID(0x17, 0x05),      /* EIOAM1  */
-       NCP_REGION_ID(0x19, 0x05),      /* TMGR    */
-       NCP_REGION_ID(0x1a, 0x05),      /* MPPY    */
-       NCP_REGION_ID(0x1a, 0x23),      /* MPPY2   */
-       NCP_REGION_ID(0x1a, 0x21),      /* MPPY3   */
-       NCP_REGION_ID(0x1b, 0x05),      /* PIC     */
-       NCP_REGION_ID(0x1c, 0x05),      /* PAB     */
-       NCP_REGION_ID(0x1f, 0x05),      /* EIOAM0  */
-       NCP_REGION_ID(0x31, 0x05),      /* ISB     */
-       NCP_REGION_ID(0x28, 0x05),      /* EIOASM0 */
-       NCP_REGION_ID(0x29, 0x05),      /* EIOASM1 */
-       NCP_REGION_ID(0x2a, 0x05),      /* EIOAS2  */
-       NCP_REGION_ID(0x2b, 0x05),      /* EIOAS3  */
-       NCP_REGION_ID(0x2c, 0x05),      /* EIOAS4  */
-       NCP_REGION_ID(0x2d, 0x05),      /* EIOAS5  */
-       NCP_REGION_ID(0x32, 0x05),      /* ISBS    */
+       NCP_REGION_ID(0x0b, 0x05),      /* SPPV2   */
+       NCP_REGION_ID(0x0c, 0x05),      /* SED     */
+       NCP_REGION_ID(0x0e, 0x05),      /* DPI_HFA */
+       NCP_REGION_ID(0x14, 0x05),      /* MTM     */
+       NCP_REGION_ID(0x14, 0x0a),      /* MTM2    */
+       NCP_REGION_ID(0x15, 0x00),      /* MME     */
+       NCP_REGION_ID(0x16, 0x05),      /* NCAV2   */
+       NCP_REGION_ID(0x16, 0x10),      /* NCAV22  */
+       NCP_REGION_ID(0x17, 0x05),      /* EIOAM1  */
+       NCP_REGION_ID(0x19, 0x05),      /* TMGR    */
+       NCP_REGION_ID(0x1a, 0x05),      /* MPPY    */
+       NCP_REGION_ID(0x1a, 0x23),      /* MPPY2   */
+       NCP_REGION_ID(0x1a, 0x21),      /* MPPY3   */
+       NCP_REGION_ID(0x1b, 0x05),      /* PIC     */
+       NCP_REGION_ID(0x1c, 0x05),      /* PAB     */
+       NCP_REGION_ID(0x1f, 0x05),      /* EIOAM0  */
+       NCP_REGION_ID(0x31, 0x05),      /* ISB     */
+       NCP_REGION_ID(0x28, 0x05),      /* EIOASM0 */
+       NCP_REGION_ID(0x29, 0x05),      /* EIOASM1 */
+       NCP_REGION_ID(0x2a, 0x05),      /* EIOAS2  */
+       NCP_REGION_ID(0x2b, 0x05),      /* EIOAS3  */
+       NCP_REGION_ID(0x2c, 0x05),      /* EIOAS4  */
+       NCP_REGION_ID(0x2d, 0x05),      /* EIOAS5  */
+       NCP_REGION_ID(0x32, 0x05),      /* ISBS    */
        NCP_REGION_ID(0xff, 0xff)
 };
 
-static void quiesce_vp_engine(void)
+/*
+  
------------------------------------------------------------------------------
+  flush_l3
+
+  This is NOT a general function to flush the L3 cache.  There are a number of
+  assumptions that are not usually true...
+
+  1) All other cores are " quiesced".
+  2) There is no need to worry about preemption or interrupts.
+*/
+
+static void
+flush_l3(void)
+{
+
+       unsigned long hnf_offsets[] = {
+               0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+       };
+
+       int i;
+       unsigned long status;
+       int retries;
+
+       for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i)
+               writel(0x0, dickens + (0x10000 * hnf_offsets[i]) + 0x10);
+
+       for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i) {
+               retries = 10000;
+
+               do {
+                       status = readl(dickens +
+                                      (0x10000 * hnf_offsets[i]) + 0x18);
+                       udelay(1);
+               } while ((0 < --retries) && (0x0 != (status & 0xf)));
+
+               if (0 == retries)
+                       BUG();
+       }
+
+       for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i)
+               writel(0x3, dickens + (0x10000 * hnf_offsets[i]) + 0x10);
+
+       for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i) {
+               retries = 10000;
+
+               do {
+                       status = readl(dickens +
+                                      (0x10000 * hnf_offsets[i]) + 0x18);
+                       udelay(1);
+               } while ((0 < --retries) && (0xc != (status & 0xf)));
+
+               if (0 == retries)
+                       BUG();
+       }
+
+       asm volatile ("dsb" : : : "memory");
+       asm volatile ("dmb" : : : "memory");
+
+       return;
+}
+
+static void
+quiesce_vp_engine(void)
 {
-       unsigned long *pCnalRegions = ncp_caal_regions_acp55xx;
-       unsigned long *pRegion;
+       unsigned long   *pCnalRegions = ncp_caal_regions_acp55xx;
+       unsigned long     *pRegion;
        unsigned ort, owt;
-       unsigned long buf = 0;
-       unsigned short node, target;
-       int loop;
+       unsigned long      buf = 0;
+       unsigned short     node, target;
+       int      loop;
 
        pr_info("quiescing VP engines...\n");
        pRegion = pCnalRegions;
-       while (*pRegion != NCP_REGION_ID(0xff, 0xff)) {
 
+       while (*pRegion != NCP_REGION_ID(0xff, 0xff)) {
                /* set read/write transaction limits to zero */
                ncr_write(*pRegion, 0x8, 4, &buf);
                ncr_write(*pRegion, 0xc, 4, &buf);
@@ -92,6 +147,7 @@ static void quiesce_vp_engine(void)
 
        pRegion = pCnalRegions;
        loop = 0;
+
        while (*pRegion != NCP_REGION_ID(0xff, 0xff)) {
                node = (*pRegion & 0xffff0000) >> 16;
                target = *pRegion & 0x0000ffff;
@@ -102,12 +158,12 @@ static void quiesce_vp_engine(void)
                if ((ort == 0) && (owt == 0)) {
                        /* this engine has been quiesced, move on to the next */
                        pr_info("quiesced region 0x%02x.0x%02x\n",
-                               node, target);
+                                       node, target);
                        pRegion++;
                } else {
                        if (loop++ > 10000) {
                                pr_info("Unable to quiesce region 0x%02x.0x%02x 
ort=0x%x, owt=0x%x\n",
-                                       node, target, ort, owt);
+                                      node, target, ort, owt);
                                pRegion++;
                                loop = 0;
                                continue;
@@ -118,13 +174,15 @@ static void quiesce_vp_engine(void)
        return;
 }
 
-static inline void ncp_ddr_shutdown(void)
+static inline void
+ncp_ddr_shutdown(void)
 {
        unsigned long value;
        int loop = 1;
-       unsigned long cdr2[2] = { 0x00002200, 0x00000f00 };
+       unsigned long cdr2[2] = {0x00002200, 0x00000f00};
        int smId;
 
+
        /*
         * Most of the PIO command has already been set up.
         * issue config ring write - enter DDR self-refresh mode
@@ -132,76 +190,88 @@ static inline void ncp_ddr_shutdown(void)
 
        for (smId = 0; smId < 2; smId++) {
                /* CDR2 - Node.target */
-               ncr_register_write(cdr2[smId],
-                                  (unsigned *)(nca_address + 0xf8));
+               ncr_register_write(cdr2[smId], (unsigned *) (nca + 0xf8));
                /* CDR0 - */
-               ncr_register_write(0x80050003,
-                                  (unsigned *)(nca_address + 0xf0));
+               ncr_register_write(0x80050003, (unsigned *) (nca + 0xf0));
                do {
-                       kill_time(100000);
-                       value =
-                           ncr_register_read((unsigned *)(nca_address + 0xf0));
+                       value = ncr_register_read((unsigned *)
+                                                 (nca + 0xf0));
                } while ((0x80000000UL & value));
        }
 
        /* check interrupt status for completion */
        /* CDR1 - word offset 0x104 (byte offset 0x410) */
-       ncr_register_write(0x00000104, (unsigned *)(nca_address + 0xf4));
+       ncr_register_write(0x00000104, (unsigned *) (nca + 0xf4));
 
        for (smId = 0; smId < 2; smId++) {
                /* CDR2 - Node.target */
-               ncr_register_write(cdr2[smId],
-                                  (unsigned *)(nca_address + 0xf8));
+               ncr_register_write(cdr2[smId], (unsigned *) (nca + 0xf8));
                do {
-                       ncr_register_write(loop,
-                                          (unsigned *)(nca_address + 0x11f0));
+                       ncr_register_write(loop, (unsigned *)
+                                          (nca + 0x11f0));
 
                        /* issue config ring read */
-                       ncr_register_write(0x80040003,
-                                          (unsigned *)(nca_address + 0xf0));
+                       ncr_register_write(0x80040003, (unsigned *)
+                                          (nca + 0xf0));
                        do {
-                               kill_time(100000);
-                               value =
-                                   ncr_register_read((unsigned *)(nca_address +
-                                                                  0xf0));
+                               value = ncr_register_read((unsigned *)
+                                                         (nca + 0xf0));
                        } while ((0x80000000UL & value));
 
-                       value =
-                           ncr_register_read((unsigned *)(nca_address +
-                                                          0x1000));
-                       ncr_register_write(value,
-                                          (unsigned *)(nca_address + 0x1200));
+                       value = ncr_register_read((unsigned *)
+                                                 (nca + 0x1000));
+                       ncr_register_write(value, (unsigned *)
+                                          (nca + 0x1200));
 
                        loop++;
                } while ((value & 0x0200) == 0);
        }
 
-       /* indicate DDR retention reset */
-       writel(0x00000001, apb_base + 0x300dc); /* set persist_scratch bit 0 */
+       /*
+         Indicate DDR Retention Reset
+       */
+
+       /* set bit 0 of persist_scratch */
+       writel(0x00000001, apb + 0x300dc);
 
-       /* issue chip reset */
-       writel(0x00000040, apb_base + 0x31004); /* Internal Boot, 0xffff0000
-                                                  Target */
-       writel(0x80000000, apb_base + 0x3180c); /* Set ResetReadDone */
-       writel(0x00080802, apb_base + 0x31008); /* Chip Reset */
+       /*
+         Issue Chip Reset
+       */
+
+       /* Intrnl Boot, 0xffff0000 Target */
+       writel(0x00000040, apb + 0x31004);
+       /* Set ResetReadDone */
+       writel(0x80000000, apb + 0x3180c);
+       /* Chip Reset */
+       writel(0x00080802, apb + 0x31008);
+
+       return;
 }
 
-void initiate_retention_reset(void)
+void
+initiate_retention_reset(void)
 {
        unsigned long ctl_244 = 0;
        unsigned long value;
+       unsigned long delay;
 
-       if (NULL == nca_address)
-               nca_address = ioremap(0x002020100000ULL, 0x20000);
+       if (NULL == nca || NULL == apb || NULL == dickens)
+               BUG();
 
-       /* send stop message to other CPUs */
-       local_irq_disable();
+       system_state = SYSTEM_RESTART;
        asm volatile ("dsb" : : : "memory");
        asm volatile ("dmb" : : : "memory");
-       system_state = SYSTEM_RESTART;
+       usermodehelper_disable();
+       device_shutdown();
+       cpu_hotplug_disable();
+       syscore_shutdown();
        smp_send_stop();
 
-       kill_time(1000000);
+       for (delay = 0; delay < 10000; ++delay)
+               udelay(1000);
+
+       flush_cache_all();
+       flush_l3();
 
        /* TODO - quiesce VP engines */
        quiesce_vp_engine();
@@ -213,8 +283,7 @@ void initiate_retention_reset(void)
        ncr_write(NCP_REGION_ID(15, 0), 0x414, 4, &value);
 
        /* unlock reset register for later */
-       apb_base = ioremap(0x2010000000, 0x40000);
-       writel(0x000000ab, apb_base + 0x31000); /* Access Key */
+       writel(0x000000ab, apb + 0x31000); /* Access Key */
 
        /* prepare to put DDR in self refresh power-down mode */
        /* first read the CTL_244 register and OR in the LP_CMD value */
@@ -224,14 +293,15 @@ void initiate_retention_reset(void)
        /*
         * set up for CRBW operation
         */
+
        /* write register value into CDAR[0] */
-       ncr_register_write(ctl_244, (unsigned *)(nca_address + 0x1000));
+       ncr_register_write(ctl_244, (unsigned *) (nca + 0x1000));
 
        /* CDR2 - Node.target = 34.0 */
-       ncr_register_write(0x00002200, (unsigned *)(nca_address + 0xf8));
+       ncr_register_write(0x00002200, (unsigned *) (nca + 0xf8));
 
        /* CDR1 - word offset 0xf4 (byte offset 0x3d0) */
-       ncr_register_write(0x000000f4, (unsigned *)(nca_address + 0xf4));
+       ncr_register_write(0x000000f4, (unsigned *) (nca + 0xf4));
 
        /*
         * issue instruction barrier
@@ -242,34 +312,38 @@ void initiate_retention_reset(void)
        prefetch(ncp_ddr_shutdown);
 
        ncp_ddr_shutdown();
+
+       return;
 }
+EXPORT_SYMBOL(initiate_retention_reset);
 
-static ssize_t axxia_ddr_retention_trigger(struct file *file,
-                                          const char __user *buf,
-                                          size_t count, loff_t *ppos)
+static ssize_t
+axxia_ddr_retention_trigger(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
 {
        initiate_retention_reset();
        return 0;
 }
 
-static const struct file_operations axxia_ddr_retention_proc_ops = {
-       .write = axxia_ddr_retention_trigger,
-       .llseek = noop_llseek,
+static const struct file_operations proc_ops = {
+       .write      = axxia_ddr_retention_trigger,
+       .llseek     = noop_llseek,
 };
 
-void axxia_ddr_retention_init(void)
+#define PROC_PATH "driver/axxia_ddr_retention_reset"
+
+void
+axxia_ddr_retention_init(void)
 {
-       if (!proc_create("driver/axxia_ddr_retention_reset", S_IWUSR, NULL,
-                        &axxia_ddr_retention_proc_ops))
-               pr_info("Failed to register DDR retention proc interface\n");
-}
-EXPORT_SYMBOL(initiate_retention_reset);
+       if (!of_find_compatible_node(NULL, NULL, "lsi,axm5516"))
+               return;
 
-#else
+       if (!proc_create(PROC_PATH, S_IWUSR, NULL, &proc_ops)) {
+               pr_err("Failed to register DDR retention proc interface\n");
+               return;
+       }
 
-void axxia_ddr_retention_init(void)
-{
-       return;
+       apb = ioremap(0x2010000000, 0x40000);
+       nca = ioremap(0x002020100000ULL, 0x20000);
+       dickens = ioremap(0x2000000000, 0x1000000);
 }
-
-#endif /* CONFIG_ARCH_AXXIA_SIM */
diff --git a/arch/arm/mach-axxia/include/mach/ncr.h 
b/arch/arm/mach-axxia/include/mach/ncr.h
new file mode 100644
index 0000000..926d366
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/ncr.h
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/mach-axxia/include/mach/ncr.h
+ *
+ * Copyright (C) 2010 LSI
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307        
 USA
+ */
+
+#ifndef __ARCH_ARM_MACH_AXXIA_NCR_H
+#define __ARCH_ARM_MACH_AXXIA_NCR_H
+
+#ifndef NCP_REGION_ID
+#define NCP_REGION_ID(node, target) \
+((unsigned long) ((((node) & 0xffff) << 16) | ((target) & 0xffff)))
+#endif
+
+#ifndef NCP_NODE_ID
+#define NCP_NODE_ID(region) (((region) >> 16) & 0xffff)
+#endif
+
+#ifndef NCP_TARGET_ID
+#define NCP_TARGET_ID(region) ((region) & 0xffff)
+#endif
+
+unsigned long ncr_register_read(unsigned *);
+void ncr_register_write(const unsigned, unsigned *);
+int ncr_read(unsigned long, unsigned long, int, void *);
+int ncr_write(unsigned long, unsigned long, int, void *);
+int ncr_init(void);
+void ncr_exit(void);
+
+#endif /* __ARCH_ARM_MACH_AXXIA_NCR_H */
diff --git a/arch/arm/mach-axxia/ncr.c b/arch/arm/mach-axxia/ncr.c
new file mode 100644
index 0000000..58b959a
--- /dev/null
+++ b/arch/arm/mach-axxia/ncr.c
@@ -0,0 +1,486 @@
+/*
+ *  Copyright (C) 2009 LSI Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+
+#include <asm/io.h>
+
+#include <mach/ncr.h>
+
+#ifdef CONFIG_ARCH_AXXIA
+#define NCA_PHYS_ADDRESS         0x002020100000ULL
+#define APB2SER_PHY_PHYS_ADDRESS 0x002010000000ULL
+#else
+#define NCA_PHYS_ADDRESS         0x002000520000ULL
+#endif
+
+static void __iomem *nca_address;
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+static void __iomem *apb2ser0_address;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+
+#define WFC_TIMEOUT (400000)
+
+#define LOCK_DOMAIN 0
+
+typedef union {
+       unsigned long raw;
+       struct {
+#ifdef __BIG_ENDIAN
+               unsigned long start_done:1;
+               unsigned long unused:6;
+               unsigned long local_bit:1;
+               unsigned long status:2;
+               unsigned long byte_swap_enable:1;
+               unsigned long cfg_cmpl_int_enable:1;
+               unsigned long cmd_type:4;
+               unsigned long dbs:16;
+#else
+       unsigned long dbs:16;
+       unsigned long cmd_type:4;
+       unsigned long cfg_cmpl_int_enable:1;
+       unsigned long byte_swap_enable:1;
+       unsigned long status:2;
+       unsigned long local_bit:1;
+       unsigned long unused:6;
+       unsigned long start_done:1;
+#endif
+} __attribute__ ((packed)) bits;
+} __attribute__ ((packed)) command_data_register_0_t;
+
+typedef union {
+       unsigned long raw;
+       struct {
+               unsigned long target_address:32;
+       } __attribute__ ((packed)) bits;
+} __attribute__ ((packed)) command_data_register_1_t;
+
+typedef union {
+       unsigned long raw;
+       struct {
+#ifdef __BIG_ENDIAN
+               unsigned long unused:16;
+               unsigned long target_node_id:8;
+               unsigned long target_id_address_upper:8;
+#else
+               unsigned long target_id_address_upper:8;
+               unsigned long target_node_id:8;
+               unsigned long unused:16;
+#endif
+       } __attribute__ ((packed)) bits;
+} __attribute__ ((packed)) command_data_register_2_t;
+
+#ifdef CONFIG_ARM
+
+/*
+  ----------------------------------------------------------------------
+  ncr_register_read
+*/
+
+unsigned long
+ncr_register_read(unsigned *address)
+{
+       unsigned long value;
+
+       value = ioread32be(address);
+
+       return value;
+}
+
+/*
+  ----------------------------------------------------------------------
+  ncr_register_write
+*/
+
+void
+ncr_register_write(const unsigned value, unsigned *address)
+{
+       iowrite32be(value, address);
+
+       return;
+}
+
+#else
+
+/*
+  ----------------------------------------------------------------------
+  ncr_register_read
+*/
+
+unsigned long
+ncr_register_read(unsigned *address)
+{
+       unsigned long value;
+
+       value = in_be32((unsigned *)address);
+
+       return value;
+}
+
+/*
+  ----------------------------------------------------------------------
+  ncr_register_write
+*/
+
+void
+ncr_register_write(const unsigned value, unsigned *address)
+{
+       out_be32(address, value);
+
+       return;
+}
+
+#endif
+
+/*
+  
------------------------------------------------------------------------------
+  ncr_lock
+*/
+
+static int
+ncr_lock(int domain)
+{
+       unsigned long offset;
+       unsigned long value;
+       int loops = 10000;
+
+       offset = (0xff80 + (domain * 4));
+
+       do {
+               value = ncr_register_read((unsigned *)(nca_address + offset));
+       } while ((0 != value) && (0 < --loops));
+
+       if (0 == loops)
+               return -1;
+
+       return 0;
+}
+
+/*
+  
------------------------------------------------------------------------------
+  ncr_unlock
+*/
+
+static void
+ncr_unlock(int domain)
+{
+       unsigned long offset;
+
+       offset = (0xff80 + (domain * 4));
+       ncr_register_write(0, (unsigned *)(nca_address + offset));
+
+       return;
+}
+
+/*
+  ======================================================================
+  ======================================================================
+  Public Interface
+  ======================================================================
+  ======================================================================
+*/
+
+/*
+  ----------------------------------------------------------------------
+  ncr_read
+*/
+
+int
+ncr_read(unsigned long region, unsigned long address, int number,
+        void *buffer)
+{
+       command_data_register_0_t cdr0;
+       command_data_register_1_t cdr1;
+       command_data_register_2_t cdr2;
+       int wfc_timeout = WFC_TIMEOUT;
+
+       if (NULL == nca_address)
+               return -1;
+
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+       if (NULL == apb2ser0_address)
+               return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+
+       if (0 != ncr_lock(LOCK_DOMAIN))
+               return -1;
+
+       if (NCP_NODE_ID(region) != 0x0153) {
+               /*
+               Set up the read command.
+               */
+
+               cdr2.raw = 0;
+               cdr2.bits.target_node_id = NCP_NODE_ID(region);
+               cdr2.bits.target_id_address_upper = NCP_TARGET_ID(region);
+               ncr_register_write(cdr2.raw, (unsigned *) (nca_address + 0xf8));
+
+               cdr1.raw = 0;
+               cdr1.bits.target_address = (address >> 2);
+               ncr_register_write(cdr1.raw, (unsigned *) (nca_address + 0xf4));
+
+               cdr0.raw = 0;
+               cdr0.bits.start_done = 1;
+
+               if (0xff == cdr2.bits.target_id_address_upper)
+                       cdr0.bits.local_bit = 1;
+
+               cdr0.bits.cmd_type = 4;
+               /* TODO: Verify number... */
+               cdr0.bits.dbs = (number - 1);
+               ncr_register_write(cdr0.raw, (unsigned *) (nca_address + 0xf0));
+               mb();
+
+               /*
+               Wait for completion.
+               */
+
+               do {
+                       --wfc_timeout;
+               } while ((0x80000000UL ==
+                               ncr_register_read((unsigned *)(nca_address + 
0xf0))) &&
+                               0 < wfc_timeout);
+
+               if (0 == wfc_timeout) {
+                       ncr_unlock(LOCK_DOMAIN);
+                       return -1;
+               }
+
+               /*
+               Copy data words to the buffer.
+               */
+
+               address = (unsigned long)(nca_address + 0x1000);
+               while (4 <= number) {
+                       *((unsigned long *) buffer) =
+                               ncr_register_read((unsigned *) address);
+                       address += 4;
+                       number -= 4;
+               }
+
+               if (0 < number) {
+                       unsigned long temp =
+                               ncr_register_read((unsigned *) address);
+                       memcpy((void *) buffer, &temp, number);
+               }
+       } else {
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+               void __iomem *targ_address = apb2ser0_address +
+                               (address & (~0x3));
+               /*
+               Copy data words to the buffer.
+               */
+
+               while (4 <= number) {
+                       *((unsigned long *) buffer) =
+                               *((unsigned long *) targ_address);
+                       targ_address += 4;
+                       number -= 4;
+               }
+#else
+               ncr_unlock(LOCK_DOMAIN);
+               return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+       }
+
+       ncr_unlock(LOCK_DOMAIN);
+
+       return 0;
+}
+EXPORT_SYMBOL(ncr_read);
+
+/*
+  ----------------------------------------------------------------------
+  ncr_write
+*/
+
+int
+ncr_write(unsigned long region, unsigned long address, int number,
+         void *buffer)
+{
+       command_data_register_0_t cdr0;
+       command_data_register_1_t cdr1;
+       command_data_register_2_t cdr2;
+       unsigned long data_word_base;
+       int dbs = (number - 1);
+       int wfc_timeout = WFC_TIMEOUT;
+
+       if (NULL == nca_address)
+               return -1;
+
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+       if (NULL == apb2ser0_address)
+               return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+
+       if (0 != ncr_lock(LOCK_DOMAIN))
+               return -1;
+
+       if (NCP_NODE_ID(region) != 0x0153) {
+               /*
+                 Set up the write.
+               */
+
+               cdr2.raw = 0;
+               cdr2.bits.target_node_id = NCP_NODE_ID(region);
+               cdr2.bits.target_id_address_upper = NCP_TARGET_ID(region);
+               ncr_register_write(cdr2.raw, (unsigned *) (nca_address + 0xf8));
+
+               cdr1.raw = 0;
+               cdr1.bits.target_address = (address >> 2);
+               ncr_register_write(cdr1.raw, (unsigned *) (nca_address + 0xf4));
+
+               /*
+                 Copy from buffer to the data words.
+               */
+
+               data_word_base = (unsigned long)(nca_address + 0x1000);
+
+               while (4 <= number) {
+                       ncr_register_write(*((unsigned long *) buffer),
+                                       (unsigned *) data_word_base);
+                       data_word_base += 4;
+                       buffer += 4;
+                       number -= 4;
+               }
+
+               if (0 < number) {
+                       unsigned long temp = 0;
+
+                       memcpy((void *) &temp, (void *) buffer, number);
+                       ncr_register_write(temp, (unsigned *) data_word_base);
+                       data_word_base += number;
+                       buffer += number;
+                       number = 0;
+               }
+
+               cdr0.raw = 0;
+               cdr0.bits.start_done = 1;
+
+               if (0xff == cdr2.bits.target_id_address_upper)
+                       cdr0.bits.local_bit = 1;
+
+               cdr0.bits.cmd_type = 5;
+               /* TODO: Verify number... */
+               cdr0.bits.dbs = dbs;
+               ncr_register_write(cdr0.raw, (unsigned *) (nca_address + 0xf0));
+               mb();
+
+               /*
+               Wait for completion.
+               */
+
+               do {
+                       --wfc_timeout;
+               } while ((0x80000000UL ==
+                               ncr_register_read((unsigned *)(nca_address + 
0xf0))) &&
+                               0 < wfc_timeout);
+
+               if (0 == wfc_timeout) {
+                       ncr_unlock(LOCK_DOMAIN);
+                       return -1;
+               }
+
+               /*
+               Check status.
+               */
+
+               if (0x3 != ((ncr_register_read((unsigned *) (nca_address + 
0xf0)) &
+                                               0x00c00000) >> 22)) {
+                       unsigned long status;
+
+                       status = ncr_register_read((unsigned *)(nca_address +
+                                                               0xe4));
+                       ncr_unlock(LOCK_DOMAIN);
+
+                       return status;
+               }
+       } else {
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+               void __iomem *targ_address = apb2ser0_address +
+                                            (address & (~0x3));
+               /*
+                 Copy from buffer to the data words.
+               */
+
+               while (4 <= number) {
+                       *((unsigned long *) targ_address) =
+                               *((unsigned long *) buffer);
+                       targ_address += 4;
+                       number -= 4;
+               }
+#else
+               ncr_unlock(LOCK_DOMAIN);
+               return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+       }
+
+       ncr_unlock(LOCK_DOMAIN);
+
+       return 0;
+}
+EXPORT_SYMBOL(ncr_write);
+
+/*
+  ----------------------------------------------------------------------
+  ncr_init
+*/
+
+int
+ncr_init(void)
+{
+       nca_address = ioremap(NCA_PHYS_ADDRESS, 0x20000);
+
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+       apb2ser0_address = ioremap(APB2SER_PHY_PHYS_ADDRESS, 0x10000);
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+
+       pr_info("ncr: available\n");
+
+       return 0;
+}
+EXPORT_SYMBOL(ncr_init);
+
+/*
+  ----------------------------------------------------------------------
+  ncr_exit
+*/
+
+void __exit
+ncr_exit(void)
+{
+       /* Unmap the NCA. */
+       if (NULL != nca_address)
+               iounmap(nca_address);
+
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+       /* Unmap the APB2SER0 PHY. */
+       if (NULL != apb2ser0_address)
+               iounmap(apb2ser0_address);
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+
+       return;
+}
+EXPORT_SYMBOL(ncr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Register Ring access for LSI's ACP board");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 62457bc..6272797 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -537,7 +537,7 @@ config LSI_MTC
 
 config LSI_NCR
        tristate "LSI NCR Access"
-       depends on ARCH_AXXIA || ACP
+       depends on ACP
        help
          Provides access to the LSI Axxia NCR bus.
 
diff --git a/drivers/misc/lsi-smmon.c b/drivers/misc/lsi-smmon.c
index 0c0db5d..5ab644b 100644
--- a/drivers/misc/lsi-smmon.c
+++ b/drivers/misc/lsi-smmon.c
@@ -17,7 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 
-#include "lsi-ncr.h"
+#include <mach/ncr.h>
 
 #ifndef CONFIG_ARCH_AXXIA
 #error "Only AXM55xx is Supported At Present!"
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.c 
b/drivers/net/ethernet/lsi/lsi_acp_net.c
index 03bb287..8924b19 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_net.c
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.c
@@ -82,13 +82,18 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/dma-mapping.h>
-
 #include <linux/uaccess.h>
 #include <linux/io.h>
+
 #include <asm/dma.h>
 
-#include "lsi_acp_net.h"
+#ifdef CONFIG_AXXIA
+#include <mach/ncr.h>
+#else
 #include "../../../misc/lsi-ncr.h"
+#endif
+
+#include "lsi_acp_net.h"
 
 /* Define to disable full duplex mode on Amarillo boards */
 #undef AMARILLO_WA
-- 
1.7.9.5

_______________________________________________
linux-yocto mailing list
[email protected]
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to