From: John Jacques <[email protected]>

Add support for node 0x153 on 5500.

Support indirect accesses correctly.

Signed-off-by: John Jacques <[email protected]>
---
 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

-- 
_______________________________________________
linux-yocto mailing list
[email protected]
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to