[linux-yocto] [PATCH 45/52] misc: Updated lsi-ncr driver for ARM support

Daniel Dragomir daniel.dragomir at windriver.com
Wed Jan 28 09:18:59 PST 2015


From: SangeethaRao <sangeetha.rao at lsi.com>

Updated LSI NCR driver to use CPU jiffies for ncr_lock() timeout. Also,
LSI NCR driver under drivers/misc/lsi-ncr.c is integrated as the common
driver for ARM/PPC platforms.

Signed-off-by: SangeethaRao <sangeetha.rao at lsi.com>
---
 arch/arm/mach-axxia/Makefile |   2 +-
 arch/arm/mach-axxia/ncr.c    | 660 -------------------------------------------
 drivers/misc/Kconfig         |   2 +-
 drivers/misc/lsi-ncr.c       | 523 ++++++++++++++++++++++++----------
 4 files changed, 382 insertions(+), 805 deletions(-)
 delete mode 100644 arch/arm/mach-axxia/ncr.c

diff --git a/arch/arm/mach-axxia/Makefile b/arch/arm/mach-axxia/Makefile
index 5b4c6f9..de95182 100644
--- a/arch/arm/mach-axxia/Makefile
+++ b/arch/arm/mach-axxia/Makefile
@@ -5,7 +5,7 @@ obj-y					+= axxia.o
 obj-y					+= clock.o
 obj-y					+= io.o
 obj-y					+= ssp-gpio.o
-obj-y					+= ncr.o
+#obj-y					+= ncr.o
 obj-y					+= timers.o
 obj-y					+= pci.o
 obj-y					+= ddr_retention.o ddr_shutdown.o
diff --git a/arch/arm/mach-axxia/ncr.c b/arch/arm/mach-axxia/ncr.c
deleted file mode 100644
index 995e8a0..0000000
--- a/arch/arm/mach-axxia/ncr.c
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- *  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)
-
-static DEFINE_RAW_SPINLOCK(ncr_spin_lock);
-static unsigned long flags;
-
-#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
-
-/*
- * like iowrite32be but without the barrier.
- * The iowmb barrier in the standard macro includes a outer_cache_sync
- * which we don't want for Axxia register IO.
- */
-#define axxia_write32be(v,p) ({  __raw_writel((__force __u32)cpu_to_be32(v), p); })
-
-/*
-  ----------------------------------------------------------------------
-  ncr_register_read
-*/
-
-inline unsigned long
-ncr_register_read(unsigned *address)
-{
-	unsigned long value;
-
-	value = ioread32be(address);
-
-	return value;
-}
-
-/*
-  ----------------------------------------------------------------------
-  ncr_register_write
-*/
-
-void
-inline ncr_register_write(const unsigned value, unsigned *address)
-{
-	axxia_write32be(value, address);
-    asm volatile ("mcr p15,0,%0,c7,c5,4" : : "r" (0));  /* isb */
-
-	return;
-}
-
-#else
-
-/*
-  ----------------------------------------------------------------------
-  ncr_register_read
-*/
-
-inline unsigned long
-ncr_register_read(unsigned *address)
-{
-	unsigned long value;
-
-	value = in_be32((unsigned *)address);
-
-	return value;
-}
-
-/*
-  ----------------------------------------------------------------------
-  ncr_register_write
-*/
-
-inline 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;
-	command_data_register_0_t cdr0;
-
-	raw_spin_lock_irqsave(&ncr_spin_lock, flags);
-	offset = (0xff80 + (domain * 4));
-
-	do {
-		value = ncr_register_read((unsigned *)(nca_address + offset));
-	} while ((0 != value) && (0 < --loops));
-
-	if (0 == loops) {
-		raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
-		printk(KERN_ERR "ncr_lock() Timeout!\n");
-		BUG();
-
-		return -1;
-	}
-
-	/*
-	  Make sure any previous commands completed, and check for errors.
-	*/
-
-	loops = 10000;
-
-	do {
-		--loops;
-		cdr0.raw =
-			ncr_register_read((unsigned *)(nca_address + 0xf0));
-	} while ((0x1 == cdr0.bits.status) &&
-		 (0 < loops));
-
-	if (0 == loops) {
-		raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
-		printk(KERN_ERR
-		       "ncr_lock() Previous command didn't complete!\n");
-		BUG();
-
-		return -1;
-	}
-
-	if (0x2 == cdr0.bits.status) {
-		printk(KERN_ERR "Previous ncr access failed!\n");
-	}
-
-	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));
-	raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
-
-	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) && (NCP_NODE_ID(region) != 0x115)) {
-		/*
-		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;
-			cdr0.raw =
-				ncr_register_read((unsigned *)
-						  (nca_address + 0xf0));
-		} while (1 == cdr0.bits.start_done && 0 < wfc_timeout);
-
-		if (0 == wfc_timeout) {
-			ncr_unlock(LOCK_DOMAIN);
-			printk(KERN_ERR "ncr_read() Timeout!\n");
-			BUG();
-
-			return -1;
-		}
-
-		if (0x3 != cdr0.bits.status) {
-			ncr_unlock(LOCK_DOMAIN);
-			printk(KERN_ERR "ncr_write() failed: 0x%x\n",
-			       cdr0.bits.status);
-
-			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;
-			buffer += 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
-		if (NCP_NODE_ID(region) != 0x115) {
-			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 {
-			void __iomem *base;
-			if (0xffff < address) {
-				ncr_unlock(LOCK_DOMAIN);
-				return -1;
-			}
-
-			switch (NCP_TARGET_ID(region)) {
-			case 0:
-				base = (apb2ser0_address + 0x1e0);
-				break;
-			case 1:
-				base = (apb2ser0_address + 0x1f0);
-				break;
-			case 2:
-				base = (apb2ser0_address + 0x200);
-				break;
-			case 3:
-				base = (apb2ser0_address + 0x210);
-				break;
-			case 4:
-				base = (apb2ser0_address + 0x220);
-				break;
-			case 5:
-				base = (apb2ser0_address + 0x230);
-				break;
-			default:
-				ncr_unlock(LOCK_DOMAIN);
-				return -1;
-			}
-			if ((NCP_TARGET_ID(region) == 0x1) ||
-				(NCP_TARGET_ID(region) == 0x4)) {
-				writel((0x84c00000 + address), (base + 4));
-			} else {
-				writel((0x85400000 + address), (base + 4));
-			}
-			do {
-				--wfc_timeout;
-				*((unsigned long *) buffer) =
-					readl(base + 4);
-			} while (0 != (*((unsigned long *) buffer) & 0x80000000)
-					&& 0 < wfc_timeout);
-
-			if (0 == wfc_timeout) {
-				ncr_unlock(LOCK_DOMAIN);
-				return -1;
-			}
-
-			if ((NCP_TARGET_ID(region) == 0x1) ||
-				(NCP_TARGET_ID(region) == 0x4)) {
-				*((unsigned short *) buffer) =
-					readl(base + 8);
-			} else {
-				*((unsigned long *) buffer) =
-					readl(base + 8);
-			}
-
-		}
-#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) && (NCP_NODE_ID(region) != 0x115)) {
-		/*
-		  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;
-			cdr0.raw =
-				ncr_register_read((unsigned *)
-						  (nca_address + 0xf0));
-		} while (1 == cdr0.bits.start_done && 0 < wfc_timeout);
-
-		if (0 == wfc_timeout) {
-			ncr_unlock(LOCK_DOMAIN);
-			printk(KERN_ERR "ncr_write() Timeout!\n");
-			BUG();
-
-			return -1;
-		}
-
-		/*
-		Check status.
-		*/
-
-		if ((0x3 != cdr0.bits.status) && (0x00c00000) >> 22) {
-			unsigned long status;
-
-			status = ncr_register_read((unsigned *)(nca_address +
-								0xe4));
-			ncr_unlock(LOCK_DOMAIN);
-			printk(KERN_ERR
-			       "ncr_write() Error: 0x%x 0x%lx\n",
-			       cdr0.bits.status, status);
-
-			return status;
-		}
-	} else {
-#ifdef APB2SER_PHY_PHYS_ADDRESS
-	if (NCP_NODE_ID(region) != 0x115) {
-		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 {
-		void __iomem *base;
-		if (0xffff < address) {
-			ncr_unlock(LOCK_DOMAIN);
-			return -1;
-		}
-
-		switch (NCP_TARGET_ID(region)) {
-			case 0:
-				base = (apb2ser0_address + 0x1e0);
-				break;
-			case 1:
-				base = (apb2ser0_address + 0x1f0);
-				break;
-			case 2:
-				base = (apb2ser0_address + 0x200);
-				break;
-			case 3:
-				base = (apb2ser0_address + 0x210);
-				break;
-			case 4:
-				base = (apb2ser0_address + 0x220);
-				break;
-			case 5:
-				base = (apb2ser0_address + 0x230);
-				break;
-			default:
-				ncr_unlock(LOCK_DOMAIN);
-				return -1;
-		}
-		if ((NCP_TARGET_ID(region) == 0x1) ||
-				(NCP_TARGET_ID(region) == 0x4)) {
-			writel(*((unsigned short *) buffer), base);
-			writel((0xc4c00000 + address), (base + 4));
-		} else {
-			writel(*((unsigned long *) buffer), base);
-			writel((0xc5400000 + address), (base + 4));
-		}
-			do {
-				--wfc_timeout;
-				*((unsigned long *) buffer) =
-					readl(base + 4);
-			} while (0 != (*((unsigned long *) buffer) & 0x80000000)
-				&& 0 < wfc_timeout);
-
-			if (0 == wfc_timeout) {
-				ncr_unlock(LOCK_DOMAIN);
-				return -1;
-			}
-		}
-#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 c6fa981..02a3210 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -547,7 +547,7 @@ config LSI_MTC
 
 config LSI_NCR
 	tristate "LSI NCR Access"
-	depends on ACP
+	depends on ARCH_AXXIA || ACP
 	help
 	  Provides access to the LSI Axxia NCR bus.
 
diff --git a/drivers/misc/lsi-ncr.c b/drivers/misc/lsi-ncr.c
index 23bcbe6..9bd185b 100644
--- a/drivers/misc/lsi-ncr.c
+++ b/drivers/misc/lsi-ncr.c
@@ -21,21 +21,29 @@
  */
 
 #include <linux/module.h>
+#include <linux/jiffies.h>
 
 #include <asm/io.h>
 
 #include "lsi-ncr.h"
 
-static void __iomem *nca_address;
-
 #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)
 
+static DEFINE_RAW_SPINLOCK(ncr_spin_lock);
+static unsigned long flags;
+
 #define LOCK_DOMAIN 0
 
 typedef union {
@@ -88,11 +96,19 @@ typedef union {
 #ifdef CONFIG_ARM
 
 /*
+ * like iowrite32be but without the barrier.
+ * The iowmb barrier in the standard macro includes a outer_cache_sync
+ * which we don't want for Axxia register IO.
+ */
+#define axxia_write32be(v, p) \
+	({  __raw_writel((__force __u32)cpu_to_be32(v), p); })
+
+/*
   ----------------------------------------------------------------------
   ncr_register_read
 */
 
-unsigned long
+inline unsigned long
 ncr_register_read(unsigned *address)
 {
 	unsigned long value;
@@ -108,9 +124,10 @@ ncr_register_read(unsigned *address)
 */
 
 void
-ncr_register_write(const unsigned value, unsigned *address)
+inline ncr_register_write(const unsigned value, unsigned *address)
 {
-	iowrite32be(value, address);
+	axxia_write32be(value, address);
+	asm volatile ("mcr p15,0,%0,c7,c5,4" : : "r" (0));  /* isb */
 
 	return;
 }
@@ -122,7 +139,7 @@ ncr_register_write(const unsigned value, unsigned *address)
   ncr_register_read
 */
 
-unsigned long
+inline unsigned long
 ncr_register_read(unsigned *address)
 {
 	unsigned long value;
@@ -137,7 +154,7 @@ ncr_register_read(unsigned *address)
   ncr_register_write
 */
 
-void
+inline void
 ncr_register_write(const unsigned value, unsigned *address)
 {
 	out_be32(address, value);
@@ -157,16 +174,43 @@ ncr_lock(int domain)
 {
 	unsigned long offset;
 	unsigned long value;
-	int loops = 10000;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+	command_data_register_0_t cdr0;
 
+	raw_spin_lock_irqsave(&ncr_spin_lock, flags);
 	offset = (0xff80 + (domain * 4));
 
 	do {
 		value = ncr_register_read((unsigned *)(nca_address + offset));
-	} while ((0 != value) && (0 < --loops));
+	} while ((0 != value) && (time_before(jiffies, timeout)));
+
+	if (!(time_before(jiffies, timeout))) {
+		raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
+		pr_err("ncr_lock() Timeout!\n");
+		BUG();
 
-	if (0 == loops)
 		return -1;
+	}
+	/*
+	  Make sure any previous commands completed, and check for errors.
+	*/
+	timeout = jiffies + msecs_to_jiffies(1000);
+
+	do {
+		cdr0.raw =
+			ncr_register_read((unsigned *)(nca_address + 0xf0));
+	} while ((0x1 == cdr0.bits.status) &&
+		(time_before(jiffies, timeout)));
+
+	if (!(time_before(jiffies, timeout))) {
+		raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
+		pr_err("ncr_lock() Previous command didn't complete!\n");
+		BUG();
+
+		return -1;
+	}
+	if (0x2 == cdr0.bits.status)
+		pr_err("Previous ncr access failed!\n");
 
 	return 0;
 }
@@ -183,6 +227,7 @@ ncr_unlock(int domain)
 
 	offset = (0xff80 + (domain * 4));
 	ncr_register_write(0, (unsigned *)(nca_address + offset));
+	raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
 
 	return;
 }
@@ -210,73 +255,171 @@ ncr_read(unsigned long region, unsigned long address, int number,
 	int wfc_timeout = WFC_TIMEOUT;
 
 	if (NULL == nca_address)
-		nca_address = ioremap(NCA_PHYS_ADDRESS, 0x20000);
-
-	if (0 != ncr_lock(LOCK_DOMAIN))
 		return -1;
 
-	/*
-	  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.
-	*/
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+	if (NULL == apb2ser0_address)
+		return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
 
-	do {
-		--wfc_timeout;
-	} while ((0x80000000UL ==
-		  ncr_register_read((unsigned *)(nca_address + 0xf0))) &&
-		 0 < wfc_timeout);
+	if (0 != ncr_lock(LOCK_DOMAIN))
+		return -1;
 
-	if (0 == wfc_timeout) {
+	if ((NCP_NODE_ID(region) != 0x0153) && (NCP_NODE_ID(region) != 0x115)) {
+		/*
+		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;
+			cdr0.raw =
+				ncr_register_read((unsigned *)
+						  (nca_address + 0xf0));
+		} while (1 == cdr0.bits.start_done && 0 < wfc_timeout);
+
+		if (0 == wfc_timeout) {
+			ncr_unlock(LOCK_DOMAIN);
+			pr_err("ncr_read() Timeout!\n");
+			BUG();
+
+			return -1;
+		}
+
+		if (0x3 != cdr0.bits.status) {
+			ncr_unlock(LOCK_DOMAIN);
+			pr_err("ncr_write() failed: 0x%x\n",
+			       cdr0.bits.status);
+
+			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;
+			buffer += 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
+		if (NCP_NODE_ID(region) != 0x115) {
+			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 {
+			void __iomem *base;
+			if (0xffff < address) {
+				ncr_unlock(LOCK_DOMAIN);
+				return -1;
+			}
+
+			switch (NCP_TARGET_ID(region)) {
+			case 0:
+				base = (apb2ser0_address + 0x1e0);
+				break;
+			case 1:
+				base = (apb2ser0_address + 0x1f0);
+				break;
+			case 2:
+				base = (apb2ser0_address + 0x200);
+				break;
+			case 3:
+				base = (apb2ser0_address + 0x210);
+				break;
+			case 4:
+				base = (apb2ser0_address + 0x220);
+				break;
+			case 5:
+				base = (apb2ser0_address + 0x230);
+				break;
+			default:
+				ncr_unlock(LOCK_DOMAIN);
+				return -1;
+			}
+			if ((NCP_TARGET_ID(region) == 0x1) ||
+				(NCP_TARGET_ID(region) == 0x4)) {
+				writel((0x84c00000 + address), (base + 4));
+			} else {
+				writel((0x85400000 + address), (base + 4));
+			}
+			do {
+				--wfc_timeout;
+				*((unsigned long *) buffer) =
+					readl(base + 4);
+			} while (0 != (*((unsigned long *) buffer) & 0x80000000)
+					&& 0 < wfc_timeout);
+
+			if (0 == wfc_timeout) {
+				ncr_unlock(LOCK_DOMAIN);
+				return -1;
+			}
+
+			if ((NCP_TARGET_ID(region) == 0x1) ||
+				(NCP_TARGET_ID(region) == 0x4)) {
+				*((unsigned short *) buffer) =
+					readl(base + 8);
+			} else {
+				*((unsigned long *) buffer) =
+					readl(base + 8);
+			}
+
+		}
+#else
 		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);
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
 	}
 
 	ncr_unlock(LOCK_DOMAIN);
 
 	return 0;
 }
+EXPORT_SYMBOL(ncr_read);
 
 /*
   ----------------------------------------------------------------------
@@ -295,94 +438,176 @@ ncr_write(unsigned long region, unsigned long address, int number,
 	int wfc_timeout = WFC_TIMEOUT;
 
 	if (NULL == nca_address)
-		nca_address = ioremap(NCA_PHYS_ADDRESS, 0x20000);
-
-	if (0 != ncr_lock(LOCK_DOMAIN))
 		return -1;
 
-	/*
-	  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);
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+	if (NULL == apb2ser0_address)
 		return -1;
-	}
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
 
-	/*
-	  Check status.
-	*/
-
-	if (0x3 !=
-	    ((ncr_register_read((unsigned *) (nca_address + 0xf0)) &
-		0x00c00000) >> 22)) {
-		unsigned long status;
+	if (0 != ncr_lock(LOCK_DOMAIN))
+		return -1;
 
-		status = ncr_register_read((unsigned *)(nca_address + 0xe4));
+	if ((NCP_NODE_ID(region) != 0x0153) && (NCP_NODE_ID(region) != 0x115)) {
+		/*
+		  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;
+			cdr0.raw =
+				ncr_register_read((unsigned *)
+						  (nca_address + 0xf0));
+		} while (1 == cdr0.bits.start_done && 0 < wfc_timeout);
+
+		if (0 == wfc_timeout) {
+			ncr_unlock(LOCK_DOMAIN);
+			pr_err("ncr_write() Timeout!\n");
+			BUG();
+
+			return -1;
+		}
+
+		/*
+		Check status.
+		*/
+
+		if ((0x3 != cdr0.bits.status) && (0x00c00000) >> 22) {
+			unsigned long status;
+
+			status = ncr_register_read((unsigned *)(nca_address +
+								0xe4));
+			ncr_unlock(LOCK_DOMAIN);
+			pr_err("ncr_write() Error: 0x%x 0x%lx\n",
+			       cdr0.bits.status, status);
+
+			return status;
+		}
+	} else {
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+	if (NCP_NODE_ID(region) != 0x115) {
+		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 {
+		void __iomem *base;
+		if (0xffff < address) {
+			ncr_unlock(LOCK_DOMAIN);
+			return -1;
+		}
+
+		switch (NCP_TARGET_ID(region)) {
+		case 0:
+			base = (apb2ser0_address + 0x1e0);
+			break;
+		case 1:
+			base = (apb2ser0_address + 0x1f0);
+			break;
+		case 2:
+			base = (apb2ser0_address + 0x200);
+			break;
+		case 3:
+			base = (apb2ser0_address + 0x210);
+			break;
+		case 4:
+			base = (apb2ser0_address + 0x220);
+			break;
+		case 5:
+			base = (apb2ser0_address + 0x230);
+			break;
+		default:
+			ncr_unlock(LOCK_DOMAIN);
+			return -1;
+		}
+		if ((NCP_TARGET_ID(region) == 0x1) ||
+				(NCP_TARGET_ID(region) == 0x4)) {
+			writel(*((unsigned short *) buffer), base);
+			writel((0xc4c00000 + address), (base + 4));
+		} else {
+			writel(*((unsigned long *) buffer), base);
+			writel((0xc5400000 + address), (base + 4));
+		}
+			do {
+				--wfc_timeout;
+				*((unsigned long *) buffer) =
+					readl(base + 4);
+			} while (0 != (*((unsigned long *) buffer) & 0x80000000)
+				&& 0 < wfc_timeout);
+
+			if (0 == wfc_timeout) {
+				ncr_unlock(LOCK_DOMAIN);
+				return -1;
+			}
+		}
+#else
 		ncr_unlock(LOCK_DOMAIN);
-
-		return status;
+		return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
 	}
 
 	ncr_unlock(LOCK_DOMAIN);
 
 	return 0;
 }
+EXPORT_SYMBOL(ncr_write);
 
 /*
   ----------------------------------------------------------------------
@@ -394,9 +619,16 @@ 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;
 }
 
+
 module_init(ncr_init);
 
 /*
@@ -411,13 +643,18 @@ ncr_exit(void)
 	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;
 }
 
+
 module_exit(ncr_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Register Ring access for LSI's ACP board");
 
-EXPORT_SYMBOL(ncr_read);
-EXPORT_SYMBOL(ncr_write);
-- 
1.8.1.4



More information about the linux-yocto mailing list