* added an ALIGN macro for easing readability and use it for 128 alignments
* use HDAC_STREAM_POSITION register value to check the current buffer cycle in interrupt handler * added B_FULL_LOCK flags for area allocation, not sure it's handled but at least more correct * buffer descriptors now use a low and high address fields * applied a byte mask on format * enabled PCI bus mastering if not yet done * the PCI space register TCSEL (Traffic Class Select Register, which sets PCI express QOS) is now reset to TC0 (clear 0-2 bits) as needed on some boards like mine to ensure good playback Playback is finally working correctly here on ICH8 HDA! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26847 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
28fd262f0e
commit
1708513ca8
@ -26,6 +26,7 @@
|
||||
(((controller)->num_input_streams + (controller)->num_output_streams \
|
||||
+ (index)) * HDAC_STREAM_SIZE)
|
||||
|
||||
#define ALIGN(size, align) (((size) + align - 1) & ~(align - 1))
|
||||
#define PAGE_ALIGN(size) (((size) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1))
|
||||
|
||||
static const struct {
|
||||
@ -73,6 +74,7 @@ static void
|
||||
stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
|
||||
{
|
||||
uint8 status;
|
||||
uint32 position, bufferSize;
|
||||
|
||||
if (!stream->running)
|
||||
return;
|
||||
@ -83,20 +85,24 @@ stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
|
||||
|
||||
stream->Write8(HDAC_STREAM_STATUS, status);
|
||||
|
||||
if ((status & STATUS_BUFFER_COMPLETED) != 0) {
|
||||
if ((status & STATUS_BUFFER_COMPLETED) == 0) {
|
||||
dprintf("hda: stream status %x\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
position = stream->Read32(HDAC_STREAM_POSITION);
|
||||
bufferSize = ALIGN(stream->sample_size * stream->num_channels * stream->buffer_length, 128);
|
||||
|
||||
// Buffer Completed Interrupt
|
||||
acquire_spinlock(&stream->lock);
|
||||
|
||||
stream->real_time = system_time();
|
||||
stream->frames_count += stream->buffer_length;
|
||||
stream->buffer_cycle = (stream->buffer_cycle + 1)
|
||||
% stream->num_buffers;
|
||||
stream->buffer_cycle = 1 - (position / bufferSize);
|
||||
|
||||
release_spinlock(&stream->lock);
|
||||
|
||||
release_sem_etc(stream->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
} else
|
||||
dprintf("hda: stream status %x\n", status);
|
||||
}
|
||||
|
||||
|
||||
@ -301,9 +307,8 @@ init_corb_rirb_pos(hda_controller* controller)
|
||||
}
|
||||
|
||||
/* Determine rirb offset in memory and total size of corb+alignment+rirb */
|
||||
rirbOffset = (controller->corb_length * sizeof(corb_t) + 0x7f) & ~0x7f;
|
||||
posOffset = (rirbOffset + controller->rirb_length * sizeof(rirb_t) + 0x7f)
|
||||
& ~0x7f;
|
||||
rirbOffset = ALIGN(controller->corb_length * sizeof(corb_t), 128);
|
||||
posOffset = ALIGN(rirbOffset + controller->rirb_length * sizeof(rirb_t), 128);
|
||||
posSize = 8 * (controller->num_input_streams
|
||||
+ controller->num_output_streams + controller->num_bidir_streams);
|
||||
|
||||
@ -312,7 +317,7 @@ init_corb_rirb_pos(hda_controller* controller)
|
||||
/* Allocate memory area */
|
||||
controller->corb_rirb_pos_area = create_area("hda corb/rirb/pos",
|
||||
(void**)&controller->corb, B_ANY_KERNEL_ADDRESS, memSize,
|
||||
B_CONTIGUOUS, 0);
|
||||
B_FULL_LOCK | B_CONTIGUOUS, 0);
|
||||
if (controller->corb_rirb_pos_area < 0)
|
||||
return controller->corb_rirb_pos_area;
|
||||
|
||||
@ -418,7 +423,6 @@ hda_stream_new(hda_audio_group* audioGroup, int type)
|
||||
dprintf("%s: Unknown stream type %d!\n", __func__, type);
|
||||
free(stream);
|
||||
stream = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
// find I/O and Pin widgets for this stream
|
||||
@ -500,7 +504,8 @@ hda_stream_setup_buffers(hda_audio_group* audioGroup, hda_stream* stream,
|
||||
/* Calculate size of buffer (aligned to 128 bytes) */
|
||||
bufferSize = stream->sample_size * stream->num_channels
|
||||
* stream->buffer_length;
|
||||
bufferSize = (bufferSize + 127) & (~127);
|
||||
bufferSize = ALIGN(bufferSize, 128);
|
||||
|
||||
dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld ****************\n",
|
||||
stream->sample_size, stream->num_channels, stream->buffer_length);
|
||||
|
||||
@ -510,7 +515,7 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
|
||||
|
||||
/* Allocate memory for buffers */
|
||||
stream->buffer_area = create_area("hda buffers", (void**)&buffer,
|
||||
B_ANY_KERNEL_ADDRESS, alloc, B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
|
||||
B_ANY_KERNEL_ADDRESS, alloc, B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
|
||||
if (stream->buffer_area < B_OK)
|
||||
return stream->buffer_area;
|
||||
|
||||
@ -539,7 +544,7 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
|
||||
|
||||
stream->buffer_descriptors_area = create_area("hda buffer descriptors",
|
||||
(void**)&bufferDescriptors, B_ANY_KERNEL_ADDRESS, alloc,
|
||||
B_CONTIGUOUS, 0);
|
||||
B_FULL_LOCK | B_CONTIGUOUS, 0);
|
||||
if (stream->buffer_descriptors_area < B_OK) {
|
||||
delete_area(stream->buffer_area);
|
||||
return stream->buffer_descriptors_area;
|
||||
@ -560,14 +565,15 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
|
||||
|
||||
/* Setup buffer descriptor list (BDL) entries */
|
||||
for (index = 0; index < stream->num_buffers; index++, bufferDescriptors++) {
|
||||
bufferDescriptors->address = stream->physical_buffers[index];
|
||||
bufferDescriptors->lower = stream->physical_buffers[index];
|
||||
bufferDescriptors->upper = 0;
|
||||
bufferDescriptors->length = bufferSize;
|
||||
bufferDescriptors->ioc = 1;
|
||||
// we want an interrupt after every buffer
|
||||
}
|
||||
|
||||
/* Configure stream registers */
|
||||
format = stream->num_channels - 1;
|
||||
format = (stream->num_channels - 1) & 0xf;
|
||||
switch (stream->sample_format) {
|
||||
case B_FMT_8BIT_S: format |= FORMAT_8BIT; stream->bps = 8; break;
|
||||
case B_FMT_16BIT: format |= FORMAT_16BIT; stream->bps = 16; break;
|
||||
@ -598,8 +604,8 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
|
||||
stream->Write32(HDAC_STREAM_BUFFERS_BASE_UPPER, 0);
|
||||
stream->Write16(HDAC_STREAM_LAST_VALID, stream->num_buffers - 1);
|
||||
/* total cyclic buffer size in _bytes_ */
|
||||
stream->Write32(HDAC_STREAM_BUFFER_SIZE, stream->sample_size
|
||||
* stream->num_channels * stream->num_buffers * stream->buffer_length);
|
||||
stream->Write32(HDAC_STREAM_BUFFER_SIZE, bufferSize
|
||||
* stream->num_buffers);
|
||||
stream->Write8(HDAC_STREAM_CONTROL2, stream->id << 4);
|
||||
|
||||
stream->controller->Write32(HDAC_DMA_POSITION_BASE_LOWER,
|
||||
@ -667,8 +673,9 @@ hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, uint32 count)
|
||||
status_t
|
||||
hda_hw_init(hda_controller* controller)
|
||||
{
|
||||
uint16 capabilities, stateStatus;
|
||||
uint16 capabilities, stateStatus, cmd;
|
||||
status_t status;
|
||||
uint8 tcsel;
|
||||
|
||||
/* Map MMIO registers */
|
||||
controller->regs_area = map_physical_memory("hda_hw_regs",
|
||||
@ -680,6 +687,15 @@ hda_hw_init(hda_controller* controller)
|
||||
goto error;
|
||||
}
|
||||
|
||||
cmd = (gPci->read_pci_config)(controller->pci_info.bus,
|
||||
controller->pci_info.device, controller->pci_info.function, PCI_command, 2);
|
||||
if (!(cmd & PCI_command_master)) {
|
||||
(gPci->write_pci_config)(controller->pci_info.bus,
|
||||
controller->pci_info.device, controller->pci_info.function,
|
||||
PCI_command, 2, cmd | PCI_command_master);
|
||||
dprintf("hda: enabling PCI bus mastering\n");
|
||||
}
|
||||
|
||||
/* Absolute minimum hw is online; we can now install interrupt handler */
|
||||
controller->irq = controller->pci_info.u.h0.interrupt_line;
|
||||
status = install_io_interrupt_handler(controller->irq,
|
||||
@ -687,6 +703,13 @@ hda_hw_init(hda_controller* controller)
|
||||
if (status != B_OK)
|
||||
goto no_irq;
|
||||
|
||||
/* TCSEL is reset to TC0 (clear 0-2 bits) */
|
||||
tcsel = (gPci->read_pci_config)(controller->pci_info.bus,
|
||||
controller->pci_info.device, controller->pci_info.function, PCI_HDA_TCSEL, 1);
|
||||
(gPci->write_pci_config)(controller->pci_info.bus,
|
||||
controller->pci_info.device, controller->pci_info.function,
|
||||
PCI_HDA_TCSEL, 1, tcsel & 0xf8);
|
||||
|
||||
capabilities = controller->Read16(HDAC_GLOBAL_CAP);
|
||||
controller->num_input_streams = GLOBAL_CAP_INPUT_STREAMS(capabilities);
|
||||
controller->num_output_streams = GLOBAL_CAP_OUTPUT_STREAMS(capabilities);
|
||||
|
@ -131,6 +131,9 @@
|
||||
#define HDAC_STREAM_BUFFERS_BASE_LOWER 0x18 // 32bits, BDPL
|
||||
#define HDAC_STREAM_BUFFERS_BASE_UPPER 0x1c // 32bits, BDPU
|
||||
|
||||
/* PCI space register definitions */
|
||||
#define PCI_HDA_TCSEL 0x44
|
||||
|
||||
typedef uint32 corb_t;
|
||||
typedef struct {
|
||||
uint32 response;
|
||||
@ -141,7 +144,8 @@ typedef struct {
|
||||
#define RESPONSE_FLAGS_UNSOLICITED (1 << 4)
|
||||
|
||||
typedef struct {
|
||||
uint64 address;
|
||||
uint32 lower;
|
||||
uint32 upper;
|
||||
uint32 length;
|
||||
uint32 ioc;
|
||||
} bdl_entry_t;
|
||||
|
Loading…
Reference in New Issue
Block a user