Merge branch 'fix/intel' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorMark Brown <broonie@kernel.org>
Wed, 11 Mar 2015 12:53:41 +0000 (12:53 +0000)
committerMark Brown <broonie@kernel.org>
Wed, 11 Mar 2015 12:53:41 +0000 (12:53 +0000)
1  2 
sound/soc/intel/sst-haswell-dsp.c
sound/soc/intel/sst-haswell-ipc.c

@@@ -207,9 -207,6 +207,6 @@@ static int hsw_parse_fw_image(struct ss
                module = (void *)module + sizeof(*module) + module->mod_size;
        }
  
-       /* allocate scratch mem regions */
-       sst_block_alloc_scratch(dsp);
        return 0;
  }
  
@@@ -306,7 -303,7 +303,7 @@@ static void hsw_reset(struct sst_dsp *s
  static int hsw_set_dsp_D0(struct sst_dsp *sst)
  {
        int tries = 10;
 -      u32 reg;
 +      u32 reg, fw_dump_bit;
  
        /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
@@@ -368,9 -365,7 +365,9 @@@ finish
        can't be accessed, please enable each block before accessing. */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
        reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
 -      writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
 +      /* for D0, always enable the block(DSRAM[0]) used for FW dump */
 +      fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
 +      writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
  
  
        /* disable DMA finish function for SSP0 & SSP1 */
@@@ -493,7 -488,6 +490,7 @@@ static const struct sst_sram_shift sram
        {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */
        {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */
  };
 +
  static u32 hsw_block_get_bit(struct sst_mem_block *block)
  {
        u32 bit = 0, shift = 0, index;
@@@ -590,9 -584,7 +587,9 @@@ static int hsw_block_disable(struct sst
  
        val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
        bit = hsw_block_get_bit(block);
 -      writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
 +      /* don't disable DSRAM[0], keep it always enable for FW dump*/
 +      if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT))
 +              writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
  
        /* wait 18 DSP clock ticks */
        udelay(10);
@@@ -617,7 -609,7 +614,7 @@@ static int hsw_init(struct sst_dsp *sst
        const struct sst_adsp_memregion *region;
        struct device *dev;
        int ret = -ENODEV, i, j, region_count;
 -      u32 offset, size;
 +      u32 offset, size, fw_dump_bit;
  
        dev = sst->dma_dev;
  
                }
        }
  
 +      /* always enable the block(DSRAM[0]) used for FW dump */
 +      fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
        /* set default power gating control, enable power gating control for all blocks. that is,
        can't be accessed, please enable each block before accessing. */
 -      writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0);
 +      writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
  
        return 0;
  }
@@@ -31,7 -31,6 +31,7 @@@
  #include <linux/dma-mapping.h>
  #include <linux/debugfs.h>
  #include <linux/pm_runtime.h>
 +#include <sound/asound.h>
  
  #include "sst-haswell-ipc.h"
  #include "sst-dsp.h"
@@@ -95,8 -94,6 +95,8 @@@
  /* Mailbox */
  #define IPC_MAX_MAILBOX_BYTES 256
  
 +#define INVALID_STREAM_HW_ID  0xffffffff
 +
  /* Global Message - Types and Replies */
  enum ipc_glb_type {
        IPC_GLB_GET_FW_VERSION = 0,             /* Retrieves firmware version */
@@@ -243,9 -240,6 +243,9 @@@ struct sst_hsw_stream 
        u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
        void *pdata;
  
 +      /* record the fw read position when playback */
 +      snd_pcm_uframes_t old_position;
 +      bool play_silence;
        struct list_head node;
  };
  
@@@ -281,6 -275,7 +281,6 @@@ struct sst_hsw 
        /* FW config */
        struct sst_hsw_ipc_fw_ready fw_ready;
        struct sst_hsw_ipc_fw_version version;
 -      struct sst_module *scratch;
        bool fw_done;
        struct sst_fw *sst_fw;
  
@@@ -342,6 -337,12 +342,6 @@@ static inline u32 msg_get_stage_type(u3
        return (msg & IPC_STG_TYPE_MASK) >>  IPC_STG_TYPE_SHIFT;
  }
  
 -static inline u32 msg_set_stage_type(u32 msg, u32 type)
 -{
 -      return (msg & ~IPC_STG_TYPE_MASK) +
 -              (type << IPC_STG_TYPE_SHIFT);
 -}
 -
  static inline u32 msg_get_stream_id(u32 msg)
  {
        return (msg & IPC_STR_ID_MASK) >>  IPC_STR_ID_SHIFT;
@@@ -968,6 -969,45 +968,6 @@@ int sst_hsw_fw_get_version(struct sst_h
  }
  
  /* Mixer Controls */
 -int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
 -      u32 stage_id, u32 channel)
 -{
 -      int ret;
 -
 -      ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel,
 -              &stream->mute_volume[channel]);
 -      if (ret < 0)
 -              return ret;
 -
 -      ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0);
 -      if (ret < 0) {
 -              dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
 -                      stream->reply.stream_hw_id, channel);
 -              return ret;
 -      }
 -
 -      stream->mute[channel] = 1;
 -      return 0;
 -}
 -
 -int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
 -      u32 stage_id, u32 channel)
 -
 -{
 -      int ret;
 -
 -      stream->mute[channel] = 0;
 -      ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel,
 -              stream->mute_volume[channel]);
 -      if (ret < 0) {
 -              dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
 -                      stream->reply.stream_hw_id, channel);
 -              return ret;
 -      }
 -
 -      return 0;
 -}
 -
  int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
        u32 stage_id, u32 channel, u32 *volume)
  {
        return 0;
  }
  
 -int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
 -      struct sst_hsw_stream *stream, u64 curve_duration,
 -      enum sst_hsw_volume_curve curve)
 -{
 -      /* curve duration in steps of 100ns */
 -      stream->vol_req.curve_duration = curve_duration;
 -      stream->vol_req.curve_type = curve;
 -
 -      return 0;
 -}
 -
  /* stream volume */
  int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
        return 0;
  }
  
 -int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
 -{
 -      int ret;
 -
 -      ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel,
 -              &hsw->mute_volume[channel]);
 -      if (ret < 0)
 -              return ret;
 -
 -      ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0);
 -      if (ret < 0) {
 -              dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
 -                      channel);
 -              return ret;
 -      }
 -
 -      hsw->mute[channel] = 1;
 -      return 0;
 -}
 -
 -int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
 -{
 -      int ret;
 -
 -      ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel,
 -              hsw->mixer_info.volume_register_address[channel]);
 -      if (ret < 0) {
 -              dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
 -                      channel);
 -              return ret;
 -      }
 -
 -      hsw->mute[channel] = 0;
 -      return 0;
 -}
 -
  int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 *volume)
  {
        return 0;
  }
  
 -int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
 -       u64 curve_duration, enum sst_hsw_volume_curve curve)
 -{
 -      /* curve duration in steps of 100ns */
 -      hsw->curve_duration = curve_duration;
 -      hsw->curve_type = curve;
 -
 -      return 0;
 -}
 -
  /* global mixer volume */
  int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 volume)
@@@ -1111,7 -1208,6 +1111,7 @@@ struct sst_hsw_stream *sst_hsw_stream_n
                return NULL;
  
        spin_lock_irqsave(&sst->spinlock, flags);
 +      stream->reply.stream_hw_id = INVALID_STREAM_HW_ID;
        list_add(&stream->node, &hsw->stream_list);
        stream->notify_position = notify_position;
        stream->pdata = data;
@@@ -1351,32 -1447,50 +1351,32 @@@ int sst_hsw_stream_commit(struct sst_hs
        return 0;
  }
  
 -/* Stream Information - these calls could be inline but we want the IPC
 - ABI to be opaque to client PCM drivers to cope with any future ABI changes */
 -int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
 +snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream)
  {
 -      return stream->reply.stream_hw_id;
 +      return stream->old_position;
  }
  
 -int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
 -      struct sst_hsw_stream *stream)
 +void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
 +      struct sst_hsw_stream *stream, snd_pcm_uframes_t val)
  {
 -      return stream->reply.mixer_hw_id;
 +      stream->old_position = val;
  }
  
 -u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
 +bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream)
  {
 -      return stream->reply.read_position_register_address;
 -}
 -
 -u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
 -      struct sst_hsw_stream *stream)
 -{
 -      return stream->reply.presentation_position_register_address;
 -}
 -
 -u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
 -      struct sst_hsw_stream *stream, u32 channel)
 -{
 -      if (channel >= 2)
 -              return 0;
 -
 -      return stream->reply.peak_meter_register_address[channel];
 +      return stream->play_silence;
  }
  
 -u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
 -      struct sst_hsw_stream *stream, u32 channel)
 +void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
 +      struct sst_hsw_stream *stream, bool val)
  {
 -      if (channel >= 2)
 -              return 0;
 -
 -      return stream->reply.volume_register_address[channel];
 +      stream->play_silence = val;
  }
  
 +/* Stream Information - these calls could be inline but we want the IPC
 + ABI to be opaque to client PCM drivers to cope with any future ABI changes */
  int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
  {
        struct sst_hsw_ipc_stream_info_reply *reply;
@@@ -1514,6 -1628,30 +1514,6 @@@ u64 sst_hsw_get_dsp_presentation_positi
        return ppos;
  }
  
 -int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
 -      struct sst_hsw_stream *stream, u32 stage_id, u32 position)
 -{
 -      u32 header;
 -      int ret;
 -
 -      trace_stream_write_position(stream->reply.stream_hw_id, position);
 -
 -      header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
 -              IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
 -      header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
 -      header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT);
 -      header |= (stage_id << IPC_STG_ID_SHIFT);
 -      stream->wpos.position = position;
 -
 -      ret = ipc_tx_message_nowait(hsw, header, &stream->wpos,
 -              sizeof(stream->wpos));
 -      if (ret < 0)
 -              dev_err(hsw->dev, "error: stream %d set position %d failed\n",
 -                      stream->reply.stream_hw_id, position);
 -
 -      return ret;
 -}
 -
  /* physical BE config */
  int sst_hsw_device_set_config(struct sst_hsw *hsw,
        enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
@@@ -1732,6 -1870,7 +1732,7 @@@ static void sst_hsw_drop_all(struct sst
  int sst_hsw_dsp_load(struct sst_hsw *hsw)
  {
        struct sst_dsp *dsp = hsw->dsp;
+       struct sst_fw *sst_fw, *t;
        int ret;
  
        dev_dbg(hsw->dev, "loading audio DSP....");
                return ret;
        }
  
-       ret = sst_fw_reload(hsw->sst_fw);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: SST FW reload failed\n");
-               sst_dsp_dma_put_channel(dsp);
-               return -ENOMEM;
+       list_for_each_entry_safe_reverse(sst_fw, t, &dsp->fw_list, list) {
+               ret = sst_fw_reload(sst_fw);
+               if (ret < 0) {
+                       dev_err(hsw->dev, "error: SST FW reload failed\n");
+                       sst_dsp_dma_put_channel(dsp);
+                       return -ENOMEM;
+               }
        }
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               return -EINVAL;
  
        sst_dsp_dma_put_channel(dsp);
        return 0;
@@@ -1809,12 -1953,17 +1815,17 @@@ int sst_hsw_dsp_runtime_suspend(struct 
  
  int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw)
  {
-       sst_fw_unload(hsw->sst_fw);
-       sst_block_free_scratch(hsw->dsp);
+       struct sst_fw *sst_fw, *t;
+       struct sst_dsp *dsp = hsw->dsp;
+       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+               sst_fw_unload(sst_fw);
+       }
+       sst_block_free_scratch(dsp);
  
        hsw->boot_complete = false;
  
-       sst_dsp_sleep(hsw->dsp);
+       sst_dsp_sleep(dsp);
  
        return 0;
  }
@@@ -1943,6 -2092,11 +1954,11 @@@ int sst_hsw_dsp_init(struct device *dev
                goto fw_err;
        }
  
+       /* allocate scratch mem regions */
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               goto boot_err;
        /* wait for DSP boot completion */
        sst_dsp_boot(hsw->dsp);
        ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
@@@ -1994,6 -2148,7 +2010,6 @@@ void sst_hsw_dsp_free(struct device *de
        dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
                        hsw->dx_context, hsw->dx_context_paddr);
        sst_dsp_free(hsw->dsp);
 -      kfree(hsw->scratch);
        kthread_stop(hsw->tx_thread);
        kfree(hsw->msg);
  }