162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cnl-sst.c - DSP library functions for CNL platform 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016-17, Intel Corporation. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Guneshwor Singh <guneshwor.o.singh@intel.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Modified from: 1062306a36Sopenharmony_ci * HDA DSP library functions for SKL platform 1162306a36Sopenharmony_ci * Copyright (C) 2014-15, Intel Corporation. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/firmware.h> 2162306a36Sopenharmony_ci#include <linux/device.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "../common/sst-dsp.h" 2462306a36Sopenharmony_ci#include "../common/sst-dsp-priv.h" 2562306a36Sopenharmony_ci#include "../common/sst-ipc.h" 2662306a36Sopenharmony_ci#include "cnl-sst-dsp.h" 2762306a36Sopenharmony_ci#include "skl.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define CNL_FW_ROM_INIT 0x1 3062306a36Sopenharmony_ci#define CNL_FW_INIT 0x5 3162306a36Sopenharmony_ci#define CNL_IPC_PURGE 0x01004000 3262306a36Sopenharmony_ci#define CNL_INIT_TIMEOUT 300 3362306a36Sopenharmony_ci#define CNL_BASEFW_TIMEOUT 3000 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define CNL_ADSP_SRAM0_BASE 0x80000 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Firmware status window */ 3862306a36Sopenharmony_ci#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE 3962306a36Sopenharmony_ci#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define CNL_INSTANCE_ID 0 4262306a36Sopenharmony_ci#define CNL_BASE_FW_MODULE_ID 0 4362306a36Sopenharmony_ci#define CNL_ADSP_FW_HDR_OFFSET 0x2000 4462306a36Sopenharmony_ci#define CNL_ROM_CTRL_DMA_ID 0x9 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci int ret, stream_tag; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); 5262306a36Sopenharmony_ci if (stream_tag <= 0) { 5362306a36Sopenharmony_ci dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag); 5462306a36Sopenharmony_ci return stream_tag; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ctx->dsp_ops.stream_tag = stream_tag; 5862306a36Sopenharmony_ci memcpy(ctx->dmab.area, fwdata, fwsize); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK); 6162306a36Sopenharmony_ci if (ret < 0) { 6262306a36Sopenharmony_ci dev_err(ctx->dev, "dsp core0 power up failed\n"); 6362306a36Sopenharmony_ci ret = -EIO; 6462306a36Sopenharmony_ci goto base_fw_load_failed; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* purge FW request */ 6862306a36Sopenharmony_ci sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR, 6962306a36Sopenharmony_ci CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE | 7062306a36Sopenharmony_ci ((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID))); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); 7362306a36Sopenharmony_ci if (ret < 0) { 7462306a36Sopenharmony_ci dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret); 7562306a36Sopenharmony_ci ret = -EIO; 7662306a36Sopenharmony_ci goto base_fw_load_failed; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci ret = sst_dsp_register_poll(ctx, CNL_ADSP_REG_HIPCIDA, 8062306a36Sopenharmony_ci CNL_ADSP_REG_HIPCIDA_DONE, 8162306a36Sopenharmony_ci CNL_ADSP_REG_HIPCIDA_DONE, 8262306a36Sopenharmony_ci BXT_INIT_TIMEOUT, "HIPCIDA Done"); 8362306a36Sopenharmony_ci if (ret < 0) { 8462306a36Sopenharmony_ci dev_err(ctx->dev, "timeout for purge request: %d\n", ret); 8562306a36Sopenharmony_ci goto base_fw_load_failed; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* enable interrupt */ 8962306a36Sopenharmony_ci cnl_ipc_int_enable(ctx); 9062306a36Sopenharmony_ci cnl_ipc_op_int_enable(ctx); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, 9362306a36Sopenharmony_ci CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT, 9462306a36Sopenharmony_ci "rom load"); 9562306a36Sopenharmony_ci if (ret < 0) { 9662306a36Sopenharmony_ci dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret); 9762306a36Sopenharmony_ci goto base_fw_load_failed; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cibase_fw_load_failed: 10362306a36Sopenharmony_ci ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); 10462306a36Sopenharmony_ci cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return ret; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int sst_transfer_fw_host_dma(struct sst_dsp *ctx) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci int ret; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag); 11462306a36Sopenharmony_ci ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, 11562306a36Sopenharmony_ci CNL_FW_INIT, CNL_BASEFW_TIMEOUT, 11662306a36Sopenharmony_ci "firmware boot"); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag); 11962306a36Sopenharmony_ci ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return ret; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int cnl_load_base_firmware(struct sst_dsp *ctx) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct firmware stripped_fw; 12762306a36Sopenharmony_ci struct skl_dev *cnl = ctx->thread_context; 12862306a36Sopenharmony_ci int ret, i; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (!ctx->fw) { 13162306a36Sopenharmony_ci ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); 13262306a36Sopenharmony_ci if (ret < 0) { 13362306a36Sopenharmony_ci dev_err(ctx->dev, "request firmware failed: %d\n", ret); 13462306a36Sopenharmony_ci goto cnl_load_base_firmware_failed; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* parse uuids if first boot */ 13962306a36Sopenharmony_ci if (cnl->is_first_boot) { 14062306a36Sopenharmony_ci ret = snd_skl_parse_uuids(ctx, ctx->fw, 14162306a36Sopenharmony_ci CNL_ADSP_FW_HDR_OFFSET, 0); 14262306a36Sopenharmony_ci if (ret < 0) 14362306a36Sopenharmony_ci goto cnl_load_base_firmware_failed; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci stripped_fw.data = ctx->fw->data; 14762306a36Sopenharmony_ci stripped_fw.size = ctx->fw->size; 14862306a36Sopenharmony_ci skl_dsp_strip_extended_manifest(&stripped_fw); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { 15162306a36Sopenharmony_ci ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); 15262306a36Sopenharmony_ci if (!ret) 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci dev_dbg(ctx->dev, "prepare firmware failed: %d\n", ret); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (ret < 0) 15862306a36Sopenharmony_ci goto cnl_load_base_firmware_failed; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ret = sst_transfer_fw_host_dma(ctx); 16162306a36Sopenharmony_ci if (ret < 0) { 16262306a36Sopenharmony_ci dev_err(ctx->dev, "transfer firmware failed: %d\n", ret); 16362306a36Sopenharmony_ci cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); 16462306a36Sopenharmony_ci goto cnl_load_base_firmware_failed; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, 16862306a36Sopenharmony_ci msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); 16962306a36Sopenharmony_ci if (ret == 0) { 17062306a36Sopenharmony_ci dev_err(ctx->dev, "FW ready timed-out\n"); 17162306a36Sopenharmony_ci cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); 17262306a36Sopenharmony_ci ret = -EIO; 17362306a36Sopenharmony_ci goto cnl_load_base_firmware_failed; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci cnl->fw_loaded = true; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cicnl_load_base_firmware_failed: 18162306a36Sopenharmony_ci dev_err(ctx->dev, "firmware load failed: %d\n", ret); 18262306a36Sopenharmony_ci release_firmware(ctx->fw); 18362306a36Sopenharmony_ci ctx->fw = NULL; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return ret; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct skl_dev *cnl = ctx->thread_context; 19162306a36Sopenharmony_ci unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); 19262306a36Sopenharmony_ci struct skl_ipc_dxstate_info dx; 19362306a36Sopenharmony_ci int ret; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (!cnl->fw_loaded) { 19662306a36Sopenharmony_ci cnl->boot_complete = false; 19762306a36Sopenharmony_ci ret = cnl_load_base_firmware(ctx); 19862306a36Sopenharmony_ci if (ret < 0) { 19962306a36Sopenharmony_ci dev_err(ctx->dev, "fw reload failed: %d\n", ret); 20062306a36Sopenharmony_ci return ret; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci cnl->cores.state[core_id] = SKL_DSP_RUNNING; 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ret = cnl_dsp_enable_core(ctx, core_mask); 20862306a36Sopenharmony_ci if (ret < 0) { 20962306a36Sopenharmony_ci dev_err(ctx->dev, "enable dsp core %d failed: %d\n", 21062306a36Sopenharmony_ci core_id, ret); 21162306a36Sopenharmony_ci goto err; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (core_id == SKL_DSP_CORE0_ID) { 21562306a36Sopenharmony_ci /* enable interrupt */ 21662306a36Sopenharmony_ci cnl_ipc_int_enable(ctx); 21762306a36Sopenharmony_ci cnl_ipc_op_int_enable(ctx); 21862306a36Sopenharmony_ci cnl->boot_complete = false; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, 22162306a36Sopenharmony_ci msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); 22262306a36Sopenharmony_ci if (ret == 0) { 22362306a36Sopenharmony_ci dev_err(ctx->dev, 22462306a36Sopenharmony_ci "dsp boot timeout, status=%#x error=%#x\n", 22562306a36Sopenharmony_ci sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS), 22662306a36Sopenharmony_ci sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE)); 22762306a36Sopenharmony_ci ret = -ETIMEDOUT; 22862306a36Sopenharmony_ci goto err; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci } else { 23162306a36Sopenharmony_ci dx.core_mask = core_mask; 23262306a36Sopenharmony_ci dx.dx_mask = core_mask; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, 23562306a36Sopenharmony_ci CNL_BASE_FW_MODULE_ID, &dx); 23662306a36Sopenharmony_ci if (ret < 0) { 23762306a36Sopenharmony_ci dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n", 23862306a36Sopenharmony_ci core_id, ret); 23962306a36Sopenharmony_ci goto err; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci cnl->cores.state[core_id] = SKL_DSP_RUNNING; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_cierr: 24662306a36Sopenharmony_ci cnl_dsp_disable_core(ctx, core_mask); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return ret; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct skl_dev *cnl = ctx->thread_context; 25462306a36Sopenharmony_ci unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); 25562306a36Sopenharmony_ci struct skl_ipc_dxstate_info dx; 25662306a36Sopenharmony_ci int ret; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci dx.core_mask = core_mask; 25962306a36Sopenharmony_ci dx.dx_mask = SKL_IPC_D3_MASK; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, 26262306a36Sopenharmony_ci CNL_BASE_FW_MODULE_ID, &dx); 26362306a36Sopenharmony_ci if (ret < 0) { 26462306a36Sopenharmony_ci dev_err(ctx->dev, 26562306a36Sopenharmony_ci "dsp core %d to d3 failed; continue reset\n", 26662306a36Sopenharmony_ci core_id); 26762306a36Sopenharmony_ci cnl->fw_loaded = false; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* disable interrupts if core 0 */ 27162306a36Sopenharmony_ci if (core_id == SKL_DSP_CORE0_ID) { 27262306a36Sopenharmony_ci skl_ipc_op_int_disable(ctx); 27362306a36Sopenharmony_ci skl_ipc_int_disable(ctx); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ret = cnl_dsp_disable_core(ctx, core_mask); 27762306a36Sopenharmony_ci if (ret < 0) { 27862306a36Sopenharmony_ci dev_err(ctx->dev, "disable dsp core %d failed: %d\n", 27962306a36Sopenharmony_ci core_id, ret); 28062306a36Sopenharmony_ci return ret; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci cnl->cores.state[core_id] = SKL_DSP_RESET; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic unsigned int cnl_get_errno(struct sst_dsp *ctx) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic const struct skl_dsp_fw_ops cnl_fw_ops = { 29462306a36Sopenharmony_ci .set_state_D0 = cnl_set_dsp_D0, 29562306a36Sopenharmony_ci .set_state_D3 = cnl_set_dsp_D3, 29662306a36Sopenharmony_ci .load_fw = cnl_load_base_firmware, 29762306a36Sopenharmony_ci .get_fw_errcode = cnl_get_errno, 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic struct sst_ops cnl_ops = { 30162306a36Sopenharmony_ci .irq_handler = cnl_dsp_sst_interrupt, 30262306a36Sopenharmony_ci .write = sst_shim32_write, 30362306a36Sopenharmony_ci .read = sst_shim32_read, 30462306a36Sopenharmony_ci .free = cnl_dsp_free, 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29 30862306a36Sopenharmony_ci#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1 30962306a36Sopenharmony_ci#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \ 31062306a36Sopenharmony_ci & CNL_IPC_GLB_NOTIFY_RSP_MASK) 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct sst_dsp *dsp = context; 31562306a36Sopenharmony_ci struct skl_dev *cnl = dsp->thread_context; 31662306a36Sopenharmony_ci struct sst_generic_ipc *ipc = &cnl->ipc; 31762306a36Sopenharmony_ci struct skl_ipc_header header = {0}; 31862306a36Sopenharmony_ci u32 hipcida, hipctdr, hipctdd; 31962306a36Sopenharmony_ci int ipc_irq = 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* here we handle ipc interrupts only */ 32262306a36Sopenharmony_ci if (!(dsp->intr_status & CNL_ADSPIS_IPC)) 32362306a36Sopenharmony_ci return IRQ_NONE; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA); 32662306a36Sopenharmony_ci hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR); 32762306a36Sopenharmony_ci hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* reply message from dsp */ 33062306a36Sopenharmony_ci if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) { 33162306a36Sopenharmony_ci sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, 33262306a36Sopenharmony_ci CNL_ADSP_REG_HIPCCTL_DONE, 0); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* clear done bit - tell dsp operation is complete */ 33562306a36Sopenharmony_ci sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA, 33662306a36Sopenharmony_ci CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci ipc_irq = 1; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* unmask done interrupt */ 34162306a36Sopenharmony_ci sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, 34262306a36Sopenharmony_ci CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* new message from dsp */ 34662306a36Sopenharmony_ci if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) { 34762306a36Sopenharmony_ci header.primary = hipctdr; 34862306a36Sopenharmony_ci header.extension = hipctdd; 34962306a36Sopenharmony_ci dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", 35062306a36Sopenharmony_ci header.primary); 35162306a36Sopenharmony_ci dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", 35262306a36Sopenharmony_ci header.extension); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { 35562306a36Sopenharmony_ci /* Handle Immediate reply from DSP Core */ 35662306a36Sopenharmony_ci skl_ipc_process_reply(ipc, header); 35762306a36Sopenharmony_ci } else { 35862306a36Sopenharmony_ci dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); 35962306a36Sopenharmony_ci skl_ipc_process_notification(ipc, header); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci /* clear busy interrupt */ 36262306a36Sopenharmony_ci sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR, 36362306a36Sopenharmony_ci CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* set done bit to ack dsp */ 36662306a36Sopenharmony_ci sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA, 36762306a36Sopenharmony_ci CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE); 36862306a36Sopenharmony_ci ipc_irq = 1; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (ipc_irq == 0) 37262306a36Sopenharmony_ci return IRQ_NONE; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci cnl_ipc_int_enable(dsp); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* continue to send any remaining messages */ 37762306a36Sopenharmony_ci schedule_work(&ipc->kwork); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return IRQ_HANDLED; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic struct sst_dsp_device cnl_dev = { 38362306a36Sopenharmony_ci .thread = cnl_dsp_irq_thread_handler, 38462306a36Sopenharmony_ci .ops = &cnl_ops, 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (msg->tx.size) 39262306a36Sopenharmony_ci sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); 39362306a36Sopenharmony_ci sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD, 39462306a36Sopenharmony_ci header->extension); 39562306a36Sopenharmony_ci sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR, 39662306a36Sopenharmony_ci header->primary | CNL_ADSP_REG_HIPCIDR_BUSY); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci u32 hipcidr; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int cnl_ipc_init(struct device *dev, struct skl_dev *cnl) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct sst_generic_ipc *ipc; 41162306a36Sopenharmony_ci int err; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ipc = &cnl->ipc; 41462306a36Sopenharmony_ci ipc->dsp = cnl->dsp; 41562306a36Sopenharmony_ci ipc->dev = dev; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci ipc->tx_data_max_size = CNL_ADSP_W1_SZ; 41862306a36Sopenharmony_ci ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci err = sst_ipc_init(ipc); 42162306a36Sopenharmony_ci if (err) 42262306a36Sopenharmony_ci return err; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * overriding tx_msg and is_dsp_busy since 42662306a36Sopenharmony_ci * ipc registers are different for cnl 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci ipc->ops.tx_msg = cnl_ipc_tx_msg; 42962306a36Sopenharmony_ci ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; 43062306a36Sopenharmony_ci ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ciint cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, 43662306a36Sopenharmony_ci const char *fw_name, struct skl_dsp_loader_ops dsp_ops, 43762306a36Sopenharmony_ci struct skl_dev **dsp) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct skl_dev *cnl; 44062306a36Sopenharmony_ci struct sst_dsp *sst; 44162306a36Sopenharmony_ci int ret; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev); 44462306a36Sopenharmony_ci if (ret < 0) { 44562306a36Sopenharmony_ci dev_err(dev, "%s: no device\n", __func__); 44662306a36Sopenharmony_ci return ret; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci cnl = *dsp; 45062306a36Sopenharmony_ci sst = cnl->dsp; 45162306a36Sopenharmony_ci sst->fw_ops = cnl_fw_ops; 45262306a36Sopenharmony_ci sst->addr.lpe = mmio_base; 45362306a36Sopenharmony_ci sst->addr.shim = mmio_base; 45462306a36Sopenharmony_ci sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE; 45562306a36Sopenharmony_ci sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE; 45662306a36Sopenharmony_ci sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ; 45762306a36Sopenharmony_ci sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ), 46062306a36Sopenharmony_ci CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE, 46162306a36Sopenharmony_ci CNL_ADSP_W1_SZ); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ret = cnl_ipc_init(dev, cnl); 46462306a36Sopenharmony_ci if (ret) { 46562306a36Sopenharmony_ci skl_dsp_free(sst); 46662306a36Sopenharmony_ci return ret; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci cnl->boot_complete = false; 47062306a36Sopenharmony_ci init_waitqueue_head(&cnl->boot_wait); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return skl_dsp_acquire_irq(sst); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cnl_sst_dsp_init); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciint cnl_sst_init_fw(struct device *dev, struct skl_dev *skl) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci int ret; 47962306a36Sopenharmony_ci struct sst_dsp *sst = skl->dsp; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci ret = skl->dsp->fw_ops.load_fw(sst); 48262306a36Sopenharmony_ci if (ret < 0) { 48362306a36Sopenharmony_ci dev_err(dev, "load base fw failed: %d", ret); 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci skl_dsp_init_core_state(sst); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci skl->is_first_boot = false; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cnl_sst_init_fw); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_civoid cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci if (skl->dsp->fw) 49862306a36Sopenharmony_ci release_firmware(skl->dsp->fw); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci skl_freeup_uuid_list(skl); 50162306a36Sopenharmony_ci cnl_ipc_free(&skl->ipc); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci skl->dsp->ops->free(skl->dsp); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 50862306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel Cannonlake IPC driver"); 509