Changeset 772 for GPL/trunk/alsa-kernel/hda/hdac_stream.c
- Timestamp:
- Apr 19, 2025, 8:08:37 PM (4 months ago)
- Location:
- GPL/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GPL/trunk
- Property svn:mergeinfo changed
/GPL/branches/uniaud32-6.6-LTS (added) merged: 765,768-769 /GPL/branches/uniaud32-exp (added) merged: 735-741,743-744,748-751,753-760,762-764 /GPL/branches/uniaud32-next merged: 718-734
- Property svn:mergeinfo changed
-
GPL/trunk/alsa-kernel/hda/hdac_stream.c
r717 r772 8 8 #include <linux/export.h> 9 9 #include <linux/clocksource.h> 10 #include <sound/compress_driver.h> 10 11 #include <sound/core.h> 11 12 #include <sound/pcm.h> … … 19 20 #endif 20 21 22 /* 23 * the hdac_stream library is intended to be used with the following 24 * transitions. The states are not formally defined in the code but loosely 25 * inspired by boolean variables. Note that the 'prepared' field is not used 26 * in this library but by the callers during the hw_params/prepare transitions 27 * 28 * | 29 * stream_init() | 30 * v 31 * +--+-------+ 32 * | unused | 33 * +--+----+--+ 34 * | ^ 35 * stream_assign() | | stream_release() 36 * v | 37 * +--+----+--+ 38 * | opened | 39 * +--+----+--+ 40 * | ^ 41 * stream_reset() | | 42 * stream_setup() | | stream_cleanup() 43 * v | 44 * +--+----+--+ 45 * | prepared | 46 * +--+----+--+ 47 * | ^ 48 * stream_start() | | stream_stop() 49 * v | 50 * +--+----+--+ 51 * | running | 52 * +----------+ 53 */ 54 21 55 /** 22 56 * snd_hdac_get_stream_stripe_ctl - get stripe control value … … 76 110 snd_hdac_dsp_lock_init(azx_dev); 77 111 list_add_tail(&azx_dev->list, &bus->stream_list); 112 113 if (bus->spbcap) { 114 azx_dev->spib_addr = (void*)bus->spbcap + AZX_SPB_BASE + 115 AZX_SPB_INTERVAL * idx + 116 AZX_SPB_SPIB; 117 118 azx_dev->fifo_addr = (void*)bus->spbcap + AZX_SPB_BASE + 119 AZX_SPB_INTERVAL * idx + 120 AZX_SPB_MAXFIFO; 121 } 122 123 if (bus->drsmcap) 124 azx_dev->dpibr_addr = (void*)bus->drsmcap + AZX_DRSM_BASE + 125 AZX_DRSM_INTERVAL * idx; 78 126 } 79 127 EXPORT_SYMBOL_GPL(snd_hdac_stream_init); … … 82 130 * snd_hdac_stream_start - start a stream 83 131 * @azx_dev: HD-audio core stream to start 84 * @fresh_start: false = wallclock timestamp relative to period wallclock85 132 * 86 133 * Start a stream, set start_wallclk and set the running flag. 87 134 */ 88 void snd_hdac_stream_start(struct hdac_stream *azx_dev , bool fresh_start)135 void snd_hdac_stream_start(struct hdac_stream *azx_dev) 89 136 { 90 137 struct hdac_bus *bus = azx_dev->bus; … … 94 141 95 142 azx_dev->start_wallclk = snd_hdac_chip_readl(bus, WALLCLK); 96 if (!fresh_start)97 azx_dev->start_wallclk -= azx_dev->period_wallclk;98 143 99 144 /* enable SIE */ … … 111 156 } 112 157 /* set DMA start and interrupt mask */ 113 snd_hdac_stream_updateb(azx_dev, SD_CTL, 158 if (bus->access_sdnctl_in_dword) 159 snd_hdac_stream_updatel(azx_dev, SD_CTL, 160 0, SD_CTL_DMA_START | SD_INT_MASK); 161 else 162 snd_hdac_stream_updateb(azx_dev, SD_CTL, 114 163 0, SD_CTL_DMA_START | SD_INT_MASK); 115 164 azx_dev->running = true; … … 118 167 119 168 /** 120 * snd_hdac_stream_clear - stop a stream DMA169 * snd_hdac_stream_clear - helper to clear stream registers and stop DMA transfers 121 170 * @azx_dev: HD-audio core stream to stop 122 171 */ 123 void snd_hdac_stream_clear(struct hdac_stream *azx_dev)172 static void snd_hdac_stream_clear(struct hdac_stream *azx_dev) 124 173 { 125 174 snd_hdac_stream_updateb(azx_dev, SD_CTL, … … 130 179 azx_dev->running = false; 131 180 } 132 EXPORT_SYMBOL_GPL(snd_hdac_stream_clear);133 181 134 182 /** … … 149 197 150 198 /** 199 * snd_hdac_stop_streams - stop all streams 200 * @bus: HD-audio core bus 201 */ 202 void snd_hdac_stop_streams(struct hdac_bus *bus) 203 { 204 struct hdac_stream *stream; 205 206 list_for_each_entry(stream, &bus->stream_list, list, struct hdac_stream) 207 snd_hdac_stream_stop(stream); 208 } 209 EXPORT_SYMBOL_GPL(snd_hdac_stop_streams); 210 211 /** 212 * snd_hdac_stop_streams_and_chip - stop all streams and chip if running 213 * @bus: HD-audio core bus 214 */ 215 void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus) 216 { 217 if (bus->chip_init) { 218 snd_hdac_stop_streams(bus); 219 snd_hdac_bus_stop_chip(bus); 220 } 221 } 222 EXPORT_SYMBOL_GPL(snd_hdac_stop_streams_and_chip); 223 224 /** 151 225 * snd_hdac_stream_reset - reset a stream 152 226 * @azx_dev: HD-audio core stream to reset … … 155 229 { 156 230 unsigned char val; 231 #ifdef TARGET_OS2 157 232 int timeout; 233 #endif 158 234 int dma_run_state; 159 235 … … 163 239 164 240 snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); 241 242 #ifndef TARGET_OS2 243 /* wait for hardware to report that the stream entered reset */ 244 snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RESET), 3, 300); 245 #else 165 246 udelay(3); 166 247 timeout = 300; … … 171 252 break; 172 253 } while (--timeout); 173 254 #endif 174 255 if (azx_dev->bus->dma_stop_delay && dma_run_state) 175 256 udelay(azx_dev->bus->dma_stop_delay); 176 257 177 val &= ~SD_CTL_STREAM_RESET; 178 snd_hdac_stream_writeb(azx_dev, SD_CTL, val); 258 snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); 259 260 #ifndef TARGET_OS2 261 /* wait for hardware to report that the stream is out of reset */ 262 snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, !(val & SD_CTL_STREAM_RESET), 3, 300); 263 #else 179 264 udelay(3); 180 265 … … 187 272 break; 188 273 } while (--timeout); 189 274 #endif 190 275 /* reset first position - may not be synced with hw at this time */ 191 276 if (azx_dev->posbuf) … … 299 384 300 385 /* make a non-zero unique key for the substream */ 301 int key = (substream->pcm->device << 16) | (substream->number << 2) | 302 (substream->stream + 1); 386 int key = (substream->number << 2) | (substream->stream + 1); 387 388 if (substream->pcm) 389 key |= (substream->pcm->device << 16); 303 390 304 391 spin_lock_irq(&bus->reg_lock); … … 327 414 328 415 /** 329 * snd_hdac_stream_release - release the assigned stream416 * snd_hdac_stream_release_locked - release the assigned stream 330 417 * @azx_dev: HD-audio core stream to release 331 418 * 332 419 * Release the stream that has been assigned by snd_hdac_stream_assign(). 333 */ 334 void snd_hdac_stream_release(struct hdac_stream *azx_dev) 335 { 336 struct hdac_bus *bus = azx_dev->bus; 337 338 spin_lock_irq(&bus->reg_lock); 420 * The bus->reg_lock needs to be taken at a higher level 421 */ 422 void snd_hdac_stream_release_locked(struct hdac_stream *azx_dev) 423 { 339 424 azx_dev->opened = 0; 340 425 azx_dev->running = 0; 341 426 azx_dev->substream = NULL; 427 } 428 EXPORT_SYMBOL_GPL(snd_hdac_stream_release_locked); 429 430 /** 431 * snd_hdac_stream_release - release the assigned stream 432 * @azx_dev: HD-audio core stream to release 433 * 434 * Release the stream that has been assigned by snd_hdac_stream_assign(). 435 */ 436 void snd_hdac_stream_release(struct hdac_stream *azx_dev) 437 { 438 struct hdac_bus *bus = azx_dev->bus; 439 440 spin_lock_irq(&bus->reg_lock); 441 snd_hdac_stream_release_locked(azx_dev); 342 442 spin_unlock_irq(&bus->reg_lock); 343 443 } … … 421 521 struct hdac_bus *bus = azx_dev->bus; 422 522 struct snd_pcm_substream *substream = azx_dev->substream; 423 struct snd_pcm_runtime *runtime = substream->runtime; 523 struct snd_compr_stream *cstream = azx_dev->cstream; 524 struct snd_pcm_runtime *runtime = NULL; 525 struct snd_dma_buffer *dmab; 424 526 __le32 *bdl; 425 527 int i, ofs, periods, period_bytes; 426 528 int pos_adj, pos_align; 529 530 if (substream) { 531 runtime = substream->runtime; 532 dmab = snd_pcm_get_dma_buf(substream); 533 } else if (cstream) { 534 dmab = snd_pcm_get_dma_buf(cstream); 535 } else { 536 WARN(1, "No substream or cstream assigned\n"); 537 return -EINVAL; 538 } 427 539 428 540 /* reset BDL address */ … … 439 551 440 552 pos_adj = bus->bdl_pos_adj; 441 if ( !azx_dev->no_period_wakeup && pos_adj > 0) {553 if (runtime && !azx_dev->no_period_wakeup && pos_adj > 0) { 442 554 pos_align = pos_adj; 443 555 pos_adj = DIV_ROUND_UP(pos_adj * runtime->rate, 48000); … … 452 564 pos_adj = 0; 453 565 } else { 454 ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream), 455 azx_dev, 566 ofs = setup_bdle(bus, dmab, azx_dev, 456 567 &bdl, ofs, pos_adj, true); 457 568 if (ofs < 0) … … 463 574 for (i = 0; i < periods; i++) { 464 575 if (i == periods - 1 && pos_adj) 465 ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream), 466 azx_dev, &bdl, ofs, 467 period_bytes - pos_adj, 0); 576 ofs = setup_bdle(bus, dmab, azx_dev, 577 &bdl, ofs, period_bytes - pos_adj, 0); 468 578 else 469 ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream), 470 azx_dev, &bdl, ofs, 471 period_bytes, 579 ofs = setup_bdle(bus, dmab, azx_dev, 580 &bdl, ofs, period_bytes, 472 581 !azx_dev->no_period_wakeup); 473 582 if (ofs < 0) … … 494 603 unsigned int format_val) 495 604 { 496 605 struct snd_pcm_substream *substream = azx_dev->substream; 606 struct snd_compr_stream *cstream = azx_dev->cstream; 497 607 unsigned int bufsize, period_bytes; 498 struct snd_pcm_substream *substream = azx_dev->substream; 499 struct snd_pcm_runtime *runtime; 608 unsigned int no_period_wakeup; 500 609 int err; 501 610 502 if (!substream) 611 if (substream) { 612 bufsize = snd_pcm_lib_buffer_bytes(substream); 613 period_bytes = snd_pcm_lib_period_bytes(substream); 614 no_period_wakeup = substream->runtime->no_period_wakeup; 615 } else if (cstream) { 616 bufsize = cstream->runtime->buffer_size; 617 period_bytes = cstream->runtime->fragment_size; 618 no_period_wakeup = 0; 619 } else { 503 620 return -EINVAL; 504 runtime = substream->runtime; 505 bufsize = snd_pcm_lib_buffer_bytes(substream); 506 period_bytes = snd_pcm_lib_period_bytes(substream); 621 } 507 622 508 623 if (bufsize != azx_dev->bufsize || 509 624 period_bytes != azx_dev->period_bytes || 510 625 format_val != azx_dev->format_val || 511 runtime->no_period_wakeup != azx_dev->no_period_wakeup) {626 no_period_wakeup != azx_dev->no_period_wakeup) { 512 627 azx_dev->bufsize = bufsize; 513 628 azx_dev->period_bytes = period_bytes; 514 629 azx_dev->format_val = format_val; 515 azx_dev->no_period_wakeup = runtime->no_period_wakeup;630 azx_dev->no_period_wakeup = no_period_wakeup; 516 631 err = snd_hdac_stream_setup_periods(azx_dev); 517 632 if (err < 0) … … 589 704 bool inited = false; 590 705 u64 cycle_last = 0; 591 int i = 0;592 706 593 707 list_for_each_entry(s, &bus->stream_list, list, struct hdac_stream) { 594 if ( streams & (1 << i)) {708 if ((streams & (1 << s->index))) { 595 709 azx_timecounter_init(s, inited, cycle_last); 596 710 if (!inited) { … … 599 713 } 600 714 } 601 i++;602 715 } 603 716 … … 644 757 { 645 758 struct hdac_bus *bus = azx_dev->bus; 646 int i,nwait, timeout;759 int nwait, timeout; 647 760 struct hdac_stream *s; 648 761 649 762 for (timeout = 5000; timeout; timeout--) { 650 763 nwait = 0; 651 i = 0;652 764 list_for_each_entry(s, &bus->stream_list, list, struct hdac_stream) { 653 if (!(streams & (1 << i++)))765 if (!(streams & (1 << s->index))) 654 766 continue; 655 767 … … 680 792 EXPORT_SYMBOL_GPL(snd_hdac_stream_sync); 681 793 794 /** 795 * snd_hdac_stream_spbcap_enable - enable SPIB for a stream 796 * @bus: HD-audio core bus 797 * @enable: flag to enable/disable SPIB 798 * @index: stream index for which SPIB need to be enabled 799 */ 800 void snd_hdac_stream_spbcap_enable(struct hdac_bus *bus, 801 bool enable, int index) 802 { 803 u32 mask = 0; 804 805 if (!bus->spbcap) { 806 dev_err(bus->dev, "Address of SPB capability is NULL\n"); 807 return; 808 } 809 810 mask |= (1 << index); 811 812 if (enable) 813 snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask); 814 else 815 snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); 816 } 817 EXPORT_SYMBOL_GPL(snd_hdac_stream_spbcap_enable); 818 819 /** 820 * snd_hdac_stream_set_spib - sets the spib value of a stream 821 * @bus: HD-audio core bus 822 * @azx_dev: hdac_stream 823 * @value: spib value to set 824 */ 825 int snd_hdac_stream_set_spib(struct hdac_bus *bus, 826 struct hdac_stream *azx_dev, u32 value) 827 { 828 if (!bus->spbcap) { 829 dev_err(bus->dev, "Address of SPB capability is NULL\n"); 830 return -EINVAL; 831 } 832 833 writel(value, azx_dev->spib_addr); 834 835 return 0; 836 } 837 EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib); 838 839 /** 840 * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream 841 * @bus: HD-audio core bus 842 * @azx_dev: hdac_stream 843 * 844 * Return maxfifo for the stream 845 */ 846 int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, 847 struct hdac_stream *azx_dev) 848 { 849 if (!bus->spbcap) { 850 dev_err(bus->dev, "Address of SPB capability is NULL\n"); 851 return -EINVAL; 852 } 853 854 return readl(azx_dev->fifo_addr); 855 } 856 EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo); 857 858 /** 859 * snd_hdac_stream_drsm_enable - enable DMA resume for a stream 860 * @bus: HD-audio core bus 861 * @enable: flag to enable/disable DRSM 862 * @index: stream index for which DRSM need to be enabled 863 */ 864 void snd_hdac_stream_drsm_enable(struct hdac_bus *bus, 865 bool enable, int index) 866 { 867 u32 mask = 0; 868 869 if (!bus->drsmcap) { 870 dev_err(bus->dev, "Address of DRSM capability is NULL\n"); 871 return; 872 } 873 874 mask |= (1 << index); 875 876 if (enable) 877 snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask); 878 else 879 snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); 880 } 881 EXPORT_SYMBOL_GPL(snd_hdac_stream_drsm_enable); 882 883 #ifndef TARGET_OS2 884 /* 885 * snd_hdac_stream_wait_drsm - wait for HW to clear RSM for a stream 886 * @azx_dev: HD-audio core stream to await RSM for 887 * 888 * Returns 0 on success and -ETIMEDOUT upon a timeout. 889 */ 890 int snd_hdac_stream_wait_drsm(struct hdac_stream *azx_dev) 891 { 892 struct hdac_bus *bus = azx_dev->bus; 893 u32 mask, reg; 894 int ret; 895 896 mask = 1 << azx_dev->index; 897 898 ret = read_poll_timeout(snd_hdac_reg_readl, reg, !(reg & mask), 250, 2000, false, bus, 899 bus->drsmcap + AZX_REG_DRSM_CTL); 900 if (ret) 901 dev_dbg(bus->dev, "polling RSM 0x%08x failed: %d\n", mask, ret); 902 return ret; 903 } 904 EXPORT_SYMBOL_GPL(snd_hdac_stream_wait_drsm); 905 #endif 906 907 /** 908 * snd_hdac_stream_set_dpibr - sets the dpibr value of a stream 909 * @bus: HD-audio core bus 910 * @azx_dev: hdac_stream 911 * @value: dpib value to set 912 */ 913 int snd_hdac_stream_set_dpibr(struct hdac_bus *bus, 914 struct hdac_stream *azx_dev, u32 value) 915 { 916 if (!bus->drsmcap) { 917 dev_err(bus->dev, "Address of DRSM capability is NULL\n"); 918 return -EINVAL; 919 } 920 921 writel(value, azx_dev->dpibr_addr); 922 923 return 0; 924 } 925 EXPORT_SYMBOL_GPL(snd_hdac_stream_set_dpibr); 926 927 /** 928 * snd_hdac_stream_set_lpib - sets the lpib value of a stream 929 * @azx_dev: hdac_stream 930 * @value: lpib value to set 931 */ 932 int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value) 933 { 934 snd_hdac_stream_writel(azx_dev, SD_LPIB, value); 935 936 return 0; 937 } 938 EXPORT_SYMBOL_GPL(snd_hdac_stream_set_lpib); 939 682 940 #ifdef CONFIG_SND_HDA_DSP_LOADER 683 941 /** … … 754 1012 { 755 1013 if (start) 756 snd_hdac_stream_start(azx_dev , true);1014 snd_hdac_stream_start(azx_dev); 757 1015 else 758 1016 snd_hdac_stream_stop(azx_dev);
Note:
See TracChangeset
for help on using the changeset viewer.