Commit 756a6150 authored by Mark Brown's avatar Mark Brown

ASoC: SOF: IPC Abstraction for FW loading

Merge series from Ranjani Sridharan <ranjani.sridharan@linux.intel.com>:

This series introduces IPC abstraction for FW loading in the SOF driver
in preparation for supporting the new IPC version in the SOF firmware.
parents 66727cdb 1dd4b999
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\ control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
ipc3-topology.o ipc3.o ipc3-control.o ipc3-pcm.o ipc3-topology.o ipc3-control.o ipc3.o ipc3-pcm.o ipc3-loader.o
ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),) ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
snd-sof-objs += sof-client.o snd-sof-objs += sof-client.o
endif endif
......
...@@ -136,9 +136,6 @@ struct snd_sof_dsp_ops sof_renoir_ops = { ...@@ -136,9 +136,6 @@ struct snd_sof_dsp_ops sof_renoir_ops = {
.block_read = acp_dsp_block_read, .block_read = acp_dsp_block_read,
.block_write = acp_dsp_block_write, .block_write = acp_dsp_block_write,
/* Module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */ /*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
.pre_fw_run = acp_dsp_pre_fw_run, .pre_fw_run = acp_dsp_pre_fw_run,
......
...@@ -510,9 +510,8 @@ static struct snd_sof_dsp_ops sof_imx8_ops = { ...@@ -510,9 +510,8 @@ static struct snd_sof_dsp_ops sof_imx8_ops = {
.ipc_msg_data = sof_ipc_msg_data, .ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset, .set_stream_data_offset = sof_set_stream_data_offset,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
.get_bar_index = imx8_get_bar_index, .get_bar_index = imx8_get_bar_index,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
...@@ -572,9 +571,8 @@ static struct snd_sof_dsp_ops sof_imx8x_ops = { ...@@ -572,9 +571,8 @@ static struct snd_sof_dsp_ops sof_imx8x_ops = {
.ipc_msg_data = sof_ipc_msg_data, .ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset, .set_stream_data_offset = sof_set_stream_data_offset,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
.get_bar_index = imx8_get_bar_index, .get_bar_index = imx8_get_bar_index,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
......
...@@ -436,9 +436,8 @@ static struct snd_sof_dsp_ops sof_imx8m_ops = { ...@@ -436,9 +436,8 @@ static struct snd_sof_dsp_ops sof_imx8m_ops = {
.ipc_msg_data = sof_ipc_msg_data, .ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset, .set_stream_data_offset = sof_set_stream_data_offset,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
.get_bar_index = imx8m_get_bar_index, .get_bar_index = imx8m_get_bar_index,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
......
...@@ -613,9 +613,6 @@ static struct snd_sof_dsp_ops sof_bdw_ops = { ...@@ -613,9 +613,6 @@ static struct snd_sof_dsp_ops sof_bdw_ops = {
.pcm_open = sof_stream_pcm_open, .pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close, .pcm_close = sof_stream_pcm_close,
/* Module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */ /*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
......
...@@ -267,9 +267,6 @@ static struct snd_sof_dsp_ops sof_byt_ops = { ...@@ -267,9 +267,6 @@ static struct snd_sof_dsp_ops sof_byt_ops = {
.pcm_open = sof_stream_pcm_open, .pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close, .pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */ /*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
...@@ -349,9 +346,6 @@ static struct snd_sof_dsp_ops sof_cht_ops = { ...@@ -349,9 +346,6 @@ static struct snd_sof_dsp_ops sof_cht_ops = {
.pcm_open = sof_stream_pcm_open, .pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close, .pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */ /*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
......
...@@ -186,9 +186,6 @@ struct snd_sof_dsp_ops sof_tng_ops = { ...@@ -186,9 +186,6 @@ struct snd_sof_dsp_ops sof_tng_ops = {
.pcm_open = sof_stream_pcm_open, .pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close, .pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */ /*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
......
...@@ -137,57 +137,6 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) ...@@ -137,57 +137,6 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
} }
EXPORT_SYMBOL(snd_sof_ipc_reply); EXPORT_SYMBOL(snd_sof_ipc_reply);
int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
{
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
dev_info(sdev->dev,
"Firmware info: version %d:%d:%d-%s\n", v->major, v->minor,
v->micro, v->tag);
dev_info(sdev->dev,
"Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
SOF_ABI_VERSION_MAJOR(v->abi_version),
SOF_ABI_VERSION_MINOR(v->abi_version),
SOF_ABI_VERSION_PATCH(v->abi_version),
SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
dev_err(sdev->dev, "error: incompatible FW ABI version\n");
return -EINVAL;
}
if (SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n");
} else {
dev_err(sdev->dev, "error: FW ABI is more recent than kernel\n");
return -EINVAL;
}
}
if (ready->flags & SOF_IPC_INFO_BUILD) {
dev_info(sdev->dev,
"Firmware debug build %d on %s-%s - options:\n"
" GDB: %s\n"
" lock debug: %s\n"
" lock vdebug: %s\n",
v->build, v->date, v->time,
(ready->flags & SOF_IPC_INFO_GDB) ?
"enabled" : "disabled",
(ready->flags & SOF_IPC_INFO_LOCKS) ?
"enabled" : "disabled",
(ready->flags & SOF_IPC_INFO_LOCKSV) ?
"enabled" : "disabled");
}
/* copy the fw_version into debugfs at first boot */
memcpy(&sdev->fw_version, v, sizeof(*v));
return 0;
}
EXPORT_SYMBOL(snd_sof_ipc_valid);
struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
{ {
struct snd_sof_ipc *ipc; struct snd_sof_ipc *ipc;
...@@ -220,6 +169,12 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) ...@@ -220,6 +169,12 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
return NULL; return NULL;
} }
if (!ops->fw_loader || !ops->fw_loader->validate ||
!ops->fw_loader->parse_ext_manifest) {
dev_err(sdev->dev, "Missing IPC firmware loading ops\n");
return NULL;
}
if (!ops->pcm) { if (!ops->pcm) {
dev_err(sdev->dev, "Missing IPC PCM ops\n"); dev_err(sdev->dev, "Missing IPC PCM ops\n");
return NULL; return NULL;
......
This diff is collapsed.
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2021 Intel Corporation. All rights reserved.
*/
#ifndef __SOUND_SOC_SOF_IPC3_PRIV_H
#define __SOUND_SOC_SOF_IPC3_PRIV_H
#include "sof-priv.h"
/* IPC3 specific ops */
extern const struct sof_ipc_fw_loader_ops ipc3_loader_ops;
/* helpers for fw_ready and ext_manifest parsing */
int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
const struct sof_ipc_ext_data_hdr *ext_hdr);
int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
const struct sof_ipc_ext_data_hdr *ext_hdr);
int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev);
#endif
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <sound/sof/control.h> #include <sound/sof/control.h>
#include "sof-priv.h" #include "sof-priv.h"
#include "sof-audio.h" #include "sof-audio.h"
#include "ipc3-priv.h"
#include "ipc3-ops.h" #include "ipc3-ops.h"
#include "ops.h" #include "ops.h"
...@@ -475,8 +476,8 @@ static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t da ...@@ -475,8 +476,8 @@ static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t da
return ret; return ret;
} }
static int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev, int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
const struct sof_ipc_ext_data_hdr *ext_hdr) const struct sof_ipc_ext_data_hdr *ext_hdr)
{ {
const struct sof_ipc_window *w = const struct sof_ipc_window *w =
container_of(ext_hdr, struct sof_ipc_window, ext_hdr); container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
...@@ -500,8 +501,8 @@ static int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev, ...@@ -500,8 +501,8 @@ static int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
return 0; return 0;
} }
static int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev, int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
const struct sof_ipc_ext_data_hdr *ext_hdr) const struct sof_ipc_ext_data_hdr *ext_hdr)
{ {
int ret; int ret;
...@@ -735,6 +736,56 @@ static int ipc3_init_reply_data_buffer(struct snd_sof_dev *sdev) ...@@ -735,6 +736,56 @@ static int ipc3_init_reply_data_buffer(struct snd_sof_dev *sdev)
return 0; return 0;
} }
int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev)
{
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
dev_info(sdev->dev,
"Firmware info: version %d:%d:%d-%s\n", v->major, v->minor,
v->micro, v->tag);
dev_info(sdev->dev,
"Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
SOF_ABI_VERSION_MAJOR(v->abi_version),
SOF_ABI_VERSION_MINOR(v->abi_version),
SOF_ABI_VERSION_PATCH(v->abi_version),
SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
dev_err(sdev->dev, "incompatible FW ABI version\n");
return -EINVAL;
}
if (SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
dev_warn(sdev->dev, "FW ABI is more recent than kernel\n");
} else {
dev_err(sdev->dev, "FW ABI is more recent than kernel\n");
return -EINVAL;
}
}
if (ready->flags & SOF_IPC_INFO_BUILD) {
dev_info(sdev->dev,
"Firmware debug build %d on %s-%s - options:\n"
" GDB: %s\n"
" lock debug: %s\n"
" lock vdebug: %s\n",
v->build, v->date, v->time,
(ready->flags & SOF_IPC_INFO_GDB) ?
"enabled" : "disabled",
(ready->flags & SOF_IPC_INFO_LOCKS) ?
"enabled" : "disabled",
(ready->flags & SOF_IPC_INFO_LOCKSV) ?
"enabled" : "disabled");
}
/* copy the fw_version into debugfs at first boot */
memcpy(&sdev->fw_version, v, sizeof(*v));
return 0;
}
static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd) static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
{ {
struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
...@@ -767,7 +818,7 @@ static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd) ...@@ -767,7 +818,7 @@ static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
} }
/* make sure ABI version is compatible */ /* make sure ABI version is compatible */
ret = snd_sof_ipc_valid(sdev); ret = sof_ipc3_validate_fw_version(sdev);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1019,6 +1070,7 @@ const struct sof_ipc_ops ipc3_ops = { ...@@ -1019,6 +1070,7 @@ const struct sof_ipc_ops ipc3_ops = {
.tplg = &ipc3_tplg_ops, .tplg = &ipc3_tplg_ops,
.pm = &ipc3_pm_ops, .pm = &ipc3_pm_ops,
.pcm = &ipc3_pcm_ops, .pcm = &ipc3_pcm_ops,
.fw_loader = &ipc3_loader_ops,
.tx_msg = sof_ipc3_tx_msg, .tx_msg = sof_ipc3_tx_msg,
.rx_msg = sof_ipc3_rx_msg, .rx_msg = sof_ipc3_rx_msg,
......
This diff is collapsed.
...@@ -415,8 +415,6 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { ...@@ -415,8 +415,6 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = {
/* misc */ /* misc */
.get_bar_index = mt8195_get_bar_index, .get_bar_index = mt8195_get_bar_index,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
......
...@@ -364,6 +364,25 @@ struct sof_ipc_pm_ops { ...@@ -364,6 +364,25 @@ struct sof_ipc_pm_ops {
int (*ctx_restore)(struct snd_sof_dev *sdev); int (*ctx_restore)(struct snd_sof_dev *sdev);
}; };
/**
* struct sof_ipc_fw_loader_ops - IPC/FW-specific loader ops
* @validate: Function pointer for validating the firmware image
* @parse_ext_manifest: Function pointer for parsing the manifest of the firmware
* @load_fw_to_dsp: Optional function pointer for loading the firmware to the
* DSP.
* The function implements generic, hardware independent way
* of loading the initial firmware and its modules (if any).
* @query_fw_configuration: Optional function pointer to query information and
* configuration from the booted firmware.
* Executed after the first successful firmware boot.
*/
struct sof_ipc_fw_loader_ops {
int (*validate)(struct snd_sof_dev *sdev);
size_t (*parse_ext_manifest)(struct snd_sof_dev *sdev);
int (*load_fw_to_dsp)(struct snd_sof_dev *sdev);
int (*query_fw_configuration)(struct snd_sof_dev *sdev);
};
struct sof_ipc_tplg_ops; struct sof_ipc_tplg_ops;
struct sof_ipc_pcm_ops; struct sof_ipc_pcm_ops;
...@@ -372,6 +391,7 @@ struct sof_ipc_pcm_ops; ...@@ -372,6 +391,7 @@ struct sof_ipc_pcm_ops;
* @tplg: Pointer to IPC-specific topology ops * @tplg: Pointer to IPC-specific topology ops
* @pm: Pointer to PM ops * @pm: Pointer to PM ops
* @pcm: Pointer to PCM ops * @pcm: Pointer to PCM ops
* @fw_loader: Pointer to Firmware Loader ops
* *
* @tx_msg: Function pointer for sending a 'short' IPC message * @tx_msg: Function pointer for sending a 'short' IPC message
* @set_get_data: Function pointer for set/get data ('large' IPC message). This * @set_get_data: Function pointer for set/get data ('large' IPC message). This
...@@ -391,6 +411,7 @@ struct sof_ipc_ops { ...@@ -391,6 +411,7 @@ struct sof_ipc_ops {
const struct sof_ipc_tplg_ops *tplg; const struct sof_ipc_tplg_ops *tplg;
const struct sof_ipc_pm_ops *pm; const struct sof_ipc_pm_ops *pm;
const struct sof_ipc_pcm_ops *pcm; const struct sof_ipc_pcm_ops *pcm;
const struct sof_ipc_fw_loader_ops *fw_loader;
int (*tx_msg)(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes, int (*tx_msg)(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
void *reply_data, size_t reply_bytes, bool no_pm); void *reply_data, size_t reply_bytes, bool no_pm);
...@@ -587,8 +608,6 @@ extern struct snd_compress_ops sof_compressed_ops; ...@@ -587,8 +608,6 @@ extern struct snd_compress_ops sof_compressed_ops;
int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev); int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev);
int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev); int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev);
int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_run_firmware(struct snd_sof_dev *sdev);
int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
struct snd_sof_mod_hdr *module);
void snd_sof_fw_unload(struct snd_sof_dev *sdev); void snd_sof_fw_unload(struct snd_sof_dev *sdev);
/* /*
...@@ -602,7 +621,6 @@ static inline void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) ...@@ -602,7 +621,6 @@ static inline void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
{ {
sdev->ipc->ops->rx_msg(sdev); sdev->ipc->ops->rx_msg(sdev);
} }
int snd_sof_ipc_valid(struct snd_sof_dev *sdev);
int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
void *reply_data, size_t reply_bytes); void *reply_data, size_t reply_bytes);
int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment