[linux-yocto] [PATCH 05/15] arch/arm/mach-axxia: Support for DDR Retention Resets
Charlie Paul
cpaul.windriver at gmail.com
Mon Jan 20 09:56:12 PST 2014
From: John Jacques <john.jacques at lsi.com>
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 <john.jacques at lsi.com>
---
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
More information about the linux-yocto
mailing list