Skip to content
Merged
1 change: 1 addition & 0 deletions app/boards/intel_adsp_ace15_mtpm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y
CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y
CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n
CONFIG_PM_DEVICE_POWER_DOMAIN=y
CONFIG_PM_POLICY_CUSTOM=y

Expand Down
5 changes: 5 additions & 0 deletions src/drivers/amd/rembrandt/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ int ipc_platform_send_msg(const struct ipc_msg *msg)
return ret;
}

void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
{
/* TODO: add support */
}

int platform_ipc_init(struct ipc *ipc)
{
ipc_set_drvdata(ipc, NULL);
Expand Down
5 changes: 5 additions & 0 deletions src/drivers/amd/renoir/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ int ipc_platform_send_msg(const struct ipc_msg *msg)
return 0;
}

void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
{
/* TODO: add support */
}

int platform_ipc_init(struct ipc *ipc)
{
ipc_set_drvdata(ipc, NULL);
Expand Down
5 changes: 5 additions & 0 deletions src/drivers/imx/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ int ipc_platform_send_msg(const struct ipc_msg *msg)
return 0;
}

void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
{
/* TODO: add support */
}

#if CONFIG_HOST_PTABLE
struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc)
{
Expand Down
5 changes: 5 additions & 0 deletions src/drivers/intel/cavs/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ int ipc_platform_send_msg(const struct ipc_msg *msg)
return 0;
}

void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
{
/* TODO: add support */
}

int platform_ipc_init(struct ipc *ipc)
{
int irq;
Expand Down
5 changes: 5 additions & 0 deletions src/drivers/mediatek/mt818x/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ int ipc_platform_send_msg(const struct ipc_msg *msg)
return 0;
}

void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
{
/* TODO: add support */
}

#if CONFIG_HOST_PTABLE
struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc)
{
Expand Down
5 changes: 5 additions & 0 deletions src/drivers/mediatek/mt8195/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ int ipc_platform_send_msg(const struct ipc_msg *msg)
return 0;
}

void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
{
/* TODO: add support */
}

#if CONFIG_HOST_PTABLE
struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc)
{
Expand Down
20 changes: 20 additions & 0 deletions src/include/sof/ipc/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,26 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev);
*/
void ipc_boot_complete_msg(struct ipc_cmd_hdr *header, uint32_t data);

#if defined(CONFIG_PM_DEVICE) && defined(CONFIG_INTEL_ADSP_IPC)
/**
* @brief Send an IPC response to Host power transition request informing
* that power transition failed.
* @note Normally an reply to the Host IPC message is performed in the
* low level assembly code to make sure DSP completed all operations before
* power cut-off.
* However, when power transition fails for some reason, we should send the
* IPC response informing about the failure.
* This happens in abnormal circumstances since the response is send not during
* IPC task but during power transition logic in the Idle thread.
*/
void ipc_send_failed_power_transition_response(void);
#endif /* CONFIG_PM_DEVICE && CONFIG_INTEL_ADSP_IPC */
/**
* \brief Send a IPC notification that FW has hit
* a DSP notification.
*/
void ipc_send_panic_notification(void);

/**
* \brief Read a compact IPC message or return NULL for normal message.
* @return Pointer to the compact message data.
Expand Down
6 changes: 6 additions & 0 deletions src/include/sof/ipc/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ void ipc_platform_complete_cmd(struct ipc *ipc);
*/
int ipc_platform_send_msg(const struct ipc_msg *msg);

/**
* \brief Send IPC message to host direct without inserting in msg_list.
* @param msg The IPC message to send to host.
*/
void ipc_platform_send_msg_direct(const struct ipc_msg *msg);

/**
* \brief Retrieves the ipc_data_host_buffer allocated by the platform ipc.
* @return Pointer to the data.
Expand Down
7 changes: 7 additions & 0 deletions src/include/sof/ipc/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ void ipc_send_queued_msg(void);
*/
void ipc_msg_send(struct ipc_msg *msg, void *data, bool high_priority);

/**
* \brief Send an IPC message directly for emergency.
* @param msg The IPC message to be freed.
* @param data The message data.
*/
void ipc_msg_send_direct(struct ipc_msg *msg, void *data);

/**
* \brief Build stream position IPC message.
* @param[in,out] posn Stream position message
Expand Down
20 changes: 20 additions & 0 deletions src/ipc/ipc-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,26 @@ static void schedule_ipc_worker(void)
#endif
}

void ipc_msg_send_direct(struct ipc_msg *msg, void *data)
{
struct ipc *ipc = ipc_get();
k_spinlock_key_t key;
int ret;

key = k_spin_lock(&ipc->lock);

/* copy mailbox data to message if not already copied */
if (msg->tx_size > 0 && msg->tx_size <= SOF_IPC_MSG_MAX_SIZE &&
msg->tx_data != data) {
ret = memcpy_s(msg->tx_data, msg->tx_size, data, msg->tx_size);
assert(!ret);
}

ipc_platform_send_msg_direct(msg);

k_spin_unlock(&ipc->lock, key);
}

void ipc_msg_send(struct ipc_msg *msg, void *data, bool high_priority)
{
struct ipc *ipc = ipc_get();
Expand Down
36 changes: 32 additions & 4 deletions src/ipc/ipc-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
DECLARE_SOF_UUID("ipc-task", ipc_task_uuid, 0x8fa1d42f, 0xbc6f, 0x464b,
0x86, 0x7f, 0x54, 0x7a, 0xf0, 0x88, 0x34, 0xda);

LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL);

/**
* @brief Private data for IPC.
*
Expand Down Expand Up @@ -95,11 +97,29 @@ static int ipc_device_suspend_handler(const struct device *dev, void *arg)
{
struct ipc *ipc = (struct ipc *)arg;

/* we are not entering D3 - return error code bad message */
if (!(ipc->task_mask & IPC_TASK_POWERDOWN))
return -EBADMSG;
int ret = 0;

return 0;
if (!(ipc->task_mask & IPC_TASK_POWERDOWN)) {
tr_err(&ipc_tr,
"ipc task mask not set to IPC_TASK_POWERDOWN. Current value: %u",
ipc->task_mask);
ret = -ENOMSG;
}

if (!ipc->pm_prepare_D3) {
tr_err(&ipc_tr, "power state D3 not requested");
ret = -EBADMSG;
}

if (!list_is_empty(&ipc->msg_list)) {
tr_err(&ipc_tr, "there are queued IPC messages to be sent");
ret = -EINPROGRESS;
}

if (ret != 0)
ipc_send_failed_power_transition_response();

return ret;
}

/**
Expand Down Expand Up @@ -225,6 +245,14 @@ int ipc_platform_send_msg(const struct ipc_msg *msg)
return 0;
}

void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
{
/* prepare the message and copy to mailbox */
struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg);

intel_adsp_ipc_send_message_emergency(INTEL_ADSP_IPC_HOST_DEV, hdr->pri, hdr->ext);
}

int platform_ipc_init(struct ipc *ipc)
{
ipc_set_drvdata(ipc, NULL);
Expand Down
5 changes: 5 additions & 0 deletions src/ipc/ipc3/handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,11 @@ void ipc_boot_complete_msg(struct ipc_cmd_hdr *header, uint32_t data)
header->dat[1] = data;
}

void ipc_send_panic_notification(void)
{
/* nothing to do */
}

/*
* Global IPC Operations.
*/
Expand Down
31 changes: 29 additions & 2 deletions src/ipc/ipc4/handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ static struct ipc4_msg_data msg_data;
/* fw sends a fw ipc message to send the status of the last host ipc message */
static struct ipc_msg msg_reply;

#ifdef CONFIG_LOG_BACKEND_ADSP_MTRACE
static struct ipc_msg msg_notify;
#endif

/*
* Global IPC Operations.
Expand Down Expand Up @@ -1077,6 +1075,35 @@ void ipc_boot_complete_msg(struct ipc_cmd_hdr *header, uint32_t data)
header->ext = 0;
}

#if defined(CONFIG_PM_DEVICE) && defined(CONFIG_INTEL_ADSP_IPC)
void ipc_send_failed_power_transition_response(void)
{
struct ipc4_message_request *request = ipc_from_hdr(&msg_data.msg_in);
struct ipc4_message_reply response;

response.primary.r.status = IPC4_POWER_TRANSITION_FAILED;
response.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REPLY;
response.primary.r.msg_tgt = request->primary.r.msg_tgt;
response.primary.r.type = request->primary.r.type;

msg_reply.header = response.primary.dat;
list_init(&msg_reply.list);

ipc_msg_send_direct(&msg_reply, NULL);
}
#endif /* defined(CONFIG_PM_DEVICE) && defined(CONFIG_INTEL_ADSP_IPC) */

void ipc_send_panic_notification(void)
{
msg_notify.header = SOF_IPC4_NOTIF_HEADER(SOF_IPC4_EXCEPTION_CAUGHT);
msg_notify.extension = cpu_get_id();
msg_notify.tx_size = 0;
msg_notify.tx_data = NULL;
list_init(&msg_notify.list);

ipc_msg_send_direct(&msg_notify, NULL);
}

#ifdef CONFIG_LOG_BACKEND_ADSP_MTRACE

static bool is_notification_queued(void)
Expand Down
102 changes: 2 additions & 100 deletions src/platform/intel/ace/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@
#include <kernel/abi.h>
#include <rtos/clk.h>
#include <sof/lib/cpu.h>
#include <adsp_memory.h>
#include <zephyr/drivers/mm/mm_drv_intel_adsp_mtl_tlb.h>
#include <zephyr/pm/pm.h>
#include <intel_adsp_ipc_devtree.h>
#include <rtos/panic.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/policy.h>
#include <sof/lib/cpu.h>

#include <sof_versions.h>
#include <stdint.h>
Expand Down Expand Up @@ -84,99 +76,9 @@ int platform_boot_complete(uint32_t boot_message)
return ipc_platform_send_msg(&msg);
}

/* address where zephyr PM will save memory during D3 transition */
#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
extern void *global_imr_ram_storage;
#endif

/* Reports error message during power state transitions */
static void power_state_failure_report(int ret, bool enter, enum pm_state state)
{
const char *action_name = enter ? "enter" : "leave";

__ASSERT(!ret, "Failed to %s power state: %d. Error: %d", action_name, state, ret);
}

/**
* @brief Notifier called before every power state transition.
* Works on Primary Core only.
* @param state Power state being entered.
*/
static void notify_pm_state_entry(enum pm_state state)
{
if (!cpu_is_primary(arch_proc_id()))
return;

if (state == PM_STATE_SOFT_OFF) {
#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
size_t storage_buffer_size;

/* allocate IMR global_imr_ram_storage */
const struct device *tlb_dev = DEVICE_DT_GET(DT_NODELABEL(tlb));

__ASSERT_NO_MSG(tlb_dev);
const struct intel_adsp_tlb_api *tlb_api =
(struct intel_adsp_tlb_api *)tlb_dev->api;

/* get HPSRAM storage buffer size */
storage_buffer_size = tlb_api->get_storage_size();

/* add space for LPSRAM */
storage_buffer_size += LP_SRAM_SIZE;

/* allocate IMR buffer and store it in the global pointer */
global_imr_ram_storage = rmalloc(SOF_MEM_ZONE_SYS,
0,
SOF_MEM_CAPS_L3,
storage_buffer_size);

/* change power state and check if IPC subsystem is prepared to enter D3 */
int ret = pm_device_action_run(INTEL_ADSP_IPC_HOST_DEV, PM_DEVICE_ACTION_SUSPEND);

if (ret)
power_state_failure_report(ret, true, PM_STATE_SOFT_OFF);

#endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */
}
}

/**
* @brief Notifier called after every power state transition.
* Works on Primary Core only.
* @param state Power state being exited.
*/
static void notify_pm_state_exit(enum pm_state state)
{
if (!cpu_is_primary(arch_proc_id())) {
cpu_notify_state_exit(state);
return;
}

if (state == PM_STATE_SOFT_OFF) {
#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
/* free global_imr_ram_storage */
rfree(global_imr_ram_storage);
global_imr_ram_storage = NULL;

int ret = pm_device_action_run(INTEL_ADSP_IPC_HOST_DEV, PM_DEVICE_ACTION_RESUME);

if (ret)
power_state_failure_report(ret, false, PM_STATE_SOFT_OFF);

enum pm_device_state ipc_state = PM_DEVICE_STATE_SUSPENDING;

pm_device_state_get(INTEL_ADSP_IPC_HOST_DEV, &ipc_state);
__ASSERT_NO_MSG(ipc_state == PM_DEVICE_STATE_ACTIVE);

/* sends fw-ready message signalling successful exit from D3 state */
platform_boot_complete(0);
#endif
}
}

static struct pm_notifier pm_state_notifier = {
.state_entry = notify_pm_state_entry,
.state_exit = notify_pm_state_exit,
.state_entry = cpu_notify_state_entry,
.state_exit = cpu_notify_state_exit,
};

/* Value to be determined experimentaly */
Expand Down
Loading