static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) { u32 hipci; hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); return (hipci & SKL_ADSP_REG_HIPCI_BUSY); }
/* Get the mask for all enabled cores */ unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx) { struct skl_sst *skl = ctx->thread_context; unsigned int core_mask, en_cores_mask; u32 val; core_mask = SKL_DSP_CORES_MASK(skl->cores.count); val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); /* Cores having CPA bit set */ en_cores_mask = (val & SKL_ADSPCS_CPA_MASK(core_mask)) >> SKL_ADSPCS_CPA_SHIFT; /* And cores having CRST bit cleared */ en_cores_mask &= (~val & SKL_ADSPCS_CRST_MASK(core_mask)) >> SKL_ADSPCS_CRST_SHIFT; /* And cores having CSTALL bit cleared */ en_cores_mask &= (~val & SKL_ADSPCS_CSTALL_MASK(core_mask)) >> SKL_ADSPCS_CSTALL_SHIFT; en_cores_mask &= core_mask; dev_dbg(ctx->dev, "DSP enabled cores mask = %x\n", en_cores_mask); return en_cores_mask; }
static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask) { int ret; /* update bits */ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask), SKL_ADSPCS_CRST_MASK(core_mask)); /* poll with timeout to check if operation successful */ ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask), SKL_ADSPCS_CRST_MASK(core_mask), SKL_DSP_RESET_TO, "Set reset"); if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & SKL_ADSPCS_CRST_MASK(core_mask)) != SKL_ADSPCS_CRST_MASK(core_mask)) { dev_err(ctx->dev, "Set reset state failed: core_mask %x\n", core_mask); ret = -EIO; } return ret; }
int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask) { int ret; /* update bits */ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_SPA_MASK(core_mask), SKL_ADSPCS_SPA_MASK(core_mask)); /* poll with timeout to check if operation successful */ ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CPA_MASK(core_mask), SKL_ADSPCS_CPA_MASK(core_mask), SKL_DSP_PU_TO, "Power up"); if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & SKL_ADSPCS_CPA_MASK(core_mask)) != SKL_ADSPCS_CPA_MASK(core_mask)) { dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n", core_mask); ret = -EIO; } return ret; }
irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) { struct sst_dsp *ctx = dev_id; u32 val; irqreturn_t result = IRQ_NONE; spin_lock(&ctx->spinlock); val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS); ctx->intr_status = val; if (val == 0xffffffff) { spin_unlock(&ctx->spinlock); return IRQ_NONE; } if (val & SKL_ADSPIS_IPC) { skl_ipc_int_disable(ctx); result = IRQ_WAKE_THREAD; } if (val & SKL_ADSPIS_CL_DMA) { skl_cldma_int_disable(ctx); result = IRQ_WAKE_THREAD; } spin_unlock(&ctx->spinlock); return result; }
static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) { int ret; dev_dbg(ctx->dev, "In %s\n", __func__); /* update bits */ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK, 0); /* poll with timeout to check if operation successful */ ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK, 0, SKL_DSP_RESET_TO, "Unset reset"); if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) { dev_err(ctx->dev, "Unset reset state failed\n"); ret = -EIO; } return ret; }
static int skl_dsp_start_core(struct sst_dsp *ctx) { int ret; /* unset reset state */ ret = skl_dsp_core_unset_reset_state(ctx); if (ret < 0) { dev_dbg(ctx->dev, "dsp unset reset fails\n"); return ret; } /* run core */ dev_dbg(ctx->dev, "run core...\n"); sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & ~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); if (!is_skl_dsp_core_enable(ctx)) { skl_dsp_reset_core(ctx); dev_err(ctx->dev, "DSP core enable failed\n"); ret = -EIO; } return ret; }
static int skl_dsp_reset_core(struct sst_dsp *ctx) { /* stall core */ sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); /* set reset state */ return skl_dsp_core_set_reset_state(ctx); }
void skl_cldma_process_intr(struct sst_dsp *ctx) { u8 cl_dma_intr_status; cl_dma_intr_status = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS); if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE)) ctx->cl_dev.wake_status = SKL_CL_DMA_ERR; else ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE; ctx->cl_dev.wait_condition = true; wake_up(&ctx->cl_dev.wait_queue); }
static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) { int val; bool is_enable; val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) && (val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) && !(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) && !(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK))); dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable); return is_enable; }
static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask) { int val; bool is_enable; val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS); is_enable = (val & CNL_ADSPCS_CPA(core_mask)) && (val & CNL_ADSPCS_SPA(core_mask)) && !(val & CNL_ADSPCS_CRST(core_mask)) && !(val & CNL_ADSPCS_CSTALL(core_mask)); dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n", is_enable, core_mask); return is_enable; }
bool skl_ipc_int_status(struct sst_dsp *ctx) { return sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; }
irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) { struct sst_dsp *dsp = context; struct skl_sst *skl = sst_dsp_get_thread_context(dsp); struct sst_generic_ipc *ipc = &skl->ipc; struct skl_ipc_header header = {0}; u32 hipcie, hipct, hipcte; int ipc_irq = 0; if (dsp->intr_status & SKL_ADSPIS_CL_DMA) skl_cldma_process_intr(dsp); /* Here we handle IPC interrupts only */ if (!(dsp->intr_status & SKL_ADSPIS_IPC)) return IRQ_NONE; hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); /* reply message from DSP */ if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, SKL_ADSP_REG_HIPCCTL_DONE, 0); /* clear DONE bit - tell DSP we have completed the operation */ sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); ipc_irq = 1; /* unmask Done interrupt */ sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); } /* New message from DSP */ if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); header.primary = hipct; header.extension = hipcte; dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", header.primary); dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", header.extension); if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { /* Handle Immediate reply from DSP Core */ skl_ipc_process_reply(ipc, header); } else { dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); skl_ipc_process_notification(ipc, header); } /* clear busy interrupt */ sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); ipc_irq = 1; } if (ipc_irq == 0) return IRQ_NONE; skl_ipc_int_enable(dsp); /* continue to send any remaining messages... */ queue_kthread_work(&ipc->kworker, &ipc->kwork); return IRQ_HANDLED; }