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 | |
| parent | 2d864c499a77129dc6aa4f7552ddf2885e4a9c47 (diff) | |
| parent | 1dddab400b7ad028b21d7d5b060e4a068d6d3cd9 (diff) | |
Merge branch 'topic/hda-optimize' into topic/hda
| -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; |
