Skip to content
Closed
Show file tree
Hide file tree
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
15 changes: 15 additions & 0 deletions sound/soc/sof/intel/hda-dsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,21 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev,
return is_enable;
}

int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask)
{
int ret;

/* power up */
ret = hda_dsp_core_power_up(sdev, core_mask);
if (ret < 0) {
dev_err(sdev->dev, "dsp core power up failed: core_mask %x\n",
core_mask);
return ret;
}

return hda_dsp_core_run(sdev, core_mask);
}

int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
unsigned int core_mask)
{
Expand Down
273 changes: 273 additions & 0 deletions sound/soc/sof/intel/hda-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* Hardware interface for HDA DSP code loader
*/

#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/slab.h>
Expand All @@ -34,6 +35,8 @@
#include "../ops.h"
#include "hda.h"

#include "../../intel/skylake/skl-sst-cldma.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we need any macros we should define locally.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, my question is to create a new head file like hda-skl.h, or just define it in hda-loader.c now? For there are too much defines for the registers, I prefer using a new head file..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The registers should mostly be the same as existing ones for APL, you may need to check each one being used.


static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction)
Expand Down Expand Up @@ -372,3 +375,273 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "error: load fw failed err: %d\n", ret);
return ret;
}

/* Code loader helper APIs */
static int cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev,
struct snd_dma_buffer *dmab_data,
u32 **bdlp, int size, int with_ioc)
{
u32 *bdl = *bdlp;
int frags = 0;

while (size > 0) {
phys_addr_t addr = virt_to_phys(dmab_data->area +
(frags * size));

bdl[0] = cpu_to_le32(lower_32_bits(addr));
bdl[1] = cpu_to_le32(upper_32_bits(addr));

bdl[2] = cpu_to_le32(size);

size -= size;
bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);

bdl += 4;
frags++;
}

return frags;
}

static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable)
{
unsigned char val;
int timeout;

snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable));

udelay(3);
timeout = 300;
do {
/* waiting for hardware to report the stream Run bit set */
val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
SKL_ADSP_REG_CL_SD_CTL) &
CL_SD_CTL_RUN_MASK;
if (enable && val)
break;
else if (!enable && !val)
break;
udelay(3);
} while (--timeout);

if (timeout == 0)
dev_err(sdev->dev, "Failed to set Run bit=%d enable=%d\n",
val, enable);
}

/*
* Setup controller
* Configure the registers to update the dma buffer address and
* enable interrupts.
* Note: Using the channel 1 for transfer
*/
static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev,
struct snd_dma_buffer *dmab_bdl, unsigned int max_size,
u32 count)
{
/* make sure Run bit is cleared before setting stream register */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, so I guess this is where we differ from APL, if so is it all the register write below or only some ?

cl_skl_cldma_stream_run(sdev, 0);

snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 4 writes are to same register, cant they be done as one write ?

CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));

snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_BDLPL,
CL_SD_BDLPLBA(0));
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_BDLPU, 0);

snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CBL, 0);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_LVI, 0);

/* setting the stream register */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_BDLPL,
CL_SD_BDLPLBA(dmab_bdl->addr));
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_BDLPU,
CL_SD_BDLPUBA(dmab_bdl->addr));

snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CBL,
max_size);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_LVI,
count - 1);
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1));
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1));
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1));
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_STRM_MASK,
CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, we also need comments here.

}

/*
* skl/kbl enable core and code loader DMA has some difference with apl/cnl
* add the APIs for skl/kbl
*/
static int cl_stream_prepare_skl(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = sdev->pci;
int frags = 0;
int ret = 0;
u32 *bdl;
unsigned int bufsize = SKL_MAX_BUFFER_SIZE;

ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize,
&sdev->dmab);
if (ret < 0) {
dev_err(sdev->dev, "Alloc base fw buffer failed: %x\n", ret);
return ret;
}
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize,
&sdev->dmab_bdl);
if (ret < 0) {
dev_err(sdev->dev, "Alloc buffer for blde failed: %x\n", ret);
snd_dma_free_pages(&sdev->dmab);
return ret;
}
bdl = (u32 *)sdev->dmab_bdl.area;

frags = cl_skl_cldma_setup_bdle(sdev, &sdev->dmab, &bdl, bufsize, 1);
cl_skl_cldma_setup_controller(sdev, &sdev->dmab_bdl, bufsize, frags);
return ret;
}

static int cl_dsp_init_skl(struct snd_sof_dev *sdev, const void *fwdata,
u32 fwsize)
{
const struct sof_intel_dsp_desc *chip = sdev->hda->desc;
int ret;

/* check if the core is already enabled, if yes, reset and make it run,
* if not, powerdown and enable it again.
*/
if (hda_dsp_core_is_enabled(sdev, HDA_DSP_CORE_MASK(0))) {
/* if enabled, reset it, and run the core. */
ret = hda_dsp_core_stall_reset(sdev, HDA_DSP_CORE_MASK(0));
if (ret < 0)
goto err;

ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0));
if (ret < 0) {
dev_err(sdev->dev, "error: dsp core start failed %d\n",
ret);
ret = -EIO;
goto err;
}
} else {
/* if not enabled, power down it first and then powerup and run
* the core.
*/
ret = hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0));
if (ret < 0) {
dev_err(sdev->dev, "dsp core0 disable fail: %d\n", ret);
return ret;
}
ret = hda_dsp_enable_core(sdev, HDA_DSP_CORE_MASK(0));
}

/* prepare DMA for code loader stream */
ret = cl_stream_prepare_skl(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: dma prepare fw loading err: %x\n",
ret);
return ret;
}

/* enable the interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);

/* enable IPC DONE interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
HDA_DSP_REG_HIPCCTL_DONE,
HDA_DSP_REG_HIPCCTL_DONE);

/* enable IPC BUSY interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
HDA_DSP_REG_HIPCCTL_BUSY,
HDA_DSP_REG_HIPCCTL_BUSY);

/* polling the ROM init status information. */
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS_SKL,
HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT,
HDA_DSP_INIT_TIMEOUT);
if (ret >= 0) {
dev_err(sdev->dev, "error: can't read the ROM status!");
goto out;
}

ret = -EIO;

err:
hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0));
out:
return ret;
}

static int cl_copy_fw_skl(struct snd_sof_dev *sdev)
{
return -1;
}

int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev);
struct firmware stripped_firmware;
int ret;

stripped_firmware.data = plat_data->fw->data;
stripped_firmware.size = plat_data->fw->size;

ret = cl_dsp_init_skl(sdev, stripped_firmware.data,
stripped_firmware.size);

/* retry enabling core and ROM load. seemed to help */
if (ret < 0) {
ret = cl_dsp_init_skl(sdev, stripped_firmware.data,
stripped_firmware.size);
if (ret <= 0) {
dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n",
snd_sof_dsp_read(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_ERROR),
snd_sof_dsp_read(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS));
dev_err(sdev->dev, "Core En/ROM load fail:%d\n", ret);
goto irq_err;
}
}

/* init for booting wait */
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 fw failed err: %d\n", ret);
goto irq_err;
}

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

return ret;

irq_err:
hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);

/* disable DSP */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_GPROCEN, 0);
dev_err(sdev->dev, "error: load fw failed err: %d\n", ret);
return ret;
}
4 changes: 4 additions & 0 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@
#define SOF_SKL_NUM_DAIS 8
#endif

#define HDA_DSP_SRAM_REG_ROM_STATUS_SKL 0x8000

struct sof_intel_dsp_bdl {
u32 addr_l;
u32 addr_h;
Expand Down Expand Up @@ -377,6 +379,7 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev,
int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask);
bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev,
unsigned int core_mask);
Expand Down Expand Up @@ -466,6 +469,7 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
*/
int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot);
int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev);

/*
* HDA Controller Operations.
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/sof/intel/skl.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ struct snd_sof_dsp_ops sof_skl_ops = {
.load_firmware = hda_dsp_cl_load_fw,

/* firmware run */
.run = hda_dsp_cl_boot_firmware,
.run = hda_dsp_cl_boot_firmware_skl,

/* trace callback */
.trace_init = hda_dsp_trace_init,
Expand Down
4 changes: 2 additions & 2 deletions sound/soc/sof/sof-pci-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ static const struct sof_ops_table mach_ops[] = {
{&cnl_desc, &sof_cnl_ops},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE)
{&skl_desc, &sof_apl_ops},
{&skl_desc, &sof_skl_ops},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE)
{&kbl_desc, &sof_apl_ops},
{&kbl_desc, &sof_skl_ops},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
{&icl_desc, &sof_cnl_ops},
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ struct snd_sof_dev {
/* firmware loader */
int cl_bar;
struct snd_dma_buffer dmab;
struct snd_dma_buffer dmab_bdl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need this since we already have some existing bdl logic


struct sof_ipc_fw_ready fw_ready;

/* topology */
Expand Down