[linux-yocto] [PATCH 31/69] lsi/ncr: add support to read/write access to configuration ring resources

Paul Butler butler.paul at gmail.com
Fri Jun 14 18:00:45 PDT 2013


From: Jiang Lu <lu.jiang at windriver.com>

Extracted from lsi.patch in lsi_acp_linux_6.8.1.18 tarball.
(Available from LSI support upon request.)

The Nuevo CPU Adapter (NCA) is the hardware engine that connects the
powerpc complex with the ACP3400 data patch accellerator engines.
This driver provides the CPU with read/write access to configuration
ring resources via NCA configuration commands.

[Jiang:
	* Get the nca register virtual address by using ioremap instead
	of using a fixed virtual address bolted in tlb entry.
	* Move from driver/lsi/acp.c to arch/powerpc/sysdev/lsi_acp_ncr.c]

Signed-off-by: Jiang Lu <lu.jiang at windriver.com>
---
 arch/powerpc/include/asm/lsi/acp_ncr.h |  42 ++++
 arch/powerpc/sysdev/Makefile           |   2 +
 arch/powerpc/sysdev/lsi_acp_ncr.c      | 375 +++++++++++++++++++++++++++++++++
 3 files changed, 419 insertions(+)
 create mode 100644 arch/powerpc/include/asm/lsi/acp_ncr.h
 create mode 100644 arch/powerpc/sysdev/lsi_acp_ncr.c

diff --git a/arch/powerpc/include/asm/lsi/acp_ncr.h b/arch/powerpc/include/asm/lsi/acp_ncr.h
new file mode 100644
index 0000000..a7399e7
--- /dev/null
+++ b/arch/powerpc/include/asm/lsi/acp_ncr.h
@@ -0,0 +1,42 @@
+/*
+ * asm/lsi/acp_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 __DRIVERS_LSI_ACP_NCR_H
+#define __DRIVERS_LSI_ACP_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
+
+int ncr_read(unsigned long, unsigned long, int, void *);
+int ncr_write(unsigned long, unsigned long, int, void *);
+
+int is_asic(void);
+
+#endif /*  __DRIVERS_LSI_ACP_NCR_H */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 1bd7ecb..af96e92 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -69,3 +69,5 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 obj-$(CONFIG_PPC_XICS)		+= xics/
 
 obj-$(CONFIG_GE_FPGA)		+= ge/
+
+obj-$(CONFIG_ACP)		+= lsi_acp_ncr.o
diff --git a/arch/powerpc/sysdev/lsi_acp_ncr.c b/arch/powerpc/sysdev/lsi_acp_ncr.c
new file mode 100644
index 0000000..9802110
--- /dev/null
+++ b/arch/powerpc/sysdev/lsi_acp_ncr.c
@@ -0,0 +1,375 @@
+/*
+ *  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/io.h>
+#include <linux/module.h>
+
+#include <include/asm/lsi/acp_ncr.h>
+
+static void __iomem *nca_address;
+
+#define WFC_TIMEOUT (400000)
+
+#define LOCK_DOMAIN 0
+
+union command_data_register_0 {
+	unsigned long raw;
+	struct {
+		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;
+	} __packed bits;
+} __packed;
+
+union command_data_register_1 {
+	unsigned long raw;
+	struct {
+		unsigned long target_address:32;
+	} __packed bits;
+} __packed;
+
+union command_data_register_2 {
+	unsigned long raw;
+	struct {
+		unsigned long unused:16;
+		unsigned long target_node_id:8;
+		unsigned long target_id_address_upper:8;
+	} __packed bits;
+} __packed;
+
+/*
+  ----------------------------------------------------------------------
+  ncr_register_read
+*/
+
+static inline unsigned long
+ncr_register_read(unsigned *address)
+{
+	unsigned long value;
+
+	value = in_be32(address);
+
+	return value;
+}
+
+/*
+  ----------------------------------------------------------------------
+  ncr_register_write
+*/
+
+static inline void
+ncr_register_write(const unsigned value, unsigned *address)
+{
+	out_be32(address, value);
+}
+
+/*
+  ------------------------------------------------------------------------------
+  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)
+{
+	union command_data_register_0 cdr0;
+	union command_data_register_1 cdr1;
+	union command_data_register_2 cdr2;
+	int wfc_timeout = WFC_TIMEOUT;
+
+	if (NULL == nca_address)
+		nca_address = ioremap(0x002000520000ULL, 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.
+	*/
+
+	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);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ncr_read);
+/*
+  ------------------------------------------------------------------------------
+  is_asic
+*/
+
+int
+is_asic(void)
+{
+#ifdef CONFIG_ACPISS
+	return 0;
+#else
+	unsigned long nca_config;
+
+	if (0 == ncr_read(NCP_REGION_ID(0x16, 0xff), 0x10, 4, &nca_config))
+		return (0 == (nca_config & 0x80000000));
+
+	return -1;
+#endif
+}
+EXPORT_SYMBOL(is_asic);
+
+/*
+  ----------------------------------------------------------------------
+  ncr_write
+*/
+
+int
+ncr_write(unsigned long region, unsigned long address, int number, void *buffer)
+{
+	union command_data_register_0 cdr0;
+	union command_data_register_1 cdr1;
+	union command_data_register_2 cdr2;
+	unsigned long data_word_base;
+	int dbs = (number - 1);
+	int wfc_timeout = WFC_TIMEOUT;
+
+	if (NULL == nca_address)
+		nca_address = ioremap(0x002000520000ULL, 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);
+		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;
+	}
+
+	ncr_unlock(LOCK_DOMAIN);
+
+	return 0;
+}
+EXPORT_SYMBOL(ncr_write);
+
+/*
+  ----------------------------------------------------------------------
+  ncr_init
+*/
+
+int
+ncr_init(void)
+{
+	/* We need this to be a module so that the functions can be exported
+	 * as module symbols.
+	 */
+	return 0;
+}
+
+postcore_initcall(ncr_init);
+
+/*
+  ----------------------------------------------------------------------
+  ncr_exit
+*/
+
+void __exit
+ncr_exit(void)
+{
+	/* Unmap the NCA. */
+	iounmap(nca_address);
+}
+
+module_exit(ncr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Register Ring access for LSI's ACP board");
-- 
1.8.3




More information about the linux-yocto mailing list