All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
To: alsa-devel@alsa-project.org
Cc: Daniel Baluta <daniel.baluta@gmail.com>,
	andriy.shevchenko@intel.com, tiwai@suse.de,
	Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>,
	liam.r.girdwood@linux.intel.com, vkoul@kernel.org,
	broonie@kernel.org, Alan Cox <alan@linux.intel.com>,
	sound-open-firmware@alsa-project.org
Subject: [PATCH v3 09/14] ASoC: SOF: Add firmware loader support
Date: Tue, 11 Dec 2018 15:23:13 -0600	[thread overview]
Message-ID: <20181211212318.28644-10-pierre-louis.bossart@linux.intel.com> (raw)
In-Reply-To: <20181211212318.28644-1-pierre-louis.bossart@linux.intel.com>

From: Liam Girdwood <liam.r.girdwood@linux.intel.com>

The firmware loader exports APIs that can be called by core to load and
process multiple different file formats.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/soc/sof/loader.c | 322 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 322 insertions(+)
 create mode 100644 sound/soc/sof/loader.c

diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
new file mode 100644
index 000000000000..dbadd8c521e6
--- /dev/null
+++ b/sound/soc/sof/loader.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: (GPL-2.0 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) 2018 Intel Corporation. All rights reserved.
+//
+// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+//
+// Generic firmware loader.
+//
+
+#include <linux/firmware.h>
+#include <sound/sof.h>
+#include "ops.h"
+
+static int get_ext_windows(struct snd_sof_dev *sdev,
+			   struct sof_ipc_ext_data_hdr *ext_hdr)
+{
+	struct sof_ipc_window *w = (struct sof_ipc_window *)ext_hdr;
+
+	int ret = 0;
+	size_t size;
+
+	if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
+		return -EINVAL;
+
+	size = sizeof(*w) + sizeof(struct sof_ipc_window_elem) * w->num_windows;
+
+	/* keep a local copy of the data */
+	sdev->info_window = kmemdup(w, size, GFP_KERNEL);
+	if (!sdev->info_window)
+		return -ENOMEM;
+
+	return ret;
+}
+
+/* parse the extended FW boot data structures from FW boot message */
+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, offset, ext_data, sizeof(*ext_hdr));
+	ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data;
+
+	while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
+		/* read in ext structure */
+		offset += sizeof(*ext_hdr);
+		snd_sof_dsp_block_read(sdev, offset,
+				       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_DMA_BUFFER:
+			break;
+		case SOF_IPC_EXT_WINDOW:
+			ret = get_ext_windows(sdev, ext_hdr);
+			break;
+		default:
+			break;
+		}
+
+		if (ret < 0) {
+			dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
+				ext_hdr->type);
+			goto out;
+		}
+
+		/* move to next header */
+		offset += ext_hdr->hdr.size;
+		snd_sof_dsp_block_read(sdev, offset, ext_data,
+				       sizeof(*ext_hdr));
+		ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data;
+	}
+out:
+	kfree(ext_data);
+	return ret;
+}
+EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
+
+/* generic module parser for mmaped DSPs */
+int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
+				struct snd_sof_mod_hdr *module)
+{
+	struct snd_sof_blk_hdr *block;
+	int count;
+	u32 offset;
+
+	dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
+		module->size, module->num_blocks, module->type);
+
+	block = (void *)module + sizeof(*module);
+
+	for (count = 0; count < module->num_blocks; count++) {
+		if (block->size == 0) {
+			dev_warn(sdev->dev,
+				 "warning: block %d size zero\n", count);
+			dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
+				 block->type, block->offset);
+			continue;
+		}
+
+		switch (block->type) {
+		case SOF_BLK_IMAGE:
+		case SOF_BLK_CACHE:
+		case SOF_BLK_REGS:
+		case SOF_BLK_SIG:
+		case SOF_BLK_ROM:
+			continue;	/* not handled atm */
+		case SOF_BLK_TEXT:
+		case SOF_BLK_DATA:
+			offset = block->offset;
+			break;
+		default:
+			dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
+				block->type, count);
+			return -EINVAL;
+		}
+
+		dev_dbg(sdev->dev,
+			"block %d type 0x%x size 0x%x ==>  offset 0x%x\n",
+			count, block->type, block->size, offset);
+
+		snd_sof_dsp_block_write(sdev, offset,
+					(void *)block + sizeof(*block),
+					block->size);
+
+		/* next block */
+		block = (void *)block + sizeof(*block) + block->size;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
+
+static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
+{
+	struct snd_sof_fw_header *header;
+
+	/* Read the header information from the data pointer */
+	header = (struct snd_sof_fw_header *)fw->data;
+
+	/* verify FW sig */
+	if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
+		dev_err(sdev->dev, "error: invalid firmware signature\n");
+		return -EINVAL;
+	}
+
+	/* check size is valid */
+	if (fw->size != header->file_size + sizeof(*header)) {
+		dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
+			fw->size, header->file_size + sizeof(*header));
+		return -EINVAL;
+	}
+
+	dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
+		header->file_size, header->num_modules,
+		header->abi, sizeof(*header));
+
+	return 0;
+}
+
+static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
+{
+	struct snd_sof_fw_header *header;
+	struct snd_sof_mod_hdr *module;
+	int (*load_module)(struct snd_sof_dev *sof_dev,
+			   struct snd_sof_mod_hdr *hdr);
+	int ret, count;
+
+	header = (struct snd_sof_fw_header *)fw->data;
+	load_module = sdev->ops->load_module;
+	if (!load_module)
+		return -EINVAL;
+
+	/* parse each module */
+	module = (void *)fw->data + sizeof(*header);
+	for (count = 0; count < header->num_modules; count++) {
+		/* module */
+		ret = load_module(sdev, module);
+		if (ret < 0) {
+			dev_err(sdev->dev, "error: invalid module %d\n", count);
+			return ret;
+		}
+		module = (void *)module + sizeof(*module) + module->size;
+	}
+
+	return 0;
+}
+
+int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
+{
+	struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev);
+	const char *fw_filename;
+	int ret;
+
+	/* set code loading condition to true */
+	sdev->code_loading = 1;
+	fw_filename = plat_data->machine->sof_fw_filename;
+
+	ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
+
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: request firmware failed err: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* make sure the FW header and file is valid */
+	ret = check_header(sdev, plat_data->fw);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: invalid FW header\n");
+		goto error;
+	}
+
+	/* prepare the DSP for FW loading */
+	ret = snd_sof_dsp_reset(sdev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: failed to reset DSP\n");
+		goto error;
+	}
+
+	/* parse and load firmware modules to DSP */
+	ret = load_modules(sdev, plat_data->fw);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: invalid FW modules\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	release_firmware(plat_data->fw);
+	return ret;
+
+}
+EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
+
+int snd_sof_load_firmware(struct snd_sof_dev *sdev)
+{
+	dev_dbg(sdev->dev, "loading firmware\n");
+
+	if (sdev->ops->load_firmware)
+		return sdev->ops->load_firmware(sdev);
+	return 0;
+}
+EXPORT_SYMBOL(snd_sof_load_firmware);
+
+int snd_sof_run_firmware(struct snd_sof_dev *sdev)
+{
+	int ret;
+
+	init_waitqueue_head(&sdev->boot_wait);
+	sdev->boot_complete = false;
+
+	/* create fw_version debugfs to store boot version info */
+	if (sdev->first_boot) {
+		ret = snd_sof_debugfs_buf_create_item(sdev, &sdev->fw_version,
+						      sizeof(sdev->fw_version),
+						      "fw_version");
+
+		if (ret < 0) {
+			dev_err(sdev->dev, "error: cannot create debugfs for fw_version\n");
+			return ret;
+		}
+	}
+
+	/* perform pre fw run operations */
+	ret = snd_sof_dsp_pre_fw_run(sdev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: failed pre fw run op\n");
+		return ret;
+	}
+
+	dev_dbg(sdev->dev, "booting DSP firmware\n");
+
+	/* boot the firmware on the DSP */
+	ret = snd_sof_dsp_run(sdev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: failed to reset DSP\n");
+		return ret;
+	}
+
+	/* now wait for the DSP to boot */
+	ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete,
+				 msecs_to_jiffies(sdev->boot_timeout));
+	if (ret == 0) {
+		dev_err(sdev->dev, "error: firmware boot timeout\n");
+		snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
+			SOF_DBG_TEXT | SOF_DBG_PCI);
+		return -EIO;
+	}
+
+	dev_info(sdev->dev, "firmware boot complete\n");
+
+	/* perform post fw run operations */
+	ret = snd_sof_dsp_post_fw_run(sdev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: failed post fw run op\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(snd_sof_run_firmware);
+
+void snd_sof_fw_unload(struct snd_sof_dev *sdev)
+{
+	/* TODO: support module unloading at runtime */
+}
+EXPORT_SYMBOL(snd_sof_fw_unload);
-- 
2.17.1

  parent reply	other threads:[~2018-12-11 21:23 UTC|newest]

Thread overview: 101+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-11 21:23 [PATCH v3 00/14] Sound Open Firmware (SOF) core Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 01/14] ASoC: SOF: Add Sound Open Firmware driver core Pierre-Louis Bossart
2018-12-11 22:20   ` Andy Shevchenko
2018-12-11 23:20     ` Pierre-Louis Bossart
2018-12-12  7:51   ` Takashi Iwai
2018-12-12 14:53     ` Pierre-Louis Bossart
2018-12-12 20:42   ` Daniel Baluta
2018-12-12 22:35     ` Pierre-Louis Bossart
2019-01-29 16:49   ` Daniel Baluta
2019-01-30 16:12     ` Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 02/14] ASoC: SOF: Add Sound Open Firmware KControl support Pierre-Louis Bossart
2018-12-11 22:23   ` Andy Shevchenko
2018-12-11 22:48     ` Pierre-Louis Bossart
2018-12-11 23:25       ` Andy Shevchenko
2018-12-12 20:18     ` Pierre-Louis Bossart
2018-12-12  7:35   ` Takashi Iwai
2018-12-12 15:01     ` Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 03/14] ASoC: SOF: Add driver debug support Pierre-Louis Bossart
2018-12-11 22:32   ` Andy Shevchenko
2018-12-11 23:29     ` Pierre-Louis Bossart
2019-01-09 19:40   ` Mark Brown
2019-01-10 20:47     ` Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 04/14] ASoC: SOF: Add support for IPC IO between DSP and Host Pierre-Louis Bossart
2018-12-11 22:57   ` Andy Shevchenko
2018-12-11 23:38     ` Pierre-Louis Bossart
2018-12-12  8:17   ` Takashi Iwai
2018-12-12 15:19     ` Pierre-Louis Bossart
2018-12-12 15:34       ` Takashi Iwai
2018-12-13  5:24       ` Keyon Jie
2018-12-13  7:48         ` Takashi Iwai
2018-12-13  9:13           ` Keyon Jie
2018-12-13  8:06         ` Keyon Jie
2018-12-13  8:59           ` rander.wang
2019-01-09 20:37   ` Mark Brown
2019-01-10 20:11     ` Pierre-Louis Bossart
2019-01-22 19:04       ` Mark Brown
2019-01-22 21:05         ` Pierre-Louis Bossart
2019-01-22 21:13           ` Mark Brown
2019-01-23  5:51           ` [Sound-open-firmware] " Keyon Jie
2019-01-14 15:10   ` Daniel Baluta
2019-01-14 17:39     ` Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 05/14] ASoC: SOF: Add PCM operations support Pierre-Louis Bossart
2018-12-12  8:04   ` Takashi Iwai
2018-12-12 13:12     ` Andy Shevchenko
2018-12-12 15:29     ` [Sound-open-firmware] " Pierre-Louis Bossart
2018-12-12 15:43       ` Takashi Iwai
2018-12-12 16:10         ` Pierre-Louis Bossart
2018-12-12 22:09   ` Daniel Baluta
2018-12-11 21:23 ` [PATCH v3 06/14] ASoC: SOF: Add support for loading topologies Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 07/14] ASoC: SOF: Add DSP firmware logger support Pierre-Louis Bossart
2018-12-11 23:21   ` Andy Shevchenko
2018-12-11 23:43     ` Pierre-Louis Bossart
2018-12-12  6:44       ` Takashi Iwai
2018-12-12 11:11   ` Takashi Iwai
2018-12-12 16:04     ` [Sound-open-firmware] " Pierre-Louis Bossart
2018-12-12 16:12       ` Takashi Iwai
2018-12-12 17:01         ` Pierre-Louis Bossart
2019-01-09 20:44   ` Mark Brown
2019-01-09 21:39     ` Pierre-Louis Bossart
2019-01-22 18:57       ` Mark Brown
2019-01-22 20:33         ` Pierre-Louis Bossart
2019-01-22 20:41           ` Mark Brown
2019-01-22 20:52             ` Pierre-Louis Bossart
2019-01-22 21:08               ` Mark Brown
2019-01-22 21:13                 ` Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 08/14] ASoC: SOF: Add DSP HW abstraction operations Pierre-Louis Bossart
2018-12-11 23:16   ` Andy Shevchenko
2018-12-11 23:45     ` Pierre-Louis Bossart
2019-01-09 20:51   ` Mark Brown
2019-01-09 21:37     ` Pierre-Louis Bossart
2019-01-22 18:56       ` Mark Brown
2018-12-11 21:23 ` Pierre-Louis Bossart [this message]
2018-12-11 22:38   ` [PATCH v3 09/14] ASoC: SOF: Add firmware loader support Andy Shevchenko
2018-12-11 23:54     ` Pierre-Louis Bossart
2019-01-09 20:55       ` Mark Brown
2018-12-12 11:23   ` Takashi Iwai
2018-12-12 16:06     ` [Sound-open-firmware] " Pierre-Louis Bossart
2019-01-09 21:02   ` Mark Brown
2019-01-09 21:24     ` Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 10/14] ASoC: SOF: Add userspace ABI support Pierre-Louis Bossart
2018-12-21 11:10   ` Daniel Baluta
2018-12-21 14:59     ` [Sound-open-firmware] " Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 11/14] ASoC: SOF: Add PM support Pierre-Louis Bossart
2018-12-12 11:32   ` Takashi Iwai
2018-12-12 16:08     ` Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 12/14] ASoC: SOF: Add Nocodec machine driver support Pierre-Louis Bossart
2018-12-11 21:23 ` [PATCH v3 13/14] ASoC: SOF: Add xtensa support Pierre-Louis Bossart
2018-12-11 23:08   ` Andy Shevchenko
2018-12-12  0:00     ` Pierre-Louis Bossart
     [not found]       ` <93aff9af-c693-c951-4821-e9e334133ed0@linux.intel.com>
2018-12-13  9:58         ` [Sound-open-firmware] " rander.wang
2018-12-17 13:45           ` Takashi Iwai
2018-12-17 14:24             ` Mark Brown
2018-12-11 21:23 ` [PATCH v3 14/14] ASoC: SOF: Add utils Pierre-Louis Bossart
2018-12-11 23:06   ` Andy Shevchenko
2018-12-12  0:06     ` Pierre-Louis Bossart
     [not found] <mailman.3934.1544619824.753.alsa-devel@alsa-project.org>
2018-12-20  2:11 ` [PATCH v3 09/14] ASoC: SOF: Add firmware, loader support Bard liao
2018-12-20  8:16   ` Takashi Iwai
2018-12-20 15:07     ` Pierre-Louis Bossart
2018-12-21  9:05       ` Bard liao
2018-12-21  9:57         ` Takashi Iwai
2018-12-21 15:43           ` Liam Girdwood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181211212318.28644-10-pierre-louis.bossart@linux.intel.com \
    --to=pierre-louis.bossart@linux.intel.com \
    --cc=alan@linux.intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=andriy.shevchenko@intel.com \
    --cc=broonie@kernel.org \
    --cc=daniel.baluta@gmail.com \
    --cc=liam.r.girdwood@linux.intel.com \
    --cc=sound-open-firmware@alsa-project.org \
    --cc=tiwai@suse.de \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.