18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  bxt-sst.c - DSP library functions for BXT platform
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2015-16 Intel Corp
68c2ecf20Sopenharmony_ci *  Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
78c2ecf20Sopenharmony_ci *	   Jeeja KP <jeeja.kp@intel.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/firmware.h>
138c2ecf20Sopenharmony_ci#include <linux/device.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "../common/sst-dsp.h"
168c2ecf20Sopenharmony_ci#include "../common/sst-dsp-priv.h"
178c2ecf20Sopenharmony_ci#include "skl.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define BXT_BASEFW_TIMEOUT	3000
208c2ecf20Sopenharmony_ci#define BXT_ROM_INIT_TIMEOUT	70
218c2ecf20Sopenharmony_ci#define BXT_IPC_PURGE_FW	0x01004000
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define BXT_ROM_INIT		0x5
248c2ecf20Sopenharmony_ci#define BXT_ADSP_SRAM0_BASE	0x80000
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* Firmware status window */
278c2ecf20Sopenharmony_ci#define BXT_ADSP_FW_STATUS	BXT_ADSP_SRAM0_BASE
288c2ecf20Sopenharmony_ci#define BXT_ADSP_ERROR_CODE     (BXT_ADSP_FW_STATUS + 0x4)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define BXT_ADSP_SRAM1_BASE	0xA0000
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define BXT_INSTANCE_ID 0
338c2ecf20Sopenharmony_ci#define BXT_BASE_FW_MODULE_ID 0
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* Delay before scheduling D0i3 entry */
388c2ecf20Sopenharmony_ci#define BXT_D0I3_DELAY 5000
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	 return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic int
468c2ecf20Sopenharmony_cibxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct snd_dma_buffer dmab;
498c2ecf20Sopenharmony_ci	struct skl_dev *skl = ctx->thread_context;
508c2ecf20Sopenharmony_ci	struct firmware stripped_fw;
518c2ecf20Sopenharmony_ci	int ret = 0, i, dma_id, stream_tag;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	/* library indices start from 1 to N. 0 represents base FW */
548c2ecf20Sopenharmony_ci	for (i = 1; i < lib_count; i++) {
558c2ecf20Sopenharmony_ci		ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw,
568c2ecf20Sopenharmony_ci					BXT_ADSP_FW_BIN_HDR_OFFSET, i);
578c2ecf20Sopenharmony_ci		if (ret < 0)
588c2ecf20Sopenharmony_ci			goto load_library_failed;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40,
618c2ecf20Sopenharmony_ci					stripped_fw.size, &dmab);
628c2ecf20Sopenharmony_ci		if (stream_tag <= 0) {
638c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "Lib prepare DMA err: %x\n",
648c2ecf20Sopenharmony_ci					stream_tag);
658c2ecf20Sopenharmony_ci			ret = stream_tag;
668c2ecf20Sopenharmony_ci			goto load_library_failed;
678c2ecf20Sopenharmony_ci		}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		dma_id = stream_tag - 1;
708c2ecf20Sopenharmony_ci		memcpy(dmab.area, stripped_fw.data, stripped_fw.size);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci		ctx->dsp_ops.trigger(ctx->dev, true, stream_tag);
738c2ecf20Sopenharmony_ci		ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i, true);
748c2ecf20Sopenharmony_ci		if (ret < 0)
758c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n",
768c2ecf20Sopenharmony_ci					linfo[i].name, ret);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		ctx->dsp_ops.trigger(ctx->dev, false, stream_tag);
798c2ecf20Sopenharmony_ci		ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return ret;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ciload_library_failed:
858c2ecf20Sopenharmony_ci	skl_release_library(linfo, lib_count);
868c2ecf20Sopenharmony_ci	return ret;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/*
908c2ecf20Sopenharmony_ci * First boot sequence has some extra steps. Core 0 waits for power
918c2ecf20Sopenharmony_ci * status on core 1, so power up core 1 also momentarily, keep it in
928c2ecf20Sopenharmony_ci * reset/stall and then turn it off
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_cistatic int sst_bxt_prepare_fw(struct sst_dsp *ctx,
958c2ecf20Sopenharmony_ci			const void *fwdata, u32 fwsize)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	int stream_tag, ret;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
1008c2ecf20Sopenharmony_ci	if (stream_tag <= 0) {
1018c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n",
1028c2ecf20Sopenharmony_ci				stream_tag);
1038c2ecf20Sopenharmony_ci		return stream_tag;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	ctx->dsp_ops.stream_tag = stream_tag;
1078c2ecf20Sopenharmony_ci	memcpy(ctx->dmab.area, fwdata, fwsize);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* Step 1: Power up core 0 and core1 */
1108c2ecf20Sopenharmony_ci	ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK |
1118c2ecf20Sopenharmony_ci				SKL_DSP_CORE_MASK(1));
1128c2ecf20Sopenharmony_ci	if (ret < 0) {
1138c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "dsp core0/1 power up failed\n");
1148c2ecf20Sopenharmony_ci		goto base_fw_load_failed;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* Step 2: Purge FW request */
1188c2ecf20Sopenharmony_ci	sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY |
1198c2ecf20Sopenharmony_ci				(BXT_IPC_PURGE_FW | ((stream_tag - 1) << 9)));
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* Step 3: Unset core0 reset state & unstall/run core0 */
1228c2ecf20Sopenharmony_ci	ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
1238c2ecf20Sopenharmony_ci	if (ret < 0) {
1248c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret);
1258c2ecf20Sopenharmony_ci		ret = -EIO;
1268c2ecf20Sopenharmony_ci		goto base_fw_load_failed;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* Step 4: Wait for DONE Bit */
1308c2ecf20Sopenharmony_ci	ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE,
1318c2ecf20Sopenharmony_ci					SKL_ADSP_REG_HIPCIE_DONE,
1328c2ecf20Sopenharmony_ci					SKL_ADSP_REG_HIPCIE_DONE,
1338c2ecf20Sopenharmony_ci					BXT_INIT_TIMEOUT, "HIPCIE Done");
1348c2ecf20Sopenharmony_ci	if (ret < 0) {
1358c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret);
1368c2ecf20Sopenharmony_ci		goto base_fw_load_failed;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/* Step 5: power down core1 */
1408c2ecf20Sopenharmony_ci	ret = skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
1418c2ecf20Sopenharmony_ci	if (ret < 0) {
1428c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "dsp core1 power down failed\n");
1438c2ecf20Sopenharmony_ci		goto base_fw_load_failed;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Step 6: Enable Interrupt */
1478c2ecf20Sopenharmony_ci	skl_ipc_int_enable(ctx);
1488c2ecf20Sopenharmony_ci	skl_ipc_op_int_enable(ctx);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* Step 7: Wait for ROM init */
1518c2ecf20Sopenharmony_ci	ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
1528c2ecf20Sopenharmony_ci			SKL_FW_INIT, BXT_ROM_INIT_TIMEOUT, "ROM Load");
1538c2ecf20Sopenharmony_ci	if (ret < 0) {
1548c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret);
1558c2ecf20Sopenharmony_ci		goto base_fw_load_failed;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return ret;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cibase_fw_load_failed:
1618c2ecf20Sopenharmony_ci	ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
1628c2ecf20Sopenharmony_ci	skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
1638c2ecf20Sopenharmony_ci	skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
1648c2ecf20Sopenharmony_ci	return ret;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	int ret;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
1728c2ecf20Sopenharmony_ci	ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
1738c2ecf20Sopenharmony_ci			BXT_ROM_INIT, BXT_BASEFW_TIMEOUT, "Firmware boot");
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
1768c2ecf20Sopenharmony_ci	ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return ret;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int bxt_load_base_firmware(struct sst_dsp *ctx)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct firmware stripped_fw;
1848c2ecf20Sopenharmony_ci	struct skl_dev *skl = ctx->thread_context;
1858c2ecf20Sopenharmony_ci	int ret, i;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (ctx->fw == NULL) {
1888c2ecf20Sopenharmony_ci		ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
1898c2ecf20Sopenharmony_ci		if (ret < 0) {
1908c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "Request firmware failed %d\n", ret);
1918c2ecf20Sopenharmony_ci			return ret;
1928c2ecf20Sopenharmony_ci		}
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* prase uuids on first boot */
1968c2ecf20Sopenharmony_ci	if (skl->is_first_boot) {
1978c2ecf20Sopenharmony_ci		ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0);
1988c2ecf20Sopenharmony_ci		if (ret < 0)
1998c2ecf20Sopenharmony_ci			goto sst_load_base_firmware_failed;
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	stripped_fw.data = ctx->fw->data;
2038c2ecf20Sopenharmony_ci	stripped_fw.size = ctx->fw->size;
2048c2ecf20Sopenharmony_ci	skl_dsp_strip_extended_manifest(&stripped_fw);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) {
2088c2ecf20Sopenharmony_ci		ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
2098c2ecf20Sopenharmony_ci		if (ret == 0)
2108c2ecf20Sopenharmony_ci			break;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (ret < 0) {
2148c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
2158c2ecf20Sopenharmony_ci			sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
2168c2ecf20Sopenharmony_ci			sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret);
2198c2ecf20Sopenharmony_ci		goto sst_load_base_firmware_failed;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	ret = sst_transfer_fw_host_dma(ctx);
2238c2ecf20Sopenharmony_ci	if (ret < 0) {
2248c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Transfer firmware failed %d\n", ret);
2258c2ecf20Sopenharmony_ci		dev_info(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
2268c2ecf20Sopenharmony_ci			sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
2278c2ecf20Sopenharmony_ci			sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci		skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
2308c2ecf20Sopenharmony_ci	} else {
2318c2ecf20Sopenharmony_ci		dev_dbg(ctx->dev, "Firmware download successful\n");
2328c2ecf20Sopenharmony_ci		ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
2338c2ecf20Sopenharmony_ci					msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
2348c2ecf20Sopenharmony_ci		if (ret == 0) {
2358c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n");
2368c2ecf20Sopenharmony_ci			skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
2378c2ecf20Sopenharmony_ci			ret = -EIO;
2388c2ecf20Sopenharmony_ci		} else {
2398c2ecf20Sopenharmony_ci			ret = 0;
2408c2ecf20Sopenharmony_ci			skl->fw_loaded = true;
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	return ret;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cisst_load_base_firmware_failed:
2478c2ecf20Sopenharmony_ci	release_firmware(ctx->fw);
2488c2ecf20Sopenharmony_ci	ctx->fw = NULL;
2498c2ecf20Sopenharmony_ci	return ret;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci/*
2538c2ecf20Sopenharmony_ci * Decide the D0i3 state that can be targeted based on the usecase
2548c2ecf20Sopenharmony_ci * ref counts and DSP state
2558c2ecf20Sopenharmony_ci *
2568c2ecf20Sopenharmony_ci * Decision Matrix:  (X= dont care; state = target state)
2578c2ecf20Sopenharmony_ci *
2588c2ecf20Sopenharmony_ci * DSP state != SKL_DSP_RUNNING ; state = no d0i3
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci * DSP state == SKL_DSP_RUNNING , the following matrix applies
2618c2ecf20Sopenharmony_ci * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3
2628c2ecf20Sopenharmony_ci * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3
2638c2ecf20Sopenharmony_ci * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3
2648c2ecf20Sopenharmony_ci * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3
2658c2ecf20Sopenharmony_ci */
2668c2ecf20Sopenharmony_cistatic int bxt_d0i3_target_state(struct sst_dsp *ctx)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct skl_dev *skl = ctx->thread_context;
2698c2ecf20Sopenharmony_ci	struct skl_d0i3_data *d0i3 = &skl->d0i3;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING)
2728c2ecf20Sopenharmony_ci		return SKL_DSP_D0I3_NONE;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (d0i3->non_d0i3)
2758c2ecf20Sopenharmony_ci		return SKL_DSP_D0I3_NONE;
2768c2ecf20Sopenharmony_ci	else if (d0i3->streaming)
2778c2ecf20Sopenharmony_ci		return SKL_DSP_D0I3_STREAMING;
2788c2ecf20Sopenharmony_ci	else if (d0i3->non_streaming)
2798c2ecf20Sopenharmony_ci		return SKL_DSP_D0I3_NON_STREAMING;
2808c2ecf20Sopenharmony_ci	else
2818c2ecf20Sopenharmony_ci		return SKL_DSP_D0I3_NONE;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic void bxt_set_dsp_D0i3(struct work_struct *work)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	int ret;
2878c2ecf20Sopenharmony_ci	struct skl_ipc_d0ix_msg msg;
2888c2ecf20Sopenharmony_ci	struct skl_dev *skl = container_of(work,
2898c2ecf20Sopenharmony_ci			struct skl_dev, d0i3.work.work);
2908c2ecf20Sopenharmony_ci	struct sst_dsp *ctx = skl->dsp;
2918c2ecf20Sopenharmony_ci	struct skl_d0i3_data *d0i3 = &skl->d0i3;
2928c2ecf20Sopenharmony_ci	int target_state;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "In %s:\n", __func__);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* D0i3 entry allowed only if core 0 alone is running */
2978c2ecf20Sopenharmony_ci	if (skl_dsp_get_enabled_cores(ctx) !=  SKL_DSP_CORE0_MASK) {
2988c2ecf20Sopenharmony_ci		dev_warn(ctx->dev,
2998c2ecf20Sopenharmony_ci				"D0i3 allowed when only core0 running:Exit\n");
3008c2ecf20Sopenharmony_ci		return;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	target_state = bxt_d0i3_target_state(ctx);
3048c2ecf20Sopenharmony_ci	if (target_state == SKL_DSP_D0I3_NONE)
3058c2ecf20Sopenharmony_ci		return;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	msg.instance_id = 0;
3088c2ecf20Sopenharmony_ci	msg.module_id = 0;
3098c2ecf20Sopenharmony_ci	msg.wake = 1;
3108c2ecf20Sopenharmony_ci	msg.streaming = 0;
3118c2ecf20Sopenharmony_ci	if (target_state == SKL_DSP_D0I3_STREAMING)
3128c2ecf20Sopenharmony_ci		msg.streaming = 1;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	ret =  skl_ipc_set_d0ix(&skl->ipc, &msg);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (ret < 0) {
3178c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n");
3188c2ecf20Sopenharmony_ci		return;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	/* Set Vendor specific register D0I3C.I3 to enable D0i3*/
3228c2ecf20Sopenharmony_ci	if (skl->update_d0i3c)
3238c2ecf20Sopenharmony_ci		skl->update_d0i3c(skl->dev, true);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	d0i3->state = target_state;
3268c2ecf20Sopenharmony_ci	skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct skl_dev *skl = ctx->thread_context;
3328c2ecf20Sopenharmony_ci	struct skl_d0i3_data *d0i3 = &skl->d0i3;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* Schedule D0i3 only if the usecase ref counts are appropriate */
3358c2ecf20Sopenharmony_ci	if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) {
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		schedule_delayed_work(&d0i3->work,
3408c2ecf20Sopenharmony_ci				msecs_to_jiffies(BXT_D0I3_DELAY));
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return 0;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int bxt_set_dsp_D0i0(struct sst_dsp *ctx)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	int ret;
3498c2ecf20Sopenharmony_ci	struct skl_ipc_d0ix_msg msg;
3508c2ecf20Sopenharmony_ci	struct skl_dev *skl = ctx->thread_context;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "In %s:\n", __func__);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* First Cancel any pending attempt to put DSP to D0i3 */
3558c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&skl->d0i3.work);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* If DSP is currently in D0i3, bring it to D0i0 */
3588c2ecf20Sopenharmony_ci	if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3)
3598c2ecf20Sopenharmony_ci		return 0;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "Set DSP to D0i0\n");
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	msg.instance_id = 0;
3648c2ecf20Sopenharmony_ci	msg.module_id = 0;
3658c2ecf20Sopenharmony_ci	msg.streaming = 0;
3668c2ecf20Sopenharmony_ci	msg.wake = 0;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING)
3698c2ecf20Sopenharmony_ci		msg.streaming = 1;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* Clear Vendor specific register D0I3C.I3 to disable D0i3*/
3728c2ecf20Sopenharmony_ci	if (skl->update_d0i3c)
3738c2ecf20Sopenharmony_ci		skl->update_d0i3c(skl->dev, false);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	ret =  skl_ipc_set_d0ix(&skl->ipc, &msg);
3768c2ecf20Sopenharmony_ci	if (ret < 0) {
3778c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to set DSP to D0i0\n");
3788c2ecf20Sopenharmony_ci		return ret;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
3828c2ecf20Sopenharmony_ci	skl->d0i3.state = SKL_DSP_D0I3_NONE;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct skl_dev *skl = ctx->thread_context;
3908c2ecf20Sopenharmony_ci	int ret;
3918c2ecf20Sopenharmony_ci	struct skl_ipc_dxstate_info dx;
3928c2ecf20Sopenharmony_ci	unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (skl->fw_loaded == false) {
3958c2ecf20Sopenharmony_ci		skl->boot_complete = false;
3968c2ecf20Sopenharmony_ci		ret = bxt_load_base_firmware(ctx);
3978c2ecf20Sopenharmony_ci		if (ret < 0) {
3988c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "reload fw failed: %d\n", ret);
3998c2ecf20Sopenharmony_ci			return ret;
4008c2ecf20Sopenharmony_ci		}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		if (skl->lib_count > 1) {
4038c2ecf20Sopenharmony_ci			ret = bxt_load_library(ctx, skl->lib_info,
4048c2ecf20Sopenharmony_ci						skl->lib_count);
4058c2ecf20Sopenharmony_ci			if (ret < 0) {
4068c2ecf20Sopenharmony_ci				dev_err(ctx->dev, "reload libs failed: %d\n", ret);
4078c2ecf20Sopenharmony_ci				return ret;
4088c2ecf20Sopenharmony_ci			}
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci		skl->cores.state[core_id] = SKL_DSP_RUNNING;
4118c2ecf20Sopenharmony_ci		return ret;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* If core 0 is being turned on, turn on core 1 as well */
4158c2ecf20Sopenharmony_ci	if (core_id == SKL_DSP_CORE0_ID)
4168c2ecf20Sopenharmony_ci		ret = skl_dsp_core_power_up(ctx, core_mask |
4178c2ecf20Sopenharmony_ci				SKL_DSP_CORE_MASK(1));
4188c2ecf20Sopenharmony_ci	else
4198c2ecf20Sopenharmony_ci		ret = skl_dsp_core_power_up(ctx, core_mask);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (ret < 0)
4228c2ecf20Sopenharmony_ci		goto err;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (core_id == SKL_DSP_CORE0_ID) {
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		/*
4278c2ecf20Sopenharmony_ci		 * Enable interrupt after SPA is set and before
4288c2ecf20Sopenharmony_ci		 * DSP is unstalled
4298c2ecf20Sopenharmony_ci		 */
4308c2ecf20Sopenharmony_ci		skl_ipc_int_enable(ctx);
4318c2ecf20Sopenharmony_ci		skl_ipc_op_int_enable(ctx);
4328c2ecf20Sopenharmony_ci		skl->boot_complete = false;
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	ret = skl_dsp_start_core(ctx, core_mask);
4368c2ecf20Sopenharmony_ci	if (ret < 0)
4378c2ecf20Sopenharmony_ci		goto err;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (core_id == SKL_DSP_CORE0_ID) {
4408c2ecf20Sopenharmony_ci		ret = wait_event_timeout(skl->boot_wait,
4418c2ecf20Sopenharmony_ci				skl->boot_complete,
4428c2ecf20Sopenharmony_ci				msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* If core 1 was turned on for booting core 0, turn it off */
4458c2ecf20Sopenharmony_ci		skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
4468c2ecf20Sopenharmony_ci		if (ret == 0) {
4478c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "%s: DSP boot timeout\n", __func__);
4488c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
4498c2ecf20Sopenharmony_ci				sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
4508c2ecf20Sopenharmony_ci				sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
4518c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "Failed to set core0 to D0 state\n");
4528c2ecf20Sopenharmony_ci			ret = -EIO;
4538c2ecf20Sopenharmony_ci			goto err;
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* Tell FW if additional core in now On */
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (core_id != SKL_DSP_CORE0_ID) {
4608c2ecf20Sopenharmony_ci		dx.core_mask = core_mask;
4618c2ecf20Sopenharmony_ci		dx.dx_mask = core_mask;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
4648c2ecf20Sopenharmony_ci					BXT_BASE_FW_MODULE_ID, &dx);
4658c2ecf20Sopenharmony_ci		if (ret < 0) {
4668c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "IPC set_dx for core %d fail: %d\n",
4678c2ecf20Sopenharmony_ci								core_id, ret);
4688c2ecf20Sopenharmony_ci			goto err;
4698c2ecf20Sopenharmony_ci		}
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	skl->cores.state[core_id] = SKL_DSP_RUNNING;
4738c2ecf20Sopenharmony_ci	return 0;
4748c2ecf20Sopenharmony_cierr:
4758c2ecf20Sopenharmony_ci	if (core_id == SKL_DSP_CORE0_ID)
4768c2ecf20Sopenharmony_ci		core_mask |= SKL_DSP_CORE_MASK(1);
4778c2ecf20Sopenharmony_ci	skl_dsp_disable_core(ctx, core_mask);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return ret;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	int ret;
4858c2ecf20Sopenharmony_ci	struct skl_ipc_dxstate_info dx;
4868c2ecf20Sopenharmony_ci	struct skl_dev *skl = ctx->thread_context;
4878c2ecf20Sopenharmony_ci	unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	dx.core_mask = core_mask;
4908c2ecf20Sopenharmony_ci	dx.dx_mask = SKL_IPC_D3_MASK;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "core mask=%x dx_mask=%x\n",
4938c2ecf20Sopenharmony_ci			dx.core_mask, dx.dx_mask);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
4968c2ecf20Sopenharmony_ci				BXT_BASE_FW_MODULE_ID, &dx);
4978c2ecf20Sopenharmony_ci	if (ret < 0) {
4988c2ecf20Sopenharmony_ci		dev_err(ctx->dev,
4998c2ecf20Sopenharmony_ci		"Failed to set DSP to D3:core id = %d;Continue reset\n",
5008c2ecf20Sopenharmony_ci		core_id);
5018c2ecf20Sopenharmony_ci		/*
5028c2ecf20Sopenharmony_ci		 * In case of D3 failure, re-download the firmware, so set
5038c2ecf20Sopenharmony_ci		 * fw_loaded to false.
5048c2ecf20Sopenharmony_ci		 */
5058c2ecf20Sopenharmony_ci		skl->fw_loaded = false;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (core_id == SKL_DSP_CORE0_ID) {
5098c2ecf20Sopenharmony_ci		/* disable Interrupt */
5108c2ecf20Sopenharmony_ci		skl_ipc_op_int_disable(ctx);
5118c2ecf20Sopenharmony_ci		skl_ipc_int_disable(ctx);
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci	ret = skl_dsp_disable_core(ctx, core_mask);
5148c2ecf20Sopenharmony_ci	if (ret < 0) {
5158c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to disable core %d\n", ret);
5168c2ecf20Sopenharmony_ci		return ret;
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci	skl->cores.state[core_id] = SKL_DSP_RESET;
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic const struct skl_dsp_fw_ops bxt_fw_ops = {
5238c2ecf20Sopenharmony_ci	.set_state_D0 = bxt_set_dsp_D0,
5248c2ecf20Sopenharmony_ci	.set_state_D3 = bxt_set_dsp_D3,
5258c2ecf20Sopenharmony_ci	.set_state_D0i3 = bxt_schedule_dsp_D0i3,
5268c2ecf20Sopenharmony_ci	.set_state_D0i0 = bxt_set_dsp_D0i0,
5278c2ecf20Sopenharmony_ci	.load_fw = bxt_load_base_firmware,
5288c2ecf20Sopenharmony_ci	.get_fw_errcode = bxt_get_errorcode,
5298c2ecf20Sopenharmony_ci	.load_library = bxt_load_library,
5308c2ecf20Sopenharmony_ci};
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic struct sst_ops skl_ops = {
5338c2ecf20Sopenharmony_ci	.irq_handler = skl_dsp_sst_interrupt,
5348c2ecf20Sopenharmony_ci	.write = sst_shim32_write,
5358c2ecf20Sopenharmony_ci	.read = sst_shim32_read,
5368c2ecf20Sopenharmony_ci	.free = skl_dsp_free,
5378c2ecf20Sopenharmony_ci};
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic struct sst_dsp_device skl_dev = {
5408c2ecf20Sopenharmony_ci	.thread = skl_dsp_irq_thread_handler,
5418c2ecf20Sopenharmony_ci	.ops = &skl_ops,
5428c2ecf20Sopenharmony_ci};
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ciint bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
5458c2ecf20Sopenharmony_ci			const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
5468c2ecf20Sopenharmony_ci			struct skl_dev **dsp)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct skl_dev *skl;
5498c2ecf20Sopenharmony_ci	struct sst_dsp *sst;
5508c2ecf20Sopenharmony_ci	int ret;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev);
5538c2ecf20Sopenharmony_ci	if (ret < 0) {
5548c2ecf20Sopenharmony_ci		dev_err(dev, "%s: no device\n", __func__);
5558c2ecf20Sopenharmony_ci		return ret;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	skl = *dsp;
5598c2ecf20Sopenharmony_ci	sst = skl->dsp;
5608c2ecf20Sopenharmony_ci	sst->fw_ops = bxt_fw_ops;
5618c2ecf20Sopenharmony_ci	sst->addr.lpe = mmio_base;
5628c2ecf20Sopenharmony_ci	sst->addr.shim = mmio_base;
5638c2ecf20Sopenharmony_ci	sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE;
5648c2ecf20Sopenharmony_ci	sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE;
5658c2ecf20Sopenharmony_ci	sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ;
5668c2ecf20Sopenharmony_ci	sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
5698c2ecf20Sopenharmony_ci			SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	ret = skl_ipc_init(dev, skl);
5728c2ecf20Sopenharmony_ci	if (ret) {
5738c2ecf20Sopenharmony_ci		skl_dsp_free(sst);
5748c2ecf20Sopenharmony_ci		return ret;
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* set the D0i3 check */
5788c2ecf20Sopenharmony_ci	skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	skl->boot_complete = false;
5818c2ecf20Sopenharmony_ci	init_waitqueue_head(&skl->boot_wait);
5828c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
5838c2ecf20Sopenharmony_ci	skl->d0i3.state = SKL_DSP_D0I3_NONE;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	return skl_dsp_acquire_irq(sst);
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ciint bxt_sst_init_fw(struct device *dev, struct skl_dev *skl)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	int ret;
5928c2ecf20Sopenharmony_ci	struct sst_dsp *sst = skl->dsp;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	ret = sst->fw_ops.load_fw(sst);
5958c2ecf20Sopenharmony_ci	if (ret < 0) {
5968c2ecf20Sopenharmony_ci		dev_err(dev, "Load base fw failed: %x\n", ret);
5978c2ecf20Sopenharmony_ci		return ret;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	skl_dsp_init_core_state(sst);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (skl->lib_count > 1) {
6038c2ecf20Sopenharmony_ci		ret = sst->fw_ops.load_library(sst, skl->lib_info,
6048c2ecf20Sopenharmony_ci						skl->lib_count);
6058c2ecf20Sopenharmony_ci		if (ret < 0) {
6068c2ecf20Sopenharmony_ci			dev_err(dev, "Load Library failed : %x\n", ret);
6078c2ecf20Sopenharmony_ci			return ret;
6088c2ecf20Sopenharmony_ci		}
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci	skl->is_first_boot = false;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	return 0;
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bxt_sst_init_fw);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_civoid bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	skl_release_library(skl->lib_info, skl->lib_count);
6208c2ecf20Sopenharmony_ci	if (skl->dsp->fw)
6218c2ecf20Sopenharmony_ci		release_firmware(skl->dsp->fw);
6228c2ecf20Sopenharmony_ci	skl_freeup_uuid_list(skl);
6238c2ecf20Sopenharmony_ci	skl_ipc_free(&skl->ipc);
6248c2ecf20Sopenharmony_ci	skl->dsp->ops->free(skl->dsp);
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
6298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Broxton IPC driver");
630