18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * cnl-sst.c - DSP library functions for CNL platform 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016-17, Intel Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Guneshwor Singh <guneshwor.o.singh@intel.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Modified from: 108c2ecf20Sopenharmony_ci * HDA DSP library functions for SKL platform 118c2ecf20Sopenharmony_ci * Copyright (C) 2014-15, Intel Corporation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/firmware.h> 218c2ecf20Sopenharmony_ci#include <linux/device.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "../common/sst-dsp.h" 248c2ecf20Sopenharmony_ci#include "../common/sst-dsp-priv.h" 258c2ecf20Sopenharmony_ci#include "../common/sst-ipc.h" 268c2ecf20Sopenharmony_ci#include "cnl-sst-dsp.h" 278c2ecf20Sopenharmony_ci#include "skl.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define CNL_FW_ROM_INIT 0x1 308c2ecf20Sopenharmony_ci#define CNL_FW_INIT 0x5 318c2ecf20Sopenharmony_ci#define CNL_IPC_PURGE 0x01004000 328c2ecf20Sopenharmony_ci#define CNL_INIT_TIMEOUT 300 338c2ecf20Sopenharmony_ci#define CNL_BASEFW_TIMEOUT 3000 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define CNL_ADSP_SRAM0_BASE 0x80000 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Firmware status window */ 388c2ecf20Sopenharmony_ci#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE 398c2ecf20Sopenharmony_ci#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define CNL_INSTANCE_ID 0 428c2ecf20Sopenharmony_ci#define CNL_BASE_FW_MODULE_ID 0 438c2ecf20Sopenharmony_ci#define CNL_ADSP_FW_HDR_OFFSET 0x2000 448c2ecf20Sopenharmony_ci#define CNL_ROM_CTRL_DMA_ID 0x9 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci int ret, stream_tag; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); 528c2ecf20Sopenharmony_ci if (stream_tag <= 0) { 538c2ecf20Sopenharmony_ci dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag); 548c2ecf20Sopenharmony_ci return stream_tag; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ctx->dsp_ops.stream_tag = stream_tag; 588c2ecf20Sopenharmony_ci memcpy(ctx->dmab.area, fwdata, fwsize); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK); 618c2ecf20Sopenharmony_ci if (ret < 0) { 628c2ecf20Sopenharmony_ci dev_err(ctx->dev, "dsp core0 power up failed\n"); 638c2ecf20Sopenharmony_ci ret = -EIO; 648c2ecf20Sopenharmony_ci goto base_fw_load_failed; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* purge FW request */ 688c2ecf20Sopenharmony_ci sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR, 698c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE | 708c2ecf20Sopenharmony_ci ((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID))); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); 738c2ecf20Sopenharmony_ci if (ret < 0) { 748c2ecf20Sopenharmony_ci dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret); 758c2ecf20Sopenharmony_ci ret = -EIO; 768c2ecf20Sopenharmony_ci goto base_fw_load_failed; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci ret = sst_dsp_register_poll(ctx, CNL_ADSP_REG_HIPCIDA, 808c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCIDA_DONE, 818c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCIDA_DONE, 828c2ecf20Sopenharmony_ci BXT_INIT_TIMEOUT, "HIPCIDA Done"); 838c2ecf20Sopenharmony_ci if (ret < 0) { 848c2ecf20Sopenharmony_ci dev_err(ctx->dev, "timeout for purge request: %d\n", ret); 858c2ecf20Sopenharmony_ci goto base_fw_load_failed; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* enable interrupt */ 898c2ecf20Sopenharmony_ci cnl_ipc_int_enable(ctx); 908c2ecf20Sopenharmony_ci cnl_ipc_op_int_enable(ctx); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, 938c2ecf20Sopenharmony_ci CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT, 948c2ecf20Sopenharmony_ci "rom load"); 958c2ecf20Sopenharmony_ci if (ret < 0) { 968c2ecf20Sopenharmony_ci dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret); 978c2ecf20Sopenharmony_ci goto base_fw_load_failed; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cibase_fw_load_failed: 1038c2ecf20Sopenharmony_ci ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); 1048c2ecf20Sopenharmony_ci cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return ret; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int sst_transfer_fw_host_dma(struct sst_dsp *ctx) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int ret; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag); 1148c2ecf20Sopenharmony_ci ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, 1158c2ecf20Sopenharmony_ci CNL_FW_INIT, CNL_BASEFW_TIMEOUT, 1168c2ecf20Sopenharmony_ci "firmware boot"); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag); 1198c2ecf20Sopenharmony_ci ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return ret; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int cnl_load_base_firmware(struct sst_dsp *ctx) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct firmware stripped_fw; 1278c2ecf20Sopenharmony_ci struct skl_dev *cnl = ctx->thread_context; 1288c2ecf20Sopenharmony_ci int ret, i; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (!ctx->fw) { 1318c2ecf20Sopenharmony_ci ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); 1328c2ecf20Sopenharmony_ci if (ret < 0) { 1338c2ecf20Sopenharmony_ci dev_err(ctx->dev, "request firmware failed: %d\n", ret); 1348c2ecf20Sopenharmony_ci goto cnl_load_base_firmware_failed; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* parse uuids if first boot */ 1398c2ecf20Sopenharmony_ci if (cnl->is_first_boot) { 1408c2ecf20Sopenharmony_ci ret = snd_skl_parse_uuids(ctx, ctx->fw, 1418c2ecf20Sopenharmony_ci CNL_ADSP_FW_HDR_OFFSET, 0); 1428c2ecf20Sopenharmony_ci if (ret < 0) 1438c2ecf20Sopenharmony_ci goto cnl_load_base_firmware_failed; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci stripped_fw.data = ctx->fw->data; 1478c2ecf20Sopenharmony_ci stripped_fw.size = ctx->fw->size; 1488c2ecf20Sopenharmony_ci skl_dsp_strip_extended_manifest(&stripped_fw); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { 1518c2ecf20Sopenharmony_ci ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); 1528c2ecf20Sopenharmony_ci if (!ret) 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci dev_dbg(ctx->dev, "prepare firmware failed: %d\n", ret); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (ret < 0) 1588c2ecf20Sopenharmony_ci goto cnl_load_base_firmware_failed; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = sst_transfer_fw_host_dma(ctx); 1618c2ecf20Sopenharmony_ci if (ret < 0) { 1628c2ecf20Sopenharmony_ci dev_err(ctx->dev, "transfer firmware failed: %d\n", ret); 1638c2ecf20Sopenharmony_ci cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); 1648c2ecf20Sopenharmony_ci goto cnl_load_base_firmware_failed; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, 1688c2ecf20Sopenharmony_ci msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); 1698c2ecf20Sopenharmony_ci if (ret == 0) { 1708c2ecf20Sopenharmony_ci dev_err(ctx->dev, "FW ready timed-out\n"); 1718c2ecf20Sopenharmony_ci cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); 1728c2ecf20Sopenharmony_ci ret = -EIO; 1738c2ecf20Sopenharmony_ci goto cnl_load_base_firmware_failed; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci cnl->fw_loaded = true; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cicnl_load_base_firmware_failed: 1818c2ecf20Sopenharmony_ci dev_err(ctx->dev, "firmware load failed: %d\n", ret); 1828c2ecf20Sopenharmony_ci release_firmware(ctx->fw); 1838c2ecf20Sopenharmony_ci ctx->fw = NULL; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct skl_dev *cnl = ctx->thread_context; 1918c2ecf20Sopenharmony_ci unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); 1928c2ecf20Sopenharmony_ci struct skl_ipc_dxstate_info dx; 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (!cnl->fw_loaded) { 1968c2ecf20Sopenharmony_ci cnl->boot_complete = false; 1978c2ecf20Sopenharmony_ci ret = cnl_load_base_firmware(ctx); 1988c2ecf20Sopenharmony_ci if (ret < 0) { 1998c2ecf20Sopenharmony_ci dev_err(ctx->dev, "fw reload failed: %d\n", ret); 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci cnl->cores.state[core_id] = SKL_DSP_RUNNING; 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = cnl_dsp_enable_core(ctx, core_mask); 2088c2ecf20Sopenharmony_ci if (ret < 0) { 2098c2ecf20Sopenharmony_ci dev_err(ctx->dev, "enable dsp core %d failed: %d\n", 2108c2ecf20Sopenharmony_ci core_id, ret); 2118c2ecf20Sopenharmony_ci goto err; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (core_id == SKL_DSP_CORE0_ID) { 2158c2ecf20Sopenharmony_ci /* enable interrupt */ 2168c2ecf20Sopenharmony_ci cnl_ipc_int_enable(ctx); 2178c2ecf20Sopenharmony_ci cnl_ipc_op_int_enable(ctx); 2188c2ecf20Sopenharmony_ci cnl->boot_complete = false; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, 2218c2ecf20Sopenharmony_ci msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); 2228c2ecf20Sopenharmony_ci if (ret == 0) { 2238c2ecf20Sopenharmony_ci dev_err(ctx->dev, 2248c2ecf20Sopenharmony_ci "dsp boot timeout, status=%#x error=%#x\n", 2258c2ecf20Sopenharmony_ci sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS), 2268c2ecf20Sopenharmony_ci sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE)); 2278c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 2288c2ecf20Sopenharmony_ci goto err; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci } else { 2318c2ecf20Sopenharmony_ci dx.core_mask = core_mask; 2328c2ecf20Sopenharmony_ci dx.dx_mask = core_mask; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, 2358c2ecf20Sopenharmony_ci CNL_BASE_FW_MODULE_ID, &dx); 2368c2ecf20Sopenharmony_ci if (ret < 0) { 2378c2ecf20Sopenharmony_ci dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n", 2388c2ecf20Sopenharmony_ci core_id, ret); 2398c2ecf20Sopenharmony_ci goto err; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci cnl->cores.state[core_id] = SKL_DSP_RUNNING; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_cierr: 2468c2ecf20Sopenharmony_ci cnl_dsp_disable_core(ctx, core_mask); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct skl_dev *cnl = ctx->thread_context; 2548c2ecf20Sopenharmony_ci unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); 2558c2ecf20Sopenharmony_ci struct skl_ipc_dxstate_info dx; 2568c2ecf20Sopenharmony_ci int ret; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci dx.core_mask = core_mask; 2598c2ecf20Sopenharmony_ci dx.dx_mask = SKL_IPC_D3_MASK; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, 2628c2ecf20Sopenharmony_ci CNL_BASE_FW_MODULE_ID, &dx); 2638c2ecf20Sopenharmony_ci if (ret < 0) { 2648c2ecf20Sopenharmony_ci dev_err(ctx->dev, 2658c2ecf20Sopenharmony_ci "dsp core %d to d3 failed; continue reset\n", 2668c2ecf20Sopenharmony_ci core_id); 2678c2ecf20Sopenharmony_ci cnl->fw_loaded = false; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* disable interrupts if core 0 */ 2718c2ecf20Sopenharmony_ci if (core_id == SKL_DSP_CORE0_ID) { 2728c2ecf20Sopenharmony_ci skl_ipc_op_int_disable(ctx); 2738c2ecf20Sopenharmony_ci skl_ipc_int_disable(ctx); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci ret = cnl_dsp_disable_core(ctx, core_mask); 2778c2ecf20Sopenharmony_ci if (ret < 0) { 2788c2ecf20Sopenharmony_ci dev_err(ctx->dev, "disable dsp core %d failed: %d\n", 2798c2ecf20Sopenharmony_ci core_id, ret); 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci cnl->cores.state[core_id] = SKL_DSP_RESET; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic unsigned int cnl_get_errno(struct sst_dsp *ctx) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic const struct skl_dsp_fw_ops cnl_fw_ops = { 2948c2ecf20Sopenharmony_ci .set_state_D0 = cnl_set_dsp_D0, 2958c2ecf20Sopenharmony_ci .set_state_D3 = cnl_set_dsp_D3, 2968c2ecf20Sopenharmony_ci .load_fw = cnl_load_base_firmware, 2978c2ecf20Sopenharmony_ci .get_fw_errcode = cnl_get_errno, 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic struct sst_ops cnl_ops = { 3018c2ecf20Sopenharmony_ci .irq_handler = cnl_dsp_sst_interrupt, 3028c2ecf20Sopenharmony_ci .write = sst_shim32_write, 3038c2ecf20Sopenharmony_ci .read = sst_shim32_read, 3048c2ecf20Sopenharmony_ci .free = cnl_dsp_free, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29 3088c2ecf20Sopenharmony_ci#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1 3098c2ecf20Sopenharmony_ci#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \ 3108c2ecf20Sopenharmony_ci & CNL_IPC_GLB_NOTIFY_RSP_MASK) 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct sst_dsp *dsp = context; 3158c2ecf20Sopenharmony_ci struct skl_dev *cnl = dsp->thread_context; 3168c2ecf20Sopenharmony_ci struct sst_generic_ipc *ipc = &cnl->ipc; 3178c2ecf20Sopenharmony_ci struct skl_ipc_header header = {0}; 3188c2ecf20Sopenharmony_ci u32 hipcida, hipctdr, hipctdd; 3198c2ecf20Sopenharmony_ci int ipc_irq = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* here we handle ipc interrupts only */ 3228c2ecf20Sopenharmony_ci if (!(dsp->intr_status & CNL_ADSPIS_IPC)) 3238c2ecf20Sopenharmony_ci return IRQ_NONE; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA); 3268c2ecf20Sopenharmony_ci hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR); 3278c2ecf20Sopenharmony_ci hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* reply message from dsp */ 3308c2ecf20Sopenharmony_ci if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) { 3318c2ecf20Sopenharmony_ci sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, 3328c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCCTL_DONE, 0); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* clear done bit - tell dsp operation is complete */ 3358c2ecf20Sopenharmony_ci sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA, 3368c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ipc_irq = 1; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* unmask done interrupt */ 3418c2ecf20Sopenharmony_ci sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, 3428c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* new message from dsp */ 3468c2ecf20Sopenharmony_ci if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) { 3478c2ecf20Sopenharmony_ci header.primary = hipctdr; 3488c2ecf20Sopenharmony_ci header.extension = hipctdd; 3498c2ecf20Sopenharmony_ci dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", 3508c2ecf20Sopenharmony_ci header.primary); 3518c2ecf20Sopenharmony_ci dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", 3528c2ecf20Sopenharmony_ci header.extension); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { 3558c2ecf20Sopenharmony_ci /* Handle Immediate reply from DSP Core */ 3568c2ecf20Sopenharmony_ci skl_ipc_process_reply(ipc, header); 3578c2ecf20Sopenharmony_ci } else { 3588c2ecf20Sopenharmony_ci dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); 3598c2ecf20Sopenharmony_ci skl_ipc_process_notification(ipc, header); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci /* clear busy interrupt */ 3628c2ecf20Sopenharmony_ci sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR, 3638c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* set done bit to ack dsp */ 3668c2ecf20Sopenharmony_ci sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA, 3678c2ecf20Sopenharmony_ci CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE); 3688c2ecf20Sopenharmony_ci ipc_irq = 1; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (ipc_irq == 0) 3728c2ecf20Sopenharmony_ci return IRQ_NONE; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci cnl_ipc_int_enable(dsp); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* continue to send any remaining messages */ 3778c2ecf20Sopenharmony_ci schedule_work(&ipc->kwork); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic struct sst_dsp_device cnl_dev = { 3838c2ecf20Sopenharmony_ci .thread = cnl_dsp_irq_thread_handler, 3848c2ecf20Sopenharmony_ci .ops = &cnl_ops, 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (msg->tx.size) 3928c2ecf20Sopenharmony_ci sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); 3938c2ecf20Sopenharmony_ci sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD, 3948c2ecf20Sopenharmony_ci header->extension); 3958c2ecf20Sopenharmony_ci sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR, 3968c2ecf20Sopenharmony_ci header->primary | CNL_ADSP_REG_HIPCIDR_BUSY); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci u32 hipcidr; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int cnl_ipc_init(struct device *dev, struct skl_dev *cnl) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct sst_generic_ipc *ipc; 4118c2ecf20Sopenharmony_ci int err; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci ipc = &cnl->ipc; 4148c2ecf20Sopenharmony_ci ipc->dsp = cnl->dsp; 4158c2ecf20Sopenharmony_ci ipc->dev = dev; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ipc->tx_data_max_size = CNL_ADSP_W1_SZ; 4188c2ecf20Sopenharmony_ci ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci err = sst_ipc_init(ipc); 4218c2ecf20Sopenharmony_ci if (err) 4228c2ecf20Sopenharmony_ci return err; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* 4258c2ecf20Sopenharmony_ci * overriding tx_msg and is_dsp_busy since 4268c2ecf20Sopenharmony_ci * ipc registers are different for cnl 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci ipc->ops.tx_msg = cnl_ipc_tx_msg; 4298c2ecf20Sopenharmony_ci ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; 4308c2ecf20Sopenharmony_ci ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ciint cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, 4368c2ecf20Sopenharmony_ci const char *fw_name, struct skl_dsp_loader_ops dsp_ops, 4378c2ecf20Sopenharmony_ci struct skl_dev **dsp) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct skl_dev *cnl; 4408c2ecf20Sopenharmony_ci struct sst_dsp *sst; 4418c2ecf20Sopenharmony_ci int ret; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev); 4448c2ecf20Sopenharmony_ci if (ret < 0) { 4458c2ecf20Sopenharmony_ci dev_err(dev, "%s: no device\n", __func__); 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci cnl = *dsp; 4508c2ecf20Sopenharmony_ci sst = cnl->dsp; 4518c2ecf20Sopenharmony_ci sst->fw_ops = cnl_fw_ops; 4528c2ecf20Sopenharmony_ci sst->addr.lpe = mmio_base; 4538c2ecf20Sopenharmony_ci sst->addr.shim = mmio_base; 4548c2ecf20Sopenharmony_ci sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE; 4558c2ecf20Sopenharmony_ci sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE; 4568c2ecf20Sopenharmony_ci sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ; 4578c2ecf20Sopenharmony_ci sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ), 4608c2ecf20Sopenharmony_ci CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE, 4618c2ecf20Sopenharmony_ci CNL_ADSP_W1_SZ); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ret = cnl_ipc_init(dev, cnl); 4648c2ecf20Sopenharmony_ci if (ret) { 4658c2ecf20Sopenharmony_ci skl_dsp_free(sst); 4668c2ecf20Sopenharmony_ci return ret; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci cnl->boot_complete = false; 4708c2ecf20Sopenharmony_ci init_waitqueue_head(&cnl->boot_wait); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return skl_dsp_acquire_irq(sst); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cnl_sst_dsp_init); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ciint cnl_sst_init_fw(struct device *dev, struct skl_dev *skl) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci int ret; 4798c2ecf20Sopenharmony_ci struct sst_dsp *sst = skl->dsp; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci ret = skl->dsp->fw_ops.load_fw(sst); 4828c2ecf20Sopenharmony_ci if (ret < 0) { 4838c2ecf20Sopenharmony_ci dev_err(dev, "load base fw failed: %d", ret); 4848c2ecf20Sopenharmony_ci return ret; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci skl_dsp_init_core_state(sst); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci skl->is_first_boot = false; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cnl_sst_init_fw); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_civoid cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci if (skl->dsp->fw) 4988c2ecf20Sopenharmony_ci release_firmware(skl->dsp->fw); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci skl_freeup_uuid_list(skl); 5018c2ecf20Sopenharmony_ci cnl_ipc_free(&skl->ipc); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci skl->dsp->ops->free(skl->dsp); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5088c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Cannonlake IPC driver"); 509