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