diff options
Diffstat (limited to 'sound/soc/intel/skylake/skl-sst-dsp.c')
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-dsp.c | 260 |
1 files changed, 186 insertions, 74 deletions
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 13c19855ee1a..c3deefab65d6 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -34,33 +34,84 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) mutex_unlock(&ctx->mutex); } -static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) +/* + * Initialize core power state and usage count. To be called after + * successful first boot. Hence core 0 will be running and other cores + * will be reset + */ +void skl_dsp_init_core_state(struct sst_dsp *ctx) +{ + struct skl_sst *skl = ctx->thread_context; + int i; + + skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; + skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1; + + for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) { + skl->cores.state[i] = SKL_DSP_RESET; + skl->cores.usage_count[i] = 0; + } +} + +/* 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, - SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)); + 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, - SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK), + 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(SKL_DSP_CORES_MASK)) != - SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) { - dev_err(ctx->dev, "Set reset state failed\n"); + 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; } -static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) +int skl_dsp_core_unset_reset_state( + struct sst_dsp *ctx, unsigned int core_mask) { int ret; @@ -68,152 +119,160 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) /* update bits */ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK, 0); + SKL_ADSPCS_CRST_MASK(core_mask), 0); /* poll with timeout to check if operation successful */ ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK, + SKL_ADSPCS_CRST_MASK(core_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"); + SKL_ADSPCS_CRST_MASK(core_mask)) != 0) { + dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n", + core_mask); ret = -EIO; } return ret; } -static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) +static bool +is_skl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask) { 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))); + is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) && + (val & SKL_ADSPCS_SPA_MASK(core_mask)) && + !(val & SKL_ADSPCS_CRST_MASK(core_mask)) && + !(val & SKL_ADSPCS_CSTALL_MASK(core_mask))); + + dev_dbg(ctx->dev, "DSP core(s) enabled? %d : core_mask %x\n", + is_enable, core_mask); - dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable); return is_enable; } -static int skl_dsp_reset_core(struct sst_dsp *ctx) +static int skl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask) { /* 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)); + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CSTALL_MASK(core_mask), + SKL_ADSPCS_CSTALL_MASK(core_mask)); /* set reset state */ - return skl_dsp_core_set_reset_state(ctx); + return skl_dsp_core_set_reset_state(ctx, core_mask); } -static int skl_dsp_start_core(struct sst_dsp *ctx) +int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask) { 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"); + ret = skl_dsp_core_unset_reset_state(ctx, core_mask); + if (ret < 0) 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"); + dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask); + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CSTALL_MASK(core_mask), 0); + + if (!is_skl_dsp_core_enable(ctx, core_mask)) { + skl_dsp_reset_core(ctx, core_mask); + dev_err(ctx->dev, "DSP start core failed: core_mask %x\n", + core_mask); ret = -EIO; } return ret; } -static int skl_dsp_core_power_up(struct sst_dsp *ctx) +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, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)); + 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, - SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK), + 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(SKL_DSP_CORES_MASK)) != - SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) { - dev_err(ctx->dev, "DSP core power up failed\n"); + 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; } -static int skl_dsp_core_power_down(struct sst_dsp *ctx) +int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask) { /* update bits */ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_SPA_MASK, 0); + SKL_ADSPCS_SPA_MASK(core_mask), 0); /* poll with timeout to check if operation successful */ return sst_dsp_register_poll(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CPA_MASK, + SKL_ADSPCS_CPA_MASK(core_mask), 0, SKL_DSP_PD_TO, "Power down"); } -int skl_dsp_enable_core(struct sst_dsp *ctx) +int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask) { int ret; /* power up */ - ret = skl_dsp_core_power_up(ctx); + ret = skl_dsp_core_power_up(ctx, core_mask); if (ret < 0) { - dev_dbg(ctx->dev, "dsp core power up failed\n"); + dev_err(ctx->dev, "dsp core power up failed: core_mask %x\n", + core_mask); return ret; } - return skl_dsp_start_core(ctx); + return skl_dsp_start_core(ctx, core_mask); } -int skl_dsp_disable_core(struct sst_dsp *ctx) +int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask) { int ret; - ret = skl_dsp_reset_core(ctx); + ret = skl_dsp_reset_core(ctx, core_mask); if (ret < 0) { - dev_err(ctx->dev, "dsp core reset failed\n"); + dev_err(ctx->dev, "dsp core reset failed: core_mask %x\n", + core_mask); return ret; } /* power down core*/ - ret = skl_dsp_core_power_down(ctx); + ret = skl_dsp_core_power_down(ctx, core_mask); if (ret < 0) { - dev_err(ctx->dev, "dsp core power down failed\n"); + dev_err(ctx->dev, "dsp core power down fail mask %x: %d\n", + core_mask, ret); return ret; } - if (is_skl_dsp_core_enable(ctx)) { - dev_err(ctx->dev, "DSP core disable failed\n"); + if (is_skl_dsp_core_enable(ctx, core_mask)) { + dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n", + core_mask, ret); ret = -EIO; } @@ -224,28 +283,25 @@ int skl_dsp_boot(struct sst_dsp *ctx) { int ret; - if (is_skl_dsp_core_enable(ctx)) { - dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n"); - ret = skl_dsp_reset_core(ctx); + if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) { + ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK); if (ret < 0) { - dev_err(ctx->dev, "dsp reset failed\n"); + dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret); return ret; } - ret = skl_dsp_start_core(ctx); + ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); if (ret < 0) { - dev_err(ctx->dev, "dsp start failed\n"); + dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret); return ret; } } else { - dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n"); - ret = skl_dsp_disable_core(ctx); - + ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); if (ret < 0) { - dev_err(ctx->dev, "dsp disable core failes\n"); + dev_err(ctx->dev, "dsp core0 disable fail: %d\n", ret); return ret; } - ret = skl_dsp_enable_core(ctx); + ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK); } return ret; @@ -281,16 +337,74 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) return result; } +/* + * skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context + * within the dapm mutex. Hence no separate lock is used. + */ +int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) +{ + struct skl_sst *skl = ctx->thread_context; + int ret = 0; + + if (core_id >= skl->cores.count) { + dev_err(ctx->dev, "invalid core id: %d\n", core_id); + return -EINVAL; + } + + if (skl->cores.state[core_id] == SKL_DSP_RESET) { + ret = ctx->fw_ops.set_state_D0(ctx, core_id); + if (ret < 0) { + dev_err(ctx->dev, "unable to get core%d\n", core_id); + return ret; + } + } + + skl->cores.usage_count[core_id]++; + + dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", + core_id, skl->cores.state[core_id], + skl->cores.usage_count[core_id]); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_dsp_get_core); + +int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) +{ + struct skl_sst *skl = ctx->thread_context; + int ret = 0; + + if (core_id >= skl->cores.count) { + dev_err(ctx->dev, "invalid core id: %d\n", core_id); + return -EINVAL; + } + + if (--skl->cores.usage_count[core_id] == 0) { + ret = ctx->fw_ops.set_state_D3(ctx, core_id); + if (ret < 0) { + dev_err(ctx->dev, "unable to put core %d: %d\n", + core_id, ret); + skl->cores.usage_count[core_id]++; + } + } + + dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", + core_id, skl->cores.state[core_id], + skl->cores.usage_count[core_id]); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_dsp_put_core); int skl_dsp_wake(struct sst_dsp *ctx) { - return ctx->fw_ops.set_state_D0(ctx); + return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID); } EXPORT_SYMBOL_GPL(skl_dsp_wake); int skl_dsp_sleep(struct sst_dsp *ctx) { - return ctx->fw_ops.set_state_D3(ctx); + return skl_dsp_put_core(ctx, SKL_DSP_CORE0_ID); } EXPORT_SYMBOL_GPL(skl_dsp_sleep); @@ -337,9 +451,7 @@ void skl_dsp_free(struct sst_dsp *dsp) free_irq(dsp->irq, dsp); skl_ipc_op_int_disable(dsp); - skl_ipc_int_disable(dsp); - - skl_dsp_disable_core(dsp); + skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK); } EXPORT_SYMBOL_GPL(skl_dsp_free); |