* 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:
parent
1a662751d5
commit
a941060027
@ -51,17 +51,85 @@ enum {
|
||||
};
|
||||
|
||||
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,
|
||||
which is can have multiple channels (for stereo or better).
|
||||
*/
|
||||
struct hda_stream {
|
||||
uint32 id; /* HDA controller stream # */
|
||||
uint32 off; /* HDA I/O/B descriptor offset */
|
||||
bool running; /* Is this stream active? */
|
||||
uint32 offset; /* HDA I/O/B descriptor offset */
|
||||
bool running;
|
||||
spinlock lock; /* Write lock */
|
||||
uint32 type;
|
||||
|
||||
hda_controller* controller;
|
||||
|
||||
uint32 pin_widget; /* PIN Widget ID */
|
||||
uint32 io_widgets[MAX_IO_WIDGETS]; /* Input/Output Converter Widget ID */
|
||||
uint32 num_io_widgets;
|
||||
@ -87,6 +155,36 @@ struct hda_stream {
|
||||
area_id buffer_area;
|
||||
area_id buffer_descriptors_area;
|
||||
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 {
|
||||
@ -174,40 +272,6 @@ struct hda_codec {
|
||||
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 */
|
||||
extern device_hooks gDriverHooks;
|
||||
|
@ -14,9 +14,17 @@
|
||||
|
||||
|
||||
#define MAKE_RATE(base, multiply, divide) \
|
||||
((base == 44100 ? FMT_44_1_BASE_RATE : 0) \
|
||||
| ((multiply - 1) << FMT_MULTIPLY_RATE_SHIFT) \
|
||||
| ((divide - 1) << FMT_DIVIDE_RATE_SHIFT))
|
||||
((base == 44100 ? FORMAT_44_1_BASE_RATE : 0) \
|
||||
| ((multiply - 1) << FORMAT_MULTIPLY_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 {
|
||||
uint32 multi_rate;
|
||||
@ -67,13 +75,13 @@ stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
|
||||
if (!stream->running)
|
||||
return;
|
||||
|
||||
status = OREG8(controller, stream->off, STS);
|
||||
status = stream->Read8(HDAC_STREAM_STATUS);
|
||||
if (status == 0)
|
||||
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
|
||||
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);
|
||||
} else
|
||||
dprintf("HDA: stream status %x\n", status);
|
||||
dprintf("hda: stream status %x\n", status);
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
hda_interrupt_handler(hda_controller* controller)
|
||||
{
|
||||
int32 rc = B_HANDLED_INTERRUPT;
|
||||
int32 handled = B_HANDLED_INTERRUPT;
|
||||
|
||||
/* Check if this interrupt is ours */
|
||||
uint32 intsts = REG32(controller, INTSTS);
|
||||
if ((intsts & INTSTS_GIS) == 0)
|
||||
uint32 intrStatus = controller->Read32(HDAC_INTR_STATUS);
|
||||
if ((intrStatus & INTR_STATUS_GLOBAL) == 0)
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
|
||||
/* Controller or stream related? */
|
||||
if (intsts & INTSTS_CIS) {
|
||||
uint32 stateStatus = REG16(controller, STATESTS);
|
||||
uint8 rirbStatus = REG8(controller, RIRBSTS);
|
||||
uint8 corbStatus = REG8(controller, CORBSTS);
|
||||
if (intrStatus & INTR_STATUS_CONTROLLER) {
|
||||
uint32 stateStatus = controller->Read16(HDAC_STATE_STATUS);
|
||||
uint8 rirbStatus = controller->Read8(HDAC_RIRB_STATUS);
|
||||
uint8 corbStatus = controller->Read8(HDAC_CORB_STATUS);
|
||||
|
||||
if (stateStatus) {
|
||||
/* Detected Codec state change */
|
||||
REG16(controller, STATESTS) = stateStatus;
|
||||
controller->Write16(HDAC_STATE_STATUS, stateStatus);
|
||||
controller->codec_status = stateStatus;
|
||||
}
|
||||
|
||||
/* Check for incoming responses */
|
||||
if (rirbStatus) {
|
||||
REG8(controller, RIRBSTS) = rirbStatus;
|
||||
controller->Write8(HDAC_RIRB_STATUS, rirbStatus);
|
||||
|
||||
if (rirbStatus & RIRBSTS_RINTFL) {
|
||||
uint16 writePos = (REG16(controller, RIRBWP) + 1)
|
||||
if ((rirbStatus & RIRB_STATUS_RESPONSE) != 0) {
|
||||
uint16 writePos = (controller->Read16(HDAC_RIRB_WRITE_POS) + 1)
|
||||
% controller->rirb_length;
|
||||
|
||||
for (; controller->rirb_read_pos != writePos;
|
||||
@ -146,26 +154,26 @@ hda_interrupt_handler(hda_controller* controller)
|
||||
/* Store response in codec */
|
||||
codec->responses[codec->response_count++] = response;
|
||||
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");
|
||||
}
|
||||
|
||||
/* Check for sending errors */
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
if (intsts & ~(INTSTS_CIS | INTSTS_GIS)) {
|
||||
if ((intrStatus & INTR_STATUS_STREAM_MASK) != 0) {
|
||||
for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
|
||||
if ((intsts & (1 << index)) != 0) {
|
||||
if ((intrStatus & (1 << index)) != 0) {
|
||||
if (controller->streams[index]) {
|
||||
stream_handle_interrupt(controller,
|
||||
controller->streams[index]);
|
||||
@ -179,25 +187,80 @@ hda_interrupt_handler(hda_controller* controller)
|
||||
|
||||
/* NOTE: See HDA001 => CIS/GIS cannot be cleared! */
|
||||
|
||||
return rc;
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
REG32(controller, GCTL) |= GCTL_CRST;
|
||||
// stop DMA
|
||||
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);
|
||||
} 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;
|
||||
|
||||
/* Determine and set size of CORB */
|
||||
corbSize = REG8(controller, CORBSIZE);
|
||||
if (corbSize & CORBSIZE_CAP_256E) {
|
||||
corbSize = controller->Read8(HDAC_CORB_SIZE);
|
||||
if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
|
||||
controller->corb_length = 256;
|
||||
REG8(controller, CORBSIZE) = CORBSIZE_SZ_256E;
|
||||
} else if (corbSize & CORBSIZE_CAP_16E) {
|
||||
controller->Write8(HDAC_CORB_SIZE, CORB_SIZE_256_ENTRIES);
|
||||
} else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
|
||||
controller->corb_length = 16;
|
||||
REG8(controller, CORBSIZE) = CORBSIZE_SZ_16E;
|
||||
} else if (corbSize & CORBSIZE_CAP_2E) {
|
||||
controller->Write8(HDAC_CORB_SIZE, CORB_SIZE_16_ENTRIES);
|
||||
} else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
|
||||
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 */
|
||||
rirbSize = REG8(controller, RIRBSIZE);
|
||||
if (rirbSize & RIRBSIZE_CAP_256E) {
|
||||
rirbSize = controller->Read8(HDAC_RIRB_SIZE);
|
||||
if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
|
||||
controller->rirb_length = 256;
|
||||
REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_256E;
|
||||
} else if (rirbSize & RIRBSIZE_CAP_16E) {
|
||||
controller->Write8(HDAC_RIRB_SIZE, RIRB_SIZE_256_ENTRIES);
|
||||
} else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
|
||||
controller->rirb_length = 16;
|
||||
REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_16E;
|
||||
} else if (rirbSize & RIRBSIZE_CAP_2E) {
|
||||
controller->Write8(HDAC_RIRB_SIZE, RIRB_SIZE_16_ENTRIES);
|
||||
} else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
|
||||
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 */
|
||||
@ -267,39 +330,43 @@ init_corb_rirb_pos(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;
|
||||
controller->Write32(HDAC_CORB_BASE_LOWER, (uint32)pe.address);
|
||||
controller->Write32(HDAC_CORB_BASE_UPPER, 0);
|
||||
controller->Write32(HDAC_RIRB_BASE_LOWER, (uint32)pe.address + rirbOffset);
|
||||
controller->Write32(HDAC_RIRB_BASE_UPPER, 0);
|
||||
|
||||
/* Program DMA position update */
|
||||
REG32(controller, DMA_POSITION_BASE_LOWER) = (uint32)pe.address + posOffset;
|
||||
REG32(controller, DMA_POSITION_BASE_UPPER) = 0;
|
||||
controller->Write32(HDAC_DMA_POSITION_BASE_LOWER,
|
||||
(uint32)pe.address + posOffset);
|
||||
controller->Write32(HDAC_DMA_POSITION_BASE_UPPER, 0);
|
||||
|
||||
controller->stream_positions = (uint32*)
|
||||
((uint8*)controller->corb + posOffset);
|
||||
|
||||
/* Reset CORB read pointer */
|
||||
/* NOTE: See HDA011 for corrected procedure! */
|
||||
REG16(controller, CORBRP) = CORBRP_RST;
|
||||
controller->Write16(HDAC_CORB_READ_POS, CORB_READ_POS_RESET);
|
||||
do {
|
||||
spin(10);
|
||||
} while ( !(REG16(controller, CORBRP) & CORBRP_RST) );
|
||||
REG16(controller, CORBRP) = 0;
|
||||
} while ((controller->Read16(HDAC_CORB_READ_POS)
|
||||
& CORB_READ_POS_RESET) == 0);
|
||||
controller->Write16(HDAC_CORB_READ_POS, 0);
|
||||
|
||||
/* Reset RIRB write pointer */
|
||||
REG16(controller, RIRBWP) = RIRBWP_RST;
|
||||
controller->Write16(HDAC_RIRB_WRITE_POS, RIRB_WRITE_POS_RESET);
|
||||
|
||||
/* Generate interrupt for every response */
|
||||
REG16(controller, RINTCNT) = 1;
|
||||
controller->Write16(HDAC_RESPONSE_INTR_COUNT, 1);
|
||||
|
||||
/* Setup cached read/write indices */
|
||||
controller->rirb_read_pos = 1;
|
||||
controller->corb_write_pos = 0;
|
||||
|
||||
/* Gentlemen, start your engines... */
|
||||
REG8(controller, CORBCTL) = CORBCTL_RUN | CORBCTL_MEIE;
|
||||
REG8(controller, RIRBCTL) = RIRBCTL_DMAEN | RIRBCTL_OIC | RIRBCTL_RINTCTL;
|
||||
controller->Write8(HDAC_CORB_CONTROL,
|
||||
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;
|
||||
}
|
||||
@ -337,17 +404,18 @@ hda_stream_new(hda_audio_group* audioGroup, int type)
|
||||
stream->buffer_area = B_ERROR;
|
||||
stream->buffer_descriptors_area = B_ERROR;
|
||||
stream->type = type;
|
||||
stream->controller = controller;
|
||||
|
||||
switch (type) {
|
||||
case STREAM_PLAYBACK:
|
||||
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;
|
||||
break;
|
||||
|
||||
case STREAM_RECORD:
|
||||
stream->id = 2;
|
||||
stream->off = 0;
|
||||
stream->offset = HDAC_INPUT_STREAM_OFFSET(controller, 0);
|
||||
controller->streams[0] = stream;
|
||||
break;
|
||||
|
||||
@ -374,22 +442,18 @@ hda_stream_new(hda_audio_group* audioGroup, int type)
|
||||
status_t
|
||||
hda_stream_start(hda_controller* controller, hda_stream* stream)
|
||||
{
|
||||
stream->buffer_ready_sem = create_sem(0,
|
||||
stream->type == STREAM_PLAYBACK ? "hda_playback_sem" : "hda_record_sem");
|
||||
stream->buffer_ready_sem = create_sem(0, stream->type == STREAM_PLAYBACK
|
||||
? "hda_playback_sem" : "hda_record_sem");
|
||||
if (stream->buffer_ready_sem < B_OK)
|
||||
return stream->buffer_ready_sem;
|
||||
|
||||
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
|
||||
controller->Write32(HDAC_INTR_CONTROL, controller->Read32(HDAC_INTR_CONTROL)
|
||||
| (1 << (stream->offset / HDAC_STREAM_SIZE)));
|
||||
stream->Write8(HDAC_STREAM_CONTROL0, stream->Read8(HDAC_STREAM_CONTROL0)
|
||||
| CONTROL0_BUFFER_COMPLETED_INTR | CONTROL0_FIFO_ERROR_INTR
|
||||
| CONTROL0_DESCRIPTOR_ERROR_INTR | CONTROL0_RUN);
|
||||
|
||||
stream->running = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -400,14 +464,11 @@ hda_stream_start(hda_controller* controller, hda_stream* stream)
|
||||
status_t
|
||||
hda_stream_stop(hda_controller* controller, hda_stream* stream)
|
||||
{
|
||||
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->Write8(HDAC_STREAM_CONTROL0, stream->Read8(HDAC_STREAM_CONTROL0)
|
||||
& ~(CONTROL0_BUFFER_COMPLETED_INTR | CONTROL0_FIFO_ERROR_INTR
|
||||
| CONTROL0_DESCRIPTOR_ERROR_INTR | CONTROL0_RUN));
|
||||
controller->Write32(HDAC_INTR_CONTROL, controller->Read32(HDAC_INTR_CONTROL)
|
||||
& ~(1 << (stream->offset / HDAC_STREAM_SIZE)));
|
||||
|
||||
stream->running = false;
|
||||
delete_sem(stream->buffer_ready_sem);
|
||||
@ -513,14 +574,14 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
|
||||
/* Configure stream registers */
|
||||
format = stream->num_channels - 1;
|
||||
switch (stream->sample_format) {
|
||||
case B_FMT_8BIT_S: format |= FMT_8BIT; stream->bps = 8; break;
|
||||
case B_FMT_16BIT: format |= FMT_16BIT; stream->bps = 16; break;
|
||||
case B_FMT_20BIT: format |= FMT_20BIT; stream->bps = 20; break;
|
||||
case B_FMT_24BIT: format |= FMT_24BIT; stream->bps = 24; break;
|
||||
case B_FMT_32BIT: format |= FMT_32BIT; stream->bps = 32; break;
|
||||
case B_FMT_8BIT_S: format |= FORMAT_8BIT; stream->bps = 8; break;
|
||||
case B_FMT_16BIT: format |= FORMAT_16BIT; stream->bps = 16; break;
|
||||
case B_FMT_20BIT: format |= FORMAT_20BIT; stream->bps = 20; break;
|
||||
case B_FMT_24BIT: format |= FORMAT_24BIT; stream->bps = 24; break;
|
||||
case B_FMT_32BIT: format |= FORMAT_32BIT; stream->bps = 32; break;
|
||||
|
||||
default:
|
||||
dprintf("%s: Invalid sample format: 0x%lx\n", __func__,
|
||||
dprintf("hda: Invalid sample format: 0x%lx\n",
|
||||
stream->sample_format);
|
||||
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,
|
||||
stream->rate, stream->bps);
|
||||
|
||||
OREG16(audioGroup->codec->controller, stream->off, FMT) = format;
|
||||
OREG32(audioGroup->codec->controller, stream->off, BDPL)
|
||||
= stream->physical_buffer_descriptors;
|
||||
OREG32(audioGroup->codec->controller, stream->off, BDPU) = 0;
|
||||
OREG16(audioGroup->codec->controller, stream->off, LVI)
|
||||
= stream->num_buffers - 1;
|
||||
stream->Write16(HDAC_STREAM_FORMAT, format);
|
||||
stream->Write32(HDAC_STREAM_BUFFERS_BASE_LOWER,
|
||||
stream->physical_buffer_descriptors);
|
||||
stream->Write32(HDAC_STREAM_BUFFERS_BASE_UPPER, 0);
|
||||
stream->Write16(HDAC_STREAM_LAST_VALID, stream->num_buffers - 1);
|
||||
/* total cyclic buffer size in _bytes_ */
|
||||
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, CTL2) = stream->id << 4;
|
||||
stream->Write32(HDAC_STREAM_BUFFER_SIZE, stream->sample_size
|
||||
* stream->num_channels * stream->num_buffers * stream->buffer_length);
|
||||
stream->Write8(HDAC_STREAM_CONTROL2, stream->id << 4);
|
||||
|
||||
REG32(audioGroup->codec->controller, DMA_POSITION_BASE_LOWER)
|
||||
|= DMA_POSITION_ENABLED;
|
||||
stream->controller->Write32(HDAC_DMA_POSITION_BASE_LOWER,
|
||||
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++) {
|
||||
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);
|
||||
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);
|
||||
hda_send_verbs(audioGroup->codec, verb, response, 2);
|
||||
hda_send_verbs(codec, verb, response, 2);
|
||||
}
|
||||
|
||||
snooze(1000);
|
||||
@ -572,12 +633,11 @@ hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, uint32 count)
|
||||
{
|
||||
hda_controller *controller = codec->controller;
|
||||
uint32 sent = 0;
|
||||
status_t rc;
|
||||
|
||||
codec->response_count = 0;
|
||||
|
||||
while (sent < count) {
|
||||
uint32 readPos = REG16(controller, CORBRP);
|
||||
uint32 readPos = controller->Read16(HDAC_CORB_READ_POS);
|
||||
uint32 queued = 0;
|
||||
|
||||
while (sent < count) {
|
||||
@ -594,11 +654,11 @@ hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, uint32 count)
|
||||
queued++;
|
||||
}
|
||||
|
||||
REG16(controller, CORBWP) = controller->corb_write_pos;
|
||||
rc = acquire_sem_etc(codec->response_sem, queued, B_RELATIVE_TIMEOUT,
|
||||
1000ULL * 50);
|
||||
if (rc < B_OK)
|
||||
return rc;
|
||||
controller->Write16(HDAC_CORB_WRITE_POS, controller->corb_write_pos);
|
||||
status_t status = acquire_sem_etc(codec->response_sem, queued,
|
||||
B_RELATIVE_TIMEOUT, 50000ULL);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (responses != NULL)
|
||||
@ -612,9 +672,8 @@ hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, uint32 count)
|
||||
status_t
|
||||
hda_hw_init(hda_controller* controller)
|
||||
{
|
||||
status_t rc;
|
||||
uint16 gcap;
|
||||
uint32 index;
|
||||
uint16 capabilities;
|
||||
status_t status;
|
||||
|
||||
/* Map MMIO registers */
|
||||
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,
|
||||
0, (void**)&controller->regs);
|
||||
if (controller->regs_area < B_OK) {
|
||||
rc = controller->regs_area;
|
||||
status = controller->regs_area;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Absolute minimum hw is online; we can now install interrupt handler */
|
||||
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);
|
||||
if (rc != B_OK)
|
||||
if (status != B_OK)
|
||||
goto no_irq;
|
||||
|
||||
/* show some hw features */
|
||||
gcap = REG16(controller, GCAP);
|
||||
dprintf("HDA: HDA v%d.%d, O:%d/I:%d/B:%d, #SDO:%d, 64bit:%s\n",
|
||||
REG8(controller, VMAJ), REG8(controller, VMIN),
|
||||
GCAP_OSS(gcap), GCAP_ISS(gcap), GCAP_BSS(gcap),
|
||||
GCAP_NSDO(gcap) ? GCAP_NSDO(gcap) *2 : 1,
|
||||
gcap & GCAP_64OK ? "yes" : "no" );
|
||||
capabilities = controller->Read16(HDAC_GLOBAL_CAP);
|
||||
controller->num_input_streams = GLOBAL_CAP_INPUT_STREAMS(capabilities);
|
||||
controller->num_output_streams = GLOBAL_CAP_OUTPUT_STREAMS(capabilities);
|
||||
controller->num_bidir_streams = GLOBAL_CAP_BIDIR_STREAMS(capabilities);
|
||||
|
||||
controller->num_input_streams = GCAP_OSS(gcap);
|
||||
controller->num_output_streams = GCAP_ISS(gcap);
|
||||
controller->num_bidir_streams = GCAP_BSS(gcap);
|
||||
/* show some hw features */
|
||||
dprintf("hda: HDA v%d.%d, O:%ld/I:%ld/B:%ld, #SDO:%d, 64bit:%s\n",
|
||||
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 */
|
||||
rc = hda_hw_start(controller);
|
||||
if (rc != B_OK)
|
||||
status = reset_controller(controller);
|
||||
if (status != B_OK)
|
||||
goto reset_failed;
|
||||
|
||||
/* Setup CORB/RIRB/DMA POS */
|
||||
rc = init_corb_rirb_pos(controller);
|
||||
if (rc != B_OK)
|
||||
status = init_corb_rirb_pos(controller);
|
||||
if (status != B_OK)
|
||||
goto corb_rirb_failed;
|
||||
|
||||
REG16(controller, WAKEEN) = 0x7fff;
|
||||
controller->Write16(HDAC_WAKE_ENABLE, 0x7fff);
|
||||
|
||||
/* Enable controller interrupts */
|
||||
REG32(controller, INTCTL) = INTCTL_GIE | INTCTL_CIE;
|
||||
|
||||
/* Wait for codecs to warm up */
|
||||
snooze(1000);
|
||||
controller->Write32(HDAC_INTR_CONTROL, INTR_CONTROL_GLOBAL_ENABLE
|
||||
| INTR_CONTROL_CONTROLLER_ENABLE);
|
||||
|
||||
if (!controller->codec_status) {
|
||||
rc = ENODEV;
|
||||
status = ENODEV;
|
||||
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)
|
||||
hda_codec_new(controller, index);
|
||||
}
|
||||
|
||||
for (index = 0; index < HDA_MAX_CODECS; index++) {
|
||||
for (uint32 index = 0; index < HDA_MAX_CODECS; index++) {
|
||||
if (controller->codecs[index]
|
||||
&& controller->codecs[index]->num_audio_groups > 0) {
|
||||
controller->active_codec = controller->codecs[index];
|
||||
@ -684,10 +743,10 @@ hda_hw_init(hda_controller* controller)
|
||||
if (controller->active_codec != NULL)
|
||||
return B_OK;
|
||||
|
||||
rc = ENODEV;
|
||||
status = ENODEV;
|
||||
|
||||
corb_rirb_failed:
|
||||
REG32(controller, INTCTL) = 0;
|
||||
controller->Write32(HDAC_INTR_CONTROL, 0);
|
||||
|
||||
reset_failed:
|
||||
remove_io_interrupt_handler(controller->irq,
|
||||
@ -699,9 +758,9 @@ no_irq:
|
||||
controller->regs = NULL;
|
||||
|
||||
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 */
|
||||
hda_hw_stop(controller);
|
||||
|
||||
/* Stop CORB/RIRB */
|
||||
REG8(controller, CORBCTL) = 0;
|
||||
REG8(controller, RIRBCTL) = 0;
|
||||
reset_controller(controller);
|
||||
|
||||
REG32(controller, CORBLBASE) = 0;
|
||||
REG32(controller, RIRBLBASE) = 0;
|
||||
REG32(controller, DMA_POSITION_BASE_LOWER) = 0;
|
||||
/* Disable interrupts, and remove interrupt handler */
|
||||
controller->Write32(HDAC_INTR_CONTROL, 0);
|
||||
|
||||
/* Disable interrupts, reset controller, and remove interrupt handler */
|
||||
REG32(controller, INTCTL) = 0;
|
||||
REG32(controller, GCTL) &= ~GCTL_CRST;
|
||||
remove_io_interrupt_handler(controller->irq,
|
||||
(interrupt_handler)hda_interrupt_handler, controller);
|
||||
|
||||
|
@ -4,135 +4,132 @@
|
||||
*
|
||||
* Authors:
|
||||
* Ithamar Adema, ithamar AT unet DOT nl
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
*/
|
||||
#ifndef HDAC_REGS_H
|
||||
#define HDAC_REGS_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) \
|
||||
(*(vuint32*)((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg))
|
||||
#define OREG16(controller, stream, reg) \
|
||||
(*(vuint16*)((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg))
|
||||
#define OREG8(controller, stream, reg) \
|
||||
(*((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg))
|
||||
/* Controller register definitions */
|
||||
#define HDAC_GLOBAL_CAP 0x00 // 16bits, GCAP
|
||||
#define GLOBAL_CAP_OUTPUT_STREAMS(cap) (((cap) >> 12) & 15)
|
||||
#define GLOBAL_CAP_INPUT_STREAMS(cap) (((cap) >> 8) & 15)
|
||||
#define GLOBAL_CAP_BIDIR_STREAMS(cap) (((cap) >> 3) & 15)
|
||||
#define GLOBAL_CAP_NUM_SDO(cap) ((((cap) >> 1) & 3) ? (cap & 6) : 1)
|
||||
#define GLOBAL_CAP_64BIT(cap) (((cap) & 1) != 0)
|
||||
|
||||
/* Register definitions */
|
||||
#define HDAC_GCAP 0x00 /* 16bits */
|
||||
#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_VERSION_MINOR 0x02 // 8bits, VMIN
|
||||
#define HDAC_VERSION_MAJOR 0x03 // 8bits, VMAJ
|
||||
|
||||
#define HDAC_VMIN 0x02 /* 8bits */
|
||||
#define HDAC_VMAJ 0x03 /* 8bits */
|
||||
#define HDAC_GLOBAL_CONTROL 0x08 // 32bits, GCTL
|
||||
#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 GCTL_UNSOL (1 << 8) /* Accept Unsolicited responses */
|
||||
#define GCTL_FCNTRL (1 << 1) /* Flush Control */
|
||||
#define GCTL_CRST (1 << 0) /* Controller Reset */
|
||||
#define HDAC_WAKE_ENABLE 0x0c // 16bits, WAKEEN
|
||||
#define HDAC_STATE_STATUS 0x0e // 16bits, STATESTS
|
||||
|
||||
#define HDAC_WAKEEN 0x0c /* 16bits */
|
||||
#define HDAC_STATESTS 0x0e /* 16bits */
|
||||
#define HDAC_INTR_CONTROL 0x20 // 32bits, INTCTL
|
||||
#define INTR_CONTROL_GLOBAL_ENABLE (1 << 31)
|
||||
#define INTR_CONTROL_CONTROLLER_ENABLE (1 << 30)
|
||||
|
||||
#define HDAC_INTCTL 0x20 /* 32bits */
|
||||
#define INTCTL_GIE (1 << 31) /* Global Interrupt Enable */
|
||||
#define INTCTL_CIE (1 << 30) /* Controller Interrupt Enable */
|
||||
#define HDAC_INTR_STATUS 0x24 // 32bits, INTSTS
|
||||
#define INTR_STATUS_GLOBAL (1 << 31)
|
||||
#define INTR_STATUS_CONTROLLER (1 << 30)
|
||||
#define INTR_STATUS_STREAM_MASK 0x3fffffff
|
||||
|
||||
#define HDAC_INTSTS 0x24 /* 32bits */
|
||||
#define INTSTS_GIS (1 << 31) /* Global Interrupt Status */
|
||||
#define INTSTS_CIS (1 << 30) /* Controller Interrupt Status */
|
||||
#define HDAC_CORB_BASE_LOWER 0x40 // 32bits, CORBLBASE
|
||||
#define HDAC_CORB_BASE_UPPER 0x44 // 32bits, CORBUBASE
|
||||
#define HDAC_CORB_WRITE_POS 0x48 // 16bits, CORBWP
|
||||
|
||||
#define HDAC_CORBLBASE 0x40 /* 32bits */
|
||||
#define HDAC_CORBUBASE 0x44 /* 32bits */
|
||||
#define HDAC_CORBWP 0x48 /* 16bits */
|
||||
#define HDAC_CORB_READ_POS 0x4a // 16bits, CORBRP
|
||||
#define CORB_READ_POS_RESET (1 << 15)
|
||||
|
||||
#define HDAC_CORBRP 0x4a /* 16bits */
|
||||
#define CORBRP_RST (1 << 15)
|
||||
#define HDAC_CORB_CONTROL 0x4c // 8bits, CORBCTL
|
||||
#define CORB_CONTROL_RUN (1 << 1)
|
||||
#define CORB_CONTROL_MEMORY_ERROR_INTR (1 << 0)
|
||||
|
||||
#define HDAC_CORBCTL 0x4c /* 8bits */
|
||||
#define CORBCTL_RUN (1 << 1)
|
||||
#define CORBCTL_MEIE (1 << 0)
|
||||
#define HDAC_CORB_STATUS 0x4d // 8bits, CORBSTS
|
||||
#define CORB_STATUS_MEMORY_ERROR (1 << 0)
|
||||
|
||||
#define HDAC_CORBSTS 0x4d /* 8bits */
|
||||
#define CORBSTS_MEI (1 << 0)
|
||||
#define HDAC_CORB_SIZE 0x4e // 8bits, CORBSIZE
|
||||
#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 CORBSIZE_CAP_2E (1 << 4)
|
||||
#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_RIRB_BASE_LOWER 0x50 // 32bits, RIRBLBASE
|
||||
#define HDAC_RIRB_BASE_UPPER 0x54 // 32bits, RIRBUBASE
|
||||
|
||||
#define HDAC_RIRBLBASE 0x50 /* 32bits */
|
||||
#define HDAC_RIRBUBASE 0x54 /* 32bits */
|
||||
#define HDAC_RIRB_WRITE_POS 0x58 // 16bits, RIRBWP
|
||||
#define RIRB_WRITE_POS_RESET (1 << 15)
|
||||
|
||||
#define HDAC_RIRBWP 0x58 /* 16bits */
|
||||
#define RIRBWP_RST (1 << 15)
|
||||
#define HDAC_RESPONSE_INTR_COUNT 0x5a // 16bits, RINTCNT
|
||||
|
||||
#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 RIRBCTL_OIC (1 << 2)
|
||||
#define RIRBCTL_DMAEN (1 << 1)
|
||||
#define RIRBCTL_RINTCTL (1 << 0)
|
||||
#define HDAC_RIRB_STATUS 0x5d // 8bits, RIRBSTS
|
||||
#define RIRB_STATUS_OVERRUN (1 << 2)
|
||||
#define RIRB_STATUS_RESPONSE (1 << 0)
|
||||
|
||||
#define HDAC_RIRBSTS 0x5d
|
||||
#define RIRBSTS_OIS (1 << 2)
|
||||
#define RIRBSTS_RINTFL (1 << 0)
|
||||
#define HDAC_RIRB_SIZE 0x5e // 8bits, RIRBSIZE
|
||||
#define RIRB_SIZE_CAP_2_ENTRIES (1 << 4)
|
||||
#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 RIRBSIZE_CAP_2E (1 << 4)
|
||||
#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 HDAC_DMA_POSITION_BASE_LOWER 0x70 // 32bits, DPLBASE
|
||||
#define HDAC_DMA_POSITION_BASE_UPPER 0x74 // 32bits, DPUBASE
|
||||
#define DMA_POSITION_ENABLED 1
|
||||
|
||||
#define HDAC_SDBASE 0x80
|
||||
#define HDAC_SDSIZE 0x20
|
||||
/* Stream Descriptor Registers */
|
||||
#define HDAC_STREAM_BASE 0x80
|
||||
#define HDAC_STREAM_SIZE 0x20
|
||||
|
||||
#define HDAC_SD_CTL0 0x00 /* 8bits */
|
||||
#define CTL0_SRST (1 << 0)
|
||||
#define CTL0_RUN (1 << 1)
|
||||
#define CTL0_IOCE (1 << 2)
|
||||
#define CTL0_FEIE (1 << 3)
|
||||
#define CTL0_DEIE (1 << 4)
|
||||
#define HDAC_SD_CTL1 0x01 /* 8bits */
|
||||
#define HDAC_SD_CTL2 0x02 /* 8bits */
|
||||
#define CTL2_DIR (1 << 3)
|
||||
#define CTL2_TP (1 << 2)
|
||||
#define HDAC_SD_STS 0x03 /* 8bits */
|
||||
#define STS_BCIS (1 << 2)
|
||||
#define STS_FIFOE (1 << 3)
|
||||
#define STS_DESE (1 << 4)
|
||||
#define STS_FIFORDY (1 << 5)
|
||||
#define HDAC_SD_LPIB 0x04 /* 32bits */
|
||||
#define HDAC_SD_CBL 0x08 /* 32bits */
|
||||
#define HDAC_SD_LVI 0x0C /* 16bits */
|
||||
#define HDAC_SD_FIFOS 0x10 /* 16bits */
|
||||
#define HDAC_SD_FMT 0x12 /* 16bits */
|
||||
#define FMT_8BIT (0 << 4)
|
||||
#define FMT_16BIT (1 << 4)
|
||||
#define FMT_20BIT (2 << 4)
|
||||
#define FMT_24BIT (3 << 4)
|
||||
#define FMT_32BIT (4 << 4)
|
||||
#define FMT_44_1_BASE_RATE (1 << 14)
|
||||
#define FMT_MULTIPLY_RATE_SHIFT 11
|
||||
#define FMT_DIVIDE_RATE_SHIFT 8
|
||||
#define HDAC_SD_BDPL 0x18 /* 32bits */
|
||||
#define HDAC_SD_BDPU 0x1C /* 32bits */
|
||||
#define HDAC_STREAM_CONTROL0 0x00 // 8bits, CTL0
|
||||
#define CONTROL0_RESET (1 << 0)
|
||||
#define CONTROL0_RUN (1 << 1)
|
||||
#define CONTROL0_BUFFER_COMPLETED_INTR (1 << 2)
|
||||
#define CONTROL0_FIFO_ERROR_INTR (1 << 3)
|
||||
#define CONTROL0_DESCRIPTOR_ERROR_INTR (1 << 4)
|
||||
#define HDAC_STREAM_CONTROL1 0x01 // 8bits, CTL1
|
||||
#define HDAC_STREAM_CONTROL2 0x02 // 8bits, CTL2
|
||||
#define CONTROL2_STREAM_MASK 0xf0
|
||||
#define CONTROL2_STREAM_SHIFT 4
|
||||
#define CONTROL2_BIDIR (1 << 3)
|
||||
#define CONTROL2_TRAFFIC_PRIORITY (1 << 2)
|
||||
#define CONTROL2_STRIPE_SDO_MASK 0x03
|
||||
#define HDAC_STREAM_STATUS 0x03 // 8bits, STS
|
||||
#define STATUS_BUFFER_COMPLETED (1 << 2)
|
||||
#define STATUS_FIFO_ERROR (1 << 3)
|
||||
#define STATUS_DESCRIPTOR_ERROR (1 << 4)
|
||||
#define STATUS_FIFO_READY (1 << 5)
|
||||
#define HDAC_STREAM_POSITION 0x04 // 32bits, LPIB
|
||||
#define HDAC_STREAM_BUFFER_SIZE 0x08 // 32bits, CBL
|
||||
#define HDAC_STREAM_LAST_VALID 0x0c // 16bits, LVI
|
||||
#define HDAC_STREAM_FIFO_SIZE 0x10 // 16bits, FIFOS
|
||||
#define HDAC_STREAM_FORMAT 0x12 // 16bits, FMT
|
||||
#define FORMAT_8BIT (0 << 4)
|
||||
#define FORMAT_16BIT (1 << 4)
|
||||
#define FORMAT_20BIT (2 << 4)
|
||||
#define FORMAT_24BIT (3 << 4)
|
||||
#define FORMAT_32BIT (4 << 4)
|
||||
#define FORMAT_44_1_BASE_RATE (1 << 14)
|
||||
#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 struct {
|
||||
@ -140,8 +137,8 @@ typedef struct {
|
||||
uint32 flags;
|
||||
} rirb_t;
|
||||
|
||||
#define RESPONSE_FLAGS_CODEC_MASK 0x0000000f
|
||||
#define RESPONSE_FLAGS_UNSOLICITED (1 << 4)
|
||||
#define RESPONSE_FLAGS_CODEC_MASK 0x0000000f
|
||||
#define RESPONSE_FLAGS_UNSOLICITED (1 << 4)
|
||||
|
||||
typedef struct {
|
||||
uint64 address;
|
||||
|
Loading…
Reference in New Issue
Block a user