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

Paul Butler butler.paul at gmail.com
Mon Jun 10 18:45:55 PDT 2013


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

Extracted from lsi.patch in lsi_acp_linux_6.8.1.18 tarball.

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