1*a750ba5fSSubhransu S. Prusty /* 2*a750ba5fSSubhransu S. Prusty * skl-sst.c - HDA DSP library functions for SKL platform 3*a750ba5fSSubhransu S. Prusty * 4*a750ba5fSSubhransu S. Prusty * Copyright (C) 2014-15, Intel Corporation. 5*a750ba5fSSubhransu S. Prusty * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> 6*a750ba5fSSubhransu S. Prusty * Jeeja KP <jeeja.kp@intel.com> 7*a750ba5fSSubhransu S. Prusty * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8*a750ba5fSSubhransu S. Prusty * 9*a750ba5fSSubhransu S. Prusty * This program is free software; you can redistribute it and/or modify 10*a750ba5fSSubhransu S. Prusty * it under the terms of the GNU General Public License as version 2, as 11*a750ba5fSSubhransu S. Prusty * published by the Free Software Foundation. 12*a750ba5fSSubhransu S. Prusty * 13*a750ba5fSSubhransu S. Prusty * This program is distributed in the hope that it will be useful, but 14*a750ba5fSSubhransu S. Prusty * WITHOUT ANY WARRANTY; without even the implied warranty of 15*a750ba5fSSubhransu S. Prusty * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16*a750ba5fSSubhransu S. Prusty * General Public License for more details. 17*a750ba5fSSubhransu S. Prusty */ 18*a750ba5fSSubhransu S. Prusty 19*a750ba5fSSubhransu S. Prusty #include <linux/module.h> 20*a750ba5fSSubhransu S. Prusty #include <linux/delay.h> 21*a750ba5fSSubhransu S. Prusty #include <linux/device.h> 22*a750ba5fSSubhransu S. Prusty #include "../common/sst-dsp.h" 23*a750ba5fSSubhransu S. Prusty #include "../common/sst-dsp-priv.h" 24*a750ba5fSSubhransu S. Prusty #include "../common/sst-ipc.h" 25*a750ba5fSSubhransu S. Prusty #include "skl-sst-ipc.h" 26*a750ba5fSSubhransu S. Prusty 27*a750ba5fSSubhransu S. Prusty #define SKL_BASEFW_TIMEOUT 300 28*a750ba5fSSubhransu S. Prusty #define SKL_INIT_TIMEOUT 1000 29*a750ba5fSSubhransu S. Prusty 30*a750ba5fSSubhransu S. Prusty /* Intel HD Audio SRAM Window 0*/ 31*a750ba5fSSubhransu S. Prusty #define SKL_ADSP_SRAM0_BASE 0x8000 32*a750ba5fSSubhransu S. Prusty 33*a750ba5fSSubhransu S. Prusty /* Firmware status window */ 34*a750ba5fSSubhransu S. Prusty #define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE 35*a750ba5fSSubhransu S. Prusty #define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) 36*a750ba5fSSubhransu S. Prusty 37*a750ba5fSSubhransu S. Prusty #define SKL_INSTANCE_ID 0 38*a750ba5fSSubhransu S. Prusty #define SKL_BASE_FW_MODULE_ID 0 39*a750ba5fSSubhransu S. Prusty 40*a750ba5fSSubhransu S. Prusty static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) 41*a750ba5fSSubhransu S. Prusty { 42*a750ba5fSSubhransu S. Prusty u32 cur_sts; 43*a750ba5fSSubhransu S. Prusty 44*a750ba5fSSubhransu S. Prusty cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK; 45*a750ba5fSSubhransu S. Prusty 46*a750ba5fSSubhransu S. Prusty return (cur_sts == status); 47*a750ba5fSSubhransu S. Prusty } 48*a750ba5fSSubhransu S. Prusty 49*a750ba5fSSubhransu S. Prusty static int skl_transfer_firmware(struct sst_dsp *ctx, 50*a750ba5fSSubhransu S. Prusty const void *basefw, u32 base_fw_size) 51*a750ba5fSSubhransu S. Prusty { 52*a750ba5fSSubhransu S. Prusty int ret = 0; 53*a750ba5fSSubhransu S. Prusty 54*a750ba5fSSubhransu S. Prusty ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); 55*a750ba5fSSubhransu S. Prusty if (ret < 0) 56*a750ba5fSSubhransu S. Prusty return ret; 57*a750ba5fSSubhransu S. Prusty 58*a750ba5fSSubhransu S. Prusty ret = sst_dsp_register_poll(ctx, 59*a750ba5fSSubhransu S. Prusty SKL_ADSP_FW_STATUS, 60*a750ba5fSSubhransu S. Prusty SKL_FW_STS_MASK, 61*a750ba5fSSubhransu S. Prusty SKL_FW_RFW_START, 62*a750ba5fSSubhransu S. Prusty SKL_BASEFW_TIMEOUT, 63*a750ba5fSSubhransu S. Prusty "Firmware boot"); 64*a750ba5fSSubhransu S. Prusty 65*a750ba5fSSubhransu S. Prusty ctx->cl_dev.ops.cl_stop_dma(ctx); 66*a750ba5fSSubhransu S. Prusty 67*a750ba5fSSubhransu S. Prusty return ret; 68*a750ba5fSSubhransu S. Prusty } 69*a750ba5fSSubhransu S. Prusty 70*a750ba5fSSubhransu S. Prusty static int skl_load_base_firmware(struct sst_dsp *ctx) 71*a750ba5fSSubhransu S. Prusty { 72*a750ba5fSSubhransu S. Prusty int ret = 0, i; 73*a750ba5fSSubhransu S. Prusty const struct firmware *fw = NULL; 74*a750ba5fSSubhransu S. Prusty struct skl_sst *skl = ctx->thread_context; 75*a750ba5fSSubhransu S. Prusty u32 reg; 76*a750ba5fSSubhransu S. Prusty 77*a750ba5fSSubhransu S. Prusty ret = request_firmware(&fw, "dsp_fw_release.bin", ctx->dev); 78*a750ba5fSSubhransu S. Prusty if (ret < 0) { 79*a750ba5fSSubhransu S. Prusty dev_err(ctx->dev, "Request firmware failed %d\n", ret); 80*a750ba5fSSubhransu S. Prusty skl_dsp_disable_core(ctx); 81*a750ba5fSSubhransu S. Prusty return -EIO; 82*a750ba5fSSubhransu S. Prusty } 83*a750ba5fSSubhransu S. Prusty 84*a750ba5fSSubhransu S. Prusty /* enable Interrupt */ 85*a750ba5fSSubhransu S. Prusty skl_ipc_int_enable(ctx); 86*a750ba5fSSubhransu S. Prusty skl_ipc_op_int_enable(ctx); 87*a750ba5fSSubhransu S. Prusty 88*a750ba5fSSubhransu S. Prusty /* check ROM Status */ 89*a750ba5fSSubhransu S. Prusty for (i = SKL_INIT_TIMEOUT; i > 0; --i) { 90*a750ba5fSSubhransu S. Prusty if (skl_check_fw_status(ctx, SKL_FW_INIT)) { 91*a750ba5fSSubhransu S. Prusty dev_dbg(ctx->dev, 92*a750ba5fSSubhransu S. Prusty "ROM loaded, we can continue with FW loading\n"); 93*a750ba5fSSubhransu S. Prusty break; 94*a750ba5fSSubhransu S. Prusty } 95*a750ba5fSSubhransu S. Prusty mdelay(1); 96*a750ba5fSSubhransu S. Prusty } 97*a750ba5fSSubhransu S. Prusty if (!i) { 98*a750ba5fSSubhransu S. Prusty reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS); 99*a750ba5fSSubhransu S. Prusty dev_err(ctx->dev, 100*a750ba5fSSubhransu S. Prusty "Timeout waiting for ROM init done, reg:0x%x\n", reg); 101*a750ba5fSSubhransu S. Prusty ret = -EIO; 102*a750ba5fSSubhransu S. Prusty goto skl_load_base_firmware_failed; 103*a750ba5fSSubhransu S. Prusty } 104*a750ba5fSSubhransu S. Prusty 105*a750ba5fSSubhransu S. Prusty ret = skl_transfer_firmware(ctx, fw->data, fw->size); 106*a750ba5fSSubhransu S. Prusty if (ret < 0) { 107*a750ba5fSSubhransu S. Prusty dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); 108*a750ba5fSSubhransu S. Prusty goto skl_load_base_firmware_failed; 109*a750ba5fSSubhransu S. Prusty } else { 110*a750ba5fSSubhransu S. Prusty ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, 111*a750ba5fSSubhransu S. Prusty msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); 112*a750ba5fSSubhransu S. Prusty if (ret == 0) { 113*a750ba5fSSubhransu S. Prusty dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); 114*a750ba5fSSubhransu S. Prusty ret = -EIO; 115*a750ba5fSSubhransu S. Prusty goto skl_load_base_firmware_failed; 116*a750ba5fSSubhransu S. Prusty } 117*a750ba5fSSubhransu S. Prusty 118*a750ba5fSSubhransu S. Prusty dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); 119*a750ba5fSSubhransu S. Prusty skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); 120*a750ba5fSSubhransu S. Prusty } 121*a750ba5fSSubhransu S. Prusty release_firmware(fw); 122*a750ba5fSSubhransu S. Prusty 123*a750ba5fSSubhransu S. Prusty return 0; 124*a750ba5fSSubhransu S. Prusty 125*a750ba5fSSubhransu S. Prusty skl_load_base_firmware_failed: 126*a750ba5fSSubhransu S. Prusty skl_dsp_disable_core(ctx); 127*a750ba5fSSubhransu S. Prusty release_firmware(fw); 128*a750ba5fSSubhransu S. Prusty return ret; 129*a750ba5fSSubhransu S. Prusty } 130*a750ba5fSSubhransu S. Prusty 131*a750ba5fSSubhransu S. Prusty static int skl_set_dsp_D0(struct sst_dsp *ctx) 132*a750ba5fSSubhransu S. Prusty { 133*a750ba5fSSubhransu S. Prusty int ret; 134*a750ba5fSSubhransu S. Prusty 135*a750ba5fSSubhransu S. Prusty ret = skl_load_base_firmware(ctx); 136*a750ba5fSSubhransu S. Prusty if (ret < 0) { 137*a750ba5fSSubhransu S. Prusty dev_err(ctx->dev, "unable to load firmware\n"); 138*a750ba5fSSubhransu S. Prusty return ret; 139*a750ba5fSSubhransu S. Prusty } 140*a750ba5fSSubhransu S. Prusty 141*a750ba5fSSubhransu S. Prusty skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); 142*a750ba5fSSubhransu S. Prusty 143*a750ba5fSSubhransu S. Prusty return ret; 144*a750ba5fSSubhransu S. Prusty } 145*a750ba5fSSubhransu S. Prusty 146*a750ba5fSSubhransu S. Prusty static int skl_set_dsp_D3(struct sst_dsp *ctx) 147*a750ba5fSSubhransu S. Prusty { 148*a750ba5fSSubhransu S. Prusty int ret; 149*a750ba5fSSubhransu S. Prusty struct skl_ipc_dxstate_info dx; 150*a750ba5fSSubhransu S. Prusty struct skl_sst *skl = ctx->thread_context; 151*a750ba5fSSubhransu S. Prusty 152*a750ba5fSSubhransu S. Prusty dev_dbg(ctx->dev, "In %s:\n", __func__); 153*a750ba5fSSubhransu S. Prusty mutex_lock(&ctx->mutex); 154*a750ba5fSSubhransu S. Prusty if (!is_skl_dsp_running(ctx)) { 155*a750ba5fSSubhransu S. Prusty mutex_unlock(&ctx->mutex); 156*a750ba5fSSubhransu S. Prusty return 0; 157*a750ba5fSSubhransu S. Prusty } 158*a750ba5fSSubhransu S. Prusty mutex_unlock(&ctx->mutex); 159*a750ba5fSSubhransu S. Prusty 160*a750ba5fSSubhransu S. Prusty dx.core_mask = SKL_DSP_CORE0_MASK; 161*a750ba5fSSubhransu S. Prusty dx.dx_mask = SKL_IPC_D3_MASK; 162*a750ba5fSSubhransu S. Prusty ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); 163*a750ba5fSSubhransu S. Prusty if (ret < 0) { 164*a750ba5fSSubhransu S. Prusty dev_err(ctx->dev, "Failed to set DSP to D3 state\n"); 165*a750ba5fSSubhransu S. Prusty return ret; 166*a750ba5fSSubhransu S. Prusty } 167*a750ba5fSSubhransu S. Prusty 168*a750ba5fSSubhransu S. Prusty ret = skl_dsp_disable_core(ctx); 169*a750ba5fSSubhransu S. Prusty if (ret < 0) { 170*a750ba5fSSubhransu S. Prusty dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret); 171*a750ba5fSSubhransu S. Prusty ret = -EIO; 172*a750ba5fSSubhransu S. Prusty } 173*a750ba5fSSubhransu S. Prusty skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); 174*a750ba5fSSubhransu S. Prusty 175*a750ba5fSSubhransu S. Prusty return ret; 176*a750ba5fSSubhransu S. Prusty } 177*a750ba5fSSubhransu S. Prusty 178*a750ba5fSSubhransu S. Prusty static unsigned int skl_get_errorcode(struct sst_dsp *ctx) 179*a750ba5fSSubhransu S. Prusty { 180*a750ba5fSSubhransu S. Prusty return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); 181*a750ba5fSSubhransu S. Prusty } 182*a750ba5fSSubhransu S. Prusty 183*a750ba5fSSubhransu S. Prusty static struct skl_dsp_fw_ops skl_fw_ops = { 184*a750ba5fSSubhransu S. Prusty .set_state_D0 = skl_set_dsp_D0, 185*a750ba5fSSubhransu S. Prusty .set_state_D3 = skl_set_dsp_D3, 186*a750ba5fSSubhransu S. Prusty .load_fw = skl_load_base_firmware, 187*a750ba5fSSubhransu S. Prusty .get_fw_errcode = skl_get_errorcode, 188*a750ba5fSSubhransu S. Prusty }; 189*a750ba5fSSubhransu S. Prusty 190*a750ba5fSSubhransu S. Prusty static struct sst_ops skl_ops = { 191*a750ba5fSSubhransu S. Prusty .irq_handler = skl_dsp_sst_interrupt, 192*a750ba5fSSubhransu S. Prusty .write = sst_shim32_write, 193*a750ba5fSSubhransu S. Prusty .read = sst_shim32_read, 194*a750ba5fSSubhransu S. Prusty .ram_read = sst_memcpy_fromio_32, 195*a750ba5fSSubhransu S. Prusty .ram_write = sst_memcpy_toio_32, 196*a750ba5fSSubhransu S. Prusty .free = skl_dsp_free, 197*a750ba5fSSubhransu S. Prusty }; 198*a750ba5fSSubhransu S. Prusty 199*a750ba5fSSubhransu S. Prusty static struct sst_dsp_device skl_dev = { 200*a750ba5fSSubhransu S. Prusty .thread = skl_dsp_irq_thread_handler, 201*a750ba5fSSubhransu S. Prusty .ops = &skl_ops, 202*a750ba5fSSubhransu S. Prusty }; 203*a750ba5fSSubhransu S. Prusty 204*a750ba5fSSubhransu S. Prusty int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, 205*a750ba5fSSubhransu S. Prusty struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) 206*a750ba5fSSubhransu S. Prusty { 207*a750ba5fSSubhransu S. Prusty struct skl_sst *skl; 208*a750ba5fSSubhransu S. Prusty struct sst_dsp *sst; 209*a750ba5fSSubhransu S. Prusty int ret; 210*a750ba5fSSubhransu S. Prusty 211*a750ba5fSSubhransu S. Prusty skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); 212*a750ba5fSSubhransu S. Prusty if (skl == NULL) 213*a750ba5fSSubhransu S. Prusty return -ENOMEM; 214*a750ba5fSSubhransu S. Prusty 215*a750ba5fSSubhransu S. Prusty skl->dev = dev; 216*a750ba5fSSubhransu S. Prusty skl_dev.thread_context = skl; 217*a750ba5fSSubhransu S. Prusty 218*a750ba5fSSubhransu S. Prusty skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); 219*a750ba5fSSubhransu S. Prusty if (!skl->dsp) { 220*a750ba5fSSubhransu S. Prusty dev_err(skl->dev, "%s: no device\n", __func__); 221*a750ba5fSSubhransu S. Prusty return -ENODEV; 222*a750ba5fSSubhransu S. Prusty } 223*a750ba5fSSubhransu S. Prusty 224*a750ba5fSSubhransu S. Prusty sst = skl->dsp; 225*a750ba5fSSubhransu S. Prusty 226*a750ba5fSSubhransu S. Prusty sst->addr.lpe = mmio_base; 227*a750ba5fSSubhransu S. Prusty sst->addr.shim = mmio_base; 228*a750ba5fSSubhransu S. Prusty sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), 229*a750ba5fSSubhransu S. Prusty SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); 230*a750ba5fSSubhransu S. Prusty 231*a750ba5fSSubhransu S. Prusty sst->dsp_ops = dsp_ops; 232*a750ba5fSSubhransu S. Prusty sst->fw_ops = skl_fw_ops; 233*a750ba5fSSubhransu S. Prusty 234*a750ba5fSSubhransu S. Prusty ret = skl_ipc_init(dev, skl); 235*a750ba5fSSubhransu S. Prusty if (ret) 236*a750ba5fSSubhransu S. Prusty return ret; 237*a750ba5fSSubhransu S. Prusty 238*a750ba5fSSubhransu S. Prusty skl->boot_complete = false; 239*a750ba5fSSubhransu S. Prusty init_waitqueue_head(&skl->boot_wait); 240*a750ba5fSSubhransu S. Prusty 241*a750ba5fSSubhransu S. Prusty ret = skl_dsp_boot(sst); 242*a750ba5fSSubhransu S. Prusty if (ret < 0) { 243*a750ba5fSSubhransu S. Prusty dev_err(skl->dev, "Boot dsp core failed ret: %d", ret); 244*a750ba5fSSubhransu S. Prusty goto free_ipc; 245*a750ba5fSSubhransu S. Prusty } 246*a750ba5fSSubhransu S. Prusty 247*a750ba5fSSubhransu S. Prusty ret = skl_cldma_prepare(sst); 248*a750ba5fSSubhransu S. Prusty if (ret < 0) { 249*a750ba5fSSubhransu S. Prusty dev_err(dev, "CL dma prepare failed : %d", ret); 250*a750ba5fSSubhransu S. Prusty goto free_ipc; 251*a750ba5fSSubhransu S. Prusty } 252*a750ba5fSSubhransu S. Prusty 253*a750ba5fSSubhransu S. Prusty 254*a750ba5fSSubhransu S. Prusty ret = sst->fw_ops.load_fw(sst); 255*a750ba5fSSubhransu S. Prusty if (ret < 0) { 256*a750ba5fSSubhransu S. Prusty dev_err(dev, "Load base fw failed : %d", ret); 257*a750ba5fSSubhransu S. Prusty return ret; 258*a750ba5fSSubhransu S. Prusty } 259*a750ba5fSSubhransu S. Prusty 260*a750ba5fSSubhransu S. Prusty if (dsp) 261*a750ba5fSSubhransu S. Prusty *dsp = skl; 262*a750ba5fSSubhransu S. Prusty 263*a750ba5fSSubhransu S. Prusty return 0; 264*a750ba5fSSubhransu S. Prusty 265*a750ba5fSSubhransu S. Prusty free_ipc: 266*a750ba5fSSubhransu S. Prusty skl_ipc_free(&skl->ipc); 267*a750ba5fSSubhransu S. Prusty return ret; 268*a750ba5fSSubhransu S. Prusty } 269*a750ba5fSSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_sst_dsp_init); 270*a750ba5fSSubhransu S. Prusty 271*a750ba5fSSubhransu S. Prusty void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) 272*a750ba5fSSubhransu S. Prusty { 273*a750ba5fSSubhransu S. Prusty skl_ipc_free(&ctx->ipc); 274*a750ba5fSSubhransu S. Prusty ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); 275*a750ba5fSSubhransu S. Prusty ctx->dsp->ops->free(ctx->dsp); 276*a750ba5fSSubhransu S. Prusty } 277*a750ba5fSSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); 278*a750ba5fSSubhransu S. Prusty 279*a750ba5fSSubhransu S. Prusty MODULE_LICENSE("GPL v2"); 280*a750ba5fSSubhransu S. Prusty MODULE_DESCRIPTION("Intel Skylake IPC driver"); 281