diff options
| author | Timur Tabi <timur@freescale.com> | 2008-08-01 15:58:44 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2008-08-04 06:26:23 -0400 |
| commit | bf9c8c9ddef7ef761ae9747349175adad0ef16ce (patch) | |
| tree | 0b69a7dff8c7a0e9cce8f05e64d0e24cba4374db | |
| parent | 11589418a1c4cf68be9367f802898d35e07809c4 (diff) | |
ALSA: ASoC: fix SNDCTL_DSP_SYNC support in Freescale 8610 sound drivers
If an OSS application calls SNDCTL_DSP_SYNC, then ALSA will call the driver's
_hw_params and _prepare functions again. On the Freescale MPC8610 DMA ASoC
driver, this caused the DMA controller to be unneccessarily re-programmed, and
apparently it doesn't like that. The DMA will then not operate when
instructed. This patch relocates much of the DMA programming to
fsl_dma_open(), which is called only once.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/soc/fsl/fsl_dma.c | 235 |
1 files changed, 124 insertions, 111 deletions
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 7ceea2bba1f5..d2d3da9729f2 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
| @@ -327,14 +327,75 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, | |||
| 327 | * fsl_dma_open: open a new substream. | 327 | * fsl_dma_open: open a new substream. |
| 328 | * | 328 | * |
| 329 | * Each substream has its own DMA buffer. | 329 | * Each substream has its own DMA buffer. |
| 330 | * | ||
| 331 | * ALSA divides the DMA buffer into N periods. We create NUM_DMA_LINKS link | ||
| 332 | * descriptors that ping-pong from one period to the next. For example, if | ||
| 333 | * there are six periods and two link descriptors, this is how they look | ||
| 334 | * before playback starts: | ||
| 335 | * | ||
| 336 | * The last link descriptor | ||
| 337 | * ____________ points back to the first | ||
| 338 | * | | | ||
| 339 | * V | | ||
| 340 | * ___ ___ | | ||
| 341 | * | |->| |->| | ||
| 342 | * |___| |___| | ||
| 343 | * | | | ||
| 344 | * | | | ||
| 345 | * V V | ||
| 346 | * _________________________________________ | ||
| 347 | * | | | | | | | The DMA buffer is | ||
| 348 | * | | | | | | | divided into 6 parts | ||
| 349 | * |______|______|______|______|______|______| | ||
| 350 | * | ||
| 351 | * and here's how they look after the first period is finished playing: | ||
| 352 | * | ||
| 353 | * ____________ | ||
| 354 | * | | | ||
| 355 | * V | | ||
| 356 | * ___ ___ | | ||
| 357 | * | |->| |->| | ||
| 358 | * |___| |___| | ||
| 359 | * | | | ||
| 360 | * |______________ | ||
| 361 | * | | | ||
| 362 | * V V | ||
| 363 | * _________________________________________ | ||
| 364 | * | | | | | | | | ||
| 365 | * | | | | | | | | ||
| 366 | * |______|______|______|______|______|______| | ||
| 367 | * | ||
| 368 | * The first link descriptor now points to the third period. The DMA | ||
| 369 | * controller is currently playing the second period. When it finishes, it | ||
| 370 | * will jump back to the first descriptor and play the third period. | ||
| 371 | * | ||
| 372 | * There are four reasons we do this: | ||
| 373 | * | ||
| 374 | * 1. The only way to get the DMA controller to automatically restart the | ||
| 375 | * transfer when it gets to the end of the buffer is to use chaining | ||
| 376 | * mode. Basic direct mode doesn't offer that feature. | ||
| 377 | * 2. We need to receive an interrupt at the end of every period. The DMA | ||
| 378 | * controller can generate an interrupt at the end of every link transfer | ||
| 379 | * (aka segment). Making each period into a DMA segment will give us the | ||
| 380 | * interrupts we need. | ||
| 381 | * 3. By creating only two link descriptors, regardless of the number of | ||
| 382 | * periods, we do not need to reallocate the link descriptors if the | ||
| 383 | * number of periods changes. | ||
| 384 | * 4. All of the audio data is still stored in a single, contiguous DMA | ||
| 385 | * buffer, which is what ALSA expects. We're just dividing it into | ||
| 386 | * contiguous parts, and creating a link descriptor for each one. | ||
| 330 | */ | 387 | */ |
| 331 | static int fsl_dma_open(struct snd_pcm_substream *substream) | 388 | static int fsl_dma_open(struct snd_pcm_substream *substream) |
| 332 | { | 389 | { |
| 333 | struct snd_pcm_runtime *runtime = substream->runtime; | 390 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 334 | struct fsl_dma_private *dma_private; | 391 | struct fsl_dma_private *dma_private; |
| 392 | struct ccsr_dma_channel __iomem *dma_channel; | ||
| 335 | dma_addr_t ld_buf_phys; | 393 | dma_addr_t ld_buf_phys; |
| 394 | u64 temp_link; /* Pointer to next link descriptor */ | ||
| 395 | u32 mr; | ||
| 336 | unsigned int channel; | 396 | unsigned int channel; |
| 337 | int ret = 0; | 397 | int ret = 0; |
| 398 | unsigned int i; | ||
| 338 | 399 | ||
| 339 | /* | 400 | /* |
| 340 | * Reject any DMA buffer whose size is not a multiple of the period | 401 | * Reject any DMA buffer whose size is not a multiple of the period |
| @@ -395,68 +456,74 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
| 395 | snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); | 456 | snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); |
| 396 | runtime->private_data = dma_private; | 457 | runtime->private_data = dma_private; |
| 397 | 458 | ||
| 459 | /* Program the fixed DMA controller parameters */ | ||
| 460 | |||
| 461 | dma_channel = dma_private->dma_channel; | ||
| 462 | |||
| 463 | temp_link = dma_private->ld_buf_phys + | ||
| 464 | sizeof(struct fsl_dma_link_descriptor); | ||
| 465 | |||
| 466 | for (i = 0; i < NUM_DMA_LINKS; i++) { | ||
| 467 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | ||
| 468 | |||
| 469 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
| 470 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
| 471 | link->next = cpu_to_be64(temp_link); | ||
| 472 | |||
| 473 | temp_link += sizeof(struct fsl_dma_link_descriptor); | ||
| 474 | } | ||
| 475 | /* The last link descriptor points to the first */ | ||
| 476 | dma_private->link[i - 1].next = cpu_to_be64(dma_private->ld_buf_phys); | ||
| 477 | |||
| 478 | /* Tell the DMA controller where the first link descriptor is */ | ||
| 479 | out_be32(&dma_channel->clndar, | ||
| 480 | CCSR_DMA_CLNDAR_ADDR(dma_private->ld_buf_phys)); | ||
| 481 | out_be32(&dma_channel->eclndar, | ||
| 482 | CCSR_DMA_ECLNDAR_ADDR(dma_private->ld_buf_phys)); | ||
| 483 | |||
| 484 | /* The manual says the BCR must be clear before enabling EMP */ | ||
| 485 | out_be32(&dma_channel->bcr, 0); | ||
| 486 | |||
| 487 | /* | ||
| 488 | * Program the mode register for interrupts, external master control, | ||
| 489 | * and source/destination hold. Also clear the Channel Abort bit. | ||
| 490 | */ | ||
| 491 | mr = in_be32(&dma_channel->mr) & | ||
| 492 | ~(CCSR_DMA_MR_CA | CCSR_DMA_MR_DAHE | CCSR_DMA_MR_SAHE); | ||
| 493 | |||
| 494 | /* | ||
| 495 | * We want External Master Start and External Master Pause enabled, | ||
| 496 | * because the SSI is controlling the DMA controller. We want the DMA | ||
| 497 | * controller to be set up in advance, and then we signal only the SSI | ||
| 498 | * to start transferring. | ||
| 499 | * | ||
| 500 | * We want End-Of-Segment Interrupts enabled, because this will generate | ||
| 501 | * an interrupt at the end of each segment (each link descriptor | ||
| 502 | * represents one segment). Each DMA segment is the same thing as an | ||
| 503 | * ALSA period, so this is how we get an interrupt at the end of every | ||
| 504 | * period. | ||
| 505 | * | ||
| 506 | * We want Error Interrupt enabled, so that we can get an error if | ||
| 507 | * the DMA controller is mis-programmed somehow. | ||
| 508 | */ | ||
| 509 | mr |= CCSR_DMA_MR_EOSIE | CCSR_DMA_MR_EIE | CCSR_DMA_MR_EMP_EN | | ||
| 510 | CCSR_DMA_MR_EMS_EN; | ||
| 511 | |||
| 512 | /* For playback, we want the destination address to be held. For | ||
| 513 | capture, set the source address to be held. */ | ||
| 514 | mr |= (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
| 515 | CCSR_DMA_MR_DAHE : CCSR_DMA_MR_SAHE; | ||
| 516 | |||
| 517 | out_be32(&dma_channel->mr, mr); | ||
| 518 | |||
| 398 | return 0; | 519 | return 0; |
| 399 | } | 520 | } |
| 400 | 521 | ||
| 401 | /** | 522 | /** |
| 402 | * fsl_dma_hw_params: allocate the DMA buffer and the DMA link descriptors. | 523 | * fsl_dma_hw_params: continue initializing the DMA links |
| 403 | * | ||
| 404 | * ALSA divides the DMA buffer into N periods. We create NUM_DMA_LINKS link | ||
| 405 | * descriptors that ping-pong from one period to the next. For example, if | ||
| 406 | * there are six periods and two link descriptors, this is how they look | ||
| 407 | * before playback starts: | ||
| 408 | * | ||
| 409 | * The last link descriptor | ||
| 410 | * ____________ points back to the first | ||
| 411 | * | | | ||
| 412 | * V | | ||
| 413 | * ___ ___ | | ||
| 414 | * | |->| |->| | ||
| 415 | * |___| |___| | ||
| 416 | * | | | ||
| 417 | * | | | ||
| 418 | * V V | ||
| 419 | * _________________________________________ | ||
| 420 | * | | | | | | | The DMA buffer is | ||
| 421 | * | | | | | | | divided into 6 parts | ||
| 422 | * |______|______|______|______|______|______| | ||
| 423 | * | ||
| 424 | * and here's how they look after the first period is finished playing: | ||
| 425 | * | ||
| 426 | * ____________ | ||
| 427 | * | | | ||
| 428 | * V | | ||
| 429 | * ___ ___ | | ||
| 430 | * | |->| |->| | ||
| 431 | * |___| |___| | ||
| 432 | * | | | ||
| 433 | * |______________ | ||
| 434 | * | | | ||
| 435 | * V V | ||
| 436 | * _________________________________________ | ||
| 437 | * | | | | | | | | ||
| 438 | * | | | | | | | | ||
| 439 | * |______|______|______|______|______|______| | ||
| 440 | * | 524 | * |
| 441 | * The first link descriptor now points to the third period. The DMA | 525 | * This function obtains hardware parameters about the opened stream and |
| 442 | * controller is currently playing the second period. When it finishes, it | 526 | * programs the DMA controller accordingly. |
| 443 | * will jump back to the first descriptor and play the third period. | ||
| 444 | * | ||
| 445 | * There are four reasons we do this: | ||
| 446 | * | ||
| 447 | * 1. The only way to get the DMA controller to automatically restart the | ||
| 448 | * transfer when it gets to the end of the buffer is to use chaining | ||
| 449 | * mode. Basic direct mode doesn't offer that feature. | ||
| 450 | * 2. We need to receive an interrupt at the end of every period. The DMA | ||
| 451 | * controller can generate an interrupt at the end of every link transfer | ||
| 452 | * (aka segment). Making each period into a DMA segment will give us the | ||
| 453 | * interrupts we need. | ||
| 454 | * 3. By creating only two link descriptors, regardless of the number of | ||
| 455 | * periods, we do not need to reallocate the link descriptors if the | ||
| 456 | * number of periods changes. | ||
| 457 | * 4. All of the audio data is still stored in a single, contiguous DMA | ||
| 458 | * buffer, which is what ALSA expects. We're just dividing it into | ||
| 459 | * contiguous parts, and creating a link descriptor for each one. | ||
| 460 | * | 527 | * |
| 461 | * Note that due to a quirk of the SSI's STX register, the target address | 528 | * Note that due to a quirk of the SSI's STX register, the target address |
| 462 | * for the DMA operations depends on the sample size. So we don't program | 529 | * for the DMA operations depends on the sample size. So we don't program |
| @@ -468,11 +535,8 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
| 468 | { | 535 | { |
| 469 | struct snd_pcm_runtime *runtime = substream->runtime; | 536 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 470 | struct fsl_dma_private *dma_private = runtime->private_data; | 537 | struct fsl_dma_private *dma_private = runtime->private_data; |
| 471 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | ||
| 472 | 538 | ||
| 473 | dma_addr_t temp_addr; /* Pointer to next period */ | 539 | dma_addr_t temp_addr; /* Pointer to next period */ |
| 474 | u64 temp_link; /* Pointer to next link descriptor */ | ||
| 475 | u32 mr; /* Temporary variable for MR register */ | ||
| 476 | 540 | ||
| 477 | unsigned int i; | 541 | unsigned int i; |
| 478 | 542 | ||
| @@ -490,8 +554,6 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
| 490 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | 554 | dma_private->dma_buf_next = dma_private->dma_buf_phys; |
| 491 | 555 | ||
| 492 | /* | 556 | /* |
| 493 | * Initialize each link descriptor. | ||
| 494 | * | ||
| 495 | * The actual address in STX0 (destination for playback, source for | 557 | * The actual address in STX0 (destination for playback, source for |
| 496 | * capture) is based on the sample size, but we don't know the sample | 558 | * capture) is based on the sample size, but we don't know the sample |
| 497 | * size in this function, so we'll have to adjust that later. See | 559 | * size in this function, so we'll have to adjust that later. See |
| @@ -507,16 +569,11 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
| 507 | * buffer itself. | 569 | * buffer itself. |
| 508 | */ | 570 | */ |
| 509 | temp_addr = substream->dma_buffer.addr; | 571 | temp_addr = substream->dma_buffer.addr; |
| 510 | temp_link = dma_private->ld_buf_phys + | ||
| 511 | sizeof(struct fsl_dma_link_descriptor); | ||
| 512 | 572 | ||
| 513 | for (i = 0; i < NUM_DMA_LINKS; i++) { | 573 | for (i = 0; i < NUM_DMA_LINKS; i++) { |
| 514 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | 574 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; |
| 515 | 575 | ||
| 516 | link->count = cpu_to_be32(period_size); | 576 | link->count = cpu_to_be32(period_size); |
| 517 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
| 518 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
| 519 | link->next = cpu_to_be64(temp_link); | ||
| 520 | 577 | ||
| 521 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 578 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 522 | link->source_addr = cpu_to_be32(temp_addr); | 579 | link->source_addr = cpu_to_be32(temp_addr); |
| @@ -524,51 +581,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
| 524 | link->dest_addr = cpu_to_be32(temp_addr); | 581 | link->dest_addr = cpu_to_be32(temp_addr); |
| 525 | 582 | ||
| 526 | temp_addr += period_size; | 583 | temp_addr += period_size; |
| 527 | temp_link += sizeof(struct fsl_dma_link_descriptor); | ||
| 528 | } | 584 | } |
| 529 | /* The last link descriptor points to the first */ | ||
| 530 | dma_private->link[i - 1].next = cpu_to_be64(dma_private->ld_buf_phys); | ||
| 531 | |||
| 532 | /* Tell the DMA controller where the first link descriptor is */ | ||
| 533 | out_be32(&dma_channel->clndar, | ||
| 534 | CCSR_DMA_CLNDAR_ADDR(dma_private->ld_buf_phys)); | ||
| 535 | out_be32(&dma_channel->eclndar, | ||
| 536 | CCSR_DMA_ECLNDAR_ADDR(dma_private->ld_buf_phys)); | ||
| 537 | |||
| 538 | /* The manual says the BCR must be clear before enabling EMP */ | ||
| 539 | out_be32(&dma_channel->bcr, 0); | ||
| 540 | |||
| 541 | /* | ||
| 542 | * Program the mode register for interrupts, external master control, | ||
| 543 | * and source/destination hold. Also clear the Channel Abort bit. | ||
| 544 | */ | ||
| 545 | mr = in_be32(&dma_channel->mr) & | ||
| 546 | ~(CCSR_DMA_MR_CA | CCSR_DMA_MR_DAHE | CCSR_DMA_MR_SAHE); | ||
| 547 | |||
| 548 | /* | ||
| 549 | * We want External Master Start and External Master Pause enabled, | ||
| 550 | * because the SSI is controlling the DMA controller. We want the DMA | ||
| 551 | * controller to be set up in advance, and then we signal only the SSI | ||
| 552 | * to start transfering. | ||
| 553 | * | ||
| 554 | * We want End-Of-Segment Interrupts enabled, because this will generate | ||
| 555 | * an interrupt at the end of each segment (each link descriptor | ||
| 556 | * represents one segment). Each DMA segment is the same thing as an | ||
| 557 | * ALSA period, so this is how we get an interrupt at the end of every | ||
| 558 | * period. | ||
| 559 | * | ||
| 560 | * We want Error Interrupt enabled, so that we can get an error if | ||
| 561 | * the DMA controller is mis-programmed somehow. | ||
| 562 | */ | ||
| 563 | mr |= CCSR_DMA_MR_EOSIE | CCSR_DMA_MR_EIE | CCSR_DMA_MR_EMP_EN | | ||
| 564 | CCSR_DMA_MR_EMS_EN; | ||
| 565 | |||
| 566 | /* For playback, we want the destination address to be held. For | ||
| 567 | capture, set the source address to be held. */ | ||
| 568 | mr |= (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
| 569 | CCSR_DMA_MR_DAHE : CCSR_DMA_MR_SAHE; | ||
| 570 | |||
| 571 | out_be32(&dma_channel->mr, mr); | ||
| 572 | 585 | ||
| 573 | return 0; | 586 | return 0; |
| 574 | } | 587 | } |
