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