[linux-yocto] [PATCH 16/17] drivers/misc: Update the Axxia NCR Driver

Daniel Dragomir daniel.dragomir at windriver.com
Tue May 16 11:39:08 PDT 2017


From: John Jacques <john.jacques at intel.com>

Add support for node 0x153 on 5500.

Support indirect accesses correctly.

Signed-off-by: John Jacques <john.jacques at intel.com>
---
 drivers/misc/lsi-ncr.c  | 370 +++++++++++++++++++++++++++++++++++++++++++-----
 include/linux/lsi-ncr.h |   3 +
 2 files changed, 335 insertions(+), 38 deletions(-)

diff --git a/drivers/misc/lsi-ncr.c b/drivers/misc/lsi-ncr.c
index 9885e0a..adf8d41 100644
--- a/drivers/misc/lsi-ncr.c
+++ b/drivers/misc/lsi-ncr.c
@@ -23,6 +23,7 @@
 #include <linux/lsi-ncr.h>
 #include <linux/of.h>
 #include <linux/delay.h>
+#include <linux/sizes.h>
 
 static int ncr_available;
 static int nca_big_endian = 1;
@@ -136,6 +137,11 @@ union command_data_register_2 {
 	} __packed bits;
 } __packed;
 
+static int ncr_trace;
+module_param(ncr_trace, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+MODULE_PARM_DESC(ncr_trace, "NCR Tracing");
+
+
 /*
  * ncr_register_read/write
  *   low-level access functions to Axxia registers,
@@ -353,56 +359,242 @@ union ncp_apb2ser_indirect_command {
 
 /*
   ------------------------------------------------------------------------------
-  ncr_0x115
+  apb2ser_indirect_setup
 */
 
 static int
-ncr_0x115(unsigned int region, unsigned int offset, int write,
-	  unsigned int *value)
+apb2ser_indirect_setup(unsigned int region,
+		       unsigned int *indirect_offset,
+		       unsigned int *transfer_width)
+{
+	unsigned int node = NCP_NODE_ID(region);
+	unsigned int target = NCP_TARGET_ID(region);
+	unsigned int base;
+
+	if (is_5600)
+		if ((node < 0x110) || (node > 0x11a))
+			return -1;
+
+	if (is_6700)
+		if ((node < 0x110) || (node > 0x11f))
+			return -1;
+
+	if (node <= 0x114) {
+		base = (node - 0x110) * 2;
+	} else if (node >= 0x116) {
+		base = (node - 0x111) * 2;
+	} else {
+		if (is_5600)
+			base = 0x14;
+		else
+			base = 0x1e;
+	}
+
+	*indirect_offset = ((base + target) * 0x10000);
+	*transfer_width = (target > 0) ? 2 : 4;
+	udelay(10);
+
+	return 0;
+}
+
+/*
+ * ------------------------------------------------------------------------------
+ * apb2ser_indirect_access
+ */
+
+static int
+apb2ser_indirect_access(unsigned int offset,
+			unsigned int indirect_offset,
+			unsigned int transfer_width,
+			int write,
+			unsigned int *value)
 {
-	unsigned long base;
 	union ncp_apb2ser_indirect_command indcmd;
 	unsigned wfc;
 
 	memset(&indcmd, 0, sizeof(union ncp_apb2ser_indirect_command));
 	indcmd.bits.valid = 1;
 	indcmd.bits.hwrite = (0 == write) ? 0 : 1;
-	indcmd.bits.tshift = 1;
+	indcmd.bits.tshift = 0xf;
 	indcmd.bits.htrans = 2;
+	indcmd.bits.hsize = 2;
 	indcmd.bits.haddr = offset;
 
-	if (0 == NCP_TARGET_ID(region))
-		indcmd.bits.hsize = 2;
-	else
-		indcmd.bits.hsize = 1;
-
-	if (0 != is_5600)
-		base = 0x10000ULL * (0x14 + NCP_TARGET_ID(region));
-	else
-		base = 0x10000ULL * (0x1e + NCP_TARGET_ID(region));
-
-	mdelay(50);
-
 	if (0 != write)
-		writel(*value, (apb2ser0 + base));
+		writel(*value, (apb2ser0 + indirect_offset));
 
 	pr_debug("ncr: indcmd.raw=0x%x\n", indcmd.raw);
-	writel(indcmd.raw, (apb2ser0 + base + 4));
+	writel(indcmd.raw, (apb2ser0 + indirect_offset + 4));
 	wfc = WFC_TIMEOUT;
 
 	do {
 		--wfc;
-		indcmd.raw = readl(apb2ser0 + base + 4);
+		indcmd.raw = readl(apb2ser0 + indirect_offset + 4);
 	} while (1 == indcmd.bits.valid && 0 < wfc);
 
 	if (0 == wfc) {
-		printk(KERN_ERR "APB2SER Timeout: 0x%x\n", region);
+		pr_err("APB2SER Timeout!\n");
 
 		return -1;
 	}
 
 	if (0 == write)
-		*value = readl(apb2ser0 + base + 8);
+		*value = readl(apb2ser0 + indirect_offset + 8);
+
+	return 0;
+}
+
+/*
+ * ------------------------------------------------------------------------------
+ * ncr_apb2ser
+ */
+
+static int
+ncr_apb2ser(unsigned int region,
+	    unsigned int offset,
+	    int write,
+	    unsigned int *value)
+{
+	int rc;
+	unsigned int indirect_offset;
+	unsigned int transfer_width;
+
+	rc = apb2ser_indirect_setup(region, &indirect_offset, &transfer_width);
+
+	if (0 != rc) {
+		pr_err("APB2SER Indirect Setup Failed!\n");
+
+		return -1;
+	}
+
+	rc = apb2ser_indirect_access(offset, indirect_offset, transfer_width,
+				     write, value);
+
+	if (0 != rc) {
+		pr_err("APB2SER Indirect Setup Failed!\n");
+
+		return -1;
+	}
+
+	return 0;
+}
+
+union ncp_cobalt_serdes_ctrl98 {
+	unsigned short raw;
+
+	struct {
+#ifdef __BIG_ENDIAN
+	unsigned short reserved_b53 : 13;
+	unsigned short cr_ack_clear :  1;
+	unsigned short cr_rd        :  1;
+	unsigned short cr_wr        :  1;
+#else    /* Little Endian */
+	unsigned short cr_wr        :  1;
+	unsigned short cr_rd        :  1;
+	unsigned short cr_ack_clear :  1;
+	unsigned short reserved_b53 : 13;
+#endif
+	} __packed bits;
+} __packed;
+
+
+union ncp_cobalt_serdes_ctrl99 {
+	unsigned short raw;
+
+	struct {
+#ifdef __BIG_ENDIAN
+		unsigned short reserved : 15;
+		unsigned short cr_ack   :  1;
+#else    /* Little Endian */
+		unsigned short cr_ack   :  1;
+		unsigned short reserved : 15;
+#endif
+	} __packed bits;
+} __packed;
+
+/*
+ * ------------------------------------------------------------------------------
+ * ncr_apb2ser_e12
+ */
+
+static int
+ncr_apb2ser_e12(unsigned int region,
+		unsigned int offset,
+		int write,
+		unsigned int *value)
+{
+	unsigned int indirect_offset;
+	unsigned int transfer_width;
+	union ncp_cobalt_serdes_ctrl98 hss_cobalt_ctrl_98 = {0};
+	union ncp_cobalt_serdes_ctrl99 hss_cobalt_ctrl_99 = {0};
+	unsigned short e12_addr = 0;
+	unsigned int ctrl_96_off;
+	unsigned int ctrl_97_off;
+	unsigned int ctrl_98_off;
+	unsigned int ctrl_99_off;
+	unsigned int ctrl_224_off;
+
+	if (0 !=
+	    apb2ser_indirect_setup(region, &indirect_offset, &transfer_width))
+		return -1;
+
+	if (is_5600) {
+		ctrl_96_off = 0x00c0;
+		ctrl_97_off = 0x00c2;
+		ctrl_98_off = 0x00c4;
+		ctrl_99_off = 0x00c6;
+		ctrl_224_off = 0x01c0;
+	} else {
+		ctrl_96_off = 0x0180;
+		ctrl_97_off = 0x0184;
+		ctrl_98_off = 0x0188;
+		ctrl_99_off = 0x018c;
+		ctrl_224_off = 0x0380;
+		offset >>= 1;
+	}
+
+	if ((offset >= 0x1000) && (offset <= 0x10d0))
+		e12_addr = (offset - 0x1000) / 2;
+	else if (offset >= 0x2000)
+		e12_addr = offset / 2;
+
+	apb2ser_indirect_access(ctrl_96_off, indirect_offset, 4,
+				1, (unsigned int *)&e12_addr);
+
+	if (write) {
+		apb2ser_indirect_access(ctrl_97_off, indirect_offset, 4, 1,
+					value);
+		hss_cobalt_ctrl_98.bits.cr_rd = 0; /* bus read strobe */
+		hss_cobalt_ctrl_98.bits.cr_wr = 1;
+	} else  {
+		hss_cobalt_ctrl_98.bits.cr_rd = 1; /* bus read strobe */
+		hss_cobalt_ctrl_98.bits.cr_wr = 0;
+	}
+
+	hss_cobalt_ctrl_98.bits.cr_ack_clear = 0;
+	apb2ser_indirect_access(ctrl_98_off, indirect_offset, 4, 1,
+				(unsigned int *)&hss_cobalt_ctrl_98.raw);
+
+	/* poll for cr_ack to get set */
+	do {
+		apb2ser_indirect_access(ctrl_99_off, indirect_offset, 4, 0,
+					(unsigned int *)
+					&hss_cobalt_ctrl_99.raw);
+	} while (0 == hss_cobalt_ctrl_99.bits.cr_ack);
+
+	hss_cobalt_ctrl_98.bits.cr_rd = 0;
+	hss_cobalt_ctrl_98.bits.cr_wr = 0;
+	hss_cobalt_ctrl_98.bits.cr_ack_clear = 1;
+	apb2ser_indirect_access(ctrl_98_off, indirect_offset, 4, 1,
+				(unsigned int *)&hss_cobalt_ctrl_98.raw);
+
+	hss_cobalt_ctrl_98.bits.cr_ack_clear = 0;
+	apb2ser_indirect_access(ctrl_98_off, indirect_offset, 4, 1,
+				(unsigned int *)&hss_cobalt_ctrl_98.raw);
+
+	if (!write)
+		apb2ser_indirect_access(ctrl_224_off, indirect_offset, 4, 0,
+					value);
 
 	return 0;
 }
@@ -493,6 +685,20 @@ ncr_axi2ser(unsigned int region, unsigned int offset, int write,
 
 	switch (NCP_NODE_ID(region)) {
 	case 0x153:
+		if (0 != is_5500) {
+			address += (offset & (~0x3));
+
+			/*
+			 * Copy from buffer to the data words.
+			 */
+
+			if (0 != write)
+				*((unsigned long *)address) =
+					*((unsigned long *)value);
+			else
+				*((unsigned long *)value) =
+					*((unsigned long *)address);
+		}
 		break;
 	case 0x155:
 		address += 0x800000;
@@ -547,6 +753,7 @@ __ncr_read(struct ncr_io_fns *io_fn,
 	union command_data_register_0 cdr0;
 	union command_data_register_1 cdr1;
 	union command_data_register_2 cdr2;
+	unsigned char *input = buffer;
 
 	if (0 == ncr_available)
 		return -1;
@@ -555,14 +762,21 @@ __ncr_read(struct ncr_io_fns *io_fn,
 	      __FILE__, __LINE__,
 	      region, NCP_NODE_ID(region), NCP_TARGET_ID(region));
 
-	if (0x115 == NCP_NODE_ID(region)) {
-		if (0 != is_5500) {
-			if (0 != ncr_0x115_5500(region, address, 0, buffer))
-				return -1;
+	if (0x110 <= NCP_NODE_ID(region) &&
+	    0x11f >= NCP_NODE_ID(region)) {
+		int rc;
+
+		if (is_5500) {
+			rc = ncr_0x115_5500(region, address, 0, buffer);
+		} else if ((NCP_TARGET_ID(region) != 0) &&
+			   (address >= 0x1000)) {
+			rc = ncr_apb2ser_e12(region, address, 0, buffer);
 		} else {
-			if (0 != ncr_0x115(region, address, 0, buffer))
-				return -1;
+			rc = ncr_apb2ser(region, address, 0, buffer);
 		}
+
+		if (0 != rc)
+			return -1;
 	} else if (0x153 == NCP_NODE_ID(region) ||
 		   0x155 == NCP_NODE_ID(region) ||
 		   0x156 == NCP_NODE_ID(region) ||
@@ -632,6 +846,24 @@ _		  Copy data words to the buffer.
 		return -1;
 	}
 
+	if (0 != ncr_trace) {
+		int i;
+
+		printk("NCR: Read [");
+
+		for (i = 0; i < number; ++i) {
+			if ((i + 1) < number)
+				printk("0x%02x, ", *input++);
+			else
+				printk("0x%02x", *input++);
+		}
+
+		printk("] from 0x%x.0x%x.0x%lx\n",
+		       NCP_NODE_ID(region),
+		       NCP_TARGET_ID(region),
+		       address);
+	}
+
 	return 0;
 }
 
@@ -717,14 +949,40 @@ __ncr_write(struct ncr_io_fns *io_fn,
 	if (0 == ncr_available)
 		return -1;
 
-	if (0x115 == NCP_NODE_ID(region)) {
-		if (0 != is_5500) {
-			if (0 != ncr_0x115_5500(region, address, 1, buffer))
-				return -1;
+	if (0 != ncr_trace) {
+		int i;
+		unsigned char *input = buffer;
+
+		printk("NCR: Writing [");
+
+		for (i = 0; i < number; ++i) {
+			if ((i + 1) < number)
+				printk("0x%02x, ", *input++);
+			else
+				printk("0x%02x", *input++);
+		}
+
+		printk("] to 0x%x.0x%x.0x%x\n",
+		       NCP_NODE_ID(region),
+		       NCP_TARGET_ID(region),
+		       address);
+	}
+
+	if (0x110 <= NCP_NODE_ID(region) &&
+	    0x11f >= NCP_NODE_ID(region)) {
+		int rc;
+
+		if (is_5500) {
+			rc = ncr_0x115_5500(region, address, 1, buffer);
+		} else if ((NCP_TARGET_ID(region) != 0) &&
+			   (address >= 0x1000)) {
+			rc = ncr_apb2ser_e12(region, address, 1, buffer);
 		} else {
-			if (0 != ncr_0x115(region, address, 1, buffer))
-				return -1;
+			rc = ncr_apb2ser(region, address, 1, buffer);
 		}
+
+		if (0 != rc)
+			return -1;
 	} else if (0x153 == NCP_NODE_ID(region) ||
 		   0x155 == NCP_NODE_ID(region) ||
 		   0x156 == NCP_NODE_ID(region) ||
@@ -860,14 +1118,40 @@ EXPORT_SYMBOL(ncr_write32);
 
 /*
   ------------------------------------------------------------------------------
-  ncr_init
+  ncr_start_trace
 */
 
+void
+ncr_start_trace(void)
+{
+	ncr_trace = 1;
+}
+EXPORT_SYMBOL(ncr_start_trace);
+
+/*
+ * ------------------------------------------------------------------------------
+ * ncr_stop_trace
+ */
+
+void
+ncr_stop_trace(void)
+{
+	ncr_trace = 0;
+}
+EXPORT_SYMBOL(ncr_stop_trace);
+
+/*
+ * ------------------------------------------------------------------------------
+ * ncr_init
+ */
+
 static int
 ncr_init(void)
 {
+#ifdef CONFIG_ARCH_AXXIA
 	default_io_fn = &ncr_io_fn_nolock;
 
+
 	if (of_find_compatible_node(NULL, NULL, "lsi,axm5500-amarillo")) {
 		u32 pfuse;
 		u32 chip_type;
@@ -918,12 +1202,22 @@ ncr_init(void)
 		is_6700 = 1;
 		nca_big_endian = 0; /* The 6700 NCA is LE */
 	} else {
-		pr_debug("No Valid Compatible String Found for NCR!\n");
-
+		pr_err("No Valid Compatible String Found for NCR!\n");
 		return -1;
 	}
+#else
+	if (of_find_compatible_node(NULL, NULL, "lsi,acp3500")) {
+		pr_debug("Using ACP3500 Addresses\n");
+		nca = ioremap(0x002000520000ULL, 0x20000);
+		default_io_fn = &ncr_io_fn_nolock;
+	} else {
+		pr_debug("Using ACP34xx Addresses\n");
+		nca = ioremap(0x002000520000ULL, 0x20000);
+		default_io_fn = &ncr_io_fn_lock;
+	}
+#endif
 
-	pr_debug("ncr: available\n");
+	pr_info("ncr: available\n");
 	ncr_available = 1;
 
 	return 0;
diff --git a/include/linux/lsi-ncr.h b/include/linux/lsi-ncr.h
index 354a2c4..53b4138 100644
--- a/include/linux/lsi-ncr.h
+++ b/include/linux/lsi-ncr.h
@@ -42,6 +42,9 @@ int ncr_write32(unsigned int, unsigned int, unsigned int);
 int ncr_read_nolock(unsigned int, unsigned int, int, void *);
 int ncr_write_nolock(unsigned int, unsigned int, int, void *);
 
+void ncr_start_trace(void);
+void ncr_stop_trace(void);
+
  /*
   * when defined, the RTE driver module will set/clear
   * the ncr_reset_active flag to indicate when Axxia device
-- 
2.7.4



More information about the linux-yocto mailing list