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 <acas...@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