Skip to content

Commit

Permalink
ASoC:SOF:skl add cldma copy firmware
Browse files Browse the repository at this point in the history
use code loader DMA to copy firmware binary to DSP

Signed-off-by: Zhu Yingjiang <[email protected]>
  • Loading branch information
zhuyingjiang authored and lgirdwood committed Oct 15, 2018
1 parent 856bb51 commit 3309529
Showing 1 changed file with 144 additions and 2 deletions.
146 changes: 144 additions & 2 deletions sound/soc/sof/intel/hda-loader-skl.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@
#include "../ops.h"
#include "hda.h"

#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE)
#define HDA_SKL_WAIT_TIMEOUT 500 /* 500 msec */
#define HDA_SKL_CLDMA_MAX_BUFFER_SIZE (32 * PAGE_SIZE)

/* Intel HD Audio SRAM Window 0*/
#define HDA_SKL_ADSP_SRAM0_BASE 0x8000

/* Firmware status window */
#define HDA_SKL_ADSP_FW_STATUS HDA_SKL_ADSP_SRAM0_BASE

/* Stream Reset */
#define HDA_CL_SD_CTL_SRST_SHIFT 0
Expand Down Expand Up @@ -218,6 +225,14 @@ static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev,
sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, size);
}

static void cl_skl_cldma_set_intr(struct snd_sof_dev *sdev, bool enable)
{
u32 val = enable ? HDA_DSP_ADSPIC_CL_DMA : 0;

snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
HDA_DSP_ADSPIC_CL_DMA, val);
}

static void cl_skl_cldma_cleanup_spb(struct snd_sof_dev *sdev)
{
int sd_offset = SOF_DSP_REG_CL_SPBFIFO;
Expand Down Expand Up @@ -273,7 +288,7 @@ static int cl_stream_prepare_skl(struct snd_sof_dev *sdev)
int frags = 0;
int ret = 0;
u32 *bdl;
unsigned int bufsize = SKL_MAX_BUFFER_SIZE;
unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE;

ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize,
&sdev->dmab);
Expand Down Expand Up @@ -380,6 +395,7 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev)
return ret;
}

static int cl_copy_fw_skl(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev)
{
int ret;
Expand All @@ -406,6 +422,17 @@ int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev)
init_waitqueue_head(&sdev->boot_wait);
sdev->boot_complete = false;

/* at this point DSP ROM has been initialized and should be ready for
* code loading and firmware boot
*/
ret = cl_copy_fw_skl(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: load firmware failed : %d\n", ret);
goto irq_err;
}

dev_dbg(sdev->dev, "Firmware download successful, booting...\n");

return ret;

irq_err:
Expand All @@ -418,3 +445,118 @@ int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "error: load fw failed err: %d\n", ret);
return ret;
}

int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev)
{
int ret = 0;

if (!wait_event_timeout(sdev->waitq,
sdev->code_loading,
msecs_to_jiffies(HDA_SKL_WAIT_TIMEOUT))) {
dev_err(sdev->dev, "%s: Wait timeout\n", __func__);
ret = -EIO;
goto cleanup;
}

dev_dbg(sdev->dev, "%s: Event wake\n", __func__);
if (sdev->code_loading != 1) {
dev_err(sdev->dev, "%s: DMA Error\n", __func__);
ret = -EIO;
}

cleanup:
sdev->code_loading = 0;
return ret;
}

static void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev,
unsigned int bufsize,
unsigned int copysize,
const void *curr_pos,
bool intr_enable, bool trigger)
{
/* 1. copy the image into the buffer with the maximum buffer size. */
unsigned int size = (bufsize == copysize) ? bufsize : copysize;

memcpy(sdev->dmab.area, curr_pos, size);

/* 2. Setting the wait condition for every load. */
sdev->code_loading = 0;

/* 3. Set the interrupt. */
if (intr_enable)
cl_skl_cldma_set_intr(sdev, true);

/* 4. Set the SPB. */
cl_skl_cldma_setup_spb(sdev, size, trigger);

/* 5. Trigger the code loading stream. */
if (trigger)
cl_skl_cldma_stream_run(sdev, true);
}

static int
cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin,
u32 total_size, u32 bufsize)
{
int ret = 0;
unsigned int bytes_left = total_size;
const void *curr_pos = bin;

if (total_size <= 0)
return -EINVAL;

dev_dbg(sdev->dev, "Total binary size: %u\n", total_size);

while (bytes_left > 0) {
if (bytes_left > bufsize) {
cl_skl_cldma_fill_buffer(sdev, bufsize, bufsize,
curr_pos, true, true);
ret = cl_skl_cldma_wait_interruptible(sdev);
if (ret < 0) {
cl_skl_cldma_stream_run(sdev, false);
return ret;
}
bytes_left -= bufsize;
curr_pos += bufsize;
} else {
cl_skl_cldma_set_intr(sdev, false);
cl_skl_cldma_fill_buffer(sdev, bufsize, bytes_left,
curr_pos, false, true);
return 0;
}
}

return bytes_left;
}

static int cl_copy_fw_skl(struct snd_sof_dev *sdev)
{
struct skl_ext_manifest_hdr *hdr;
struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev);
struct firmware stripped_fw;
unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE;
int ret = 0;

stripped_fw.data = plat_data->fw->data;
stripped_fw.size = plat_data->fw->size;
dev_dbg(sdev->dev, "firmware size: %zu\n", stripped_fw.size);

ret = cl_skl_cldma_copy_to_buf(sdev, stripped_fw.data,
stripped_fw.size, bufsize);
if (ret < 0)
return ret;
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_SKL_ADSP_FW_STATUS,
HDA_DSP_ROM_STS_MASK,
HDA_DSP_ROM_FW_FW_LOADED,
HDA_DSP_BASEFW_TIMEOUT);

if (ret < 0)
dev_err(sdev->dev, "firmware transfer timeout!");

cl_skl_cldma_stream_run(sdev, false);
cl_cleanup_skl(sdev);

return ret;
}

0 comments on commit 3309529

Please sign in to comment.