sst_loader.c (12097B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * sst_dsp.c - Intel SST Driver for audio engine 4 * 5 * Copyright (C) 2008-14 Intel Corp 6 * Authors: Vinod Koul <vinod.koul@intel.com> 7 * Harsha Priya <priya.harsha@intel.com> 8 * Dharageswari R <dharageswari.r@intel.com> 9 * KP Jeeja <jeeja.kp@intel.com> 10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 * 12 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 * 14 * This file contains all dsp controlling functions like firmware download, 15 * setting/resetting dsp cores, etc 16 */ 17#include <linux/pci.h> 18#include <linux/delay.h> 19#include <linux/fs.h> 20#include <linux/sched.h> 21#include <linux/firmware.h> 22#include <linux/dmaengine.h> 23#include <linux/pm_runtime.h> 24#include <linux/pm_qos.h> 25#include <sound/core.h> 26#include <sound/pcm.h> 27#include <sound/soc.h> 28#include <sound/compress_driver.h> 29#include <asm/platform_sst_audio.h> 30#include "../sst-mfld-platform.h" 31#include "sst.h" 32 33void memcpy32_toio(void __iomem *dst, const void *src, int count) 34{ 35 /* __iowrite32_copy uses 32-bit count values so divide by 4 for 36 * right count in words 37 */ 38 __iowrite32_copy(dst, src, count / 4); 39} 40 41void memcpy32_fromio(void *dst, const void __iomem *src, int count) 42{ 43 /* __ioread32_copy uses 32-bit count values so divide by 4 for 44 * right count in words 45 */ 46 __ioread32_copy(dst, src, count / 4); 47} 48 49/** 50 * intel_sst_reset_dsp_mrfld - Resetting SST DSP 51 * @sst_drv_ctx: intel_sst_drv context pointer 52 * 53 * This resets DSP in case of MRFLD platfroms 54 */ 55int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx) 56{ 57 union config_status_reg_mrfld csr; 58 59 dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n"); 60 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); 61 62 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); 63 64 csr.full |= 0x7; 65 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); 66 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); 67 68 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); 69 70 csr.full &= ~(0x1); 71 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); 72 73 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); 74 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); 75 return 0; 76} 77 78/** 79 * sst_start_mrfld - Start the SST DSP processor 80 * @sst_drv_ctx: intel_sst_drv context pointer 81 * 82 * This starts the DSP in MERRIFIELD platfroms 83 */ 84int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx) 85{ 86 union config_status_reg_mrfld csr; 87 88 dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n"); 89 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); 90 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); 91 92 csr.full |= 0x7; 93 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); 94 95 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); 96 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); 97 98 csr.part.xt_snoop = 1; 99 csr.full &= ~(0x5); 100 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); 101 102 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); 103 dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n", 104 csr.full); 105 return 0; 106} 107 108static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size, 109 struct fw_module_header **module, u32 *num_modules) 110{ 111 struct sst_fw_header *header; 112 const void *sst_fw_in_mem = ctx->fw_in_mem; 113 114 dev_dbg(ctx->dev, "Enter\n"); 115 116 /* Read the header information from the data pointer */ 117 header = (struct sst_fw_header *)sst_fw_in_mem; 118 dev_dbg(ctx->dev, 119 "header sign=%s size=%x modules=%x fmt=%x size=%zx\n", 120 header->signature, header->file_size, header->modules, 121 header->file_format, sizeof(*header)); 122 123 /* verify FW */ 124 if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) || 125 (size != header->file_size + sizeof(*header))) { 126 /* Invalid FW signature */ 127 dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n"); 128 return -EINVAL; 129 } 130 *num_modules = header->modules; 131 *module = (void *)sst_fw_in_mem + sizeof(*header); 132 133 return 0; 134} 135 136/* 137 * sst_fill_memcpy_list - Fill the memcpy list 138 * 139 * @memcpy_list: List to be filled 140 * @destn: Destination addr to be filled in the list 141 * @src: Source addr to be filled in the list 142 * @size: Size to be filled in the list 143 * 144 * Adds the node to the list after required fields 145 * are populated in the node 146 */ 147static int sst_fill_memcpy_list(struct list_head *memcpy_list, 148 void *destn, const void *src, u32 size, bool is_io) 149{ 150 struct sst_memcpy_list *listnode; 151 152 listnode = kzalloc(sizeof(*listnode), GFP_KERNEL); 153 if (listnode == NULL) 154 return -ENOMEM; 155 listnode->dstn = destn; 156 listnode->src = src; 157 listnode->size = size; 158 listnode->is_io = is_io; 159 list_add_tail(&listnode->memcpylist, memcpy_list); 160 161 return 0; 162} 163 164/** 165 * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list 166 * 167 * @sst_drv_ctx : driver context 168 * @module : FW module header 169 * @memcpy_list : Pointer to the list to be populated 170 * Create the memcpy list as the number of block to be copied 171 * returns error or 0 if module sizes are proper 172 */ 173static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx, 174 struct fw_module_header *module, struct list_head *memcpy_list) 175{ 176 struct fw_block_info *block; 177 u32 count; 178 int ret_val = 0; 179 void __iomem *ram_iomem; 180 181 dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n", 182 module->signature, module->mod_size, 183 module->blocks, module->type); 184 dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point); 185 186 block = (void *)module + sizeof(*module); 187 188 for (count = 0; count < module->blocks; count++) { 189 if (block->size <= 0) { 190 dev_err(sst_drv_ctx->dev, "block size invalid\n"); 191 return -EINVAL; 192 } 193 switch (block->type) { 194 case SST_IRAM: 195 ram_iomem = sst_drv_ctx->iram; 196 break; 197 case SST_DRAM: 198 ram_iomem = sst_drv_ctx->dram; 199 break; 200 case SST_DDR: 201 ram_iomem = sst_drv_ctx->ddr; 202 break; 203 case SST_CUSTOM_INFO: 204 block = (void *)block + sizeof(*block) + block->size; 205 continue; 206 default: 207 dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n", 208 block->type, count); 209 return -EINVAL; 210 } 211 212 ret_val = sst_fill_memcpy_list(memcpy_list, 213 ram_iomem + block->ram_offset, 214 (void *)block + sizeof(*block), block->size, 1); 215 if (ret_val) 216 return ret_val; 217 218 block = (void *)block + sizeof(*block) + block->size; 219 } 220 return 0; 221} 222 223/** 224 * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy 225 * 226 * @ctx : pointer to drv context 227 * @size : size of the firmware 228 * @fw_list : pointer to list_head to be populated 229 * This function parses the FW image and saves the parsed image in the list 230 * for memcpy 231 */ 232static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size, 233 struct list_head *fw_list) 234{ 235 struct fw_module_header *module; 236 u32 count, num_modules; 237 int ret_val; 238 239 ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules); 240 if (ret_val) 241 return ret_val; 242 243 for (count = 0; count < num_modules; count++) { 244 ret_val = sst_parse_module_memcpy(ctx, module, fw_list); 245 if (ret_val) 246 return ret_val; 247 module = (void *)module + sizeof(*module) + module->mod_size; 248 } 249 250 return 0; 251} 252 253/** 254 * sst_do_memcpy - function initiates the memcpy 255 * 256 * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated 257 * 258 * Triggers the memcpy 259 */ 260static void sst_do_memcpy(struct list_head *memcpy_list) 261{ 262 struct sst_memcpy_list *listnode; 263 264 list_for_each_entry(listnode, memcpy_list, memcpylist) { 265 if (listnode->is_io) 266 memcpy32_toio((void __iomem *)listnode->dstn, 267 listnode->src, listnode->size); 268 else 269 memcpy(listnode->dstn, listnode->src, listnode->size); 270 } 271} 272 273void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx) 274{ 275 struct sst_memcpy_list *listnode, *tmplistnode; 276 277 /* Free the list */ 278 list_for_each_entry_safe(listnode, tmplistnode, 279 &sst_drv_ctx->memcpy_list, memcpylist) { 280 list_del(&listnode->memcpylist); 281 kfree(listnode); 282 } 283} 284 285static int sst_cache_and_parse_fw(struct intel_sst_drv *sst, 286 const struct firmware *fw) 287{ 288 int retval = 0; 289 290 sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL); 291 if (!sst->fw_in_mem) { 292 retval = -ENOMEM; 293 goto end_release; 294 } 295 dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem); 296 dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem)); 297 memcpy(sst->fw_in_mem, fw->data, fw->size); 298 retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list); 299 if (retval) { 300 dev_err(sst->dev, "Failed to parse fw\n"); 301 kfree(sst->fw_in_mem); 302 sst->fw_in_mem = NULL; 303 } 304 305end_release: 306 release_firmware(fw); 307 return retval; 308 309} 310 311void sst_firmware_load_cb(const struct firmware *fw, void *context) 312{ 313 struct intel_sst_drv *ctx = context; 314 315 dev_dbg(ctx->dev, "Enter\n"); 316 317 if (fw == NULL) { 318 dev_err(ctx->dev, "request fw failed\n"); 319 return; 320 } 321 322 mutex_lock(&ctx->sst_lock); 323 324 if (ctx->sst_state != SST_RESET || 325 ctx->fw_in_mem != NULL) { 326 release_firmware(fw); 327 mutex_unlock(&ctx->sst_lock); 328 return; 329 } 330 331 dev_dbg(ctx->dev, "Request Fw completed\n"); 332 sst_cache_and_parse_fw(ctx, fw); 333 mutex_unlock(&ctx->sst_lock); 334} 335 336/* 337 * sst_request_fw - requests audio fw from kernel and saves a copy 338 * 339 * This function requests the SST FW from the kernel, parses it and 340 * saves a copy in the driver context 341 */ 342static int sst_request_fw(struct intel_sst_drv *sst) 343{ 344 int retval = 0; 345 const struct firmware *fw; 346 347 retval = request_firmware(&fw, sst->firmware_name, sst->dev); 348 if (retval) { 349 dev_err(sst->dev, "request fw failed %d\n", retval); 350 return retval; 351 } 352 if (fw == NULL) { 353 dev_err(sst->dev, "fw is returning as null\n"); 354 return -EINVAL; 355 } 356 mutex_lock(&sst->sst_lock); 357 retval = sst_cache_and_parse_fw(sst, fw); 358 mutex_unlock(&sst->sst_lock); 359 360 return retval; 361} 362 363/* 364 * Writing the DDR physical base to DCCM offset 365 * so that FW can use it to setup TLB 366 */ 367static void sst_dccm_config_write(void __iomem *dram_base, 368 unsigned int ddr_base) 369{ 370 void __iomem *addr; 371 u32 bss_reset = 0; 372 373 addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET); 374 memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32)); 375 bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT); 376 addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET); 377 memcpy32_toio(addr, &bss_reset, sizeof(u32)); 378 379} 380 381void sst_post_download_mrfld(struct intel_sst_drv *ctx) 382{ 383 sst_dccm_config_write(ctx->dram, ctx->ddr_base); 384 dev_dbg(ctx->dev, "config written to DCCM\n"); 385} 386 387/** 388 * sst_load_fw - function to load FW into DSP 389 * @sst_drv_ctx: intel_sst_drv context pointer 390 * 391 * Transfers the FW to DSP using dma/memcpy 392 */ 393int sst_load_fw(struct intel_sst_drv *sst_drv_ctx) 394{ 395 int ret_val = 0; 396 struct sst_block *block; 397 398 dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n"); 399 400 if (sst_drv_ctx->sst_state != SST_RESET) 401 return -EAGAIN; 402 403 if (!sst_drv_ctx->fw_in_mem) { 404 dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n"); 405 ret_val = sst_request_fw(sst_drv_ctx); 406 if (ret_val) 407 return ret_val; 408 } 409 410 block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID); 411 if (block == NULL) 412 return -ENOMEM; 413 414 /* Prevent C-states beyond C6 */ 415 cpu_latency_qos_update_request(sst_drv_ctx->qos, 0); 416 417 sst_drv_ctx->sst_state = SST_FW_LOADING; 418 419 ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx); 420 if (ret_val) 421 goto restore; 422 423 sst_do_memcpy(&sst_drv_ctx->memcpy_list); 424 425 /* Write the DRAM/DCCM config before enabling FW */ 426 if (sst_drv_ctx->ops->post_download) 427 sst_drv_ctx->ops->post_download(sst_drv_ctx); 428 429 /* bring sst out of reset */ 430 ret_val = sst_drv_ctx->ops->start(sst_drv_ctx); 431 if (ret_val) 432 goto restore; 433 434 ret_val = sst_wait_timeout(sst_drv_ctx, block); 435 if (ret_val) { 436 dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val); 437 /* FW download failed due to timeout */ 438 ret_val = -EBUSY; 439 440 } 441 442 443restore: 444 /* Re-enable Deeper C-states beyond C6 */ 445 cpu_latency_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE); 446 sst_free_block(sst_drv_ctx, block); 447 dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n"); 448 449 if (sst_drv_ctx->ops->restore_dsp_context) 450 sst_drv_ctx->ops->restore_dsp_context(); 451 sst_drv_ctx->sst_state = SST_FW_RUNNING; 452 return ret_val; 453} 454