diff options
Diffstat (limited to 'sound/pci/hda/hda_controller.c')
-rw-r--r-- | sound/pci/hda/hda_controller.c | 1330 |
1 files changed, 270 insertions, 1060 deletions
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 26ce990592a0..e0bb6231ff0c 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -35,226 +35,26 @@ #include "hda_intel_trace.h" /* DSP lock helpers */ -#ifdef CONFIG_SND_HDA_DSP_LOADER -#define dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex) -#define dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex) -#define dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex) -#define dsp_is_locked(dev) ((dev)->locked) -#else -#define dsp_lock_init(dev) do {} while (0) -#define dsp_lock(dev) do {} while (0) -#define dsp_unlock(dev) do {} while (0) -#define dsp_is_locked(dev) 0 -#endif - -/* - * AZX stream operations. - */ - -/* start a stream */ -static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) -{ - /* - * Before stream start, initialize parameter - */ - azx_dev->insufficient = 1; - - /* enable SIE */ - azx_writel(chip, INTCTL, - azx_readl(chip, INTCTL) | (1 << azx_dev->index)); - /* set DMA start and interrupt mask */ - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) | - SD_CTL_DMA_START | SD_INT_MASK); -} - -/* stop DMA */ -static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev) -{ - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) & - ~(SD_CTL_DMA_START | SD_INT_MASK)); - azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ -} - -/* stop a stream */ -void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) -{ - azx_stream_clear(chip, azx_dev); - /* disable SIE */ - azx_writel(chip, INTCTL, - azx_readl(chip, INTCTL) & ~(1 << azx_dev->index)); -} -EXPORT_SYMBOL_GPL(azx_stream_stop); - -/* reset stream */ -static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned char val; - int timeout; - - azx_stream_clear(chip, azx_dev); - - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) | - SD_CTL_STREAM_RESET); - udelay(3); - timeout = 300; - while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) & - SD_CTL_STREAM_RESET) && --timeout) - ; - val &= ~SD_CTL_STREAM_RESET; - azx_sd_writeb(chip, azx_dev, SD_CTL, val); - udelay(3); - - timeout = 300; - /* waiting for hardware to report that the stream is out of reset */ - while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) & - SD_CTL_STREAM_RESET) && --timeout) - ; - - /* reset first position - may not be synced with hw at this time */ - *azx_dev->posbuf = 0; -} - -/* - * set up the SD for streaming - */ -static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned int val; - /* make sure the run bit is zero for SD */ - azx_stream_clear(chip, azx_dev); - /* program the stream_tag */ - val = azx_sd_readl(chip, azx_dev, SD_CTL); - val = (val & ~SD_CTL_STREAM_TAG_MASK) | - (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT); - if (!azx_snoop(chip)) - val |= SD_CTL_TRAFFIC_PRIO; - azx_sd_writel(chip, azx_dev, SD_CTL, val); - - /* program the length of samples in cyclic buffer */ - azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize); - - /* program the stream format */ - /* this value needs to be the same as the one programmed */ - azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val); - - /* program the stream LVI (last valid index) of the BDL */ - azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1); - - /* program the BDL address */ - /* lower BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); - /* upper BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPU, - upper_32_bits(azx_dev->bdl.addr)); - - /* enable the position buffer */ - if (chip->get_position[0] != azx_get_pos_lpib || - chip->get_position[1] != azx_get_pos_lpib) { - if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, - (u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE); - } - - /* set the interrupt enable bits in the descriptor control register */ - azx_sd_writel(chip, azx_dev, SD_CTL, - azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK); - - return 0; -} +#define dsp_lock(dev) snd_hdac_dsp_lock(azx_stream(dev)) +#define dsp_unlock(dev) snd_hdac_dsp_unlock(azx_stream(dev)) +#define dsp_is_locked(dev) snd_hdac_stream_is_locked(azx_stream(dev)) /* assign a stream for the PCM */ static inline struct azx_dev * azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) { - int dev, i, nums; - struct azx_dev *res = NULL; - /* make a non-zero unique key for the substream */ - int key = (substream->pcm->device << 16) | (substream->number << 2) | - (substream->stream + 1); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dev = chip->playback_index_offset; - nums = chip->playback_streams; - } else { - dev = chip->capture_index_offset; - nums = chip->capture_streams; - } - for (i = 0; i < nums; i++, dev++) { - struct azx_dev *azx_dev = &chip->azx_dev[dev]; - dsp_lock(azx_dev); - if (!azx_dev->opened && !dsp_is_locked(azx_dev)) { - if (azx_dev->assigned_key == key) { - azx_dev->opened = 1; - azx_dev->assigned_key = key; - dsp_unlock(azx_dev); - return azx_dev; - } - if (!res || - (chip->driver_caps & AZX_DCAPS_REVERSE_ASSIGN)) - res = azx_dev; - } - dsp_unlock(azx_dev); - } - if (res) { - dsp_lock(res); - res->opened = 1; - res->assigned_key = key; - dsp_unlock(res); - } - return res; + struct hdac_stream *s; + + s = snd_hdac_stream_assign(azx_bus(chip), substream); + if (!s) + return NULL; + return stream_to_azx_dev(s); } /* release the assigned stream */ static inline void azx_release_device(struct azx_dev *azx_dev) { - azx_dev->opened = 0; -} - -static cycle_t azx_cc_read(const struct cyclecounter *cc) -{ - struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc); - struct snd_pcm_substream *substream = azx_dev->substream; - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - - return azx_readl(chip, WALLCLK); -} - -static void azx_timecounter_init(struct snd_pcm_substream *substream, - bool force, cycle_t last) -{ - struct azx_dev *azx_dev = get_azx_dev(substream); - struct timecounter *tc = &azx_dev->azx_tc; - struct cyclecounter *cc = &azx_dev->azx_cc; - u64 nsec; - - cc->read = azx_cc_read; - cc->mask = CLOCKSOURCE_MASK(32); - - /* - * Converting from 24 MHz to ns means applying a 125/3 factor. - * To avoid any saturation issues in intermediate operations, - * the 125 factor is applied first. The division is applied - * last after reading the timecounter value. - * Applying the 1/3 factor as part of the multiplication - * requires at least 20 bits for a decent precision, however - * overflows occur after about 4 hours or less, not a option. - */ - - cc->mult = 125; /* saturation after 195 years */ - cc->shift = 0; - - nsec = 0; /* audio time is elapsed time since trigger */ - timecounter_init(tc, cc, nsec); - if (force) - /* - * force timecounter to use predefined value, - * used for synchronized starts - */ - tc->cycle_last = last; + snd_hdac_stream_release(azx_stream(azx_dev)); } static inline struct hda_pcm_stream * @@ -285,119 +85,6 @@ static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream, } /* - * set up a BDL entry - */ -static int setup_bdle(struct azx *chip, - struct snd_dma_buffer *dmab, - struct azx_dev *azx_dev, u32 **bdlp, - int ofs, int size, int with_ioc) -{ - u32 *bdl = *bdlp; - - while (size > 0) { - dma_addr_t addr; - int chunk; - - if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) - return -EINVAL; - - addr = snd_sgbuf_get_addr(dmab, ofs); - /* program the address field of the BDL entry */ - bdl[0] = cpu_to_le32((u32)addr); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - /* program the size field of the BDL entry */ - chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size); - /* one BDLE cannot cross 4K boundary on CTHDA chips */ - if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) { - u32 remain = 0x1000 - (ofs & 0xfff); - if (chunk > remain) - chunk = remain; - } - bdl[2] = cpu_to_le32(chunk); - /* program the IOC to enable interrupt - * only when the whole fragment is processed - */ - size -= chunk; - bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); - bdl += 4; - azx_dev->frags++; - ofs += chunk; - } - *bdlp = bdl; - return ofs; -} - -/* - * set up BDL entries - */ -static int azx_setup_periods(struct azx *chip, - struct snd_pcm_substream *substream, - struct azx_dev *azx_dev) -{ - u32 *bdl; - int i, ofs, periods, period_bytes; - int pos_adj = 0; - - /* reset BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - - period_bytes = azx_dev->period_bytes; - periods = azx_dev->bufsize / period_bytes; - - /* program the initial BDL entries */ - bdl = (u32 *)azx_dev->bdl.area; - ofs = 0; - azx_dev->frags = 0; - - if (chip->bdl_pos_adj) - pos_adj = chip->bdl_pos_adj[chip->dev_index]; - if (!azx_dev->no_period_wakeup && pos_adj > 0) { - struct snd_pcm_runtime *runtime = substream->runtime; - int pos_align = pos_adj; - pos_adj = (pos_adj * runtime->rate + 47999) / 48000; - if (!pos_adj) - pos_adj = pos_align; - else - pos_adj = ((pos_adj + pos_align - 1) / pos_align) * - pos_align; - pos_adj = frames_to_bytes(runtime, pos_adj); - if (pos_adj >= period_bytes) { - dev_warn(chip->card->dev,"Too big adjustment %d\n", - pos_adj); - pos_adj = 0; - } else { - ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), - azx_dev, - &bdl, ofs, pos_adj, true); - if (ofs < 0) - goto error; - } - } else - pos_adj = 0; - - for (i = 0; i < periods; i++) { - if (i == periods - 1 && pos_adj) - ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), - azx_dev, &bdl, ofs, - period_bytes - pos_adj, 0); - else - ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), - azx_dev, &bdl, ofs, - period_bytes, - !azx_dev->no_period_wakeup); - if (ofs < 0) - goto error; - } - return 0; - - error: - dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n", - azx_dev->bufsize, period_bytes); - return -EINVAL; -} - -/* * PCM ops */ @@ -407,13 +94,8 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); - unsigned long flags; mutex_lock(&chip->open_mutex); - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = NULL; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); azx_release_device(azx_dev); if (hinfo->ops.close) hinfo->ops.close(hinfo, apcm->codec, substream); @@ -428,18 +110,22 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; + struct azx_dev *azx_dev = get_azx_dev(substream); int ret; - dsp_lock(get_azx_dev(substream)); - if (dsp_is_locked(get_azx_dev(substream))) { + dsp_lock(azx_dev); + if (dsp_is_locked(azx_dev)) { ret = -EBUSY; goto unlock; } + azx_dev->core.bufsize = 0; + azx_dev->core.period_bytes = 0; + azx_dev->core.format_val = 0; ret = chip->ops->substream_alloc_pages(chip, substream, params_buffer_bytes(hw_params)); unlock: - dsp_unlock(get_azx_dev(substream)); + dsp_unlock(azx_dev); return ret; } @@ -453,19 +139,13 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) /* reset BDL address */ dsp_lock(azx_dev); - if (!dsp_is_locked(azx_dev)) { - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - azx_sd_writel(chip, azx_dev, SD_CTL, 0); - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; - } + if (!dsp_is_locked(azx_dev)) + snd_hdac_stream_cleanup(azx_stream(azx_dev)); snd_hda_codec_cleanup(apcm->codec, hinfo, substream); err = chip->ops->substream_free_pages(chip, substream); - azx_dev->prepared = 0; + azx_stream(azx_dev)->prepared = 0; dsp_unlock(azx_dev); return err; } @@ -477,7 +157,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct azx_dev *azx_dev = get_azx_dev(substream); struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int bufsize, period_bytes, format_val, stream_tag; + unsigned int format_val, stream_tag; int err; struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); @@ -489,9 +169,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - azx_stream_reset(chip, azx_dev); - format_val = snd_hda_calc_stream_format(apcm->codec, - runtime->rate, + snd_hdac_stream_reset(azx_stream(azx_dev)); + format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, hinfo->maxbps, @@ -504,55 +183,23 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - bufsize = snd_pcm_lib_buffer_bytes(substream); - period_bytes = snd_pcm_lib_period_bytes(substream); - - dev_dbg(chip->card->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", - bufsize, format_val); - - if (bufsize != azx_dev->bufsize || - period_bytes != azx_dev->period_bytes || - format_val != azx_dev->format_val || - runtime->no_period_wakeup != azx_dev->no_period_wakeup) { - azx_dev->bufsize = bufsize; - azx_dev->period_bytes = period_bytes; - azx_dev->format_val = format_val; - azx_dev->no_period_wakeup = runtime->no_period_wakeup; - err = azx_setup_periods(chip, substream, azx_dev); - if (err < 0) - goto unlock; - } + err = snd_hdac_stream_set_params(azx_stream(azx_dev), format_val); + if (err < 0) + goto unlock; - /* when LPIB delay correction gives a small negative value, - * we ignore it; currently set the threshold statically to - * 64 frames - */ - if (runtime->period_size > 64) - azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64); - else - azx_dev->delay_negative_threshold = 0; - - /* wallclk has 24Mhz clock source */ - azx_dev->period_wallclk = (((runtime->period_size * 24000) / - runtime->rate) * 1000); - azx_setup_controller(chip, azx_dev); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - azx_dev->fifo_size = - azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1; - else - azx_dev->fifo_size = 0; + snd_hdac_stream_setup(azx_stream(azx_dev)); - stream_tag = azx_dev->stream_tag; + stream_tag = azx_dev->core.stream_tag; /* CA-IBG chips need the playback stream starting from 1 */ if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) && stream_tag > chip->capture_streams) stream_tag -= chip->capture_streams; err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, - azx_dev->format_val, substream); + azx_dev->core.format_val, substream); unlock: if (!err) - azx_dev->prepared = 1; + azx_stream(azx_dev)->prepared = 1; dsp_unlock(azx_dev); return err; } @@ -561,28 +208,36 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; + struct hdac_bus *bus = azx_bus(chip); struct azx_dev *azx_dev; struct snd_pcm_substream *s; - int rstart = 0, start, nsync = 0, sbits = 0; - int nwait, timeout; + struct hdac_stream *hstr; + bool start; + int sbits = 0; + int sync_reg; azx_dev = get_azx_dev(substream); trace_azx_pcm_trigger(chip, azx_dev, cmd); - if (dsp_is_locked(azx_dev) || !azx_dev->prepared) + hstr = azx_stream(azx_dev); + if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) + sync_reg = AZX_REG_OLD_SSYNC; + else + sync_reg = AZX_REG_SSYNC; + + if (dsp_is_locked(azx_dev) || !hstr->prepared) return -EPIPE; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - rstart = 1; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: - start = 1; + start = true; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - start = 0; + start = false; break; default: return -EINVAL; @@ -592,115 +247,55 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (s->pcm->card != substream->pcm->card) continue; azx_dev = get_azx_dev(s); - sbits |= 1 << azx_dev->index; - nsync++; + sbits |= 1 << azx_dev->core.index; snd_pcm_trigger_done(s, substream); } - spin_lock(&chip->reg_lock); + spin_lock(&bus->reg_lock); /* first, set SYNC bits of corresponding streams */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) | sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); + snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg); snd_pcm_group_for_each_entry(s, substream) { if (s->pcm->card != substream->pcm->card) continue; azx_dev = get_azx_dev(s); if (start) { - azx_dev->start_wallclk = azx_readl(chip, WALLCLK); - if (!rstart) - azx_dev->start_wallclk -= - azx_dev->period_wallclk; - azx_stream_start(chip, azx_dev); + azx_dev->insufficient = 1; + snd_hdac_stream_start(azx_stream(azx_dev), true); } else { - azx_stream_stop(chip, azx_dev); + snd_hdac_stream_stop(azx_stream(azx_dev)); } - azx_dev->running = start; } - spin_unlock(&chip->reg_lock); - if (start) { - /* wait until all FIFOs get ready */ - for (timeout = 5000; timeout; timeout--) { - nwait = 0; - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (!(azx_sd_readb(chip, azx_dev, SD_STS) & - SD_STS_FIFO_READY)) - nwait++; - } - if (!nwait) - break; - cpu_relax(); - } - } else { - /* wait until all RUN bits are cleared */ - for (timeout = 5000; timeout; timeout--) { - nwait = 0; - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (azx_sd_readb(chip, azx_dev, SD_CTL) & - SD_CTL_DMA_START) - nwait++; - } - if (!nwait) - break; - cpu_relax(); - } - } - spin_lock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); + + snd_hdac_stream_sync(hstr, start, sbits); + + spin_lock(&bus->reg_lock); /* reset SYNC bits */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) & ~sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); - if (start) { - azx_timecounter_init(substream, 0, 0); - snd_pcm_gettime(substream->runtime, &substream->runtime->trigger_tstamp); - substream->runtime->trigger_tstamp_latched = true; - - if (nsync > 1) { - cycle_t cycle_last; - - /* same start cycle for master and group */ - azx_dev = get_azx_dev(substream); - cycle_last = azx_dev->azx_tc.cycle_last; - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_timecounter_init(s, 1, cycle_last); - } - } - } - spin_unlock(&chip->reg_lock); + snd_hdac_stream_sync_trigger(hstr, false, sbits, sync_reg); + if (start) + snd_hdac_stream_timecounter_init(hstr, sbits); + spin_unlock(&bus->reg_lock); return 0; } unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev) { - return azx_sd_readl(chip, azx_dev, SD_LPIB); + return snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev)); } EXPORT_SYMBOL_GPL(azx_get_pos_lpib); unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev) { - return le32_to_cpu(*azx_dev->posbuf); + return snd_hdac_stream_get_pos_posbuf(azx_stream(azx_dev)); } EXPORT_SYMBOL_GPL(azx_get_pos_posbuf); unsigned int azx_get_position(struct azx *chip, struct azx_dev *azx_dev) { - struct snd_pcm_substream *substream = azx_dev->substream; + struct snd_pcm_substream *substream = azx_dev->core.substream; unsigned int pos; int stream = substream->stream; int delay = 0; @@ -710,7 +305,7 @@ unsigned int azx_get_position(struct azx *chip, else /* use the position buffer as default */ pos = azx_get_pos_posbuf(chip, azx_dev); - if (pos >= azx_dev->bufsize) + if (pos >= azx_dev->core.bufsize) pos = 0; if (substream->runtime) { @@ -752,7 +347,7 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, snd_pcm_gettime(substream->runtime, system_ts); - nsec = timecounter_read(&azx_dev->azx_tc); + nsec = timecounter_read(&azx_dev->core.tc); nsec = div_u64(nsec, 3); /* can be optimized */ if (audio_tstamp_config->report_delay) nsec = azx_adjust_codec_delay(substream, nsec); @@ -802,7 +397,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) struct azx *chip = apcm->chip; struct azx_dev *azx_dev; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; int err; int buff_step; @@ -813,6 +407,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) err = -EBUSY; goto unlock; } + runtime->private_data = azx_dev; runtime->hw = azx_pcm_hw; runtime->hw.channels_min = hinfo->channels_min; runtime->hw.channels_max = hinfo->channels_max; @@ -874,12 +469,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; } - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = substream; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); - - runtime->private_data = azx_dev; snd_pcm_set_sync(substream); mutex_unlock(&chip->open_mutex); return 0; @@ -928,10 +517,11 @@ static void azx_pcm_free(struct snd_pcm *pcm) #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) -static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *cpcm) +int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, + struct hda_pcm *cpcm) { - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &_bus->core; + struct azx *chip = bus_to_azx(bus); struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; @@ -979,89 +569,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, return 0; } -/* - * CORB / RIRB interface - */ -static int azx_alloc_cmd_io(struct azx *chip) -{ - /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - return chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, - PAGE_SIZE, &chip->rb); -} - -static void azx_init_cmd_io(struct azx *chip) -{ - int timeout; - - spin_lock_irq(&chip->reg_lock); - /* CORB set up */ - chip->corb.addr = chip->rb.addr; - chip->corb.buf = (u32 *)chip->rb.area; - azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); - azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr)); - - /* set the corb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, CORBSIZE, 0x02); - /* set the corb write pointer to 0 */ - azx_writew(chip, CORBWP, 0); - - /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, AZX_CORBRP_RST); - if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) { - for (timeout = 1000; timeout > 0; timeout--) { - if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST) - break; - udelay(1); - } - if (timeout <= 0) - dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n", - azx_readw(chip, CORBRP)); - - azx_writew(chip, CORBRP, 0); - for (timeout = 1000; timeout > 0; timeout--) { - if (azx_readw(chip, CORBRP) == 0) - break; - udelay(1); - } - if (timeout <= 0) - dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n", - azx_readw(chip, CORBRP)); - } - - /* enable corb dma */ - azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN); - - /* RIRB set up */ - chip->rirb.addr = chip->rb.addr + 2048; - chip->rirb.buf = (u32 *)(chip->rb.area + 2048); - chip->rirb.wp = chip->rirb.rp = 0; - memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds)); - azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); - azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); - - /* set the rirb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, RIRBSIZE, 0x02); - /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, AZX_RIRBWP_RST); - /* set N=1, get RIRB response interrupt for new entry */ - if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) - azx_writew(chip, RINTCNT, 0xc0); - else - azx_writew(chip, RINTCNT, 1); - /* enable rirb dma and response irq */ - azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); - spin_unlock_irq(&chip->reg_lock); -} - -static void azx_free_cmd_io(struct azx *chip) -{ - spin_lock_irq(&chip->reg_lock); - /* disable ringbuffer DMAs */ - azx_writeb(chip, RIRBCTL, 0); - azx_writeb(chip, CORBCTL, 0); - spin_unlock_irq(&chip->reg_lock); -} - static unsigned int azx_command_addr(u32 cmd) { unsigned int addr = cmd >> 28; @@ -1074,92 +581,12 @@ static unsigned int azx_command_addr(u32 cmd) return addr; } -/* send a command */ -static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) -{ - struct azx *chip = bus->private_data; - unsigned int addr = azx_command_addr(val); - unsigned int wp, rp; - - spin_lock_irq(&chip->reg_lock); - - /* add command to corb */ - wp = azx_readw(chip, CORBWP); - if (wp == 0xffff) { - /* something wrong, controller likely turned to D3 */ - spin_unlock_irq(&chip->reg_lock); - return -EIO; - } - wp++; - wp %= AZX_MAX_CORB_ENTRIES; - - rp = azx_readw(chip, CORBRP); - if (wp == rp) { - /* oops, it's full */ - spin_unlock_irq(&chip->reg_lock); - return -EAGAIN; - } - - chip->rirb.cmds[addr]++; - chip->corb.buf[wp] = cpu_to_le32(val); - azx_writew(chip, CORBWP, wp); - - spin_unlock_irq(&chip->reg_lock); - - return 0; -} - -#define AZX_RIRB_EX_UNSOL_EV (1<<4) - -/* retrieve RIRB entry - called from interrupt handler */ -static void azx_update_rirb(struct azx *chip) -{ - unsigned int rp, wp; - unsigned int addr; - u32 res, res_ex; - - wp = azx_readw(chip, RIRBWP); - if (wp == 0xffff) { - /* something wrong, controller likely turned to D3 */ - return; - } - - if (wp == chip->rirb.wp) - return; - chip->rirb.wp = wp; - - while (chip->rirb.rp != wp) { - chip->rirb.rp++; - chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES; - - rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ - res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); - res = le32_to_cpu(chip->rirb.buf[rp]); - addr = res_ex & 0xf; - if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) { - dev_err(chip->card->dev, "spurious response %#x:%#x, rp = %d, wp = %d", - res, res_ex, - chip->rirb.rp, wp); - snd_BUG(); - } else if (res_ex & AZX_RIRB_EX_UNSOL_EV) - snd_hda_queue_unsol_event(chip->bus, res, res_ex); - else if (chip->rirb.cmds[addr]) { - chip->rirb.res[addr] = res; - smp_wmb(); - chip->rirb.cmds[addr]--; - } else if (printk_ratelimit()) { - dev_err(chip->card->dev, "spurious response %#x:%#x, last cmd=%#08x\n", - res, res_ex, - chip->last_cmd[addr]); - } - } -} - /* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_bus *bus, - unsigned int addr) +static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, + unsigned int *res) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); + struct hda_bus *hbus = &chip->bus; unsigned long timeout; unsigned long loopcounter; int do_poll = 0; @@ -1168,22 +595,21 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, timeout = jiffies + msecs_to_jiffies(1000); for (loopcounter = 0;; loopcounter++) { - if (chip->polling_mode || do_poll) { - spin_lock_irq(&chip->reg_lock); - azx_update_rirb(chip); - spin_unlock_irq(&chip->reg_lock); - } - if (!chip->rirb.cmds[addr]) { - smp_rmb(); - bus->rirb_error = 0; - + spin_lock_irq(&bus->reg_lock); + if (chip->polling_mode || do_poll) + snd_hdac_bus_update_rirb(bus); + if (!bus->rirb.cmds[addr]) { if (!do_poll) chip->poll_count = 0; - return chip->rirb.res[addr]; /* the last value */ + if (res) + *res = bus->rirb.res[addr]; /* the last value */ + spin_unlock_irq(&bus->reg_lock); + return 0; } + spin_unlock_irq(&bus->reg_lock); if (time_after(jiffies, timeout)) break; - if (bus->needs_damn_long_delay || loopcounter > 3000) + if (hbus->needs_damn_long_delay || loopcounter > 3000) msleep(2); /* temporary workaround */ else { udelay(10); @@ -1191,13 +617,13 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, } } - if (bus->no_response_fallback) - return -1; + if (hbus->no_response_fallback) + return -EIO; if (!chip->polling_mode && chip->poll_count < 2) { dev_dbg(chip->card->dev, "azx_get_response timeout, polling the codec once: last cmd=0x%08x\n", - chip->last_cmd[addr]); + bus->last_cmd[addr]); do_poll = 1; chip->poll_count++; goto again; @@ -1207,7 +633,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (!chip->polling_mode) { dev_warn(chip->card->dev, "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); + bus->last_cmd[addr]); chip->polling_mode = 1; goto again; } @@ -1215,12 +641,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (chip->msi) { dev_warn(chip->card->dev, "No response from codec, disabling MSI: last cmd=0x%08x\n", - chip->last_cmd[addr]); - if (chip->ops->disable_msi_reset_irq(chip) && - chip->ops->disable_msi_reset_irq(chip) < 0) { - bus->rirb_error = 1; - return -1; - } + bus->last_cmd[addr]); + if (chip->ops->disable_msi_reset_irq && + chip->ops->disable_msi_reset_irq(chip) < 0) + return -EIO; goto again; } @@ -1229,28 +653,24 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, * phase, this is likely an access to a non-existing codec * slot. Better to return an error and reset the system. */ - return -1; + return -EIO; } /* a fatal communication error; need either to reset or to fallback * to the single_cmd mode */ - bus->rirb_error = 1; - if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { - bus->response_reset = 1; - return -1; /* give a chance to retry */ + if (hbus->allow_bus_reset && !hbus->response_reset && !hbus->in_reset) { + hbus->response_reset = 1; + return -EAGAIN; /* give a chance to retry */ } dev_err(chip->card->dev, "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); + bus->last_cmd[addr]); chip->single_cmd = 1; - bus->response_reset = 0; - /* release CORB/RIRB */ - azx_free_cmd_io(chip); - /* disable unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL); - return -1; + hbus->response_reset = 0; + snd_hdac_bus_stop_cmd_io(bus); + return -EIO; } /* @@ -1272,7 +692,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) /* check IRV busy bit */ if (azx_readw(chip, IRS) & AZX_IRS_VALID) { /* reuse rirb.res as the response return value */ - chip->rirb.res[addr] = azx_readl(chip, IR); + azx_bus(chip)->rirb.res[addr] = azx_readl(chip, IR); return 0; } udelay(1); @@ -1280,18 +700,18 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) if (printk_ratelimit()) dev_dbg(chip->card->dev, "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); - chip->rirb.res[addr] = -1; + azx_bus(chip)->rirb.res[addr] = -1; return -EIO; } /* send a command */ -static int azx_single_send_cmd(struct hda_bus *bus, u32 val) +static int azx_single_send_cmd(struct hdac_bus *bus, u32 val) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); unsigned int addr = azx_command_addr(val); int timeout = 50; - bus->rirb_error = 0; + bus->last_cmd[azx_command_addr(val)] = val; while (timeout--) { /* check ICB busy bit */ if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) { @@ -1313,11 +733,12 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) } /* receive a response */ -static unsigned int azx_single_get_response(struct hda_bus *bus, - unsigned int addr) +static int azx_single_get_response(struct hdac_bus *bus, unsigned int addr, + unsigned int *res) { - struct azx *chip = bus->private_data; - return chip->rirb.res[addr]; + if (res) + *res = bus->rirb.res[addr]; + return 0; } /* @@ -1328,32 +749,37 @@ static unsigned int azx_single_get_response(struct hda_bus *bus, */ /* send a command */ -static int azx_send_cmd(struct hda_bus *bus, unsigned int val) +static int azx_send_cmd(struct hdac_bus *bus, unsigned int val) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); if (chip->disabled) return 0; - chip->last_cmd[azx_command_addr(val)] = val; if (chip->single_cmd) return azx_single_send_cmd(bus, val); else - return azx_corb_send_cmd(bus, val); + return snd_hdac_bus_send_cmd(bus, val); } /* get a response */ -static unsigned int azx_get_response(struct hda_bus *bus, - unsigned int addr) +static int azx_get_response(struct hdac_bus *bus, unsigned int addr, + unsigned int *res) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); + if (chip->disabled) return 0; if (chip->single_cmd) - return azx_single_get_response(bus, addr); + return azx_single_get_response(bus, addr, res); else - return azx_rirb_get_response(bus, addr); + return azx_rirb_get_response(bus, addr, res); } +static const struct hdac_bus_ops bus_core_ops = { + .command = azx_send_cmd, + .get_response = azx_get_response, +}; + #ifdef CONFIG_SND_HDA_DSP_LOADER /* * DSP loading code (e.g. for CA0132) @@ -1363,339 +789,132 @@ static unsigned int azx_get_response(struct hda_bus *bus, static struct azx_dev * azx_get_dsp_loader_dev(struct azx *chip) { - return &chip->azx_dev[chip->playback_index_offset]; + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; + + list_for_each_entry(s, &bus->stream_list, list) + if (s->index == chip->playback_index_offset) + return stream_to_azx_dev(s); + + return NULL; } -static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format, - unsigned int byte_size, - struct snd_dma_buffer *bufp) +int snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format, + unsigned int byte_size, + struct snd_dma_buffer *bufp) { - u32 *bdl; - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &codec->bus->core; + struct azx *chip = bus_to_azx(bus); struct azx_dev *azx_dev; + struct hdac_stream *hstr; + bool saved = false; int err; azx_dev = azx_get_dsp_loader_dev(chip); - - dsp_lock(azx_dev); - spin_lock_irq(&chip->reg_lock); - if (azx_dev->running || azx_dev->locked) { - spin_unlock_irq(&chip->reg_lock); - err = -EBUSY; - goto unlock; + hstr = azx_stream(azx_dev); + spin_lock_irq(&bus->reg_lock); + if (hstr->opened) { + chip->saved_azx_dev = *azx_dev; + saved = true; } - azx_dev->prepared = 0; - chip->saved_azx_dev = *azx_dev; - azx_dev->locked = 1; - spin_unlock_irq(&chip->reg_lock); - - err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV_SG, - byte_size, bufp); - if (err < 0) - goto err_alloc; - - azx_dev->bufsize = byte_size; - azx_dev->period_bytes = byte_size; - azx_dev->format_val = format; - - azx_stream_reset(chip, azx_dev); + spin_unlock_irq(&bus->reg_lock); - /* reset BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - - azx_dev->frags = 0; - bdl = (u32 *)azx_dev->bdl.area; - err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0); - if (err < 0) - goto error; - - azx_setup_controller(chip, azx_dev); - dsp_unlock(azx_dev); - return azx_dev->stream_tag; + err = snd_hdac_dsp_prepare(hstr, format, byte_size, bufp); + if (err < 0) { + spin_lock_irq(&bus->reg_lock); + if (saved) + *azx_dev = chip->saved_azx_dev; + spin_unlock_irq(&bus->reg_lock); + return err; + } - error: - chip->ops->dma_free_pages(chip, bufp); - err_alloc: - spin_lock_irq(&chip->reg_lock); - if (azx_dev->opened) - *azx_dev = chip->saved_azx_dev; - azx_dev->locked = 0; - spin_unlock_irq(&chip->reg_lock); - unlock: - dsp_unlock(azx_dev); + hstr->prepared = 0; return err; } +EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_prepare); -static void azx_load_dsp_trigger(struct hda_bus *bus, bool start) +void snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) { - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &codec->bus->core; + struct azx *chip = bus_to_azx(bus); struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); - if (start) - azx_stream_start(chip, azx_dev); - else - azx_stream_stop(chip, azx_dev); - azx_dev->running = start; + snd_hdac_dsp_trigger(azx_stream(azx_dev), start); } +EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_trigger); -static void azx_load_dsp_cleanup(struct hda_bus *bus, - struct snd_dma_buffer *dmab) +void snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, + struct snd_dma_buffer *dmab) { - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &codec->bus->core; + struct azx *chip = bus_to_azx(bus); struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); + struct hdac_stream *hstr = azx_stream(azx_dev); - if (!dmab->area || !azx_dev->locked) + if (!dmab->area || !hstr->locked) return; - dsp_lock(azx_dev); - /* reset BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - azx_sd_writel(chip, azx_dev, SD_CTL, 0); - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; - - chip->ops->dma_free_pages(chip, dmab); - dmab->area = NULL; - - spin_lock_irq(&chip->reg_lock); - if (azx_dev->opened) + snd_hdac_dsp_cleanup(hstr, dmab); + spin_lock_irq(&bus->reg_lock); + if (hstr->opened) *azx_dev = chip->saved_azx_dev; - azx_dev->locked = 0; - spin_unlock_irq(&chip->reg_lock); - dsp_unlock(azx_dev); + hstr->locked = false; + spin_unlock_irq(&bus->reg_lock); } +EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_cleanup); #endif /* CONFIG_SND_HDA_DSP_LOADER */ -int azx_alloc_stream_pages(struct azx *chip) -{ - int i, err; - - for (i = 0; i < chip->num_streams; i++) { - dsp_lock_init(&chip->azx_dev[i]); - /* allocate memory for the BDL for each stream */ - err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, - BDL_SIZE, - &chip->azx_dev[i].bdl); - if (err < 0) - return -ENOMEM; - } - /* allocate memory for the position buffer */ - err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, - chip->num_streams * 8, &chip->posbuf); - if (err < 0) - return -ENOMEM; - - /* allocate CORB/RIRB */ - err = azx_alloc_cmd_io(chip); - if (err < 0) - return err; - return 0; -} -EXPORT_SYMBOL_GPL(azx_alloc_stream_pages); - -void azx_free_stream_pages(struct azx *chip) -{ - int i; - if (chip->azx_dev) { - for (i = 0; i < chip->num_streams; i++) - if (chip->azx_dev[i].bdl.area) - chip->ops->dma_free_pages( - chip, &chip->azx_dev[i].bdl); - } - if (chip->rb.area) - chip->ops->dma_free_pages(chip, &chip->rb); - if (chip->posbuf.area) - chip->ops->dma_free_pages(chip, &chip->posbuf); -} -EXPORT_SYMBOL_GPL(azx_free_stream_pages); - /* - * Lowlevel interface + * reset and start the controller registers */ - -/* enter link reset */ -void azx_enter_link_reset(struct azx *chip) -{ - unsigned long timeout; - - /* reset controller */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET); - - timeout = jiffies + msecs_to_jiffies(100); - while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) && - time_before(jiffies, timeout)) - usleep_range(500, 1000); -} -EXPORT_SYMBOL_GPL(azx_enter_link_reset); - -/* exit link reset */ -static void azx_exit_link_reset(struct azx *chip) -{ - unsigned long timeout; - - azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET); - - timeout = jiffies + msecs_to_jiffies(100); - while (!azx_readb(chip, GCTL) && - time_before(jiffies, timeout)) - usleep_range(500, 1000); -} - -/* reset codec link */ -static int azx_reset(struct azx *chip, bool full_reset) -{ - if (!full_reset) - goto __skip; - - /* clear STATESTS */ - azx_writew(chip, STATESTS, STATESTS_INT_MASK); - - /* reset controller */ - azx_enter_link_reset(chip); - - /* delay for >= 100us for codec PLL to settle per spec - * Rev 0.9 section 5.5.1 - */ - usleep_range(500, 1000); - - /* Bring controller out of reset */ - azx_exit_link_reset(chip); - - /* Brent Chartrand said to wait >= 540us for codecs to initialize */ - usleep_range(1000, 1200); - - __skip: - /* check to see if controller is ready */ - if (!azx_readb(chip, GCTL)) { - dev_dbg(chip->card->dev, "azx_reset: controller not ready!\n"); - return -EBUSY; - } - - /* Accept unsolicited responses */ - if (!chip->single_cmd) - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | - AZX_GCTL_UNSOL); - - /* detect codecs */ - if (!chip->codec_mask) { - chip->codec_mask = azx_readw(chip, STATESTS); - dev_dbg(chip->card->dev, "codec_mask = 0x%x\n", - chip->codec_mask); - } - - return 0; -} - -/* enable interrupts */ -static void azx_int_enable(struct azx *chip) -{ - /* enable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | - AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); -} - -/* disable interrupts */ -static void azx_int_disable(struct azx *chip) +void azx_init_chip(struct azx *chip, bool full_reset) { - int i; - - /* disable interrupts in stream descriptor */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) & - ~SD_INT_MASK); + if (snd_hdac_bus_init_chip(azx_bus(chip), full_reset)) { + /* correct RINTCNT for CXT */ + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) + azx_writew(chip, RINTCNT, 0xc0); } - - /* disable SIE for all streams */ - azx_writeb(chip, INTCTL, 0); - - /* disable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & - ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN)); } +EXPORT_SYMBOL_GPL(azx_init_chip); -/* clear interrupts */ -static void azx_int_clear(struct azx *chip) +void azx_stop_all_streams(struct azx *chip) { - int i; - - /* clear stream status */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); - } - - /* clear STATESTS */ - azx_writew(chip, STATESTS, STATESTS_INT_MASK); - - /* clear rirb status */ - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; - /* clear int status */ - azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM); + list_for_each_entry(s, &bus->stream_list, list) + snd_hdac_stream_stop(s); } - -/* - * reset and start the controller registers - */ -void azx_init_chip(struct azx *chip, bool full_reset) -{ - if (chip->initialized) - return; - - /* reset controller */ - azx_reset(chip, full_reset); - - /* initialize interrupts */ - azx_int_clear(chip); - azx_int_enable(chip); - - /* initialize the codec command I/O */ - if (!chip->single_cmd) - azx_init_cmd_io(chip); - - /* program the position buffer */ - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr)); - - chip->initialized = 1; -} -EXPORT_SYMBOL_GPL(azx_init_chip); +EXPORT_SYMBOL_GPL(azx_stop_all_streams); void azx_stop_chip(struct azx *chip) { - if (!chip->initialized) - return; - - /* disable interrupts */ - azx_int_disable(chip); - azx_int_clear(chip); - - /* disable CORB/RIRB */ - azx_free_cmd_io(chip); - - /* disable position buffer */ - azx_writel(chip, DPLBASE, 0); - azx_writel(chip, DPUBASE, 0); - - chip->initialized = 0; + snd_hdac_bus_stop_chip(azx_bus(chip)); } EXPORT_SYMBOL_GPL(azx_stop_chip); /* * interrupt handler */ +static void stream_update(struct hdac_bus *bus, struct hdac_stream *s) +{ + struct azx *chip = bus_to_azx(bus); + struct azx_dev *azx_dev = stream_to_azx_dev(s); + + /* check whether this IRQ is really acceptable */ + if (!chip->ops->position_check || + chip->ops->position_check(chip, azx_dev)) { + spin_unlock(&bus->reg_lock); + snd_pcm_period_elapsed(azx_stream(azx_dev)->substream); + spin_lock(&bus->reg_lock); + } +} + irqreturn_t azx_interrupt(int irq, void *dev_id) { struct azx *chip = dev_id; - struct azx_dev *azx_dev; + struct hdac_bus *bus = azx_bus(chip); u32 status; - u8 sd_status; - int i; #ifdef CONFIG_PM if (azx_has_pm_runtime(chip)) @@ -1703,36 +922,20 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) return IRQ_NONE; #endif - spin_lock(&chip->reg_lock); + spin_lock(&bus->reg_lock); if (chip->disabled) { - spin_unlock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); return IRQ_NONE; } status = azx_readl(chip, INTSTS); if (status == 0 || status == 0xffffffff) { - spin_unlock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); return IRQ_NONE; } - for (i = 0; i < chip->num_streams; i++) { - azx_dev = &chip->azx_dev[i]; - if (status & azx_dev->sd_int_sta_mask) { - sd_status = azx_sd_readb(chip, azx_dev, SD_STS); - azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); - if (!azx_dev->substream || !azx_dev->running || - !(sd_status & SD_INT_COMPLETE)) - continue; - /* check whether this IRQ is really acceptable */ - if (!chip->ops->position_check || - chip->ops->position_check(chip, azx_dev)) { - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(azx_dev->substream); - spin_lock(&chip->reg_lock); - } - } - } + snd_hdac_bus_handle_stream_irq(bus, status, stream_update); /* clear rirb int */ status = azx_readb(chip, RIRBSTS); @@ -1740,12 +943,12 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) if (status & RIRB_INT_RESPONSE) { if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) udelay(80); - azx_update_rirb(chip); + snd_hdac_bus_update_rirb(bus); } azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } - spin_unlock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); return IRQ_HANDLED; } @@ -1762,29 +965,31 @@ static int probe_codec(struct azx *chip, int addr) { unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res; + struct hdac_bus *bus = azx_bus(chip); + int err; + unsigned int res = -1; - mutex_lock(&chip->bus->core.cmd_mutex); + mutex_lock(&bus->cmd_mutex); chip->probing = 1; - azx_send_cmd(chip->bus, cmd); - res = azx_get_response(chip->bus, addr); + azx_send_cmd(bus, cmd); + err = azx_get_response(bus, addr, &res); chip->probing = 0; - mutex_unlock(&chip->bus->core.cmd_mutex); - if (res == -1) + mutex_unlock(&bus->cmd_mutex); + if (err < 0 || res == -1) return -EIO; dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr); return 0; } -static void azx_bus_reset(struct hda_bus *bus) +void snd_hda_bus_reset(struct hda_bus *bus) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(&bus->core); bus->in_reset = 1; azx_stop_chip(chip); azx_init_chip(chip, true); - if (chip->initialized) - snd_hda_bus_reset(chip->bus); + if (bus->core.chip_init) + snd_hda_bus_reset_codecs(bus); bus->in_reset = 0; } @@ -1809,33 +1014,30 @@ static int get_jackpoll_interval(struct azx *chip) return j; } -static struct hda_bus_ops bus_ops = { - .command = azx_send_cmd, - .get_response = azx_get_response, - .attach_pcm = azx_attach_pcm_stream, - .bus_reset = azx_bus_reset, -#ifdef CONFIG_SND_HDA_DSP_LOADER - .load_dsp_prepare = azx_load_dsp_prepare, - .load_dsp_trigger = azx_load_dsp_trigger, - .load_dsp_cleanup = azx_load_dsp_cleanup, -#endif -}; - /* HD-audio bus initialization */ -int azx_bus_create(struct azx *chip, const char *model) +int azx_bus_init(struct azx *chip, const char *model, + const struct hdac_io_ops *io_ops) { - struct hda_bus *bus; + struct hda_bus *bus = &chip->bus; int err; - err = snd_hda_bus_new(chip->card, &bus); + err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops, + io_ops); if (err < 0) return err; - chip->bus = bus; - bus->private_data = chip; + bus->card = chip->card; + mutex_init(&bus->prepare_mutex); bus->pci = chip->pci; bus->modelname = model; - bus->ops = bus_ops; + bus->core.snoop = azx_snoop(chip); + if (chip->get_position[0] != azx_get_pos_lpib || + chip->get_position[1] != azx_get_pos_lpib) + bus->core.use_posbuf = true; + if (chip->bdl_pos_adj) + bus->core.bdl_pos_adj = chip->bdl_pos_adj[chip->dev_index]; + if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR) + bus->core.corbrp_self_clear = true; if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); @@ -1854,12 +1056,12 @@ int azx_bus_create(struct azx *chip, const char *model) return 0; } -EXPORT_SYMBOL_GPL(azx_bus_create); +EXPORT_SYMBOL_GPL(azx_bus_init); /* Probe codecs */ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) { - struct hda_bus *bus = chip->bus; + struct hdac_bus *bus = azx_bus(chip); int c, codecs, err; codecs = 0; @@ -1868,14 +1070,14 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) /* First try to probe all given codec slots */ for (c = 0; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) { if (probe_codec(chip, c) < 0) { /* Some BIOSen give you wrong codec addresses * that don't exist */ dev_warn(chip->card->dev, "Codec #%d probe error; disabling it...\n", c); - chip->codec_mask &= ~(1 << c); + bus->codec_mask &= ~(1 << c); /* More badly, accessing to a non-existing * codec often screws up the controller chip, * and disturbs the further communications. @@ -1891,9 +1093,9 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) /* Then create codec instances */ for (c = 0; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) { struct hda_codec *codec; - err = snd_hda_codec_new(bus, bus->card, c, &codec); + err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec); if (err < 0) continue; codec->jackpoll_interval = get_jackpoll_interval(chip); @@ -1913,40 +1115,39 @@ EXPORT_SYMBOL_GPL(azx_probe_codecs); int azx_codec_configure(struct azx *chip) { struct hda_codec *codec; - list_for_each_codec(codec, chip->bus) { + list_for_each_codec(codec, &chip->bus) { snd_hda_codec_configure(codec); } return 0; } EXPORT_SYMBOL_GPL(azx_codec_configure); - -static bool is_input_stream(struct azx *chip, unsigned char index) +static int stream_direction(struct azx *chip, unsigned char index) { - return (index >= chip->capture_index_offset && - index < chip->capture_index_offset + chip->capture_streams); + if (index >= chip->capture_index_offset && + index < chip->capture_index_offset + chip->capture_streams) + return SNDRV_PCM_STREAM_CAPTURE; + return SNDRV_PCM_STREAM_PLAYBACK; } /* initialize SD streams */ -int azx_init_stream(struct azx *chip) +int azx_init_streams(struct azx *chip) { int i; - int in_stream_tag = 0; - int out_stream_tag = 0; + int stream_tags[2] = { 0, 0 }; /* initialize each stream (aka device) * assign the starting bdl address to each stream (device) * and initialize */ for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); - /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ - azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); - /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ - azx_dev->sd_int_sta_mask = 1 << i; - azx_dev->index = i; + struct azx_dev *azx_dev = kzalloc(sizeof(*azx_dev), GFP_KERNEL); + int dir, tag; + + if (!azx_dev) + return -ENOMEM; + dir = stream_direction(chip, i); /* stream tag must be unique throughout * the stream direction group, * valid values 1...15 @@ -1954,17 +1155,26 @@ int azx_init_stream(struct azx *chip) * AZX_DCAPS_SEPARATE_STREAM_TAG is used */ if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) - azx_dev->stream_tag = - is_input_stream(chip, i) ? - ++in_stream_tag : - ++out_stream_tag; + tag = ++stream_tags[dir]; else - azx_dev->stream_tag = i + 1; + tag = i + 1; + snd_hdac_stream_init(azx_bus(chip), azx_stream(azx_dev), + i, dir, tag); } return 0; } -EXPORT_SYMBOL_GPL(azx_init_stream); +EXPORT_SYMBOL_GPL(azx_init_streams); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Common HDA driver functions"); +void azx_free_streams(struct azx *chip) +{ + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; + + while (!list_empty(&bus->stream_list)) { + s = list_first_entry(&bus->stream_list, struct hdac_stream, list); + list_del(&s->list); + kfree(stream_to_azx_dev(s)); + } +} +EXPORT_SYMBOL_GPL(azx_free_streams); |