* Rewrote controller reset - it now performs a full reset, and does no longer

assume the driver to be in reset when started.
* Major cleanup of the register access: now hda_controller and hda_stream both
  have member functions for this, the OREGx() and REGx() macros are gone.
* Made the register names and definitions more descriptive - the short names
  of the specs are still mentioned in the comments.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25352 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-05-07 16:30:11 +00:00
parent 1a662751d5
commit a941060027
3 changed files with 405 additions and 291 deletions

View File

@ -51,17 +51,85 @@ enum {
}; };
struct hda_codec; struct hda_codec;
struct hda_stream;
/*! This structure describes a single HDA compliant
controller. It contains a list of available streams
for use by the codecs contained, and the messaging queue
(verb/response) buffers for communication.
*/
struct hda_controller {
struct pci_info pci_info;
vint32 opened;
const char* devfs_path;
area_id regs_area;
vuint8* regs;
uint32 irq;
uint16 codec_status;
uint32 num_input_streams;
uint32 num_output_streams;
uint32 num_bidir_streams;
uint32 corb_length;
uint32 rirb_length;
uint32 rirb_read_pos;
uint32 corb_write_pos;
area_id corb_rirb_pos_area;
corb_t* corb;
rirb_t* rirb;
uint32* stream_positions;
hda_codec* codecs[HDA_MAX_CODECS + 1];
hda_codec* active_codec;
uint32 num_codecs;
hda_stream* streams[HDA_MAX_STREAMS];
uint8 Read8(uint32 reg)
{
return *(regs + reg);
}
uint16 Read16(uint32 reg)
{
return *(vuint16*)(regs + reg);
}
uint32 Read32(uint32 reg)
{
return *(vuint32*)(regs + reg);
}
void Write8(uint32 reg, uint8 value)
{
*(regs + reg) = value;
}
void Write16(uint32 reg, uint16 value)
{
*(vuint16*)(regs + reg) = value;
}
void Write32(uint32 reg, uint32 value)
{
*(vuint32*)(regs + reg) = value;
}
};
/*! This structure describes a single stream of audio data, /*! This structure describes a single stream of audio data,
which is can have multiple channels (for stereo or better). which is can have multiple channels (for stereo or better).
*/ */
struct hda_stream { struct hda_stream {
uint32 id; /* HDA controller stream # */ uint32 id; /* HDA controller stream # */
uint32 off; /* HDA I/O/B descriptor offset */ uint32 offset; /* HDA I/O/B descriptor offset */
bool running; /* Is this stream active? */ bool running;
spinlock lock; /* Write lock */ spinlock lock; /* Write lock */
uint32 type; uint32 type;
hda_controller* controller;
uint32 pin_widget; /* PIN Widget ID */ uint32 pin_widget; /* PIN Widget ID */
uint32 io_widgets[MAX_IO_WIDGETS]; /* Input/Output Converter Widget ID */ uint32 io_widgets[MAX_IO_WIDGETS]; /* Input/Output Converter Widget ID */
uint32 num_io_widgets; uint32 num_io_widgets;
@ -87,6 +155,36 @@ struct hda_stream {
area_id buffer_area; area_id buffer_area;
area_id buffer_descriptors_area; area_id buffer_descriptors_area;
uint32 physical_buffer_descriptors; /* BDL physical address */ uint32 physical_buffer_descriptors; /* BDL physical address */
uint8 Read8(uint32 reg)
{
return controller->Read8(HDAC_STREAM_BASE + offset + reg);
}
uint16 Read16(uint32 reg)
{
return controller->Read16(HDAC_STREAM_BASE + offset + reg);
}
uint8 Read32(uint32 reg)
{
return controller->Read32(HDAC_STREAM_BASE + offset + reg);
}
void Write8(uint32 reg, uint8 value)
{
*(controller->regs + HDAC_STREAM_BASE + offset + reg) = value;
}
void Write16(uint32 reg, uint8 value)
{
*(vuint16*)(controller->regs + HDAC_STREAM_BASE + offset + reg) = value;
}
void Write32(uint32 reg, uint8 value)
{
*(vuint32*)(controller->regs + HDAC_STREAM_BASE + offset + reg) = value;
}
}; };
struct hda_widget { struct hda_widget {
@ -174,40 +272,6 @@ struct hda_codec {
struct hda_controller* controller; struct hda_controller* controller;
}; };
/*! This structure describes a single HDA compliant
controller. It contains a list of available streams
for use by the codecs contained, and the messaging queue
(verb/response) buffers for communication.
*/
struct hda_controller {
struct pci_info pci_info;
vint32 opened;
const char* devfs_path;
area_id regs_area;
vuint8* regs;
uint32 irq;
uint16 codec_status;
uint32 num_input_streams;
uint32 num_output_streams;
uint32 num_bidir_streams;
uint32 corb_length;
uint32 rirb_length;
uint32 rirb_read_pos;
uint32 corb_write_pos;
area_id corb_rirb_pos_area;
corb_t* corb;
rirb_t* rirb;
uint32* stream_positions;
hda_codec* codecs[HDA_MAX_CODECS + 1];
hda_codec* active_codec;
uint32 num_codecs;
hda_stream* streams[HDA_MAX_STREAMS];
};
/* driver.c */ /* driver.c */
extern device_hooks gDriverHooks; extern device_hooks gDriverHooks;

View File

@ -14,9 +14,17 @@
#define MAKE_RATE(base, multiply, divide) \ #define MAKE_RATE(base, multiply, divide) \
((base == 44100 ? FMT_44_1_BASE_RATE : 0) \ ((base == 44100 ? FORMAT_44_1_BASE_RATE : 0) \
| ((multiply - 1) << FMT_MULTIPLY_RATE_SHIFT) \ | ((multiply - 1) << FORMAT_MULTIPLY_RATE_SHIFT) \
| ((divide - 1) << FMT_DIVIDE_RATE_SHIFT)) | ((divide - 1) << FORMAT_DIVIDE_RATE_SHIFT))
#define HDAC_INPUT_STREAM_OFFSET(controller, index) \
((index) * HDAC_STREAM_SIZE)
#define HDAC_OUTPUT_STREAM_OFFSET(controller, index) \
(((controller)->num_input_streams + (index)) * HDAC_STREAM_SIZE)
#define HDAC_BIDIR_STREAM_OFFSET(controller, index) \
(((controller)->num_input_streams + (controller)->num_output_streams \
+ (index)) * HDAC_STREAM_SIZE)
static const struct { static const struct {
uint32 multi_rate; uint32 multi_rate;
@ -67,13 +75,13 @@ stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
if (!stream->running) if (!stream->running)
return; return;
status = OREG8(controller, stream->off, STS); status = stream->Read8(HDAC_STREAM_STATUS);
if (status == 0) if (status == 0)
return; return;
OREG8(controller, stream->off, STS) = status; stream->Write8(HDAC_STREAM_STATUS, status);
if ((status & STS_BCIS) != 0) { if ((status & STATUS_BUFFER_COMPLETED) != 0) {
// Buffer Completed Interrupt // Buffer Completed Interrupt
acquire_spinlock(&stream->lock); acquire_spinlock(&stream->lock);
@ -86,38 +94,38 @@ stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
release_sem_etc(stream->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(stream->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
} else } else
dprintf("HDA: stream status %x\n", status); dprintf("hda: stream status %x\n", status);
} }
static int32 static int32
hda_interrupt_handler(hda_controller* controller) hda_interrupt_handler(hda_controller* controller)
{ {
int32 rc = B_HANDLED_INTERRUPT; int32 handled = B_HANDLED_INTERRUPT;
/* Check if this interrupt is ours */ /* Check if this interrupt is ours */
uint32 intsts = REG32(controller, INTSTS); uint32 intrStatus = controller->Read32(HDAC_INTR_STATUS);
if ((intsts & INTSTS_GIS) == 0) if ((intrStatus & INTR_STATUS_GLOBAL) == 0)
return B_UNHANDLED_INTERRUPT; return B_UNHANDLED_INTERRUPT;
/* Controller or stream related? */ /* Controller or stream related? */
if (intsts & INTSTS_CIS) { if (intrStatus & INTR_STATUS_CONTROLLER) {
uint32 stateStatus = REG16(controller, STATESTS); uint32 stateStatus = controller->Read16(HDAC_STATE_STATUS);
uint8 rirbStatus = REG8(controller, RIRBSTS); uint8 rirbStatus = controller->Read8(HDAC_RIRB_STATUS);
uint8 corbStatus = REG8(controller, CORBSTS); uint8 corbStatus = controller->Read8(HDAC_CORB_STATUS);
if (stateStatus) { if (stateStatus) {
/* Detected Codec state change */ /* Detected Codec state change */
REG16(controller, STATESTS) = stateStatus; controller->Write16(HDAC_STATE_STATUS, stateStatus);
controller->codec_status = stateStatus; controller->codec_status = stateStatus;
} }
/* Check for incoming responses */ /* Check for incoming responses */
if (rirbStatus) { if (rirbStatus) {
REG8(controller, RIRBSTS) = rirbStatus; controller->Write8(HDAC_RIRB_STATUS, rirbStatus);
if (rirbStatus & RIRBSTS_RINTFL) { if ((rirbStatus & RIRB_STATUS_RESPONSE) != 0) {
uint16 writePos = (REG16(controller, RIRBWP) + 1) uint16 writePos = (controller->Read16(HDAC_RIRB_WRITE_POS) + 1)
% controller->rirb_length; % controller->rirb_length;
for (; controller->rirb_read_pos != writePos; for (; controller->rirb_read_pos != writePos;
@ -146,26 +154,26 @@ hda_interrupt_handler(hda_controller* controller)
/* Store response in codec */ /* Store response in codec */
codec->responses[codec->response_count++] = response; codec->responses[codec->response_count++] = response;
release_sem_etc(codec->response_sem, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(codec->response_sem, 1, B_DO_NOT_RESCHEDULE);
rc = B_INVOKE_SCHEDULER; handled = B_INVOKE_SCHEDULER;
} }
} }
if (rirbStatus & RIRBSTS_OIS) if ((rirbStatus & RIRB_STATUS_OVERRUN) != 0)
dprintf("hda: RIRB Overflow\n"); dprintf("hda: RIRB Overflow\n");
} }
/* Check for sending errors */ /* Check for sending errors */
if (corbStatus) { if (corbStatus) {
REG8(controller, CORBSTS) = corbStatus; controller->Write8(HDAC_CORB_STATUS, corbStatus);
if (corbStatus & CORBSTS_MEI) if ((corbStatus & CORB_STATUS_MEMORY_ERROR) != 0)
dprintf("hda: CORB Memory Error!\n"); dprintf("hda: CORB Memory Error!\n");
} }
} }
if (intsts & ~(INTSTS_CIS | INTSTS_GIS)) { if ((intrStatus & INTR_STATUS_STREAM_MASK) != 0) {
for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) { for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
if ((intsts & (1 << index)) != 0) { if ((intrStatus & (1 << index)) != 0) {
if (controller->streams[index]) { if (controller->streams[index]) {
stream_handle_interrupt(controller, stream_handle_interrupt(controller,
controller->streams[index]); controller->streams[index]);
@ -179,25 +187,80 @@ hda_interrupt_handler(hda_controller* controller)
/* NOTE: See HDA001 => CIS/GIS cannot be cleared! */ /* NOTE: See HDA001 => CIS/GIS cannot be cleared! */
return rc; return handled;
} }
static status_t static status_t
hda_hw_start(hda_controller* controller) reset_controller(hda_controller* controller)
{ {
int timeout = 10; // stop streams
// TODO: reset controller first? (we currently reset on uninit only) for (uint32 i = 0; i < controller->num_input_streams; i++) {
controller->Write8(HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(controller, i), 0);
controller->Write8(HDAC_STREAM_STATUS + HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(controller, i), 0);
}
for (uint32 i = 0; i < controller->num_output_streams; i++) {
controller->Write8(HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(controller, i), 0);
controller->Write8(HDAC_STREAM_STATUS + HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(controller, i), 0);
}
for (uint32 i = 0; i < controller->num_bidir_streams; i++) {
controller->Write8(HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(controller, i), 0);
controller->Write8(HDAC_STREAM_STATUS + HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(controller, i), 0);
}
/* Put controller out of reset mode */ // stop DMA
REG32(controller, GCTL) |= GCTL_CRST; controller->Write8(HDAC_CORB_CONTROL, 0);
controller->Write8(HDAC_RIRB_CONTROL, 0);
do { // reset DMA position buffer
controller->Write32(HDAC_DMA_POSITION_BASE_LOWER, 0);
controller->Write32(HDAC_DMA_POSITION_BASE_UPPER, 0);
// Set reset bit - it must be asserted for at least 100us
uint32 control = controller->Read32(HDAC_GLOBAL_CONTROL);
controller->Write32(HDAC_GLOBAL_CONTROL, control & ~GLOBAL_CONTROL_RESET);
for (int timeout = 0; timeout < 10; timeout++) {
snooze(100); snooze(100);
} while (--timeout && !(REG32(controller, GCTL) & GCTL_CRST));
return timeout ? B_OK : B_TIMED_OUT; control = controller->Read32(HDAC_GLOBAL_CONTROL);
if ((control & GLOBAL_CONTROL_RESET) == 0)
break;
}
if ((control & GLOBAL_CONTROL_RESET) != 0) {
dprintf("hda: unable to reset controller\n");
return B_BUSY;
}
// Unset reset bit
control = controller->Read32(HDAC_GLOBAL_CONTROL);
controller->Write32(HDAC_GLOBAL_CONTROL, control | GLOBAL_CONTROL_RESET);
for (int timeout = 0; timeout < 10; timeout++) {
snooze(100);
control = controller->Read32(HDAC_GLOBAL_CONTROL);
if ((control & GLOBAL_CONTROL_RESET) != 0)
break;
}
if ((control & GLOBAL_CONTROL_RESET) == 0) {
dprintf("hda: unable to exit reset\n");
return B_BUSY;
}
// Wait for codecs to finish their own reset (apparently needs more
// time than documented in the specs)
snooze(1000);
return B_OK;
} }
@ -217,29 +280,29 @@ init_corb_rirb_pos(hda_controller* controller)
physical_entry pe; physical_entry pe;
/* Determine and set size of CORB */ /* Determine and set size of CORB */
corbSize = REG8(controller, CORBSIZE); corbSize = controller->Read8(HDAC_CORB_SIZE);
if (corbSize & CORBSIZE_CAP_256E) { if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
controller->corb_length = 256; controller->corb_length = 256;
REG8(controller, CORBSIZE) = CORBSIZE_SZ_256E; controller->Write8(HDAC_CORB_SIZE, CORB_SIZE_256_ENTRIES);
} else if (corbSize & CORBSIZE_CAP_16E) { } else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
controller->corb_length = 16; controller->corb_length = 16;
REG8(controller, CORBSIZE) = CORBSIZE_SZ_16E; controller->Write8(HDAC_CORB_SIZE, CORB_SIZE_16_ENTRIES);
} else if (corbSize & CORBSIZE_CAP_2E) { } else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
controller->corb_length = 2; controller->corb_length = 2;
REG8(controller, CORBSIZE) = CORBSIZE_SZ_2E; controller->Write8(HDAC_CORB_SIZE, CORB_SIZE_2_ENTRIES);
} }
/* Determine and set size of RIRB */ /* Determine and set size of RIRB */
rirbSize = REG8(controller, RIRBSIZE); rirbSize = controller->Read8(HDAC_RIRB_SIZE);
if (rirbSize & RIRBSIZE_CAP_256E) { if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
controller->rirb_length = 256; controller->rirb_length = 256;
REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_256E; controller->Write8(HDAC_RIRB_SIZE, RIRB_SIZE_256_ENTRIES);
} else if (rirbSize & RIRBSIZE_CAP_16E) { } else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
controller->rirb_length = 16; controller->rirb_length = 16;
REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_16E; controller->Write8(HDAC_RIRB_SIZE, RIRB_SIZE_16_ENTRIES);
} else if (rirbSize & RIRBSIZE_CAP_2E) { } else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
controller->rirb_length = 2; controller->rirb_length = 2;
REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_2E; controller->Write8(HDAC_RIRB_SIZE, RIRB_SIZE_2_ENTRIES);
} }
/* Determine rirb offset in memory and total size of corb+alignment+rirb */ /* Determine rirb offset in memory and total size of corb+alignment+rirb */
@ -267,39 +330,43 @@ init_corb_rirb_pos(hda_controller* controller)
} }
/* Program CORB/RIRB for these locations */ /* Program CORB/RIRB for these locations */
REG32(controller, CORBLBASE) = (uint32)pe.address; controller->Write32(HDAC_CORB_BASE_LOWER, (uint32)pe.address);
REG32(controller, CORBUBASE) = 0; controller->Write32(HDAC_CORB_BASE_UPPER, 0);
REG32(controller, RIRBLBASE) = (uint32)pe.address + rirbOffset; controller->Write32(HDAC_RIRB_BASE_LOWER, (uint32)pe.address + rirbOffset);
REG32(controller, RIRBUBASE) = 0; controller->Write32(HDAC_RIRB_BASE_UPPER, 0);
/* Program DMA position update */ /* Program DMA position update */
REG32(controller, DMA_POSITION_BASE_LOWER) = (uint32)pe.address + posOffset; controller->Write32(HDAC_DMA_POSITION_BASE_LOWER,
REG32(controller, DMA_POSITION_BASE_UPPER) = 0; (uint32)pe.address + posOffset);
controller->Write32(HDAC_DMA_POSITION_BASE_UPPER, 0);
controller->stream_positions = (uint32*) controller->stream_positions = (uint32*)
((uint8*)controller->corb + posOffset); ((uint8*)controller->corb + posOffset);
/* Reset CORB read pointer */ /* Reset CORB read pointer */
/* NOTE: See HDA011 for corrected procedure! */ /* NOTE: See HDA011 for corrected procedure! */
REG16(controller, CORBRP) = CORBRP_RST; controller->Write16(HDAC_CORB_READ_POS, CORB_READ_POS_RESET);
do { do {
spin(10); spin(10);
} while ( !(REG16(controller, CORBRP) & CORBRP_RST) ); } while ((controller->Read16(HDAC_CORB_READ_POS)
REG16(controller, CORBRP) = 0; & CORB_READ_POS_RESET) == 0);
controller->Write16(HDAC_CORB_READ_POS, 0);
/* Reset RIRB write pointer */ /* Reset RIRB write pointer */
REG16(controller, RIRBWP) = RIRBWP_RST; controller->Write16(HDAC_RIRB_WRITE_POS, RIRB_WRITE_POS_RESET);
/* Generate interrupt for every response */ /* Generate interrupt for every response */
REG16(controller, RINTCNT) = 1; controller->Write16(HDAC_RESPONSE_INTR_COUNT, 1);
/* Setup cached read/write indices */ /* Setup cached read/write indices */
controller->rirb_read_pos = 1; controller->rirb_read_pos = 1;
controller->corb_write_pos = 0; controller->corb_write_pos = 0;
/* Gentlemen, start your engines... */ /* Gentlemen, start your engines... */
REG8(controller, CORBCTL) = CORBCTL_RUN | CORBCTL_MEIE; controller->Write8(HDAC_CORB_CONTROL,
REG8(controller, RIRBCTL) = RIRBCTL_DMAEN | RIRBCTL_OIC | RIRBCTL_RINTCTL; CORB_CONTROL_RUN | CORB_CONTROL_MEMORY_ERROR_INTR);
controller->Write8(HDAC_RIRB_CONTROL, RIRB_CONTROL_DMA_ENABLE
| RIRB_CONTROL_OVERRUN_INTR | RIRB_CONTROL_RESPONSE_INTR);
return B_OK; return B_OK;
} }
@ -337,17 +404,18 @@ hda_stream_new(hda_audio_group* audioGroup, int type)
stream->buffer_area = B_ERROR; stream->buffer_area = B_ERROR;
stream->buffer_descriptors_area = B_ERROR; stream->buffer_descriptors_area = B_ERROR;
stream->type = type; stream->type = type;
stream->controller = controller;
switch (type) { switch (type) {
case STREAM_PLAYBACK: case STREAM_PLAYBACK:
stream->id = 1; stream->id = 1;
stream->off = controller->num_input_streams * HDAC_SDSIZE; stream->offset = HDAC_OUTPUT_STREAM_OFFSET(controller, 0);
controller->streams[controller->num_input_streams] = stream; controller->streams[controller->num_input_streams] = stream;
break; break;
case STREAM_RECORD: case STREAM_RECORD:
stream->id = 2; stream->id = 2;
stream->off = 0; stream->offset = HDAC_INPUT_STREAM_OFFSET(controller, 0);
controller->streams[0] = stream; controller->streams[0] = stream;
break; break;
@ -374,22 +442,18 @@ hda_stream_new(hda_audio_group* audioGroup, int type)
status_t status_t
hda_stream_start(hda_controller* controller, hda_stream* stream) hda_stream_start(hda_controller* controller, hda_stream* stream)
{ {
stream->buffer_ready_sem = create_sem(0, stream->buffer_ready_sem = create_sem(0, stream->type == STREAM_PLAYBACK
stream->type == STREAM_PLAYBACK ? "hda_playback_sem" : "hda_record_sem"); ? "hda_playback_sem" : "hda_record_sem");
if (stream->buffer_ready_sem < B_OK) if (stream->buffer_ready_sem < B_OK)
return stream->buffer_ready_sem; return stream->buffer_ready_sem;
REG32(controller, INTCTL) |= 1 << (stream->off / HDAC_SDSIZE); controller->Write32(HDAC_INTR_CONTROL, controller->Read32(HDAC_INTR_CONTROL)
OREG8(controller, stream->off, CTL0) |= CTL0_IOCE | CTL0_FEIE | CTL0_DEIE | (1 << (stream->offset / HDAC_STREAM_SIZE)));
| CTL0_RUN; stream->Write8(HDAC_STREAM_CONTROL0, stream->Read8(HDAC_STREAM_CONTROL0)
| CONTROL0_BUFFER_COMPLETED_INTR | CONTROL0_FIFO_ERROR_INTR
#if 0 | CONTROL0_DESCRIPTOR_ERROR_INTR | CONTROL0_RUN);
while (!(OREG8(controller, stream->off, CTL0) & CTL0_RUN))
snooze(1);
#endif
stream->running = true; stream->running = true;
return B_OK; return B_OK;
} }
@ -400,14 +464,11 @@ hda_stream_start(hda_controller* controller, hda_stream* stream)
status_t status_t
hda_stream_stop(hda_controller* controller, hda_stream* stream) hda_stream_stop(hda_controller* controller, hda_stream* stream)
{ {
OREG8(controller, stream->off, CTL0) &= ~(CTL0_IOCE | CTL0_FEIE | CTL0_DEIE stream->Write8(HDAC_STREAM_CONTROL0, stream->Read8(HDAC_STREAM_CONTROL0)
| CTL0_RUN); & ~(CONTROL0_BUFFER_COMPLETED_INTR | CONTROL0_FIFO_ERROR_INTR
REG32(controller, INTCTL) &= ~(1 << (stream->off / HDAC_SDSIZE)); | CONTROL0_DESCRIPTOR_ERROR_INTR | CONTROL0_RUN));
controller->Write32(HDAC_INTR_CONTROL, controller->Read32(HDAC_INTR_CONTROL)
#if 0 & ~(1 << (stream->offset / HDAC_STREAM_SIZE)));
while ((OREG8(controller, stream->off, CTL0) & CTL0_RUN) != 0)
snooze(1);
#endif
stream->running = false; stream->running = false;
delete_sem(stream->buffer_ready_sem); delete_sem(stream->buffer_ready_sem);
@ -513,14 +574,14 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
/* Configure stream registers */ /* Configure stream registers */
format = stream->num_channels - 1; format = stream->num_channels - 1;
switch (stream->sample_format) { switch (stream->sample_format) {
case B_FMT_8BIT_S: format |= FMT_8BIT; stream->bps = 8; break; case B_FMT_8BIT_S: format |= FORMAT_8BIT; stream->bps = 8; break;
case B_FMT_16BIT: format |= FMT_16BIT; stream->bps = 16; break; case B_FMT_16BIT: format |= FORMAT_16BIT; stream->bps = 16; break;
case B_FMT_20BIT: format |= FMT_20BIT; stream->bps = 20; break; case B_FMT_20BIT: format |= FORMAT_20BIT; stream->bps = 20; break;
case B_FMT_24BIT: format |= FMT_24BIT; stream->bps = 24; break; case B_FMT_24BIT: format |= FORMAT_24BIT; stream->bps = 24; break;
case B_FMT_32BIT: format |= FMT_32BIT; stream->bps = 32; break; case B_FMT_32BIT: format |= FORMAT_32BIT; stream->bps = 32; break;
default: default:
dprintf("%s: Invalid sample format: 0x%lx\n", __func__, dprintf("hda: Invalid sample format: 0x%lx\n",
stream->sample_format); stream->sample_format);
break; break;
} }
@ -536,27 +597,27 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
dprintf("IRA: %s: setup stream %ld: SR=%ld, SF=%ld\n", __func__, stream->id, dprintf("IRA: %s: setup stream %ld: SR=%ld, SF=%ld\n", __func__, stream->id,
stream->rate, stream->bps); stream->rate, stream->bps);
OREG16(audioGroup->codec->controller, stream->off, FMT) = format; stream->Write16(HDAC_STREAM_FORMAT, format);
OREG32(audioGroup->codec->controller, stream->off, BDPL) stream->Write32(HDAC_STREAM_BUFFERS_BASE_LOWER,
= stream->physical_buffer_descriptors; stream->physical_buffer_descriptors);
OREG32(audioGroup->codec->controller, stream->off, BDPU) = 0; stream->Write32(HDAC_STREAM_BUFFERS_BASE_UPPER, 0);
OREG16(audioGroup->codec->controller, stream->off, LVI) stream->Write16(HDAC_STREAM_LAST_VALID, stream->num_buffers - 1);
= stream->num_buffers - 1;
/* total cyclic buffer size in _bytes_ */ /* total cyclic buffer size in _bytes_ */
OREG32(audioGroup->codec->controller, stream->off, CBL) stream->Write32(HDAC_STREAM_BUFFER_SIZE, stream->sample_size
= stream->sample_size * stream->num_channels * stream->num_buffers * stream->num_channels * stream->num_buffers * stream->buffer_length);
* stream->buffer_length; stream->Write8(HDAC_STREAM_CONTROL2, stream->id << 4);
OREG8(audioGroup->codec->controller, stream->off, CTL2) = stream->id << 4;
REG32(audioGroup->codec->controller, DMA_POSITION_BASE_LOWER) stream->controller->Write32(HDAC_DMA_POSITION_BASE_LOWER,
|= DMA_POSITION_ENABLED; stream->controller->Read32(HDAC_DMA_POSITION_BASE_LOWER)
| DMA_POSITION_ENABLED);
hda_codec* codec = audioGroup->codec;
for (uint32 i = 0; i < stream->num_io_widgets; i++) { for (uint32 i = 0; i < stream->num_io_widgets; i++) {
verb[0] = MAKE_VERB(audioGroup->codec->addr, stream->io_widgets[i], verb[0] = MAKE_VERB(codec->addr, stream->io_widgets[i],
VID_SET_CONVERTER_FORMAT, format); VID_SET_CONVERTER_FORMAT, format);
verb[1] = MAKE_VERB(audioGroup->codec->addr, stream->io_widgets[i], verb[1] = MAKE_VERB(codec->addr, stream->io_widgets[i],
VID_SET_CONVERTER_STREAM_CHANNEL, stream->id << 4); VID_SET_CONVERTER_STREAM_CHANNEL, stream->id << 4);
hda_send_verbs(audioGroup->codec, verb, response, 2); hda_send_verbs(codec, verb, response, 2);
} }
snooze(1000); snooze(1000);
@ -572,12 +633,11 @@ hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, uint32 count)
{ {
hda_controller *controller = codec->controller; hda_controller *controller = codec->controller;
uint32 sent = 0; uint32 sent = 0;
status_t rc;
codec->response_count = 0; codec->response_count = 0;
while (sent < count) { while (sent < count) {
uint32 readPos = REG16(controller, CORBRP); uint32 readPos = controller->Read16(HDAC_CORB_READ_POS);
uint32 queued = 0; uint32 queued = 0;
while (sent < count) { while (sent < count) {
@ -594,11 +654,11 @@ hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, uint32 count)
queued++; queued++;
} }
REG16(controller, CORBWP) = controller->corb_write_pos; controller->Write16(HDAC_CORB_WRITE_POS, controller->corb_write_pos);
rc = acquire_sem_etc(codec->response_sem, queued, B_RELATIVE_TIMEOUT, status_t status = acquire_sem_etc(codec->response_sem, queued,
1000ULL * 50); B_RELATIVE_TIMEOUT, 50000ULL);
if (rc < B_OK) if (status < B_OK)
return rc; return status;
} }
if (responses != NULL) if (responses != NULL)
@ -612,9 +672,8 @@ hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, uint32 count)
status_t status_t
hda_hw_init(hda_controller* controller) hda_hw_init(hda_controller* controller)
{ {
status_t rc; uint16 capabilities;
uint16 gcap; status_t status;
uint32 index;
/* Map MMIO registers */ /* Map MMIO registers */
controller->regs_area = map_physical_memory("hda_hw_regs", controller->regs_area = map_physical_memory("hda_hw_regs",
@ -622,58 +681,58 @@ hda_hw_init(hda_controller* controller)
controller->pci_info.u.h0.base_register_sizes[0], B_ANY_KERNEL_ADDRESS, controller->pci_info.u.h0.base_register_sizes[0], B_ANY_KERNEL_ADDRESS,
0, (void**)&controller->regs); 0, (void**)&controller->regs);
if (controller->regs_area < B_OK) { if (controller->regs_area < B_OK) {
rc = controller->regs_area; status = controller->regs_area;
goto error; goto error;
} }
/* Absolute minimum hw is online; we can now install interrupt handler */ /* Absolute minimum hw is online; we can now install interrupt handler */
controller->irq = controller->pci_info.u.h0.interrupt_line; controller->irq = controller->pci_info.u.h0.interrupt_line;
rc = install_io_interrupt_handler(controller->irq, status = install_io_interrupt_handler(controller->irq,
(interrupt_handler)hda_interrupt_handler, controller, 0); (interrupt_handler)hda_interrupt_handler, controller, 0);
if (rc != B_OK) if (status != B_OK)
goto no_irq; goto no_irq;
/* show some hw features */ capabilities = controller->Read16(HDAC_GLOBAL_CAP);
gcap = REG16(controller, GCAP); controller->num_input_streams = GLOBAL_CAP_INPUT_STREAMS(capabilities);
dprintf("HDA: HDA v%d.%d, O:%d/I:%d/B:%d, #SDO:%d, 64bit:%s\n", controller->num_output_streams = GLOBAL_CAP_OUTPUT_STREAMS(capabilities);
REG8(controller, VMAJ), REG8(controller, VMIN), controller->num_bidir_streams = GLOBAL_CAP_BIDIR_STREAMS(capabilities);
GCAP_OSS(gcap), GCAP_ISS(gcap), GCAP_BSS(gcap),
GCAP_NSDO(gcap) ? GCAP_NSDO(gcap) *2 : 1,
gcap & GCAP_64OK ? "yes" : "no" );
controller->num_input_streams = GCAP_OSS(gcap); /* show some hw features */
controller->num_output_streams = GCAP_ISS(gcap); dprintf("hda: HDA v%d.%d, O:%ld/I:%ld/B:%ld, #SDO:%d, 64bit:%s\n",
controller->num_bidir_streams = GCAP_BSS(gcap); controller->Read8(HDAC_VERSION_MAJOR),
controller->Read8(HDAC_VERSION_MINOR),
controller->num_output_streams, controller->num_input_streams,
controller->num_bidir_streams,
GLOBAL_CAP_NUM_SDO(capabilities),
GLOBAL_CAP_64BIT(capabilities) ? "yes" : "no");
/* Get controller into valid state */ /* Get controller into valid state */
rc = hda_hw_start(controller); status = reset_controller(controller);
if (rc != B_OK) if (status != B_OK)
goto reset_failed; goto reset_failed;
/* Setup CORB/RIRB/DMA POS */ /* Setup CORB/RIRB/DMA POS */
rc = init_corb_rirb_pos(controller); status = init_corb_rirb_pos(controller);
if (rc != B_OK) if (status != B_OK)
goto corb_rirb_failed; goto corb_rirb_failed;
REG16(controller, WAKEEN) = 0x7fff; controller->Write16(HDAC_WAKE_ENABLE, 0x7fff);
/* Enable controller interrupts */ /* Enable controller interrupts */
REG32(controller, INTCTL) = INTCTL_GIE | INTCTL_CIE; controller->Write32(HDAC_INTR_CONTROL, INTR_CONTROL_GLOBAL_ENABLE
| INTR_CONTROL_CONTROLLER_ENABLE);
/* Wait for codecs to warm up */
snooze(1000);
if (!controller->codec_status) { if (!controller->codec_status) {
rc = ENODEV; status = ENODEV;
goto corb_rirb_failed; goto corb_rirb_failed;
} }
for (index = 0; index < HDA_MAX_CODECS; index++) { // Create codecs
for (uint32 index = 0; index < HDA_MAX_CODECS; index++) {
if ((controller->codec_status & (1 << index)) != 0) if ((controller->codec_status & (1 << index)) != 0)
hda_codec_new(controller, index); hda_codec_new(controller, index);
} }
for (uint32 index = 0; index < HDA_MAX_CODECS; index++) {
for (index = 0; index < HDA_MAX_CODECS; index++) {
if (controller->codecs[index] if (controller->codecs[index]
&& controller->codecs[index]->num_audio_groups > 0) { && controller->codecs[index]->num_audio_groups > 0) {
controller->active_codec = controller->codecs[index]; controller->active_codec = controller->codecs[index];
@ -684,10 +743,10 @@ hda_hw_init(hda_controller* controller)
if (controller->active_codec != NULL) if (controller->active_codec != NULL)
return B_OK; return B_OK;
rc = ENODEV; status = ENODEV;
corb_rirb_failed: corb_rirb_failed:
REG32(controller, INTCTL) = 0; controller->Write32(HDAC_INTR_CONTROL, 0);
reset_failed: reset_failed:
remove_io_interrupt_handler(controller->irq, remove_io_interrupt_handler(controller->irq,
@ -699,9 +758,9 @@ no_irq:
controller->regs = NULL; controller->regs = NULL;
error: error:
dprintf("ERROR: %s(%ld)\n", strerror(rc), rc); dprintf("hda: ERROR: %s(%ld)\n", strerror(status), status);
return rc; return status;
} }
@ -731,17 +790,11 @@ hda_hw_uninit(hda_controller* controller)
/* Stop all audio streams */ /* Stop all audio streams */
hda_hw_stop(controller); hda_hw_stop(controller);
/* Stop CORB/RIRB */ reset_controller(controller);
REG8(controller, CORBCTL) = 0;
REG8(controller, RIRBCTL) = 0;
REG32(controller, CORBLBASE) = 0; /* Disable interrupts, and remove interrupt handler */
REG32(controller, RIRBLBASE) = 0; controller->Write32(HDAC_INTR_CONTROL, 0);
REG32(controller, DMA_POSITION_BASE_LOWER) = 0;
/* Disable interrupts, reset controller, and remove interrupt handler */
REG32(controller, INTCTL) = 0;
REG32(controller, GCTL) &= ~GCTL_CRST;
remove_io_interrupt_handler(controller->irq, remove_io_interrupt_handler(controller->irq,
(interrupt_handler)hda_interrupt_handler, controller); (interrupt_handler)hda_interrupt_handler, controller);

View File

@ -4,135 +4,132 @@
* *
* Authors: * Authors:
* Ithamar Adema, ithamar AT unet DOT nl * Ithamar Adema, ithamar AT unet DOT nl
* Axel Dörfler, axeld@pinc-software.de
*/ */
#ifndef HDAC_REGS_H #ifndef HDAC_REGS_H
#define HDAC_REGS_H #define HDAC_REGS_H
#include <SupportDefs.h> #include <SupportDefs.h>
/* Accessors for HDA controller registers */
#define REG32(controller, reg) (*(vuint32*)((controller)->regs + HDAC_##reg))
#define REG16(controller, reg) (*(vuint16*)((controller)->regs + HDAC_##reg))
#define REG8(controller, reg) (*((controller)->regs + HDAC_##reg))
#define OREG32(controller, stream, reg) \ /* Controller register definitions */
(*(vuint32*)((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg)) #define HDAC_GLOBAL_CAP 0x00 // 16bits, GCAP
#define OREG16(controller, stream, reg) \ #define GLOBAL_CAP_OUTPUT_STREAMS(cap) (((cap) >> 12) & 15)
(*(vuint16*)((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg)) #define GLOBAL_CAP_INPUT_STREAMS(cap) (((cap) >> 8) & 15)
#define OREG8(controller, stream, reg) \ #define GLOBAL_CAP_BIDIR_STREAMS(cap) (((cap) >> 3) & 15)
(*((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg)) #define GLOBAL_CAP_NUM_SDO(cap) ((((cap) >> 1) & 3) ? (cap & 6) : 1)
#define GLOBAL_CAP_64BIT(cap) (((cap) & 1) != 0)
/* Register definitions */ #define HDAC_VERSION_MINOR 0x02 // 8bits, VMIN
#define HDAC_GCAP 0x00 /* 16bits */ #define HDAC_VERSION_MAJOR 0x03 // 8bits, VMAJ
#define GCAP_OSS(gcap) (((gcap) >> 12) & 15)
#define GCAP_ISS(gcap) (((gcap) >> 8) & 15)
#define GCAP_BSS(gcap) (((gcap) >> 3) & 15)
#define GCAP_NSDO(gcap) (((gcap) >> 1) & 3)
#define GCAP_64OK ((gcap) & 1)
#define HDAC_VMIN 0x02 /* 8bits */ #define HDAC_GLOBAL_CONTROL 0x08 // 32bits, GCTL
#define HDAC_VMAJ 0x03 /* 8bits */ #define GLOBAL_CONTROL_UNSOLICITED (1 << 8)
// accept unsolicited responses
#define GLOBAL_CONTROL_FLUSH (1 << 1)
#define GLOBAL_CONTROL_RESET (1 << 0)
#define HDAC_GCTL 0x08 /* 32bits */ #define HDAC_WAKE_ENABLE 0x0c // 16bits, WAKEEN
#define GCTL_UNSOL (1 << 8) /* Accept Unsolicited responses */ #define HDAC_STATE_STATUS 0x0e // 16bits, STATESTS
#define GCTL_FCNTRL (1 << 1) /* Flush Control */
#define GCTL_CRST (1 << 0) /* Controller Reset */
#define HDAC_WAKEEN 0x0c /* 16bits */ #define HDAC_INTR_CONTROL 0x20 // 32bits, INTCTL
#define HDAC_STATESTS 0x0e /* 16bits */ #define INTR_CONTROL_GLOBAL_ENABLE (1 << 31)
#define INTR_CONTROL_CONTROLLER_ENABLE (1 << 30)
#define HDAC_INTCTL 0x20 /* 32bits */ #define HDAC_INTR_STATUS 0x24 // 32bits, INTSTS
#define INTCTL_GIE (1 << 31) /* Global Interrupt Enable */ #define INTR_STATUS_GLOBAL (1 << 31)
#define INTCTL_CIE (1 << 30) /* Controller Interrupt Enable */ #define INTR_STATUS_CONTROLLER (1 << 30)
#define INTR_STATUS_STREAM_MASK 0x3fffffff
#define HDAC_INTSTS 0x24 /* 32bits */ #define HDAC_CORB_BASE_LOWER 0x40 // 32bits, CORBLBASE
#define INTSTS_GIS (1 << 31) /* Global Interrupt Status */ #define HDAC_CORB_BASE_UPPER 0x44 // 32bits, CORBUBASE
#define INTSTS_CIS (1 << 30) /* Controller Interrupt Status */ #define HDAC_CORB_WRITE_POS 0x48 // 16bits, CORBWP
#define HDAC_CORBLBASE 0x40 /* 32bits */ #define HDAC_CORB_READ_POS 0x4a // 16bits, CORBRP
#define HDAC_CORBUBASE 0x44 /* 32bits */ #define CORB_READ_POS_RESET (1 << 15)
#define HDAC_CORBWP 0x48 /* 16bits */
#define HDAC_CORBRP 0x4a /* 16bits */ #define HDAC_CORB_CONTROL 0x4c // 8bits, CORBCTL
#define CORBRP_RST (1 << 15) #define CORB_CONTROL_RUN (1 << 1)
#define CORB_CONTROL_MEMORY_ERROR_INTR (1 << 0)
#define HDAC_CORBCTL 0x4c /* 8bits */ #define HDAC_CORB_STATUS 0x4d // 8bits, CORBSTS
#define CORBCTL_RUN (1 << 1) #define CORB_STATUS_MEMORY_ERROR (1 << 0)
#define CORBCTL_MEIE (1 << 0)
#define HDAC_CORBSTS 0x4d /* 8bits */ #define HDAC_CORB_SIZE 0x4e // 8bits, CORBSIZE
#define CORBSTS_MEI (1 << 0) #define CORB_SIZE_CAP_2_ENTRIES (1 << 4)
#define CORB_SIZE_CAP_16_ENTRIES (1 << 5)
#define CORB_SIZE_CAP_256_ENTRIES (1 << 6)
#define CORB_SIZE_2_ENTRIES 0x00 // 8 byte
#define CORB_SIZE_16_ENTRIES 0x01 // 64 byte
#define CORB_SIZE_256_ENTRIES 0x02 // 1024 byte
#define HDAC_CORBSIZE 0x4e /* 8bits */ #define HDAC_RIRB_BASE_LOWER 0x50 // 32bits, RIRBLBASE
#define CORBSIZE_CAP_2E (1 << 4) #define HDAC_RIRB_BASE_UPPER 0x54 // 32bits, RIRBUBASE
#define CORBSIZE_CAP_16E (1 << 5)
#define CORBSIZE_CAP_256E (1 << 6)
#define CORBSIZE_SZ_2E 0
#define CORBSIZE_SZ_16E (1 << 0)
#define CORBSIZE_SZ_256E (1 << 1)
#define HDAC_RIRBLBASE 0x50 /* 32bits */ #define HDAC_RIRB_WRITE_POS 0x58 // 16bits, RIRBWP
#define HDAC_RIRBUBASE 0x54 /* 32bits */ #define RIRB_WRITE_POS_RESET (1 << 15)
#define HDAC_RIRBWP 0x58 /* 16bits */ #define HDAC_RESPONSE_INTR_COUNT 0x5a // 16bits, RINTCNT
#define RIRBWP_RST (1 << 15)
#define HDAC_RINTCNT 0x5a /* 16bits */ #define HDAC_RIRB_CONTROL 0x5c // 8bits, RIRBCTL
#define RIRB_CONTROL_OVERRUN_INTR (1 << 2)
#define RIRB_CONTROL_DMA_ENABLE (1 << 1)
#define RIRB_CONTROL_RESPONSE_INTR (1 << 0)
#define HDAC_RIRBCTL 0x5c /* 8bits */ #define HDAC_RIRB_STATUS 0x5d // 8bits, RIRBSTS
#define RIRBCTL_OIC (1 << 2) #define RIRB_STATUS_OVERRUN (1 << 2)
#define RIRBCTL_DMAEN (1 << 1) #define RIRB_STATUS_RESPONSE (1 << 0)
#define RIRBCTL_RINTCTL (1 << 0)
#define HDAC_RIRBSTS 0x5d #define HDAC_RIRB_SIZE 0x5e // 8bits, RIRBSIZE
#define RIRBSTS_OIS (1 << 2) #define RIRB_SIZE_CAP_2_ENTRIES (1 << 4)
#define RIRBSTS_RINTFL (1 << 0) #define RIRB_SIZE_CAP_16_ENTRIES (1 << 5)
#define RIRB_SIZE_CAP_256_ENTRIES (1 << 6)
#define RIRB_SIZE_2_ENTRIES 0x00
#define RIRB_SIZE_16_ENTRIES 0x01
#define RIRB_SIZE_256_ENTRIES 0x02
#define HDAC_RIRBSIZE 0x5e /* 8bits */ #define HDAC_DMA_POSITION_BASE_LOWER 0x70 // 32bits, DPLBASE
#define RIRBSIZE_CAP_2E (1 << 4) #define HDAC_DMA_POSITION_BASE_UPPER 0x74 // 32bits, DPUBASE
#define RIRBSIZE_CAP_16E (1 << 5)
#define RIRBSIZE_CAP_256E (1 << 6)
#define RIRBSIZE_SZ_2E 0
#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 DMA_POSITION_ENABLED 1
#define HDAC_SDBASE 0x80 /* Stream Descriptor Registers */
#define HDAC_SDSIZE 0x20 #define HDAC_STREAM_BASE 0x80
#define HDAC_STREAM_SIZE 0x20
#define HDAC_SD_CTL0 0x00 /* 8bits */ #define HDAC_STREAM_CONTROL0 0x00 // 8bits, CTL0
#define CTL0_SRST (1 << 0) #define CONTROL0_RESET (1 << 0)
#define CTL0_RUN (1 << 1) #define CONTROL0_RUN (1 << 1)
#define CTL0_IOCE (1 << 2) #define CONTROL0_BUFFER_COMPLETED_INTR (1 << 2)
#define CTL0_FEIE (1 << 3) #define CONTROL0_FIFO_ERROR_INTR (1 << 3)
#define CTL0_DEIE (1 << 4) #define CONTROL0_DESCRIPTOR_ERROR_INTR (1 << 4)
#define HDAC_SD_CTL1 0x01 /* 8bits */ #define HDAC_STREAM_CONTROL1 0x01 // 8bits, CTL1
#define HDAC_SD_CTL2 0x02 /* 8bits */ #define HDAC_STREAM_CONTROL2 0x02 // 8bits, CTL2
#define CTL2_DIR (1 << 3) #define CONTROL2_STREAM_MASK 0xf0
#define CTL2_TP (1 << 2) #define CONTROL2_STREAM_SHIFT 4
#define HDAC_SD_STS 0x03 /* 8bits */ #define CONTROL2_BIDIR (1 << 3)
#define STS_BCIS (1 << 2) #define CONTROL2_TRAFFIC_PRIORITY (1 << 2)
#define STS_FIFOE (1 << 3) #define CONTROL2_STRIPE_SDO_MASK 0x03
#define STS_DESE (1 << 4) #define HDAC_STREAM_STATUS 0x03 // 8bits, STS
#define STS_FIFORDY (1 << 5) #define STATUS_BUFFER_COMPLETED (1 << 2)
#define HDAC_SD_LPIB 0x04 /* 32bits */ #define STATUS_FIFO_ERROR (1 << 3)
#define HDAC_SD_CBL 0x08 /* 32bits */ #define STATUS_DESCRIPTOR_ERROR (1 << 4)
#define HDAC_SD_LVI 0x0C /* 16bits */ #define STATUS_FIFO_READY (1 << 5)
#define HDAC_SD_FIFOS 0x10 /* 16bits */ #define HDAC_STREAM_POSITION 0x04 // 32bits, LPIB
#define HDAC_SD_FMT 0x12 /* 16bits */ #define HDAC_STREAM_BUFFER_SIZE 0x08 // 32bits, CBL
#define FMT_8BIT (0 << 4) #define HDAC_STREAM_LAST_VALID 0x0c // 16bits, LVI
#define FMT_16BIT (1 << 4) #define HDAC_STREAM_FIFO_SIZE 0x10 // 16bits, FIFOS
#define FMT_20BIT (2 << 4) #define HDAC_STREAM_FORMAT 0x12 // 16bits, FMT
#define FMT_24BIT (3 << 4) #define FORMAT_8BIT (0 << 4)
#define FMT_32BIT (4 << 4) #define FORMAT_16BIT (1 << 4)
#define FMT_44_1_BASE_RATE (1 << 14) #define FORMAT_20BIT (2 << 4)
#define FMT_MULTIPLY_RATE_SHIFT 11 #define FORMAT_24BIT (3 << 4)
#define FMT_DIVIDE_RATE_SHIFT 8 #define FORMAT_32BIT (4 << 4)
#define HDAC_SD_BDPL 0x18 /* 32bits */ #define FORMAT_44_1_BASE_RATE (1 << 14)
#define HDAC_SD_BDPU 0x1C /* 32bits */ #define FORMAT_MULTIPLY_RATE_SHIFT 11
#define FORMAT_DIVIDE_RATE_SHIFT 8
#define HDAC_STREAM_BUFFERS_BASE_LOWER 0x18 // 32bits, BDPL
#define HDAC_STREAM_BUFFERS_BASE_UPPER 0x1c // 32bits, BDPU
typedef uint32 corb_t; typedef uint32 corb_t;
typedef struct { typedef struct {
@ -140,8 +137,8 @@ typedef struct {
uint32 flags; uint32 flags;
} rirb_t; } rirb_t;
#define RESPONSE_FLAGS_CODEC_MASK 0x0000000f #define RESPONSE_FLAGS_CODEC_MASK 0x0000000f
#define RESPONSE_FLAGS_UNSOLICITED (1 << 4) #define RESPONSE_FLAGS_UNSOLICITED (1 << 4)
typedef struct { typedef struct {
uint64 address; uint64 address;