Commit 6509b819 authored by Kai Vehmanen's avatar Kai Vehmanen Committed by Henrik Brix Andersen
Browse files

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: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
parent 65fc5b7f
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef SHELL_ADSP_MEMORY_WINDOW_H__
#define SHELL_ADSP_MEMORY_WINDOW_H__

#include <zephyr/kernel.h>
#include <zephyr/shell/shell.h>

#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__ */
+2 −0
Original line number Diff line number Diff line
@@ -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 */
+5 −0
Original line number Diff line number Diff line
@@ -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
)
+25 −0
Original line number Diff line number Diff line
@@ -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
+140 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/shell/shell_adsp_memory_window.h>
#include <zephyr/sys/winstream.h>
#include <zephyr/logging/log.h>

#include <adsp_memory.h>
#include <adsp_debug_window.h>

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;
}