You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2021/01/18 19:14:42 UTC

[incubator-nuttx] 01/01: xtensa/esp32: Add support to LWL

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch myupstream
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 3cd5ed705a90e4a5ad1166f3ce9cdc9c6cac2c07
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Mon Jan 18 16:09:03 2021 -0300

    xtensa/esp32: Add support to LWL
---
 arch/xtensa/Kconfig                         |  13 ++
 arch/xtensa/src/common/xtensa.h             |  17 +-
 arch/xtensa/src/common/xtensa_initialize.c  |   4 +-
 arch/xtensa/src/common/xtensa_lwl_console.c | 297 ++++++++++++++++++++++++++++
 arch/xtensa/src/esp32/Make.defs             |   4 +
 5 files changed, 333 insertions(+), 2 deletions(-)

diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 1a368a4..f427801 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -139,6 +139,19 @@ config XTENSA_IMEM_PROCFS
 	default n
 	depends on XTENSA_USE_SEPARATE_IMEM && !DISABLE_MOUNTPOINT && FS_PROCFS && FS_PROCFS_REGISTER
 
+config XTENSA_LWL_CONSOLE
+	bool "Lightweight Link Console Support"
+	default n
+	depends on DEV_CONSOLE && ARCH_CHIP_ESP32
+	---help---
+		Use the lightweight link console which provides console over a
+		debug channel by means of shared memory.  A terminal application
+		for openocd as the debugger is available in tools/ocdconsole.py.
+
+		Currently only available for ESP32 architectures, but easily
+		added to other Xtensa architectures be add up_low_console.c to
+		the architecture Make.defs file.
+
 source arch/xtensa/src/lx6/Kconfig
 if ARCH_CHIP_ESP32
 source arch/xtensa/src/esp32/Kconfig
diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h
index 5b770a4..4e4cafc 100644
--- a/arch/xtensa/src/common/xtensa.h
+++ b/arch/xtensa/src/common/xtensa.h
@@ -64,7 +64,10 @@
 #  undef  USE_SERIALDRIVER
 #  undef  USE_EARLYSERIALINIT
 #else
-#  if defined(CONFIG_CONSOLE_SYSLOG)
+#  if defined(CONFIG_XTENSA_LWL_CONSOLE)
+#    undef  USE_SERIALDRIVER
+#    undef  USE_EARLYSERIALINIT
+#  elif defined(CONFIG_CONSOLE_SYSLOG)
 #    undef  USE_SERIALDRIVER
 #    undef  USE_EARLYSERIALINIT
 #  else
@@ -324,11 +327,23 @@ void xtensa_add_region(void);
 /* Serial output */
 
 void up_lowputc(char ch);
+
+#ifdef USE_EARLYSERIALINIT
 void xtensa_early_serial_initialize(void);
+#endif
+
+#ifdef USE_SERIALDRIVER
 void xtensa_serial_initialize(void);
+#endif
 
 void rpmsg_serialinit(void);
 
+#ifdef CONFIG_XTENSA_LWL_CONSOLE
+/* Defined in src/common/xtensa_lwl_console.c */
+
+void lwlconsole_init(void);
+#endif
+
 /* Network */
 
 #if defined(CONFIG_NET) && !defined(CONFIG_NETDEV_LATEINIT)
diff --git a/arch/xtensa/src/common/xtensa_initialize.c b/arch/xtensa/src/common/xtensa_initialize.c
index 5bf57ad..bf9b499 100644
--- a/arch/xtensa/src/common/xtensa_initialize.c
+++ b/arch/xtensa/src/common/xtensa_initialize.c
@@ -207,7 +207,9 @@ void up_initialize(void)
    * serial driver).
    */
 
-#if defined(CONFIG_CONSOLE_SYSLOG)
+#if defined (CONFIG_XTENSA_LWL_CONSOLE)
+  lwlconsole_init();
+#elif defined(CONFIG_CONSOLE_SYSLOG)
   syslog_console_init();
 #endif
 
diff --git a/arch/xtensa/src/common/xtensa_lwl_console.c b/arch/xtensa/src/common/xtensa_lwl_console.c
new file mode 100644
index 0000000..a1327f8
--- /dev/null
+++ b/arch/xtensa/src/common/xtensa_lwl_console.c
@@ -0,0 +1,297 @@
+/****************************************************************************
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/fs/fs.h>
+#include <syscall.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Lightweight Link (lwl)
+ * ======================
+ *
+ * Lightweight bidirectional communication between target and debug host
+ * without any need for additional hardware.
+ *
+ * Works with openOCD and other debuggers that are capable of reading and
+ * writing memory while the target is running.
+ *
+ * Principle of operation is simple; An 'upword' of 32 bits communicates
+ * from the target to the host, a 'downword' of the same size runs in the
+ * opposite direction. These two words can be in any memory that is
+ * read/write access for both the target and the debug host. A simple ping
+ * pong handshake protocol over these words allows up/down link
+ * communication.  On the upside no additional integration is needed. On
+ * the downside it may be necessary to feed lwl with cycles to poll for
+ * changes in the downword, depending on the use case.
+ *
+ * Bit configuration
+ * -----------------
+ *
+ * Downword (Host to target);
+ *
+ * A D U VV XXX
+ *
+ * A   31    1 - Service Active (Set by host)
+ * D   30    1 - Downsense (Toggled when there is data)
+ * U   29    1 - Upsense ack (Toggled to acknowledge receipt of uplink data)
+ * VV  28-27 2 - Valid Octets (Number of octets valid in the message)
+ * XXX 26-24 3 - Port in use (Type of the message)
+ * O2  23-16 8 - Octet 2
+ * O1  15-08 8 - Octet 1
+ * O0  07-00 8 - Octet 0
+ *
+ * Upword (Target to Host);
+ *
+ * A   31    1 - Service Active (Set by device)
+ * D   30    1 - Downsense ack (Toggled to acknowledge receipt of downlink
+ *               data)
+ * U   29    1 - Upsense (Toggled when there is data)
+ * VV  28-27 2 - Valid upword octets
+ * XXX 26-24 3 - Port in use (Type of the message)
+ * O2  23-16 8 - Octet 2
+ * O1  15-08 8 - Octet 1
+ * O0  07-00 8 - Octet 0
+ *
+ */
+
+/* Protocol bits */
+
+#define LWL_GETACTIVE(x) (((x) & (1 << 31)) != 0)
+#define LWL_ACTIVE(x) (((x)&1) << 31)
+
+#define LWL_DNSENSEBIT (1 << 30)
+#define LWL_DNSENSE(x) ((x)&LWL_DNSENSEBIT)
+#define LWL_UPSENSEBIT (1 << 29)
+#define LWL_UPSENSE(x) ((x)&LWL_UPSENSEBIT)
+#define LWL_SENSEMASK (3 << 29)
+
+#define LWL_GETOCTVAL(x) (((x) >> 27) & 3)
+#define LWL_OCTVAL(x) (((x)&3) << 27)
+#define LWL_GETPORT(x) (((x) >> 24) & 7)
+#define LWL_PORT(x) (((x)&7) << 24)
+
+#define LWL_PORT_CONSOLE 1
+#define ID_SIG 0x7216A318
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static ssize_t lwlconsole_read(struct file *filep, char *buffer,
+                               size_t buflen);
+static ssize_t lwlconsole_write(struct file *filep, const char *buffer,
+                                size_t buflen);
+static int lwlconsole_ioctl(struct file *filep, int cmd, unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct lwl_entry_s
+{
+  uint32_t sig;               /* Location signature */
+  volatile uint32_t downword; /* Host to Target word */
+  uint32_t upword;            /* Target to Host word */
+};
+
+static struct lwl_entry_s g_d =
+{
+  .sig = ID_SIG
+};
+
+static const struct file_operations g_consoleops =
+{
+  NULL,                       /* open */
+  NULL,                       /* close */
+  lwlconsole_read,            /* read */
+  lwlconsole_write,           /* write */
+  NULL,                       /* seek */
+  lwlconsole_ioctl,           /* ioctl */
+  NULL                        /* poll */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+    ,
+  NULL                        /* unlink */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static bool linkactive(void)
+{
+  return (LWL_GETACTIVE(g_d.downword) != 0);
+}
+
+static bool writeword(uint32_t newupword)
+{
+  /* Check link is active */
+
+  if (!linkactive())
+    {
+      return false;
+    }
+
+  /* Spin waiting for previous data to be collected */
+
+  while (LWL_UPSENSE(g_d.downword) != LWL_UPSENSE(g_d.upword))
+    {
+    }
+
+  /* Load new data, toggling UPSENSE bit to show it is new */
+
+  g_d.upword = LWL_DNSENSE(g_d.upword) | newupword |
+               (LWL_UPSENSE(g_d.upword) ? 0 : LWL_UPSENSEBIT);
+
+  return true;
+}
+
+static bool write8bits(uint8_t port, uint8_t val)
+{
+  /* Prepare new word */
+
+  uint32_t newupword = LWL_ACTIVE(true) | LWL_OCTVAL(1) |
+                       LWL_PORT(port) | (val & 0xff);
+
+  return writeword(newupword);
+}
+
+static bool write16bits(uint8_t port, uint32_t val)
+{
+  /* Prepare new word */
+
+  uint32_t newupword = LWL_ACTIVE(true) | LWL_OCTVAL(2) |
+                       LWL_PORT(port) | (val & 0xffff);
+
+  return writeword(newupword);
+}
+
+static bool write24bits(uint8_t port, uint32_t val)
+{
+  /* Prepare new word */
+
+  uint32_t newupword = LWL_ACTIVE(true) | LWL_OCTVAL(3) |
+                       LWL_PORT(port) | (val & 0xffffff);
+
+  return writeword(newupword);
+}
+
+static bool read8bits(uint8_t port, uint8_t * store)
+{
+  if (LWL_DNSENSE(g_d.downword) == LWL_DNSENSE(g_d.upword))
+    {
+      return false;
+    }
+
+  *store = g_d.downword & 255;
+
+  /* Flip the bit to indicate the datum is read */
+
+  g_d.upword = (g_d.upword & ~LWL_DNSENSEBIT) | LWL_DNSENSE(g_d.downword);
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_ioctl
+ ****************************************************************************/
+
+static int lwlconsole_ioctl(struct file *filep, int cmd, unsigned long arg)
+{
+  return -ENOTTY;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_read
+ ****************************************************************************/
+
+static ssize_t lwlconsole_read(struct file *filep, char *buffer,
+                               size_t buflen)
+{
+  if (buflen == 0 || !linkactive())
+    {
+      return 0;
+    }
+
+  while (!read8bits(LWL_PORT_CONSOLE, (uint8_t *) buffer))
+    {
+    }
+
+  return 1;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_write
+ ****************************************************************************/
+
+static ssize_t lwlconsole_write(struct file *filep, const char *buffer,
+                                size_t buflen)
+{
+  uint32_t oc = 0;
+
+  while (buflen)
+    {
+      switch (buflen)
+        {
+          case 0:
+            return oc;
+
+          case 1:
+            if (write8bits(LWL_PORT_CONSOLE, buffer[0]))
+              {
+                oc++;
+                buffer++;
+                buflen--;
+              }
+            break;
+
+          case 2:
+            if (write16bits(LWL_PORT_CONSOLE, buffer[0] | (buffer[1] << 8)))
+              {
+                oc += 2;
+                buffer += 2;
+                buflen -= 2;
+              }
+            break;
+
+          default:
+            if (write24bits(LWL_PORT_CONSOLE, buffer[0] |
+                            (buffer[1] << 8) | (buffer[2] << 16)))
+              {
+                oc += 3;
+                buffer += 3;
+                buflen -= 3;
+              }
+            break;
+        }
+    }
+
+  return oc;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lwlconsole_init
+ ****************************************************************************/
+
+void lwlconsole_init(void)
+{
+  g_d.upword = 0;
+  register_driver("/dev/console", &g_consoleops, 0666, NULL);
+}
diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs
index a6d5e01..1e433de 100644
--- a/arch/xtensa/src/esp32/Make.defs
+++ b/arch/xtensa/src/esp32/Make.defs
@@ -86,6 +86,10 @@ ifeq ($(CONFIG_FS_HOSTFS),y)
   CMN_CSRCS += xtensa_hostfs.c
 endif
 
+ifeq ($(CONFIG_XTENSA_LWL_CONSOLE),y)
+CMN_CSRCS += xtensa_lwl_console.c
+endif
+
 # Required ESP32 files (arch/xtensa/src/lx6)
 
 CHIP_CSRCS  = esp32_allocateheap.c esp32_clockconfig.c esp32_cpuint.c