[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