ASoC: SOF: Rework the firmware ready message handling
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>: The firmware ready (fw_ready) message is sent by the firmware to notify the host that it has been booted up and caries additional information about it's configuration. All of this is IPC specific, the message itself is IPC version specific and the information itself also. Move the code to handle the fw_ready message under ipc3.c since the parsing and interpretation is IPC specific. A followup series is going to take care of the rest of the loader.c to make it IPC agnostic.
This commit is contained in:
commit
0386dd9140
|
@ -152,7 +152,6 @@ struct snd_sof_dsp_ops sof_renoir_ops = {
|
|||
.ipc_msg_data = acp_sof_ipc_msg_data,
|
||||
.get_mailbox_offset = acp_sof_ipc_get_mailbox_offset,
|
||||
.irq_thread = acp_sof_ipc_irq_thread,
|
||||
.fw_ready = sof_fw_ready,
|
||||
|
||||
/* DAI drivers */
|
||||
.drv = renoir_sof_dai,
|
||||
|
|
|
@ -374,7 +374,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
|
|||
if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run ||
|
||||
!sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
|
||||
!sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
|
||||
!sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->fw_ready) {
|
||||
!sof_ops(sdev)->ipc_msg_data) {
|
||||
dev_err(dev, "error: missing mandatory ops\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -504,7 +504,6 @@ static struct snd_sof_dsp_ops sof_imx8_ops = {
|
|||
|
||||
/* ipc */
|
||||
.send_msg = imx8_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = imx8_get_mailbox_offset,
|
||||
.get_window_offset = imx8_get_window_offset,
|
||||
|
||||
|
@ -567,7 +566,6 @@ static struct snd_sof_dsp_ops sof_imx8x_ops = {
|
|||
|
||||
/* ipc */
|
||||
.send_msg = imx8_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = imx8_get_mailbox_offset,
|
||||
.get_window_offset = imx8_get_window_offset,
|
||||
|
||||
|
|
|
@ -430,7 +430,6 @@ static struct snd_sof_dsp_ops sof_imx8m_ops = {
|
|||
|
||||
/* ipc */
|
||||
.send_msg = imx8m_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = imx8m_get_mailbox_offset,
|
||||
.get_window_offset = imx8m_get_window_offset,
|
||||
|
||||
|
|
|
@ -591,7 +591,6 @@ static struct snd_sof_dsp_ops sof_bdw_ops = {
|
|||
|
||||
/* ipc */
|
||||
.send_msg = bdw_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = bdw_get_mailbox_offset,
|
||||
.get_window_offset = bdw_get_window_offset,
|
||||
|
||||
|
|
|
@ -245,7 +245,6 @@ static struct snd_sof_dsp_ops sof_byt_ops = {
|
|||
|
||||
/* ipc */
|
||||
.send_msg = atom_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = atom_get_mailbox_offset,
|
||||
.get_window_offset = atom_get_window_offset,
|
||||
|
||||
|
@ -328,7 +327,6 @@ static struct snd_sof_dsp_ops sof_cht_ops = {
|
|||
|
||||
/* ipc */
|
||||
.send_msg = atom_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = atom_get_mailbox_offset,
|
||||
.get_window_offset = atom_get_window_offset,
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
|
|||
.mailbox_write = sof_mailbox_write,
|
||||
|
||||
/* ipc */
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
|
||||
.get_window_offset = hda_dsp_ipc_get_window_offset,
|
||||
|
||||
|
|
|
@ -164,7 +164,6 @@ struct snd_sof_dsp_ops sof_tng_ops = {
|
|||
|
||||
/* ipc */
|
||||
.send_msg = atom_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = atom_get_mailbox_offset,
|
||||
.get_window_offset = atom_get_window_offset,
|
||||
|
||||
|
|
|
@ -188,21 +188,6 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
|
|||
}
|
||||
EXPORT_SYMBOL(snd_sof_ipc_valid);
|
||||
|
||||
int sof_ipc_init_msg_memory(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_ipc_msg *msg;
|
||||
|
||||
msg = &sdev->ipc->msg;
|
||||
|
||||
msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
|
||||
if (!msg->reply_data)
|
||||
return -ENOMEM;
|
||||
|
||||
sdev->ipc->max_payload_size = SOF_IPC_MSG_MAX_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_ipc *ipc;
|
||||
|
|
|
@ -475,6 +475,310 @@ static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t da
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
|
||||
const struct sof_ipc_ext_data_hdr *ext_hdr)
|
||||
{
|
||||
const struct sof_ipc_window *w =
|
||||
container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
|
||||
|
||||
if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
|
||||
return -EINVAL;
|
||||
|
||||
if (sdev->info_window) {
|
||||
if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
|
||||
dev_err(sdev->dev, "mismatch between window descriptor from extended manifest and mailbox");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keep a local copy of the data */
|
||||
sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size, GFP_KERNEL);
|
||||
if (!sdev->info_window)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
|
||||
const struct sof_ipc_ext_data_hdr *ext_hdr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
const struct sof_ipc_cc_version *cc =
|
||||
container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
|
||||
|
||||
if (sdev->cc_version) {
|
||||
if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
|
||||
dev_err(sdev->dev,
|
||||
"Receive diverged cc_version descriptions");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev,
|
||||
"Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
|
||||
cc->name, cc->major, cc->minor, cc->micro, cc->desc, cc->optim);
|
||||
|
||||
/* create read-only cc_version debugfs to store compiler version info */
|
||||
/* use local copy of the cc_version to prevent data corruption */
|
||||
if (sdev->first_boot) {
|
||||
sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!sdev->cc_version)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
|
||||
ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
|
||||
cc->ext_hdr.hdr.size,
|
||||
"cc_version", 0444);
|
||||
|
||||
/* errors are only due to memory allocation, not debugfs */
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "snd_sof_debugfs_buf_item failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the extended FW boot data structures from FW boot message */
|
||||
static int ipc3_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset)
|
||||
{
|
||||
struct sof_ipc_ext_data_hdr *ext_hdr;
|
||||
void *ext_data;
|
||||
int ret = 0;
|
||||
|
||||
ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!ext_data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* get first header */
|
||||
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
|
||||
sizeof(*ext_hdr));
|
||||
ext_hdr = ext_data;
|
||||
|
||||
while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
|
||||
/* read in ext structure */
|
||||
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
offset + sizeof(*ext_hdr),
|
||||
(void *)((u8 *)ext_data + sizeof(*ext_hdr)),
|
||||
ext_hdr->hdr.size - sizeof(*ext_hdr));
|
||||
|
||||
dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
|
||||
ext_hdr->type, ext_hdr->hdr.size);
|
||||
|
||||
/* process structure data */
|
||||
switch (ext_hdr->type) {
|
||||
case SOF_IPC_EXT_WINDOW:
|
||||
ret = sof_ipc3_get_ext_windows(sdev, ext_hdr);
|
||||
break;
|
||||
case SOF_IPC_EXT_CC_INFO:
|
||||
ret = sof_ipc3_get_cc_info(sdev, ext_hdr);
|
||||
break;
|
||||
case SOF_IPC_EXT_UNUSED:
|
||||
case SOF_IPC_EXT_PROBE_INFO:
|
||||
case SOF_IPC_EXT_USER_ABI_INFO:
|
||||
/* They are supported but we don't do anything here */
|
||||
break;
|
||||
default:
|
||||
dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
|
||||
ext_hdr->type, ext_hdr->hdr.size);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "Failed to parse ext data type %d\n",
|
||||
ext_hdr->type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* move to next header */
|
||||
offset += ext_hdr->hdr.size;
|
||||
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
|
||||
sizeof(*ext_hdr));
|
||||
ext_hdr = ext_data;
|
||||
}
|
||||
|
||||
kfree(ext_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ipc3_get_windows(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct sof_ipc_window_elem *elem;
|
||||
u32 outbox_offset = 0;
|
||||
u32 stream_offset = 0;
|
||||
u32 inbox_offset = 0;
|
||||
u32 outbox_size = 0;
|
||||
u32 stream_size = 0;
|
||||
u32 inbox_size = 0;
|
||||
u32 debug_size = 0;
|
||||
u32 debug_offset = 0;
|
||||
int window_offset;
|
||||
int i;
|
||||
|
||||
if (!sdev->info_window) {
|
||||
dev_err(sdev->dev, "%s: No window info present\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sdev->info_window->num_windows; i++) {
|
||||
elem = &sdev->info_window->window[i];
|
||||
|
||||
window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
|
||||
if (window_offset < 0) {
|
||||
dev_warn(sdev->dev, "No offset for window %d\n", elem->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (elem->type) {
|
||||
case SOF_IPC_REGION_UPBOX:
|
||||
inbox_offset = window_offset + elem->offset;
|
||||
inbox_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
inbox_offset,
|
||||
elem->size, "inbox",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_DOWNBOX:
|
||||
outbox_offset = window_offset + elem->offset;
|
||||
outbox_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
outbox_offset,
|
||||
elem->size, "outbox",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_TRACE:
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "etrace",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_DEBUG:
|
||||
debug_offset = window_offset + elem->offset;
|
||||
debug_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "debug",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_STREAM:
|
||||
stream_offset = window_offset + elem->offset;
|
||||
stream_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
stream_offset,
|
||||
elem->size, "stream",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_REGS:
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "regs",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_EXCEPTION:
|
||||
sdev->dsp_oops_offset = window_offset + elem->offset;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "exception",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
default:
|
||||
dev_err(sdev->dev, "%s: Illegal window info: %u\n",
|
||||
__func__, elem->type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (outbox_size == 0 || inbox_size == 0) {
|
||||
dev_err(sdev->dev, "%s: Illegal mailbox window\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
sdev->dsp_box.offset = inbox_offset;
|
||||
sdev->dsp_box.size = inbox_size;
|
||||
|
||||
sdev->host_box.offset = outbox_offset;
|
||||
sdev->host_box.size = outbox_size;
|
||||
|
||||
sdev->stream_box.offset = stream_offset;
|
||||
sdev->stream_box.size = stream_size;
|
||||
|
||||
sdev->debug_box.offset = debug_offset;
|
||||
sdev->debug_box.size = debug_size;
|
||||
|
||||
dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
|
||||
inbox_offset, inbox_size);
|
||||
dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
|
||||
outbox_offset, outbox_size);
|
||||
dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
|
||||
stream_offset, stream_size);
|
||||
dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
|
||||
debug_offset, debug_size);
|
||||
}
|
||||
|
||||
static int ipc3_init_reply_data_buffer(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
|
||||
|
||||
msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
|
||||
if (!msg->reply_data)
|
||||
return -ENOMEM;
|
||||
|
||||
sdev->ipc->max_payload_size = SOF_IPC_MSG_MAX_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
|
||||
{
|
||||
struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
|
||||
int offset;
|
||||
int ret;
|
||||
|
||||
/* mailbox must be on 4k boundary */
|
||||
offset = snd_sof_dsp_get_mailbox_offset(sdev);
|
||||
if (offset < 0) {
|
||||
dev_err(sdev->dev, "%s: no mailbox offset\n", __func__);
|
||||
return offset;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev, "DSP is ready 0x%8.8x offset 0x%x\n", cmd, offset);
|
||||
|
||||
/* no need to re-check version/ABI for subsequent boots */
|
||||
if (!sdev->first_boot)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* copy data from the DSP FW ready offset
|
||||
* Subsequent error handling is not needed for BLK_TYPE_SRAM
|
||||
*/
|
||||
ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready,
|
||||
sizeof(*fw_ready));
|
||||
if (ret) {
|
||||
dev_err(sdev->dev,
|
||||
"Unable to read fw_ready, read from TYPE_SRAM failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure ABI version is compatible */
|
||||
ret = snd_sof_ipc_valid(sdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* now check for extended data */
|
||||
ipc3_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
|
||||
|
||||
ipc3_get_windows(sdev);
|
||||
|
||||
return ipc3_init_reply_data_buffer(sdev);
|
||||
}
|
||||
|
||||
/* IPC stream position. */
|
||||
static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
|
||||
{
|
||||
|
@ -633,7 +937,7 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
|
|||
case SOF_IPC_FW_READY:
|
||||
/* check for FW boot completion */
|
||||
if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
|
||||
err = sof_ops(sdev)->fw_ready(sdev, cmd);
|
||||
err = ipc3_fw_ready(sdev, cmd);
|
||||
if (err < 0)
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED);
|
||||
else
|
||||
|
|
|
@ -86,69 +86,6 @@ static int get_cc_info(struct snd_sof_dev *sdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* parse the extended FW boot data structures from FW boot message */
|
||||
static int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset)
|
||||
{
|
||||
struct sof_ipc_ext_data_hdr *ext_hdr;
|
||||
void *ext_data;
|
||||
int ret = 0;
|
||||
|
||||
ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!ext_data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* get first header */
|
||||
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
|
||||
sizeof(*ext_hdr));
|
||||
ext_hdr = ext_data;
|
||||
|
||||
while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
|
||||
/* read in ext structure */
|
||||
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
offset + sizeof(*ext_hdr),
|
||||
(void *)((u8 *)ext_data + sizeof(*ext_hdr)),
|
||||
ext_hdr->hdr.size - sizeof(*ext_hdr));
|
||||
|
||||
dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
|
||||
ext_hdr->type, ext_hdr->hdr.size);
|
||||
|
||||
/* process structure data */
|
||||
switch (ext_hdr->type) {
|
||||
case SOF_IPC_EXT_WINDOW:
|
||||
ret = get_ext_windows(sdev, ext_hdr);
|
||||
break;
|
||||
case SOF_IPC_EXT_CC_INFO:
|
||||
ret = get_cc_info(sdev, ext_hdr);
|
||||
break;
|
||||
case SOF_IPC_EXT_UNUSED:
|
||||
case SOF_IPC_EXT_PROBE_INFO:
|
||||
case SOF_IPC_EXT_USER_ABI_INFO:
|
||||
/* They are supported but we don't do anything here */
|
||||
break;
|
||||
default:
|
||||
dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
|
||||
ext_hdr->type, ext_hdr->hdr.size);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
|
||||
ext_hdr->type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* move to next header */
|
||||
offset += ext_hdr->hdr.size;
|
||||
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
|
||||
sizeof(*ext_hdr));
|
||||
ext_hdr = ext_data;
|
||||
}
|
||||
|
||||
kfree(ext_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ext_man_get_fw_version(struct snd_sof_dev *sdev,
|
||||
const struct sof_ext_man_elem_header *hdr)
|
||||
{
|
||||
|
@ -358,170 +295,6 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
|
|||
return ext_man_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* IPC Firmware ready.
|
||||
*/
|
||||
static void sof_get_windows(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct sof_ipc_window_elem *elem;
|
||||
u32 outbox_offset = 0;
|
||||
u32 stream_offset = 0;
|
||||
u32 inbox_offset = 0;
|
||||
u32 outbox_size = 0;
|
||||
u32 stream_size = 0;
|
||||
u32 inbox_size = 0;
|
||||
u32 debug_size = 0;
|
||||
u32 debug_offset = 0;
|
||||
int window_offset;
|
||||
int i;
|
||||
|
||||
if (!sdev->info_window) {
|
||||
dev_err(sdev->dev, "error: have no window info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sdev->info_window->num_windows; i++) {
|
||||
elem = &sdev->info_window->window[i];
|
||||
|
||||
window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
|
||||
if (window_offset < 0) {
|
||||
dev_warn(sdev->dev, "warn: no offset for window %d\n",
|
||||
elem->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (elem->type) {
|
||||
case SOF_IPC_REGION_UPBOX:
|
||||
inbox_offset = window_offset + elem->offset;
|
||||
inbox_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
inbox_offset,
|
||||
elem->size, "inbox",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_DOWNBOX:
|
||||
outbox_offset = window_offset + elem->offset;
|
||||
outbox_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
outbox_offset,
|
||||
elem->size, "outbox",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_TRACE:
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "etrace",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_DEBUG:
|
||||
debug_offset = window_offset + elem->offset;
|
||||
debug_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "debug",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_STREAM:
|
||||
stream_offset = window_offset + elem->offset;
|
||||
stream_size = elem->size;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
stream_offset,
|
||||
elem->size, "stream",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_REGS:
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "regs",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
case SOF_IPC_REGION_EXCEPTION:
|
||||
sdev->dsp_oops_offset = window_offset + elem->offset;
|
||||
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
|
||||
window_offset + elem->offset,
|
||||
elem->size, "exception",
|
||||
SOF_DEBUGFS_ACCESS_D0_ONLY);
|
||||
break;
|
||||
default:
|
||||
dev_err(sdev->dev, "error: get illegal window info\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (outbox_size == 0 || inbox_size == 0) {
|
||||
dev_err(sdev->dev, "error: get illegal mailbox window\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sdev->dsp_box.offset = inbox_offset;
|
||||
sdev->dsp_box.size = inbox_size;
|
||||
|
||||
sdev->host_box.offset = outbox_offset;
|
||||
sdev->host_box.size = outbox_size;
|
||||
|
||||
sdev->stream_box.offset = stream_offset;
|
||||
sdev->stream_box.size = stream_size;
|
||||
|
||||
sdev->debug_box.offset = debug_offset;
|
||||
sdev->debug_box.size = debug_size;
|
||||
|
||||
dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
|
||||
inbox_offset, inbox_size);
|
||||
dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
|
||||
outbox_offset, outbox_size);
|
||||
dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
|
||||
stream_offset, stream_size);
|
||||
dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
|
||||
debug_offset, debug_size);
|
||||
}
|
||||
|
||||
/* check for ABI compatibility and create memory windows on first boot */
|
||||
int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
|
||||
{
|
||||
struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
|
||||
int offset;
|
||||
int ret;
|
||||
|
||||
/* mailbox must be on 4k boundary */
|
||||
offset = snd_sof_dsp_get_mailbox_offset(sdev);
|
||||
if (offset < 0) {
|
||||
dev_err(sdev->dev, "error: have no mailbox offset\n");
|
||||
return offset;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
|
||||
msg_id, offset);
|
||||
|
||||
/* no need to re-check version/ABI for subsequent boots */
|
||||
if (!sdev->first_boot)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* copy data from the DSP FW ready offset
|
||||
* Subsequent error handling is not needed for BLK_TYPE_SRAM
|
||||
*/
|
||||
ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready,
|
||||
sizeof(*fw_ready));
|
||||
if (ret) {
|
||||
dev_err(sdev->dev,
|
||||
"error: unable to read fw_ready, read from TYPE_SRAM failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure ABI version is compatible */
|
||||
ret = snd_sof_ipc_valid(sdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* now check for extended data */
|
||||
snd_sof_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
|
||||
|
||||
sof_get_windows(sdev);
|
||||
|
||||
return sof_ipc_init_msg_memory(sdev);
|
||||
}
|
||||
EXPORT_SYMBOL(sof_fw_ready);
|
||||
|
||||
/* generic module parser for mmaped DSPs */
|
||||
int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
|
||||
struct snd_sof_mod_hdr *module)
|
||||
|
|
|
@ -181,11 +181,6 @@ struct snd_sof_dsp_ops {
|
|||
int (*load_firmware)(struct snd_sof_dev *sof_dev); /* mandatory */
|
||||
int (*load_module)(struct snd_sof_dev *sof_dev,
|
||||
struct snd_sof_mod_hdr *hdr); /* optional */
|
||||
/*
|
||||
* FW ready checks for ABI compatibility and creates
|
||||
* memory windows at first boot
|
||||
*/
|
||||
int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* mandatory */
|
||||
|
||||
/* connect pcm substream to a host stream */
|
||||
int (*pcm_open)(struct snd_sof_dev *sdev,
|
||||
|
@ -614,7 +609,7 @@ int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg
|
|||
void *reply_data, size_t reply_bytes);
|
||||
int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
|
||||
size_t reply_bytes);
|
||||
int sof_ipc_init_msg_memory(struct snd_sof_dev *sdev);
|
||||
|
||||
static inline void snd_sof_ipc_process_reply(struct snd_sof_dev *sdev, u32 msg_id)
|
||||
{
|
||||
snd_sof_ipc_get_reply(sdev);
|
||||
|
@ -685,8 +680,6 @@ int sof_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
|
|||
int sof_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
|
||||
u32 offset, void *dest, size_t size);
|
||||
|
||||
int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id);
|
||||
|
||||
int sof_ipc_msg_data(struct snd_sof_dev *sdev,
|
||||
struct snd_pcm_substream *substream,
|
||||
void *p, size_t sz);
|
||||
|
|
Loading…
Reference in New Issue