diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-08-08 12:33:47 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-08-08 14:18:18 -0400 |
commit | 097d9eb537ff4d88b74c3fe67392e27c478ca3c5 (patch) | |
tree | 9034d676d9096857a380aab9d99e3e88fccb6bfe /sound | |
parent | c41107c2d4fd31924533f4dbc4c3428acc2b5894 (diff) | |
parent | aeee90dfa01844168cd7f8051d0a0f969c573067 (diff) |
Merge Linus' latest into master
Conflicts:
drivers/watchdog/at91rm9200_wdt.c
drivers/watchdog/davinci_wdt.c
drivers/watchdog/ep93xx_wdt.c
drivers/watchdog/ixp2000_wdt.c
drivers/watchdog/ixp4xx_wdt.c
drivers/watchdog/ks8695_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/sa1100_wdt.c
drivers/watchdog/wdt285.c
Diffstat (limited to 'sound')
-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 | } |