diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-03-20 11:33:30 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-03-20 11:33:30 -0400 |
commit | c9840cf4cf12a4ec4fe3c4db3c28f638d06e942b (patch) | |
tree | 95073d031d11aa2c100238529fc0ce6b0b07f40f /sound | |
parent | 2d864c499a77129dc6aa4f7552ddf2885e4a9c47 (diff) | |
parent | 1dddab400b7ad028b21d7d5b060e4a068d6d3cd9 (diff) |
Merge branch 'topic/hda-optimize' into topic/hda
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_intel.c | 79 |
1 files changed, 54 insertions, 25 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6bcf5af6edce..8b2e4160de8d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -859,13 +859,18 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) | |||
859 | SD_CTL_DMA_START | SD_INT_MASK); | 859 | SD_CTL_DMA_START | SD_INT_MASK); |
860 | } | 860 | } |
861 | 861 | ||
862 | /* stop a stream */ | 862 | /* stop DMA */ |
863 | static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) | 863 | static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev) |
864 | { | 864 | { |
865 | /* stop DMA */ | ||
866 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & | 865 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & |
867 | ~(SD_CTL_DMA_START | SD_INT_MASK)); | 866 | ~(SD_CTL_DMA_START | SD_INT_MASK)); |
868 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ | 867 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ |
868 | } | ||
869 | |||
870 | /* stop a stream */ | ||
871 | static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) | ||
872 | { | ||
873 | azx_stream_clear(chip, azx_dev); | ||
869 | /* disable SIE */ | 874 | /* disable SIE */ |
870 | azx_writeb(chip, INTCTL, | 875 | azx_writeb(chip, INTCTL, |
871 | azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); | 876 | azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); |
@@ -1076,8 +1081,7 @@ static int azx_setup_periods(struct azx *chip, | |||
1076 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | 1081 | azx_sd_writel(azx_dev, SD_BDLPL, 0); |
1077 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | 1082 | azx_sd_writel(azx_dev, SD_BDLPU, 0); |
1078 | 1083 | ||
1079 | period_bytes = snd_pcm_lib_period_bytes(substream); | 1084 | period_bytes = azx_dev->period_bytes; |
1080 | azx_dev->period_bytes = period_bytes; | ||
1081 | periods = azx_dev->bufsize / period_bytes; | 1085 | periods = azx_dev->bufsize / period_bytes; |
1082 | 1086 | ||
1083 | /* program the initial BDL entries */ | 1087 | /* program the initial BDL entries */ |
@@ -1124,24 +1128,17 @@ static int azx_setup_periods(struct azx *chip, | |||
1124 | error: | 1128 | error: |
1125 | snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", | 1129 | snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", |
1126 | azx_dev->bufsize, period_bytes); | 1130 | azx_dev->bufsize, period_bytes); |
1127 | /* reset */ | ||
1128 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||
1129 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||
1130 | return -EINVAL; | 1131 | return -EINVAL; |
1131 | } | 1132 | } |
1132 | 1133 | ||
1133 | /* | 1134 | /* reset stream */ |
1134 | * set up the SD for streaming | 1135 | static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) |
1135 | */ | ||
1136 | static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | ||
1137 | { | 1136 | { |
1138 | unsigned char val; | 1137 | unsigned char val; |
1139 | int timeout; | 1138 | int timeout; |
1140 | 1139 | ||
1141 | /* make sure the run bit is zero for SD */ | 1140 | azx_stream_clear(chip, azx_dev); |
1142 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & | 1141 | |
1143 | ~SD_CTL_DMA_START); | ||
1144 | /* reset stream */ | ||
1145 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | | 1142 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | |
1146 | SD_CTL_STREAM_RESET); | 1143 | SD_CTL_STREAM_RESET); |
1147 | udelay(3); | 1144 | udelay(3); |
@@ -1158,7 +1155,15 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
1158 | while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && | 1155 | while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && |
1159 | --timeout) | 1156 | --timeout) |
1160 | ; | 1157 | ; |
1158 | } | ||
1161 | 1159 | ||
1160 | /* | ||
1161 | * set up the SD for streaming | ||
1162 | */ | ||
1163 | static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | ||
1164 | { | ||
1165 | /* make sure the run bit is zero for SD */ | ||
1166 | azx_stream_clear(chip, azx_dev); | ||
1162 | /* program the stream_tag */ | 1167 | /* program the stream_tag */ |
1163 | azx_sd_writel(azx_dev, SD_CTL, | 1168 | azx_sd_writel(azx_dev, SD_CTL, |
1164 | (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| | 1169 | (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| |
@@ -1403,6 +1408,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) | |||
1403 | runtime->private_data = azx_dev; | 1408 | runtime->private_data = azx_dev; |
1404 | snd_pcm_set_sync(substream); | 1409 | snd_pcm_set_sync(substream); |
1405 | mutex_unlock(&chip->open_mutex); | 1410 | mutex_unlock(&chip->open_mutex); |
1411 | |||
1412 | azx_stream_reset(chip, azx_dev); | ||
1406 | return 0; | 1413 | return 0; |
1407 | } | 1414 | } |
1408 | 1415 | ||
@@ -1429,6 +1436,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) | |||
1429 | static int azx_pcm_hw_params(struct snd_pcm_substream *substream, | 1436 | static int azx_pcm_hw_params(struct snd_pcm_substream *substream, |
1430 | struct snd_pcm_hw_params *hw_params) | 1437 | struct snd_pcm_hw_params *hw_params) |
1431 | { | 1438 | { |
1439 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
1440 | |||
1441 | azx_dev->bufsize = 0; | ||
1442 | azx_dev->period_bytes = 0; | ||
1443 | azx_dev->format_val = 0; | ||
1432 | return snd_pcm_lib_malloc_pages(substream, | 1444 | return snd_pcm_lib_malloc_pages(substream, |
1433 | params_buffer_bytes(hw_params)); | 1445 | params_buffer_bytes(hw_params)); |
1434 | } | 1446 | } |
@@ -1443,6 +1455,9 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
1443 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | 1455 | azx_sd_writel(azx_dev, SD_BDLPL, 0); |
1444 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | 1456 | azx_sd_writel(azx_dev, SD_BDLPU, 0); |
1445 | azx_sd_writel(azx_dev, SD_CTL, 0); | 1457 | azx_sd_writel(azx_dev, SD_CTL, 0); |
1458 | azx_dev->bufsize = 0; | ||
1459 | azx_dev->period_bytes = 0; | ||
1460 | azx_dev->format_val = 0; | ||
1446 | 1461 | ||
1447 | hinfo->ops.cleanup(hinfo, apcm->codec, substream); | 1462 | hinfo->ops.cleanup(hinfo, apcm->codec, substream); |
1448 | 1463 | ||
@@ -1456,23 +1471,37 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
1456 | struct azx_dev *azx_dev = get_azx_dev(substream); | 1471 | struct azx_dev *azx_dev = get_azx_dev(substream); |
1457 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | 1472 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; |
1458 | struct snd_pcm_runtime *runtime = substream->runtime; | 1473 | struct snd_pcm_runtime *runtime = substream->runtime; |
1474 | unsigned int bufsize, period_bytes, format_val; | ||
1475 | int err; | ||
1459 | 1476 | ||
1460 | azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream); | 1477 | format_val = snd_hda_calc_stream_format(runtime->rate, |
1461 | azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate, | 1478 | runtime->channels, |
1462 | runtime->channels, | 1479 | runtime->format, |
1463 | runtime->format, | 1480 | hinfo->maxbps); |
1464 | hinfo->maxbps); | 1481 | if (!format_val) { |
1465 | if (!azx_dev->format_val) { | ||
1466 | snd_printk(KERN_ERR SFX | 1482 | snd_printk(KERN_ERR SFX |
1467 | "invalid format_val, rate=%d, ch=%d, format=%d\n", | 1483 | "invalid format_val, rate=%d, ch=%d, format=%d\n", |
1468 | runtime->rate, runtime->channels, runtime->format); | 1484 | runtime->rate, runtime->channels, runtime->format); |
1469 | return -EINVAL; | 1485 | return -EINVAL; |
1470 | } | 1486 | } |
1471 | 1487 | ||
1488 | bufsize = snd_pcm_lib_buffer_bytes(substream); | ||
1489 | period_bytes = snd_pcm_lib_period_bytes(substream); | ||
1490 | |||
1472 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", | 1491 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", |
1473 | azx_dev->bufsize, azx_dev->format_val); | 1492 | bufsize, format_val); |
1474 | if (azx_setup_periods(chip, substream, azx_dev) < 0) | 1493 | |
1475 | return -EINVAL; | 1494 | if (bufsize != azx_dev->bufsize || |
1495 | period_bytes != azx_dev->period_bytes || | ||
1496 | format_val != azx_dev->format_val) { | ||
1497 | azx_dev->bufsize = bufsize; | ||
1498 | azx_dev->period_bytes = period_bytes; | ||
1499 | azx_dev->format_val = format_val; | ||
1500 | err = azx_setup_periods(chip, substream, azx_dev); | ||
1501 | if (err < 0) | ||
1502 | return err; | ||
1503 | } | ||
1504 | |||
1476 | azx_setup_controller(chip, azx_dev); | 1505 | azx_setup_controller(chip, azx_dev); |
1477 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 1506 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
1478 | azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; | 1507 | azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; |