Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASoC:SOF:skl add cldma copy firmware #180

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 165 additions & 1 deletion 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 @@ -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,140 @@ 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->wake_status != SKL_CL_DMA_BUF_COMPLETE) {
dev_err(ctx->dev, "%s: DMA Error\n", __func__);
ret = -EIO;
}

cleanup:
sdev->wake_status = SKL_CL_DMA_STATUS_NONE;
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 = false;

/* 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);
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);
return 0;
}
}

return bytes_left;
}

#define STRIP_FIRMWARE 1

#if STRIP_FIRMWARE
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
struct skl_ext_manifest_hdr {
u32 id;
u32 len;
u16 version_major;
u16 version_minor;
u32 entries;
};
#endif

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);

#if STRIP_FIRMWARE
hdr = (struct skl_ext_manifest_hdr *)stripped_fw.data;
if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) {
stripped_fw.size -= hdr->len;
stripped_fw.data += hdr->len;
dev_dbg(sdev->dev, "manifest header length: %d\n", hdr->len);
}
#endif

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;
}