Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  sst_dsp.c - Intel SST Driver for audio engine
0004  *
0005  *  Copyright (C) 2008-14   Intel Corp
0006  *  Authors:    Vinod Koul <vinod.koul@intel.com>
0007  *      Harsha Priya <priya.harsha@intel.com>
0008  *      Dharageswari R <dharageswari.r@intel.com>
0009  *      KP Jeeja <jeeja.kp@intel.com>
0010  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0011  *
0012  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0013  *
0014  *  This file contains all dsp controlling functions like firmware download,
0015  * setting/resetting dsp cores, etc
0016  */
0017 #include <linux/pci.h>
0018 #include <linux/delay.h>
0019 #include <linux/fs.h>
0020 #include <linux/sched.h>
0021 #include <linux/firmware.h>
0022 #include <linux/dmaengine.h>
0023 #include <linux/pm_runtime.h>
0024 #include <linux/pm_qos.h>
0025 #include <sound/core.h>
0026 #include <sound/pcm.h>
0027 #include <sound/soc.h>
0028 #include <sound/compress_driver.h>
0029 #include <asm/platform_sst_audio.h>
0030 #include "../sst-mfld-platform.h"
0031 #include "sst.h"
0032 
0033 void memcpy32_toio(void __iomem *dst, const void *src, int count)
0034 {
0035     /* __iowrite32_copy uses 32-bit count values so divide by 4 for
0036      * right count in words
0037      */
0038     __iowrite32_copy(dst, src, count / 4);
0039 }
0040 
0041 void memcpy32_fromio(void *dst, const void __iomem *src, int count)
0042 {
0043     /* __ioread32_copy uses 32-bit count values so divide by 4 for
0044      * right count in words
0045      */
0046     __ioread32_copy(dst, src, count / 4);
0047 }
0048 
0049 /**
0050  * intel_sst_reset_dsp_mrfld - Resetting SST DSP
0051  * @sst_drv_ctx: intel_sst_drv context pointer
0052  *
0053  * This resets DSP in case of MRFLD platfroms
0054  */
0055 int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx)
0056 {
0057     union config_status_reg_mrfld csr;
0058 
0059     dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n");
0060     csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
0061 
0062     dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
0063 
0064     csr.full |= 0x7;
0065     sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
0066     csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
0067 
0068     dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
0069 
0070     csr.full &= ~(0x1);
0071     sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
0072 
0073     csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
0074     dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
0075     return 0;
0076 }
0077 
0078 /**
0079  * sst_start_mrfld - Start the SST DSP processor
0080  * @sst_drv_ctx: intel_sst_drv context pointer
0081  *
0082  * This starts the DSP in MERRIFIELD platfroms
0083  */
0084 int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx)
0085 {
0086     union config_status_reg_mrfld csr;
0087 
0088     dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n");
0089     csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
0090     dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
0091 
0092     csr.full |= 0x7;
0093     sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
0094 
0095     csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
0096     dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
0097 
0098     csr.part.xt_snoop = 1;
0099     csr.full &= ~(0x5);
0100     sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
0101 
0102     csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
0103     dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n",
0104             csr.full);
0105     return 0;
0106 }
0107 
0108 static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size,
0109         struct fw_module_header **module, u32 *num_modules)
0110 {
0111     struct sst_fw_header *header;
0112     const void *sst_fw_in_mem = ctx->fw_in_mem;
0113 
0114     dev_dbg(ctx->dev, "Enter\n");
0115 
0116     /* Read the header information from the data pointer */
0117     header = (struct sst_fw_header *)sst_fw_in_mem;
0118     dev_dbg(ctx->dev,
0119         "header sign=%s size=%x modules=%x fmt=%x size=%zx\n",
0120         header->signature, header->file_size, header->modules,
0121         header->file_format, sizeof(*header));
0122 
0123     /* verify FW */
0124     if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
0125         (size != header->file_size + sizeof(*header))) {
0126         /* Invalid FW signature */
0127         dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n");
0128         return -EINVAL;
0129     }
0130     *num_modules = header->modules;
0131     *module = (void *)sst_fw_in_mem + sizeof(*header);
0132 
0133     return 0;
0134 }
0135 
0136 /*
0137  * sst_fill_memcpy_list - Fill the memcpy list
0138  *
0139  * @memcpy_list: List to be filled
0140  * @destn: Destination addr to be filled in the list
0141  * @src: Source addr to be filled in the list
0142  * @size: Size to be filled in the list
0143  *
0144  * Adds the node to the list after required fields
0145  * are populated in the node
0146  */
0147 static int sst_fill_memcpy_list(struct list_head *memcpy_list,
0148             void *destn, const void *src, u32 size, bool is_io)
0149 {
0150     struct sst_memcpy_list *listnode;
0151 
0152     listnode = kzalloc(sizeof(*listnode), GFP_KERNEL);
0153     if (listnode == NULL)
0154         return -ENOMEM;
0155     listnode->dstn = destn;
0156     listnode->src = src;
0157     listnode->size = size;
0158     listnode->is_io = is_io;
0159     list_add_tail(&listnode->memcpylist, memcpy_list);
0160 
0161     return 0;
0162 }
0163 
0164 /**
0165  * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list
0166  *
0167  * @sst_drv_ctx     : driver context
0168  * @module      : FW module header
0169  * @memcpy_list : Pointer to the list to be populated
0170  * Create the memcpy list as the number of block to be copied
0171  * returns error or 0 if module sizes are proper
0172  */
0173 static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx,
0174         struct fw_module_header *module, struct list_head *memcpy_list)
0175 {
0176     struct fw_block_info *block;
0177     u32 count;
0178     int ret_val = 0;
0179     void __iomem *ram_iomem;
0180 
0181     dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n",
0182             module->signature, module->mod_size,
0183             module->blocks, module->type);
0184     dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point);
0185 
0186     block = (void *)module + sizeof(*module);
0187 
0188     for (count = 0; count < module->blocks; count++) {
0189         if (block->size <= 0) {
0190             dev_err(sst_drv_ctx->dev, "block size invalid\n");
0191             return -EINVAL;
0192         }
0193         switch (block->type) {
0194         case SST_IRAM:
0195             ram_iomem = sst_drv_ctx->iram;
0196             break;
0197         case SST_DRAM:
0198             ram_iomem = sst_drv_ctx->dram;
0199             break;
0200         case SST_DDR:
0201             ram_iomem = sst_drv_ctx->ddr;
0202             break;
0203         case SST_CUSTOM_INFO:
0204             block = (void *)block + sizeof(*block) + block->size;
0205             continue;
0206         default:
0207             dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n",
0208                     block->type, count);
0209             return -EINVAL;
0210         }
0211 
0212         ret_val = sst_fill_memcpy_list(memcpy_list,
0213                 ram_iomem + block->ram_offset,
0214                 (void *)block + sizeof(*block), block->size, 1);
0215         if (ret_val)
0216             return ret_val;
0217 
0218         block = (void *)block + sizeof(*block) + block->size;
0219     }
0220     return 0;
0221 }
0222 
0223 /**
0224  * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy
0225  *
0226  * @ctx         : pointer to drv context
0227  * @size        : size of the firmware
0228  * @fw_list     : pointer to list_head to be populated
0229  * This function parses the FW image and saves the parsed image in the list
0230  * for memcpy
0231  */
0232 static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size,
0233                 struct list_head *fw_list)
0234 {
0235     struct fw_module_header *module;
0236     u32 count, num_modules;
0237     int ret_val;
0238 
0239     ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules);
0240     if (ret_val)
0241         return ret_val;
0242 
0243     for (count = 0; count < num_modules; count++) {
0244         ret_val = sst_parse_module_memcpy(ctx, module, fw_list);
0245         if (ret_val)
0246             return ret_val;
0247         module = (void *)module + sizeof(*module) + module->mod_size;
0248     }
0249 
0250     return 0;
0251 }
0252 
0253 /**
0254  * sst_do_memcpy - function initiates the memcpy
0255  *
0256  * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated
0257  *
0258  * Triggers the memcpy
0259  */
0260 static void sst_do_memcpy(struct list_head *memcpy_list)
0261 {
0262     struct sst_memcpy_list *listnode;
0263 
0264     list_for_each_entry(listnode, memcpy_list, memcpylist) {
0265         if (listnode->is_io)
0266             memcpy32_toio((void __iomem *)listnode->dstn,
0267                     listnode->src, listnode->size);
0268         else
0269             memcpy(listnode->dstn, listnode->src, listnode->size);
0270     }
0271 }
0272 
0273 void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx)
0274 {
0275     struct sst_memcpy_list *listnode, *tmplistnode;
0276 
0277     /* Free the list */
0278     list_for_each_entry_safe(listnode, tmplistnode,
0279                  &sst_drv_ctx->memcpy_list, memcpylist) {
0280         list_del(&listnode->memcpylist);
0281         kfree(listnode);
0282     }
0283 }
0284 
0285 static int sst_cache_and_parse_fw(struct intel_sst_drv *sst,
0286         const struct firmware *fw)
0287 {
0288     int retval = 0;
0289 
0290     sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL);
0291     if (!sst->fw_in_mem) {
0292         retval = -ENOMEM;
0293         goto end_release;
0294     }
0295     dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem);
0296     dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem));
0297     memcpy(sst->fw_in_mem, fw->data, fw->size);
0298     retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list);
0299     if (retval) {
0300         dev_err(sst->dev, "Failed to parse fw\n");
0301         kfree(sst->fw_in_mem);
0302         sst->fw_in_mem = NULL;
0303     }
0304 
0305 end_release:
0306     release_firmware(fw);
0307     return retval;
0308 
0309 }
0310 
0311 void sst_firmware_load_cb(const struct firmware *fw, void *context)
0312 {
0313     struct intel_sst_drv *ctx = context;
0314 
0315     dev_dbg(ctx->dev, "Enter\n");
0316 
0317     if (fw == NULL) {
0318         dev_err(ctx->dev, "request fw failed\n");
0319         return;
0320     }
0321 
0322     mutex_lock(&ctx->sst_lock);
0323 
0324     if (ctx->sst_state != SST_RESET ||
0325             ctx->fw_in_mem != NULL) {
0326         release_firmware(fw);
0327         mutex_unlock(&ctx->sst_lock);
0328         return;
0329     }
0330 
0331     dev_dbg(ctx->dev, "Request Fw completed\n");
0332     sst_cache_and_parse_fw(ctx, fw);
0333     mutex_unlock(&ctx->sst_lock);
0334 }
0335 
0336 /*
0337  * sst_request_fw - requests audio fw from kernel and saves a copy
0338  *
0339  * This function requests the SST FW from the kernel, parses it and
0340  * saves a copy in the driver context
0341  */
0342 static int sst_request_fw(struct intel_sst_drv *sst)
0343 {
0344     int retval = 0;
0345     const struct firmware *fw;
0346 
0347     retval = request_firmware(&fw, sst->firmware_name, sst->dev);
0348     if (retval) {
0349         dev_err(sst->dev, "request fw failed %d\n", retval);
0350         return retval;
0351     }
0352     if (fw == NULL) {
0353         dev_err(sst->dev, "fw is returning as null\n");
0354         return -EINVAL;
0355     }
0356     mutex_lock(&sst->sst_lock);
0357     retval = sst_cache_and_parse_fw(sst, fw);
0358     mutex_unlock(&sst->sst_lock);
0359 
0360     return retval;
0361 }
0362 
0363 /*
0364  * Writing the DDR physical base to DCCM offset
0365  * so that FW can use it to setup TLB
0366  */
0367 static void sst_dccm_config_write(void __iomem *dram_base,
0368         unsigned int ddr_base)
0369 {
0370     void __iomem *addr;
0371     u32 bss_reset = 0;
0372 
0373     addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET);
0374     memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32));
0375     bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT);
0376     addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET);
0377     memcpy32_toio(addr, &bss_reset, sizeof(u32));
0378 
0379 }
0380 
0381 void sst_post_download_mrfld(struct intel_sst_drv *ctx)
0382 {
0383     sst_dccm_config_write(ctx->dram, ctx->ddr_base);
0384     dev_dbg(ctx->dev, "config written to DCCM\n");
0385 }
0386 
0387 /**
0388  * sst_load_fw - function to load FW into DSP
0389  * @sst_drv_ctx: intel_sst_drv context pointer
0390  *
0391  * Transfers the FW to DSP using dma/memcpy
0392  */
0393 int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
0394 {
0395     int ret_val = 0;
0396     struct sst_block *block;
0397 
0398     dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n");
0399 
0400     if (sst_drv_ctx->sst_state !=  SST_RESET)
0401         return -EAGAIN;
0402 
0403     if (!sst_drv_ctx->fw_in_mem) {
0404         dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n");
0405         ret_val = sst_request_fw(sst_drv_ctx);
0406         if (ret_val)
0407             return ret_val;
0408     }
0409 
0410     block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID);
0411     if (block == NULL)
0412         return -ENOMEM;
0413 
0414     /* Prevent C-states beyond C6 */
0415     cpu_latency_qos_update_request(sst_drv_ctx->qos, 0);
0416 
0417     sst_drv_ctx->sst_state = SST_FW_LOADING;
0418 
0419     ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx);
0420     if (ret_val)
0421         goto restore;
0422 
0423     sst_do_memcpy(&sst_drv_ctx->memcpy_list);
0424 
0425     /* Write the DRAM/DCCM config before enabling FW */
0426     if (sst_drv_ctx->ops->post_download)
0427         sst_drv_ctx->ops->post_download(sst_drv_ctx);
0428 
0429     /* bring sst out of reset */
0430     ret_val = sst_drv_ctx->ops->start(sst_drv_ctx);
0431     if (ret_val)
0432         goto restore;
0433 
0434     ret_val = sst_wait_timeout(sst_drv_ctx, block);
0435     if (ret_val) {
0436         dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val);
0437         /* FW download failed due to timeout */
0438         ret_val = -EBUSY;
0439 
0440     }
0441 
0442 
0443 restore:
0444     /* Re-enable Deeper C-states beyond C6 */
0445     cpu_latency_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
0446     sst_free_block(sst_drv_ctx, block);
0447     dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n");
0448 
0449     if (sst_drv_ctx->ops->restore_dsp_context)
0450         sst_drv_ctx->ops->restore_dsp_context();
0451     sst_drv_ctx->sst_state = SST_FW_RUNNING;
0452     return ret_val;
0453 }
0454