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 @@
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\
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),)
snd-sof-objs += sof-client.o
endif
......
......@@ -136,9 +136,6 @@ struct snd_sof_dsp_ops sof_renoir_ops = {
.block_read = acp_dsp_block_read,
.block_write = acp_dsp_block_write,
/* Module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
.pre_fw_run = acp_dsp_pre_fw_run,
......
......@@ -510,9 +510,8 @@ static struct snd_sof_dsp_ops sof_imx8_ops = {
.ipc_msg_data = sof_ipc_msg_data,
.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,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......@@ -572,9 +571,8 @@ static struct snd_sof_dsp_ops sof_imx8x_ops = {
.ipc_msg_data = sof_ipc_msg_data,
.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,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......
......@@ -436,9 +436,8 @@ static struct snd_sof_dsp_ops sof_imx8m_ops = {
.ipc_msg_data = sof_ipc_msg_data,
.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,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......
......@@ -613,9 +613,6 @@ static struct snd_sof_dsp_ops sof_bdw_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* Module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......
......@@ -267,9 +267,6 @@ static struct snd_sof_dsp_ops sof_byt_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......@@ -349,9 +346,6 @@ static struct snd_sof_dsp_ops sof_cht_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......
......@@ -186,9 +186,6 @@ struct snd_sof_dsp_ops sof_tng_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......
......@@ -137,57 +137,6 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
}
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 *ipc;
......@@ -220,6 +169,12 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
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) {
dev_err(sdev->dev, "Missing IPC PCM ops\n");
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 @@
#include <sound/sof/control.h>
#include "sof-priv.h"
#include "sof-audio.h"
#include "ipc3-priv.h"
#include "ipc3-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
return ret;
}
static int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
const struct sof_ipc_ext_data_hdr *ext_hdr)
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);
......@@ -500,8 +501,8 @@ static int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
return 0;
}
static int sof_ipc3_get_cc_info(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 ret;
......@@ -735,6 +736,56 @@ static int ipc3_init_reply_data_buffer(struct snd_sof_dev *sdev)
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)
{
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)
}
/* make sure ABI version is compatible */
ret = snd_sof_ipc_valid(sdev);
ret = sof_ipc3_validate_fw_version(sdev);
if (ret < 0)
return ret;
......@@ -1019,6 +1070,7 @@ const struct sof_ipc_ops ipc3_ops = {
.tplg = &ipc3_tplg_ops,
.pm = &ipc3_pm_ops,
.pcm = &ipc3_pcm_ops,
.fw_loader = &ipc3_loader_ops,
.tx_msg = sof_ipc3_tx_msg,
.rx_msg = sof_ipc3_rx_msg,
......
This diff is collapsed.
......@@ -415,8 +415,6 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = {
/* misc */
.get_bar_index = mt8195_get_bar_index,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
......
......@@ -364,6 +364,25 @@ struct sof_ipc_pm_ops {
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_pcm_ops;
......@@ -372,6 +391,7 @@ struct sof_ipc_pcm_ops;
* @tplg: Pointer to IPC-specific topology ops
* @pm: Pointer to PM ops
* @pcm: Pointer to PCM ops
* @fw_loader: Pointer to Firmware Loader ops
*
* @tx_msg: Function pointer for sending a 'short' IPC message
* @set_get_data: Function pointer for set/get data ('large' IPC message). This
......@@ -391,6 +411,7 @@ struct sof_ipc_ops {
const struct sof_ipc_tplg_ops *tplg;
const struct sof_ipc_pm_ops *pm;
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,
void *reply_data, size_t reply_bytes, bool no_pm);
......@@ -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_memcpy(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);
/*
......@@ -602,7 +621,6 @@ static inline void snd_sof_ipc_msgs_rx(struct snd_sof_dev *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,
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,
......
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