| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * HD-audio stream operations |
|---|
| 3 | 4 | */ |
|---|
| .. | .. |
|---|
| 11 | 12 | #include <sound/hdaudio.h> |
|---|
| 12 | 13 | #include <sound/hda_register.h> |
|---|
| 13 | 14 | #include "trace.h" |
|---|
| 15 | + |
|---|
| 16 | +/** |
|---|
| 17 | + * snd_hdac_get_stream_stripe_ctl - get stripe control value |
|---|
| 18 | + * @bus: HD-audio core bus |
|---|
| 19 | + * @substream: PCM substream |
|---|
| 20 | + */ |
|---|
| 21 | +int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, |
|---|
| 22 | + struct snd_pcm_substream *substream) |
|---|
| 23 | +{ |
|---|
| 24 | + struct snd_pcm_runtime *runtime = substream->runtime; |
|---|
| 25 | + unsigned int channels = runtime->channels, |
|---|
| 26 | + rate = runtime->rate, |
|---|
| 27 | + bits_per_sample = runtime->sample_bits, |
|---|
| 28 | + max_sdo_lines, value, sdo_line; |
|---|
| 29 | + |
|---|
| 30 | + /* T_AZA_GCAP_NSDO is 1:2 bitfields in GCAP */ |
|---|
| 31 | + max_sdo_lines = snd_hdac_chip_readl(bus, GCAP) & AZX_GCAP_NSDO; |
|---|
| 32 | + |
|---|
| 33 | + /* following is from HD audio spec */ |
|---|
| 34 | + for (sdo_line = max_sdo_lines; sdo_line > 0; sdo_line >>= 1) { |
|---|
| 35 | + if (rate > 48000) |
|---|
| 36 | + value = (channels * bits_per_sample * |
|---|
| 37 | + (rate / 48000)) / sdo_line; |
|---|
| 38 | + else |
|---|
| 39 | + value = (channels * bits_per_sample) / sdo_line; |
|---|
| 40 | + |
|---|
| 41 | + if (value >= bus->sdo_limit) |
|---|
| 42 | + break; |
|---|
| 43 | + } |
|---|
| 44 | + |
|---|
| 45 | + /* stripe value: 0 for 1SDO, 1 for 2SDO, 2 for 4SDO lines */ |
|---|
| 46 | + return sdo_line >> 1; |
|---|
| 47 | +} |
|---|
| 48 | +EXPORT_SYMBOL_GPL(snd_hdac_get_stream_stripe_ctl); |
|---|
| 14 | 49 | |
|---|
| 15 | 50 | /** |
|---|
| 16 | 51 | * snd_hdac_stream_init - initialize each stream (aka device) |
|---|
| .. | .. |
|---|
| 48 | 83 | void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) |
|---|
| 49 | 84 | { |
|---|
| 50 | 85 | struct hdac_bus *bus = azx_dev->bus; |
|---|
| 86 | + int stripe_ctl; |
|---|
| 51 | 87 | |
|---|
| 52 | 88 | trace_snd_hdac_stream_start(bus, azx_dev); |
|---|
| 53 | 89 | |
|---|
| .. | .. |
|---|
| 56 | 92 | azx_dev->start_wallclk -= azx_dev->period_wallclk; |
|---|
| 57 | 93 | |
|---|
| 58 | 94 | /* enable SIE */ |
|---|
| 59 | | - snd_hdac_chip_updatel(bus, INTCTL, 0, 1 << azx_dev->index); |
|---|
| 95 | + snd_hdac_chip_updatel(bus, INTCTL, |
|---|
| 96 | + 1 << azx_dev->index, |
|---|
| 97 | + 1 << azx_dev->index); |
|---|
| 98 | + /* set stripe control */ |
|---|
| 99 | + if (azx_dev->stripe) { |
|---|
| 100 | + if (azx_dev->substream) |
|---|
| 101 | + stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); |
|---|
| 102 | + else |
|---|
| 103 | + stripe_ctl = 0; |
|---|
| 104 | + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, |
|---|
| 105 | + stripe_ctl); |
|---|
| 106 | + } |
|---|
| 60 | 107 | /* set DMA start and interrupt mask */ |
|---|
| 61 | 108 | snd_hdac_stream_updateb(azx_dev, SD_CTL, |
|---|
| 62 | 109 | 0, SD_CTL_DMA_START | SD_INT_MASK); |
|---|
| .. | .. |
|---|
| 73 | 120 | snd_hdac_stream_updateb(azx_dev, SD_CTL, |
|---|
| 74 | 121 | SD_CTL_DMA_START | SD_INT_MASK, 0); |
|---|
| 75 | 122 | snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ |
|---|
| 123 | + if (azx_dev->stripe) |
|---|
| 124 | + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); |
|---|
| 76 | 125 | azx_dev->running = false; |
|---|
| 77 | 126 | } |
|---|
| 78 | 127 | EXPORT_SYMBOL_GPL(snd_hdac_stream_clear); |
|---|
| .. | .. |
|---|
| 94 | 143 | EXPORT_SYMBOL_GPL(snd_hdac_stream_stop); |
|---|
| 95 | 144 | |
|---|
| 96 | 145 | /** |
|---|
| 146 | + * snd_hdac_stop_streams - stop all streams |
|---|
| 147 | + * @bus: HD-audio core bus |
|---|
| 148 | + */ |
|---|
| 149 | +void snd_hdac_stop_streams(struct hdac_bus *bus) |
|---|
| 150 | +{ |
|---|
| 151 | + struct hdac_stream *stream; |
|---|
| 152 | + |
|---|
| 153 | + list_for_each_entry(stream, &bus->stream_list, list) |
|---|
| 154 | + snd_hdac_stream_stop(stream); |
|---|
| 155 | +} |
|---|
| 156 | +EXPORT_SYMBOL_GPL(snd_hdac_stop_streams); |
|---|
| 157 | + |
|---|
| 158 | +/** |
|---|
| 159 | + * snd_hdac_stop_streams_and_chip - stop all streams and chip if running |
|---|
| 160 | + * @bus: HD-audio core bus |
|---|
| 161 | + */ |
|---|
| 162 | +void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus) |
|---|
| 163 | +{ |
|---|
| 164 | + |
|---|
| 165 | + if (bus->chip_init) { |
|---|
| 166 | + snd_hdac_stop_streams(bus); |
|---|
| 167 | + snd_hdac_bus_stop_chip(bus); |
|---|
| 168 | + } |
|---|
| 169 | +} |
|---|
| 170 | +EXPORT_SYMBOL_GPL(snd_hdac_stop_streams_and_chip); |
|---|
| 171 | + |
|---|
| 172 | +/** |
|---|
| 97 | 173 | * snd_hdac_stream_reset - reset a stream |
|---|
| 98 | 174 | * @azx_dev: HD-audio core stream to reset |
|---|
| 99 | 175 | */ |
|---|
| .. | .. |
|---|
| 101 | 177 | { |
|---|
| 102 | 178 | unsigned char val; |
|---|
| 103 | 179 | int timeout; |
|---|
| 180 | + int dma_run_state; |
|---|
| 104 | 181 | |
|---|
| 105 | 182 | snd_hdac_stream_clear(azx_dev); |
|---|
| 183 | + |
|---|
| 184 | + dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START; |
|---|
| 106 | 185 | |
|---|
| 107 | 186 | snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); |
|---|
| 108 | 187 | udelay(3); |
|---|
| .. | .. |
|---|
| 113 | 192 | if (val) |
|---|
| 114 | 193 | break; |
|---|
| 115 | 194 | } while (--timeout); |
|---|
| 195 | + |
|---|
| 196 | + if (azx_dev->bus->dma_stop_delay && dma_run_state) |
|---|
| 197 | + udelay(azx_dev->bus->dma_stop_delay); |
|---|
| 198 | + |
|---|
| 116 | 199 | val &= ~SD_CTL_STREAM_RESET; |
|---|
| 117 | 200 | snd_hdac_stream_writeb(azx_dev, SD_CTL, val); |
|---|
| 118 | 201 | udelay(3); |
|---|
| .. | .. |
|---|
| 183 | 266 | /* set the interrupt enable bits in the descriptor control register */ |
|---|
| 184 | 267 | snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_INT_MASK); |
|---|
| 185 | 268 | |
|---|
| 186 | | - if (azx_dev->direction == SNDRV_PCM_STREAM_PLAYBACK) |
|---|
| 187 | | - azx_dev->fifo_size = |
|---|
| 188 | | - snd_hdac_stream_readw(azx_dev, SD_FIFOSIZE) + 1; |
|---|
| 189 | | - else |
|---|
| 190 | | - azx_dev->fifo_size = 0; |
|---|
| 269 | + azx_dev->fifo_size = snd_hdac_stream_readw(azx_dev, SD_FIFOSIZE) + 1; |
|---|
| 191 | 270 | |
|---|
| 192 | 271 | /* when LPIB delay correction gives a small negative value, |
|---|
| 193 | 272 | * we ignore it; currently set the threshold statically to |
|---|
| .. | .. |
|---|
| 244 | 323 | int key = (substream->pcm->device << 16) | (substream->number << 2) | |
|---|
| 245 | 324 | (substream->stream + 1); |
|---|
| 246 | 325 | |
|---|
| 326 | + spin_lock_irq(&bus->reg_lock); |
|---|
| 247 | 327 | list_for_each_entry(azx_dev, &bus->stream_list, list) { |
|---|
| 248 | 328 | if (azx_dev->direction != substream->stream) |
|---|
| 249 | 329 | continue; |
|---|
| .. | .. |
|---|
| 257 | 337 | res = azx_dev; |
|---|
| 258 | 338 | } |
|---|
| 259 | 339 | if (res) { |
|---|
| 260 | | - spin_lock_irq(&bus->reg_lock); |
|---|
| 261 | 340 | res->opened = 1; |
|---|
| 262 | 341 | res->running = 0; |
|---|
| 263 | 342 | res->assigned_key = key; |
|---|
| 264 | 343 | res->substream = substream; |
|---|
| 265 | | - spin_unlock_irq(&bus->reg_lock); |
|---|
| 266 | 344 | } |
|---|
| 345 | + spin_unlock_irq(&bus->reg_lock); |
|---|
| 267 | 346 | return res; |
|---|
| 268 | 347 | } |
|---|
| 269 | 348 | EXPORT_SYMBOL_GPL(snd_hdac_stream_assign); |
|---|
| .. | .. |
|---|
| 545 | 624 | /** |
|---|
| 546 | 625 | * snd_hdac_stream_sync_trigger - turn on/off stream sync register |
|---|
| 547 | 626 | * @azx_dev: HD-audio core stream (master stream) |
|---|
| 627 | + * @set: true = set, false = clear |
|---|
| 548 | 628 | * @streams: bit flags of streams to sync |
|---|
| 629 | + * @reg: the stream sync register address |
|---|
| 549 | 630 | */ |
|---|
| 550 | 631 | void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set, |
|---|
| 551 | 632 | unsigned int streams, unsigned int reg) |
|---|
| .. | .. |
|---|
| 584 | 665 | nwait = 0; |
|---|
| 585 | 666 | i = 0; |
|---|
| 586 | 667 | list_for_each_entry(s, &bus->stream_list, list) { |
|---|
| 587 | | - if (streams & (1 << i)) { |
|---|
| 588 | | - if (start) { |
|---|
| 589 | | - /* check FIFO gets ready */ |
|---|
| 590 | | - if (!(snd_hdac_stream_readb(s, SD_STS) & |
|---|
| 591 | | - SD_STS_FIFO_READY)) |
|---|
| 592 | | - nwait++; |
|---|
| 593 | | - } else { |
|---|
| 594 | | - /* check RUN bit is cleared */ |
|---|
| 595 | | - if (snd_hdac_stream_readb(s, SD_CTL) & |
|---|
| 596 | | - SD_CTL_DMA_START) |
|---|
| 597 | | - nwait++; |
|---|
| 668 | + if (!(streams & (1 << i++))) |
|---|
| 669 | + continue; |
|---|
| 670 | + |
|---|
| 671 | + if (start) { |
|---|
| 672 | + /* check FIFO gets ready */ |
|---|
| 673 | + if (!(snd_hdac_stream_readb(s, SD_STS) & |
|---|
| 674 | + SD_STS_FIFO_READY)) |
|---|
| 675 | + nwait++; |
|---|
| 676 | + } else { |
|---|
| 677 | + /* check RUN bit is cleared */ |
|---|
| 678 | + if (snd_hdac_stream_readb(s, SD_CTL) & |
|---|
| 679 | + SD_CTL_DMA_START) { |
|---|
| 680 | + nwait++; |
|---|
| 681 | + /* |
|---|
| 682 | + * Perform stream reset if DMA RUN |
|---|
| 683 | + * bit not cleared within given timeout |
|---|
| 684 | + */ |
|---|
| 685 | + if (timeout == 1) |
|---|
| 686 | + snd_hdac_stream_reset(s); |
|---|
| 598 | 687 | } |
|---|
| 599 | 688 | } |
|---|
| 600 | | - i++; |
|---|
| 601 | 689 | } |
|---|
| 602 | 690 | if (!nwait) |
|---|
| 603 | 691 | break; |
|---|
| .. | .. |
|---|
| 634 | 722 | azx_dev->locked = true; |
|---|
| 635 | 723 | spin_unlock_irq(&bus->reg_lock); |
|---|
| 636 | 724 | |
|---|
| 637 | | - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV_SG, |
|---|
| 638 | | - byte_size, bufp); |
|---|
| 725 | + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev, |
|---|
| 726 | + byte_size, bufp); |
|---|
| 639 | 727 | if (err < 0) |
|---|
| 640 | 728 | goto err_alloc; |
|---|
| 641 | 729 | |
|---|
| .. | .. |
|---|
| 661 | 749 | return azx_dev->stream_tag; |
|---|
| 662 | 750 | |
|---|
| 663 | 751 | error: |
|---|
| 664 | | - bus->io_ops->dma_free_pages(bus, bufp); |
|---|
| 752 | + snd_dma_free_pages(bufp); |
|---|
| 665 | 753 | err_alloc: |
|---|
| 666 | 754 | spin_lock_irq(&bus->reg_lock); |
|---|
| 667 | 755 | azx_dev->locked = false; |
|---|
| .. | .. |
|---|
| 708 | 796 | azx_dev->period_bytes = 0; |
|---|
| 709 | 797 | azx_dev->format_val = 0; |
|---|
| 710 | 798 | |
|---|
| 711 | | - bus->io_ops->dma_free_pages(bus, dmab); |
|---|
| 799 | + snd_dma_free_pages(dmab); |
|---|
| 712 | 800 | dmab->area = NULL; |
|---|
| 713 | 801 | |
|---|
| 714 | 802 | spin_lock_irq(&bus->reg_lock); |
|---|