Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
0004 //
0005 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
0006 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
0007 //
0008 
0009 #include <sound/hdaudio_ext.h>
0010 #include "avs.h"
0011 #include "registers.h"
0012 #include "trace.h"
0013 
0014 #define AVS_ADSPCS_INTERVAL_US      500
0015 #define AVS_ADSPCS_TIMEOUT_US       50000
0016 #define AVS_ADSPCS_DELAY_US     1000
0017 
0018 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
0019 {
0020     u32 value, mask, reg;
0021     int ret;
0022 
0023     value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
0024     trace_avs_dsp_core_op(value, core_mask, "power", power);
0025 
0026     mask = AVS_ADSPCS_SPA_MASK(core_mask);
0027     value = power ? mask : 0;
0028 
0029     snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
0030     /* Delay the polling to avoid false positives. */
0031     usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
0032 
0033     mask = AVS_ADSPCS_CPA_MASK(core_mask);
0034     value = power ? mask : 0;
0035 
0036     ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
0037                        reg, (reg & mask) == value,
0038                        AVS_ADSPCS_INTERVAL_US,
0039                        AVS_ADSPCS_TIMEOUT_US);
0040     if (ret)
0041         dev_err(adev->dev, "core_mask %d power %s failed: %d\n",
0042             core_mask, power ? "on" : "off", ret);
0043 
0044     return ret;
0045 }
0046 
0047 int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset)
0048 {
0049     u32 value, mask, reg;
0050     int ret;
0051 
0052     value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
0053     trace_avs_dsp_core_op(value, core_mask, "reset", reset);
0054 
0055     mask = AVS_ADSPCS_CRST_MASK(core_mask);
0056     value = reset ? mask : 0;
0057 
0058     snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
0059 
0060     ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
0061                        reg, (reg & mask) == value,
0062                        AVS_ADSPCS_INTERVAL_US,
0063                        AVS_ADSPCS_TIMEOUT_US);
0064     if (ret)
0065         dev_err(adev->dev, "core_mask %d %s reset failed: %d\n",
0066             core_mask, reset ? "enter" : "exit", ret);
0067 
0068     return ret;
0069 }
0070 
0071 int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
0072 {
0073     u32 value, mask, reg;
0074     int ret;
0075 
0076     value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
0077     trace_avs_dsp_core_op(value, core_mask, "stall", stall);
0078 
0079     mask = AVS_ADSPCS_CSTALL_MASK(core_mask);
0080     value = stall ? mask : 0;
0081 
0082     snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
0083 
0084     ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
0085                        reg, (reg & mask) == value,
0086                        AVS_ADSPCS_INTERVAL_US,
0087                        AVS_ADSPCS_TIMEOUT_US);
0088     if (ret) {
0089         dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
0090             core_mask, stall ? "" : "un", ret);
0091         return ret;
0092     }
0093 
0094     /* Give HW time to propagate the change. */
0095     usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
0096     return 0;
0097 }
0098 
0099 int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask)
0100 {
0101     int ret;
0102 
0103     ret = avs_dsp_op(adev, power, core_mask, true);
0104     if (ret)
0105         return ret;
0106 
0107     ret = avs_dsp_op(adev, reset, core_mask, false);
0108     if (ret)
0109         return ret;
0110 
0111     return avs_dsp_op(adev, stall, core_mask, false);
0112 }
0113 
0114 int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask)
0115 {
0116     /* No error checks to allow for complete DSP shutdown. */
0117     avs_dsp_op(adev, stall, core_mask, true);
0118     avs_dsp_op(adev, reset, core_mask, true);
0119 
0120     return avs_dsp_op(adev, power, core_mask, false);
0121 }
0122 
0123 static int avs_dsp_enable(struct avs_dev *adev, u32 core_mask)
0124 {
0125     u32 mask;
0126     int ret;
0127 
0128     ret = avs_dsp_core_enable(adev, core_mask);
0129     if (ret < 0)
0130         return ret;
0131 
0132     mask = core_mask & ~AVS_MAIN_CORE_MASK;
0133     if (!mask)
0134         /*
0135          * without main core, fw is dead anyway
0136          * so setting D0 for it is futile.
0137          */
0138         return 0;
0139 
0140     ret = avs_ipc_set_dx(adev, mask, true);
0141     return AVS_IPC_RET(ret);
0142 }
0143 
0144 static int avs_dsp_disable(struct avs_dev *adev, u32 core_mask)
0145 {
0146     int ret;
0147 
0148     ret = avs_ipc_set_dx(adev, core_mask, false);
0149     if (ret)
0150         return AVS_IPC_RET(ret);
0151 
0152     return avs_dsp_core_disable(adev, core_mask);
0153 }
0154 
0155 static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
0156 {
0157     u32 mask;
0158     int ret;
0159 
0160     mask = BIT_MASK(core_id);
0161     if (mask == AVS_MAIN_CORE_MASK)
0162         /* nothing to do for main core */
0163         return 0;
0164     if (core_id >= adev->hw_cfg.dsp_cores) {
0165         ret = -EINVAL;
0166         goto err;
0167     }
0168 
0169     adev->core_refs[core_id]++;
0170     if (adev->core_refs[core_id] == 1) {
0171         /*
0172          * No cores other than main-core can be running for DSP
0173          * to achieve d0ix. Conscious SET_D0IX IPC failure is permitted,
0174          * simply d0ix power state will no longer be attempted.
0175          */
0176         ret = avs_dsp_disable_d0ix(adev);
0177         if (ret && ret != -AVS_EIPC)
0178             goto err_disable_d0ix;
0179 
0180         ret = avs_dsp_enable(adev, mask);
0181         if (ret)
0182             goto err_enable_dsp;
0183     }
0184 
0185     return 0;
0186 
0187 err_enable_dsp:
0188     avs_dsp_enable_d0ix(adev);
0189 err_disable_d0ix:
0190     adev->core_refs[core_id]--;
0191 err:
0192     dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
0193     return ret;
0194 }
0195 
0196 static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id)
0197 {
0198     u32 mask;
0199     int ret;
0200 
0201     mask = BIT_MASK(core_id);
0202     if (mask == AVS_MAIN_CORE_MASK)
0203         /* nothing to do for main core */
0204         return 0;
0205     if (core_id >= adev->hw_cfg.dsp_cores) {
0206         ret = -EINVAL;
0207         goto err;
0208     }
0209 
0210     adev->core_refs[core_id]--;
0211     if (!adev->core_refs[core_id]) {
0212         ret = avs_dsp_disable(adev, mask);
0213         if (ret)
0214             goto err;
0215 
0216         /* Match disable_d0ix in avs_dsp_get_core(). */
0217         avs_dsp_enable_d0ix(adev);
0218     }
0219 
0220     return 0;
0221 err:
0222     dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret);
0223     return ret;
0224 }
0225 
0226 int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
0227             u8 core_id, u8 domain, void *param, u32 param_size,
0228             u16 *instance_id)
0229 {
0230     struct avs_module_entry mentry;
0231     bool was_loaded = false;
0232     int ret, id;
0233 
0234     id = avs_module_id_alloc(adev, module_id);
0235     if (id < 0)
0236         return id;
0237 
0238     ret = avs_get_module_id_entry(adev, module_id, &mentry);
0239     if (ret)
0240         goto err_mod_entry;
0241 
0242     ret = avs_dsp_get_core(adev, core_id);
0243     if (ret)
0244         goto err_mod_entry;
0245 
0246     /* Load code into memory if this is the first instance. */
0247     if (!id && !avs_module_entry_is_loaded(&mentry)) {
0248         ret = avs_dsp_op(adev, transfer_mods, true, &mentry, 1);
0249         if (ret) {
0250             dev_err(adev->dev, "load modules failed: %d\n", ret);
0251             goto err_mod_entry;
0252         }
0253         was_loaded = true;
0254     }
0255 
0256     ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id,
0257                     core_id, domain, param, param_size);
0258     if (ret) {
0259         ret = AVS_IPC_RET(ret);
0260         goto err_ipc;
0261     }
0262 
0263     *instance_id = id;
0264     return 0;
0265 
0266 err_ipc:
0267     if (was_loaded)
0268         avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
0269     avs_dsp_put_core(adev, core_id);
0270 err_mod_entry:
0271     avs_module_id_free(adev, module_id, id);
0272     return ret;
0273 }
0274 
0275 void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
0276                u8 ppl_instance_id, u8 core_id)
0277 {
0278     struct avs_module_entry mentry;
0279     int ret;
0280 
0281     /* Modules not owned by any pipeline need to be freed explicitly. */
0282     if (ppl_instance_id == INVALID_PIPELINE_ID)
0283         avs_ipc_delete_instance(adev, module_id, instance_id);
0284 
0285     avs_module_id_free(adev, module_id, instance_id);
0286 
0287     ret = avs_get_module_id_entry(adev, module_id, &mentry);
0288     /* Unload occupied memory if this was the last instance. */
0289     if (!ret && mentry.type.load_type == AVS_MODULE_LOAD_TYPE_LOADABLE) {
0290         if (avs_is_module_ida_empty(adev, module_id)) {
0291             ret = avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
0292             if (ret)
0293                 dev_err(adev->dev, "unload modules failed: %d\n", ret);
0294         }
0295     }
0296 
0297     avs_dsp_put_core(adev, core_id);
0298 }
0299 
0300 int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
0301                 bool lp, u16 attributes, u8 *instance_id)
0302 {
0303     struct avs_fw_cfg *fw_cfg = &adev->fw_cfg;
0304     int ret, id;
0305 
0306     id = ida_alloc_max(&adev->ppl_ida, fw_cfg->max_ppl_count - 1, GFP_KERNEL);
0307     if (id < 0)
0308         return id;
0309 
0310     ret = avs_ipc_create_pipeline(adev, req_size, priority, id, lp, attributes);
0311     if (ret) {
0312         ida_free(&adev->ppl_ida, id);
0313         return AVS_IPC_RET(ret);
0314     }
0315 
0316     *instance_id = id;
0317     return 0;
0318 }
0319 
0320 int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id)
0321 {
0322     int ret;
0323 
0324     ret = avs_ipc_delete_pipeline(adev, instance_id);
0325     if (ret)
0326         ret = AVS_IPC_RET(ret);
0327 
0328     ida_free(&adev->ppl_ida, instance_id);
0329     return ret;
0330 }