* No longer enable interrupts for all possible streams - they are now enabled

on a per-stream basis in hda_stream_start().
* Also, don't turn on interrupt generation in the stream before starting the
  stream.
* Create space for the DMA position update and set it in the controller, not
  yet tested.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24144 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-02-26 16:05:55 +00:00
parent 10da43ea2e
commit 7ef3822c00
3 changed files with 46 additions and 14 deletions
@@ -195,6 +195,7 @@ struct hda_controller {
area_id rb_area;
corb_t* corb;
rirb_t* rirb;
uint32* stream_positions;
hda_codec* codecs[HDA_MAX_CODECS];
hda_codec* active_codec;
@@ -99,10 +99,14 @@ hda_stream_start(hda_controller* controller, hda_stream* stream)
if (stream->buffer_ready_sem < B_OK)
return stream->buffer_ready_sem;
OREG8(controller, stream->off, CTL0) |= CTL0_RUN;
REG32(controller, INTCTL) |= 1 << (stream->off / HDAC_SDSIZE);
OREG8(controller, stream->off, CTL0) |= CTL0_IOCE | CTL0_FEIE | CTL0_DEIE
| CTL0_RUN;
#if 0
while (!(OREG8(controller, stream->off, CTL0) & CTL0_RUN))
snooze(1);
#endif
stream->running = true;
@@ -145,10 +149,14 @@ hda_stream_check_intr(hda_controller* controller, hda_stream* stream)
status_t
hda_stream_stop(hda_controller* controller, hda_stream* stream)
{
OREG8(controller, stream->off, CTL0) &= ~CTL0_RUN;
OREG8(controller, stream->off, CTL0) &= ~(CTL0_IOCE | CTL0_FEIE | CTL0_DEIE
| CTL0_RUN);
REG32(controller, INTCTL) &= ~(1 << (stream->off / HDAC_SDSIZE));
#if 0
while ((OREG8(controller, stream->off, CTL0) & CTL0_RUN) != 0)
snooze(1);
#endif
stream->running = false;
delete_sem(stream->buffer_ready_sem);
@@ -287,10 +295,11 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
OREG32(audioGroup->codec->controller, stream->off, CBL)
= stream->sample_size * stream->num_channels * stream->num_buffers
* stream->buffer_length;
OREG8(audioGroup->codec->controller, stream->off, CTL0)
= CTL0_IOCE | CTL0_FEIE | CTL0_DEIE;
OREG8(audioGroup->codec->controller, stream->off, CTL2) = stream->id << 4;
REG32(audioGroup->codec->controller, DMA_POSITION_BASE_LOWER)
|= DMA_POSITION_ENABLED;
verb[0] = MAKE_VERB(audioGroup->codec->addr, stream->io_widget,
VID_SET_CONVERTER_FORMAT, format);
verb[1] = MAKE_VERB(audioGroup->codec->addr, stream->io_widget,
@@ -429,10 +438,10 @@ hda_hw_start(hda_controller* controller)
static status_t
hda_hw_corb_rirb_init(hda_controller* controller)
hda_hw_corb_rirb_pos_init(hda_controller* controller)
{
uint32 memSize, rirbOffset;
uint8 corbSize, rirbSize;
uint32 memSize, rirbOffset, posOffset;
uint8 corbSize, rirbSize, posSize;
status_t rc = B_OK;
physical_entry pe;
@@ -464,12 +473,17 @@ hda_hw_corb_rirb_init(hda_controller* controller)
/* Determine rirb offset in memory and total size of corb+alignment+rirb */
rirbOffset = (controller->corb_length * sizeof(corb_t) + 0x7f) & ~0x7f;
memSize = (rirbOffset + controller->rirb_length * sizeof(rirb_t)
+ B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
posOffset = (rirbOffset + controller->rirb_length * sizeof(rirb_t) + 0x7f)
& 0x7f;
posSize = 8 * (controller->num_input_streams
+ controller->num_output_streams + controller->num_bidir_streams);
memSize = (posOffset + posSize + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
/* Allocate memory area */
controller->rb_area = create_area("hda_corb_rirb", (void**)&controller->corb,
B_ANY_KERNEL_ADDRESS, memSize, B_CONTIGUOUS, 0);
controller->rb_area = create_area("hda corb/rirb/pos",
(void**)&controller->corb, B_ANY_KERNEL_ADDRESS, memSize,
B_CONTIGUOUS, 0);
if (controller->rb_area < 0)
return controller->rb_area;
@@ -483,7 +497,16 @@ hda_hw_corb_rirb_init(hda_controller* controller)
/* Program CORB/RIRB for these locations */
REG32(controller, CORBLBASE) = (uint32)pe.address;
REG32(controller, CORBUBASE) = 0;
REG32(controller, RIRBLBASE) = (uint32)pe.address + rirbOffset;
REG32(controller, RIRBUBASE) = 0;
/* Program DMA position update */
REG32(controller, DMA_POSITION_BASE_LOWER) = (uint32)pe.address + posOffset;
REG32(controller, DMA_POSITION_BASE_UPPER) = 0;
controller->stream_positions = (uint32*)
((uint8*)controller->corb + posOffset);
/* Reset CORB read pointer */
/* NOTE: See HDA011 for corrected procedure! */
@@ -556,15 +579,15 @@ hda_hw_init(hda_controller* controller)
if (rc != B_OK)
goto reset_failed;
/* Setup CORB/RIRB */
rc = hda_hw_corb_rirb_init(controller);
/* Setup CORB/RIRB/DMA POS */
rc = hda_hw_corb_rirb_pos_init(controller);
if (rc != B_OK)
goto corb_rirb_failed;
REG16(controller, WAKEEN) = 0x7fff;
/* Enable controller interrupts */
REG32(controller, INTCTL) = INTCTL_GIE | INTCTL_CIE | 0xffff;
REG32(controller, INTCTL) = INTCTL_GIE | INTCTL_CIE;
/* Wait for codecs to warm up */
snooze(1000);
@@ -641,6 +664,10 @@ hda_hw_uninit(hda_controller* controller)
REG8(controller, CORBCTL) = 0;
REG8(controller, RIRBCTL) = 0;
REG32(controller, CORBLBASE) = 0;
REG32(controller, RIRBLBASE) = 0;
REG32(controller, DMA_POSITION_BASE_LOWER) = 0;
/* Disable interrupts and remove interrupt handler */
REG32(controller, INTCTL) = 0;
REG32(controller, GCTL) &= ~GCTL_CRST;
@@ -96,6 +96,10 @@
#define RIRBSIZE_SZ_16E (1 << 0)
#define RIRBSIZE_SZ_256E (1 << 1)
#define HDAC_DMA_POSITION_BASE_LOWER 0x70 /* 32bits */
#define HDAC_DMA_POSITION_BASE_UPPER 0x74 /* 32bits */
#define DMA_POSITION_ENABLED 1
#define HDAC_SDBASE 0x80
#define HDAC_SDSIZE 0x20