From 2310452bd36b7b151dc6c631eb27436aad7539c5 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Mon, 10 Sep 2018 17:06:29 +0800 Subject: [PATCH 1/3] ASoC:SOF:skl:enable the core and get the ROM init 1. enable the skl core 2. get the ROM int Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-dsp.c | 15 +++ sound/soc/sof/intel/hda-loader.c | 153 +++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 4 + sound/soc/sof/intel/skl.c | 2 +- 4 files changed, 173 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 640bf0692413c0..d8400d85c9ae39 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -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) { diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 796d772a6a8d30..e6bc88af88f164 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -372,3 +372,156 @@ 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; } + +/* + * 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, unsigned int format, + unsigned int size, struct snd_dma_buffer *dmab, + int direction) +{ + /* the skl cl dma don't use stream tag, ret is for debug */ + int ret = 0; + 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, i; + u32 hipcie; + u32 reg; + + /* 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, 0x40, fwsize, &sdev->dmab, + SNDRV_PCM_STREAM_PLAYBACK); + + if (ret <= 0) { + dev_err(sdev->dev, "error: dma prepare fw loading err: %x\n", + ret); + return ret; + } + + memcpy(sdev->dmab.area, fwdata, fwsize); + + /* 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; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d44b2550e87fcd..e49547313511bf 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -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; @@ -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); @@ -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. diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index ab7cd2b689cba9..43b0bc169438fe 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -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, From b0c3460e946bc24a5007b2d6247b247d92df246e Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Wed, 12 Sep 2018 18:33:27 +0800 Subject: [PATCH 2/3] ASoC: SOF: skl enable the skl/kbl ops, instead of using apl_ops Signed-off-by: Zhu Yingjiang --- sound/soc/sof/sof-pci-dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index d2ec640306f305..fcef2bb1318215 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -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}, From 81b2f482f850b14fa24b3a0568b3a1860e6a4c5a Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Wed, 12 Sep 2018 18:59:56 +0800 Subject: [PATCH 3/3] SoC: SOF: skl add the cl_stream_prepare_skl API Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader.c | 146 ++++++++++++++++++++++++++++--- sound/soc/sof/sof-priv.h | 2 + 2 files changed, 135 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index e6bc88af88f164..af67a5d9371148 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -16,6 +16,7 @@ * Hardware interface for HDA DSP code loader */ +#include #include #include #include @@ -34,6 +35,8 @@ #include "../ops.h" #include "hda.h" +#include "../../intel/skylake/skl-sst-cldma.h" + static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, int direction) @@ -373,16 +376,139 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) 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 */ + 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, + 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)); +} + /* * 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, unsigned int format, - unsigned int size, struct snd_dma_buffer *dmab, - int direction) +static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) { - /* the skl cl dma don't use stream tag, ret is for debug */ + 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; } @@ -390,9 +516,7 @@ 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, i; - u32 hipcie; - u32 reg; + int ret; /* check if the core is already enabled, if yes, reset and make it run, * if not, powerdown and enable it again. @@ -423,17 +547,13 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev, const void *fwdata, } /* prepare DMA for code loader stream */ - ret = cl_stream_prepare_skl(sdev, 0x40, fwsize, &sdev->dmab, - SNDRV_PCM_STREAM_PLAYBACK); - - if (ret <= 0) { + ret = cl_stream_prepare_skl(sdev); + if (ret < 0) { dev_err(sdev->dev, "error: dma prepare fw loading err: %x\n", ret); return ret; } - memcpy(sdev->dmab.area, fwdata, fwsize); - /* enable the interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 802bf1bc7812ef..da118df09f6d3d 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -327,6 +327,8 @@ struct snd_sof_dev { /* firmware loader */ int cl_bar; struct snd_dma_buffer dmab; + struct snd_dma_buffer dmab_bdl; + struct sof_ipc_fw_ready fw_ready; /* topology */