diff options
Diffstat (limited to 'sound/soc/intel/sst/sst_loader.c')
| -rw-r--r-- | sound/soc/intel/sst/sst_loader.c | 455 |
1 files changed, 0 insertions, 455 deletions
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c deleted file mode 100644 index 7888cd707853..000000000000 --- a/sound/soc/intel/sst/sst_loader.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * sst_dsp.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-14 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file contains all dsp controlling functions like firmware download, - * setting/resetting dsp cores, etc - */ -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/fs.h> -#include <linux/sched.h> -#include <linux/firmware.h> -#include <linux/dmaengine.h> -#include <linux/pm_runtime.h> -#include <linux/pm_qos.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/compress_driver.h> -#include <asm/platform_sst_audio.h> -#include "../sst-mfld-platform.h" -#include "sst.h" -#include "../sst-dsp.h" - -static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) -{ - /* __iowrite32_copy uses 32-bit count values so divide by 4 for - * right count in words - */ - __iowrite32_copy(dst, src, count/4); -} - -/** - * intel_sst_reset_dsp_mrfld - Resetting SST DSP - * - * This resets DSP in case of MRFLD platfroms - */ -int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx) -{ - union config_status_reg_mrfld csr; - - dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n"); - csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); - - dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); - - csr.full |= 0x7; - sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); - csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); - - dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); - - csr.full &= ~(0x1); - sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); - - csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); - dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); - return 0; -} - -/** - * sst_start_merrifield - Start the SST DSP processor - * - * This starts the DSP in MERRIFIELD platfroms - */ -int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx) -{ - union config_status_reg_mrfld csr; - - dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n"); - csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); - dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); - - csr.full |= 0x7; - sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); - - csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); - dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); - - csr.part.xt_snoop = 1; - csr.full &= ~(0x5); - sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); - - csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); - dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n", - csr.full); - return 0; -} - -static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size, - struct fw_module_header **module, u32 *num_modules) -{ - struct sst_fw_header *header; - const void *sst_fw_in_mem = ctx->fw_in_mem; - - dev_dbg(ctx->dev, "Enter\n"); - - /* Read the header information from the data pointer */ - header = (struct sst_fw_header *)sst_fw_in_mem; - dev_dbg(ctx->dev, - "header sign=%s size=%x modules=%x fmt=%x size=%zx\n", - header->signature, header->file_size, header->modules, - header->file_format, sizeof(*header)); - - /* verify FW */ - if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) || - (size != header->file_size + sizeof(*header))) { - /* Invalid FW signature */ - dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n"); - return -EINVAL; - } - *num_modules = header->modules; - *module = (void *)sst_fw_in_mem + sizeof(*header); - - return 0; -} - -/* - * sst_fill_memcpy_list - Fill the memcpy list - * - * @memcpy_list: List to be filled - * @destn: Destination addr to be filled in the list - * @src: Source addr to be filled in the list - * @size: Size to be filled in the list - * - * Adds the node to the list after required fields - * are populated in the node - */ -static int sst_fill_memcpy_list(struct list_head *memcpy_list, - void *destn, const void *src, u32 size, bool is_io) -{ - struct sst_memcpy_list *listnode; - - listnode = kzalloc(sizeof(*listnode), GFP_KERNEL); - if (listnode == NULL) - return -ENOMEM; - listnode->dstn = destn; - listnode->src = src; - listnode->size = size; - listnode->is_io = is_io; - list_add_tail(&listnode->memcpylist, memcpy_list); - - return 0; -} - -/** - * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list - * - * @sst_drv_ctx : driver context - * @module : FW module header - * @memcpy_list : Pointer to the list to be populated - * Create the memcpy list as the number of block to be copied - * returns error or 0 if module sizes are proper - */ -static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx, - struct fw_module_header *module, struct list_head *memcpy_list) -{ - struct fw_block_info *block; - u32 count; - int ret_val = 0; - void __iomem *ram_iomem; - - dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n", - module->signature, module->mod_size, - module->blocks, module->type); - dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point); - - block = (void *)module + sizeof(*module); - - for (count = 0; count < module->blocks; count++) { - if (block->size <= 0) { - dev_err(sst_drv_ctx->dev, "block size invalid\n"); - return -EINVAL; - } - switch (block->type) { - case SST_IRAM: - ram_iomem = sst_drv_ctx->iram; - break; - case SST_DRAM: - ram_iomem = sst_drv_ctx->dram; - break; - case SST_DDR: - ram_iomem = sst_drv_ctx->ddr; - break; - case SST_CUSTOM_INFO: - block = (void *)block + sizeof(*block) + block->size; - continue; - default: - dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n", - block->type, count); - return -EINVAL; - } - - ret_val = sst_fill_memcpy_list(memcpy_list, - ram_iomem + block->ram_offset, - (void *)block + sizeof(*block), block->size, 1); - if (ret_val) - return ret_val; - - block = (void *)block + sizeof(*block) + block->size; - } - return 0; -} - -/** - * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy - * - * @ctx : pointer to drv context - * @size : size of the firmware - * @fw_list : pointer to list_head to be populated - * This function parses the FW image and saves the parsed image in the list - * for memcpy - */ -static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size, - struct list_head *fw_list) -{ - struct fw_module_header *module; - u32 count, num_modules; - int ret_val; - - ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules); - if (ret_val) - return ret_val; - - for (count = 0; count < num_modules; count++) { - ret_val = sst_parse_module_memcpy(ctx, module, fw_list); - if (ret_val) - return ret_val; - module = (void *)module + sizeof(*module) + module->mod_size; - } - - return 0; -} - -/** - * sst_do_memcpy - function initiates the memcpy - * - * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated - * - * Triggers the memcpy - */ -static void sst_do_memcpy(struct list_head *memcpy_list) -{ - struct sst_memcpy_list *listnode; - - list_for_each_entry(listnode, memcpy_list, memcpylist) { - if (listnode->is_io == true) - memcpy32_toio((void __iomem *)listnode->dstn, - listnode->src, listnode->size); - else - memcpy(listnode->dstn, listnode->src, listnode->size); - } -} - -void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx) -{ - struct sst_memcpy_list *listnode, *tmplistnode; - - /* Free the list */ - if (!list_empty(&sst_drv_ctx->memcpy_list)) { - list_for_each_entry_safe(listnode, tmplistnode, - &sst_drv_ctx->memcpy_list, memcpylist) { - list_del(&listnode->memcpylist); - kfree(listnode); - } - } -} - -static int sst_cache_and_parse_fw(struct intel_sst_drv *sst, - const struct firmware *fw) -{ - int retval = 0; - - sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL); - if (!sst->fw_in_mem) { - retval = -ENOMEM; - goto end_release; - } - dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem); - dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem)); - memcpy(sst->fw_in_mem, fw->data, fw->size); - retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list); - if (retval) { - dev_err(sst->dev, "Failed to parse fw\n"); - kfree(sst->fw_in_mem); - sst->fw_in_mem = NULL; - } - -end_release: - release_firmware(fw); - return retval; - -} - -void sst_firmware_load_cb(const struct firmware *fw, void *context) -{ - struct intel_sst_drv *ctx = context; - - dev_dbg(ctx->dev, "Enter\n"); - - if (fw == NULL) { - dev_err(ctx->dev, "request fw failed\n"); - return; - } - - mutex_lock(&ctx->sst_lock); - - if (ctx->sst_state != SST_RESET || - ctx->fw_in_mem != NULL) { - release_firmware(fw); - mutex_unlock(&ctx->sst_lock); - return; - } - - dev_dbg(ctx->dev, "Request Fw completed\n"); - sst_cache_and_parse_fw(ctx, fw); - mutex_unlock(&ctx->sst_lock); -} - -/* - * sst_request_fw - requests audio fw from kernel and saves a copy - * - * This function requests the SST FW from the kernel, parses it and - * saves a copy in the driver context - */ -static int sst_request_fw(struct intel_sst_drv *sst) -{ - int retval = 0; - const struct firmware *fw; - - retval = request_firmware(&fw, sst->firmware_name, sst->dev); - if (fw == NULL) { - dev_err(sst->dev, "fw is returning as null\n"); - return -EINVAL; - } - if (retval) { - dev_err(sst->dev, "request fw failed %d\n", retval); - return retval; - } - mutex_lock(&sst->sst_lock); - retval = sst_cache_and_parse_fw(sst, fw); - mutex_unlock(&sst->sst_lock); - - return retval; -} - -/* - * Writing the DDR physical base to DCCM offset - * so that FW can use it to setup TLB - */ -static void sst_dccm_config_write(void __iomem *dram_base, - unsigned int ddr_base) -{ - void __iomem *addr; - u32 bss_reset = 0; - - addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET); - memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32)); - bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT); - addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET); - memcpy32_toio(addr, &bss_reset, sizeof(u32)); - -} - -void sst_post_download_mrfld(struct intel_sst_drv *ctx) -{ - sst_dccm_config_write(ctx->dram, ctx->ddr_base); - dev_dbg(ctx->dev, "config written to DCCM\n"); -} - -/** - * sst_load_fw - function to load FW into DSP - * Transfers the FW to DSP using dma/memcpy - */ -int sst_load_fw(struct intel_sst_drv *sst_drv_ctx) -{ - int ret_val = 0; - struct sst_block *block; - - dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n"); - - if (sst_drv_ctx->sst_state != SST_RESET || - sst_drv_ctx->sst_state == SST_SHUTDOWN) - return -EAGAIN; - - if (!sst_drv_ctx->fw_in_mem) { - dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n"); - ret_val = sst_request_fw(sst_drv_ctx); - if (ret_val) - return ret_val; - } - - BUG_ON(!sst_drv_ctx->fw_in_mem); - block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID); - if (block == NULL) - return -ENOMEM; - - /* Prevent C-states beyond C6 */ - pm_qos_update_request(sst_drv_ctx->qos, 0); - - sst_drv_ctx->sst_state = SST_FW_LOADING; - - ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx); - if (ret_val) - goto restore; - - sst_do_memcpy(&sst_drv_ctx->memcpy_list); - - /* Write the DRAM/DCCM config before enabling FW */ - if (sst_drv_ctx->ops->post_download) - sst_drv_ctx->ops->post_download(sst_drv_ctx); - - /* bring sst out of reset */ - ret_val = sst_drv_ctx->ops->start(sst_drv_ctx); - if (ret_val) - goto restore; - - ret_val = sst_wait_timeout(sst_drv_ctx, block); - if (ret_val) { - dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val); - /* FW download failed due to timeout */ - ret_val = -EBUSY; - - } - - -restore: - /* Re-enable Deeper C-states beyond C6 */ - pm_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE); - sst_free_block(sst_drv_ctx, block); - dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n"); - - if (sst_drv_ctx->ops->restore_dsp_context) - sst_drv_ctx->ops->restore_dsp_context(); - sst_drv_ctx->sst_state = SST_FW_RUNNING; - return ret_val; -} - |
