Use correct sequence for resetting CORB read pointer
* Spec requires software to wait for hardware to acknowledge the reset by waiting for the bit to become set and then manually unset it and again wait for it to become unset. (cf. HDA spec 1.0a ch. 3.3.21) * Also, do read-modify-write to protect preserved bits
This commit is contained in:
parent
78b950bd2d
commit
2d498c889c
@ -495,11 +495,38 @@ init_corb_rirb_pos(hda_controller* controller)
|
||||
((uint8*)controller->corb + posOffset);
|
||||
|
||||
controller->Write16(HDAC_CORB_WRITE_POS, 0);
|
||||
// Reset CORB read pointer
|
||||
controller->Write16(HDAC_CORB_READ_POS, CORB_READ_POS_RESET);
|
||||
// Reading CORB_READ_POS_RESET as zero fails on some chips.
|
||||
// We reset the bit here.
|
||||
controller->Write16(HDAC_CORB_READ_POS, 0);
|
||||
|
||||
// Reset CORB read pointer. Preseve bits marked as RsvdP.
|
||||
// After setting the reset bit, we must wait for the hardware
|
||||
// to acknowledge it, then manually unset it and wait for that
|
||||
// to be acknowledged as well.
|
||||
uint16 corbReadPointer = controller->Read16(HDAC_CORB_READ_POS);
|
||||
|
||||
corbReadPointer |= CORB_READ_POS_RESET;
|
||||
controller->Write16(HDAC_CORB_READ_POS, corbReadPointer);
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
snooze(100);
|
||||
corbReadPointer = controller->Read16(HDAC_CORB_READ_POS);
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) != 0)
|
||||
break;
|
||||
}
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
|
||||
dprintf("hda: CORB read pointer reset failed\n");
|
||||
return B_BUSY;
|
||||
}
|
||||
|
||||
corbReadPointer &= ~CORB_READ_POS_RESET;
|
||||
controller->Write16(HDAC_CORB_READ_POS, corbReadPointer);
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
snooze(100);
|
||||
corbReadPointer = controller->Read16(HDAC_CORB_READ_POS);
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
|
||||
break;
|
||||
}
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
|
||||
dprintf("hda: CORB read pointer reset failed\n");
|
||||
return B_BUSY;
|
||||
}
|
||||
|
||||
// Reset RIRB write pointer
|
||||
controller->Write16(HDAC_RIRB_WRITE_POS, RIRB_WRITE_POS_RESET);
|
||||
|
Loading…
Reference in New Issue
Block a user