From 6509b8199b022a99e897afe5ccf6cf030c40e8e2 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 6 May 2024 15:59:49 +0300 Subject: [PATCH] shell: add shell backend for audio DSP using shared memory window Add a new shell backend implemented over a shared memory window on the Intel audio DSPs. The implementation uses the Zephyr winstream to manage the data streaming. Signed-off-by: Kai Vehmanen --- .../zephyr/shell/shell_adsp_memory_window.h | 62 ++++++++ .../common/include/adsp_debug_window.h | 2 + subsys/shell/backends/CMakeLists.txt | 5 + subsys/shell/backends/Kconfig.backends | 25 ++++ .../shell/backends/shell_adsp_memory_window.c | 140 ++++++++++++++++++ 5 files changed, 234 insertions(+) create mode 100644 include/zephyr/shell/shell_adsp_memory_window.h create mode 100644 subsys/shell/backends/shell_adsp_memory_window.c diff --git a/include/zephyr/shell/shell_adsp_memory_window.h b/include/zephyr/shell/shell_adsp_memory_window.h new file mode 100644 index 00000000000..5ccc4d280ca --- /dev/null +++ b/include/zephyr/shell/shell_adsp_memory_window.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SHELL_ADSP_MEMORY_WINDOW_H__ +#define SHELL_ADSP_MEMORY_WINDOW_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct shell_transport_api shell_adsp_memory_window_transport_api; + +struct sys_winstream; + +/** Memwindow based shell transport. */ +struct shell_adsp_memory_window { + /** Handler function registered by shell. */ + shell_transport_handler_t shell_handler; + + struct k_timer timer; + + /** Context registered by shell. */ + void *shell_context; + + /** Receive winstream object */ + struct sys_winstream *ws_rx; + + /** Transmit winstream object */ + struct sys_winstream *ws_tx; + + /** Last read sequence number */ + uint32_t read_seqno; +}; + +#define SHELL_ADSP_MEMORY_WINDOW_DEFINE(_name) \ + static struct shell_adsp_memory_window _name##_shell_adsp_memory_window;\ + struct shell_transport _name = { \ + .api = &shell_adsp_memory_window_transport_api, \ + .ctx = (struct shell_memwindow *)&_name##_shell_adsp_memory_window, \ + } + +/** + * @brief This function provides pointer to shell ADSP memory window backend instance. + * + * Function returns pointer to the shell ADSP memory window instance. This instance can be + * next used with shell_execute_cmd function in order to test commands behavior. + * + * @returns Pointer to the shell instance. + */ +const struct shell *shell_backend_adsp_memory_window_get_ptr(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SHELL_ADSP_MEMORY_WINDOW_H__ */ diff --git a/soc/intel/intel_adsp/common/include/adsp_debug_window.h b/soc/intel/intel_adsp/common/include/adsp_debug_window.h index e4e09f70aed..6e4a4f74989 100644 --- a/soc/intel/intel_adsp/common/include/adsp_debug_window.h +++ b/soc/intel/intel_adsp/common/include/adsp_debug_window.h @@ -43,6 +43,7 @@ /* debug window slots usage */ #define ADSP_DW_SLOT_NUM_TRACE 1 +#define ADSP_DW_SLOT_NUM_SHELL 0 /* debug log slot types */ #define ADSP_DW_SLOT_UNUSED 0x00000000 @@ -51,6 +52,7 @@ #define ADSP_DW_SLOT_GDB_STUB 0x42444700 #define ADSP_DW_SLOT_TELEMETRY 0x4c455400 #define ADSP_DW_SLOT_TRACE 0x54524143 +#define ADSP_DW_SLOT_SHELL 0x73686c6c #define ADSP_DW_SLOT_BROKEN 0x44414544 /* for debug and critical types */ diff --git a/subsys/shell/backends/CMakeLists.txt b/subsys/shell/backends/CMakeLists.txt index 77119962423..42867effc3b 100644 --- a/subsys/shell/backends/CMakeLists.txt +++ b/subsys/shell/backends/CMakeLists.txt @@ -29,3 +29,8 @@ zephyr_sources_ifdef( CONFIG_SHELL_BACKEND_RPMSG shell_rpmsg.c ) + +zephyr_sources_ifdef( + CONFIG_SHELL_BACKEND_ADSP_MEMORY_WINDOW + shell_adsp_memory_window.c +) diff --git a/subsys/shell/backends/Kconfig.backends b/subsys/shell/backends/Kconfig.backends index e1924872361..c433e1f1013 100644 --- a/subsys/shell/backends/Kconfig.backends +++ b/subsys/shell/backends/Kconfig.backends @@ -625,4 +625,29 @@ config SHELL_DUMMY_INIT_LOG_LEVEL endif # SHELL_BACKEND_DUMMY +config SHELL_BACKEND_ADSP_MEMORY_WINDOW + bool "Shell backend implemented over mapped memory window." + depends on SOC_FAMILY_INTEL_ADSP + help + Enable ADSP memory window backend which can be used to execute commands + from remote host processor that has access to the same memory window. + +if SHELL_BACKEND_ADSP_MEMORY_WINDOW + +config SHELL_BACKEND_ADSP_MEMORY_WINDOW_PROMPT + string "Displayed prompt name" + default "~$ " + help + Displayed prompt name for ADSP memory window backend. If prompt is set, + the shell will send two newlines during initialization. + +config SHELL_BACKEND_ADSP_MEMORY_WINDOW_POLL_INTERVAL + int "Poll interval (in microseconds)" + default 100 + help + This option can be used to modify the poll interval the backend uses + to check for new commands. + +endif # SHELL_BACKEND_ADSP_MEMORY_WINDOW + endif # SHELL_BACKENDS diff --git a/subsys/shell/backends/shell_adsp_memory_window.c b/subsys/shell/backends/shell_adsp_memory_window.c new file mode 100644 index 00000000000..519e68ea52f --- /dev/null +++ b/subsys/shell/backends/shell_adsp_memory_window.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +SHELL_ADSP_MEMORY_WINDOW_DEFINE(shell_transport_adsp_memory_window); +SHELL_DEFINE(shell_adsp_memory_window, CONFIG_SHELL_BACKEND_ADSP_MEMORY_WINDOW_PROMPT, + &shell_transport_adsp_memory_window, 256, 0, SHELL_FLAG_OLF_CRLF); + +LOG_MODULE_REGISTER(shell_adsp_memory_window); + +#define RX_WINDOW_SIZE 256 +#define POLL_INTERVAL K_MSEC(CONFIG_SHELL_BACKEND_ADSP_MEMORY_WINDOW_POLL_INTERVAL) + +BUILD_ASSERT(RX_WINDOW_SIZE < ADSP_DW_SLOT_SIZE); + +struct adsp_debug_slot_shell { + uint8_t rx_window[RX_WINDOW_SIZE]; + uint8_t tx_window[ADSP_DW_SLOT_SIZE - RX_WINDOW_SIZE]; +} __packed; + +static void timer_handler(struct k_timer *timer) +{ + const struct shell_adsp_memory_window *sh_adsp_mw = k_timer_user_data_get(timer); + + __ASSERT_NO_MSG(sh_adsp_mw->shell_handler && sh_adsp_mw->shell_context); + + sh_adsp_mw->shell_handler(SHELL_TRANSPORT_EVT_RX_RDY, + sh_adsp_mw->shell_context); +} + +static int init(const struct shell_transport *transport, + const void *config, + shell_transport_handler_t evt_handler, + void *context) +{ + struct shell_adsp_memory_window *sh_adsp_mw = + (struct shell_adsp_memory_window *)transport->ctx; + struct adsp_debug_slot_shell *dw_slot; + + if (ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type && + (ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type != + ADSP_DW_SLOT_SHELL)) { + LOG_WRN("Possible conflict with debug window slot for shell, key %#x\n", + ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type); + } + + ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type = ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type; + + sh_adsp_mw->shell_handler = evt_handler; + sh_adsp_mw->shell_context = context; + + dw_slot = (struct adsp_debug_slot_shell *)ADSP_DW->slots[ADSP_DW_SLOT_NUM_SHELL]; + + sh_adsp_mw->ws_rx = sys_winstream_init(&dw_slot->rx_window[0], sizeof(dw_slot->rx_window)); + sh_adsp_mw->ws_tx = sys_winstream_init(&dw_slot->tx_window[0], sizeof(dw_slot->tx_window)); + + LOG_DBG("shell with ADSP debug window rx/tx %u/%u\n", + sizeof(dw_slot->rx_window), sizeof(dw_slot->tx_window)); + + k_timer_init(&sh_adsp_mw->timer, timer_handler, NULL); + k_timer_user_data_set(&sh_adsp_mw->timer, (void *)sh_adsp_mw); + k_timer_start(&sh_adsp_mw->timer, POLL_INTERVAL, POLL_INTERVAL); + + return 0; +} + +static int uninit(const struct shell_transport *transport) +{ + struct shell_adsp_memory_window *sh_adsp_mw = + (struct shell_adsp_memory_window *)transport->ctx; + + k_timer_stop(&sh_adsp_mw->timer); + + return 0; +} + +static int enable(const struct shell_transport *transport, bool blocking) +{ + return 0; +} + +static int write(const struct shell_transport *transport, + const void *data, size_t length, size_t *cnt) +{ + struct shell_adsp_memory_window *sh_adsp_mw = + (struct shell_adsp_memory_window *)transport->ctx; + + sys_winstream_write(sh_adsp_mw->ws_tx, data, length); + *cnt = length; + + return 0; +} + +static int read(const struct shell_transport *transport, + void *data, size_t length, size_t *cnt) +{ + struct shell_adsp_memory_window *sh_adsp_mw = + (struct shell_adsp_memory_window *)transport->ctx; + uint32_t res; + + res = sys_winstream_read(sh_adsp_mw->ws_rx, &sh_adsp_mw->read_seqno, data, length); + *cnt = res; + + return 0; +} + +const struct shell_transport_api shell_adsp_memory_window_transport_api = { + .init = init, + .uninit = uninit, + .enable = enable, + .write = write, + .read = read +}; + +static int enable_shell_adsp_memory_window(void) +{ + bool log_backend = true; + uint32_t level = CONFIG_LOG_MAX_LEVEL; + static const struct shell_backend_config_flags cfg_flags = + SHELL_DEFAULT_BACKEND_CONFIG_FLAGS; + + shell_init(&shell_adsp_memory_window, NULL, cfg_flags, log_backend, level); + + return 0; +} +SYS_INIT(enable_shell_adsp_memory_window, POST_KERNEL, 0); + +const struct shell *shell_backend_adsp_memory_window_get_ptr(void) +{ + return &shell_adsp_memory_window; +}