From 10baa577a98100363a17413cd667379cdaa5f418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 9 Mar 2019 15:57:35 +0100 Subject: [PATCH] hda: wait between set and unset of the GLOBAL_CONTROL_RESET bit. * the spec requires 521us, 1000us is generally used. * also only uninit streams, corb and rirb when a codec reset is in progress (seen in zircon). linux instead clears HDAC_STATE_STATUS. --- .../drivers/audio/hda/hda_controller.cpp | 88 ++++++++++--------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp b/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp index b81afb7c7d..a54ae3b85b 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp +++ b/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp @@ -356,53 +356,58 @@ hda_interrupt_handler(hda_controller* controller) static status_t reset_controller(hda_controller* controller) { - // stop streams + uint32 control = controller->Read32(HDAC_GLOBAL_CONTROL); + if ((control & GLOBAL_CONTROL_RESET) != 0) { + controller->Write32(HDAC_INTR_CONTROL, 0); - 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_OUTPUT_STREAM_OFFSET(controller, i), 0); - controller->Write8(HDAC_STREAM_STATUS + HDAC_STREAM_BASE - + HDAC_OUTPUT_STREAM_OFFSET(controller, i), 0); - } - for (uint32 i = 0; i < controller->num_bidir_streams; i++) { - controller->Write8(HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE - + HDAC_BIDIR_STREAM_OFFSET(controller, i), 0); - controller->Write8(HDAC_STREAM_STATUS + HDAC_STREAM_BASE - + HDAC_BIDIR_STREAM_OFFSET(controller, i), 0); - } + // stop streams - // stop DMA - controller->ReadModifyWrite8(HDAC_CORB_CONTROL, HDAC_CORB_CONTROL_MASK, 0); - controller->ReadModifyWrite8(HDAC_RIRB_CONTROL, HDAC_RIRB_CONTROL_MASK, 0); + 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_OUTPUT_STREAM_OFFSET(controller, i), 0); + controller->Write8(HDAC_STREAM_STATUS + HDAC_STREAM_BASE + + HDAC_OUTPUT_STREAM_OFFSET(controller, i), 0); + } + for (uint32 i = 0; i < controller->num_bidir_streams; i++) { + controller->Write8(HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + + HDAC_BIDIR_STREAM_OFFSET(controller, i), 0); + controller->Write8(HDAC_STREAM_STATUS + HDAC_STREAM_BASE + + HDAC_BIDIR_STREAM_OFFSET(controller, i), 0); + } - uint8 corbControl = 0; - uint8 rirbControl = 0; - for (int timeout = 0; timeout < 10; timeout++) { - snooze(100); + // stop DMA + controller->ReadModifyWrite8(HDAC_CORB_CONTROL, HDAC_CORB_CONTROL_MASK, 0); + controller->ReadModifyWrite8(HDAC_RIRB_CONTROL, HDAC_RIRB_CONTROL_MASK, 0); - corbControl = controller->Read8(HDAC_CORB_CONTROL); - rirbControl = controller->Read8(HDAC_RIRB_CONTROL); - if (corbControl == 0 && rirbControl == 0) - break; + uint8 corbControl = 0; + uint8 rirbControl = 0; + for (int timeout = 0; timeout < 10; timeout++) { + snooze(100); + + corbControl = controller->Read8(HDAC_CORB_CONTROL); + rirbControl = controller->Read8(HDAC_RIRB_CONTROL); + if (corbControl == 0 && rirbControl == 0) + break; + } + if (corbControl != 0 || rirbControl != 0) { + dprintf("hda: unable to stop dma\n"); + return B_BUSY; + } + + // reset DMA position buffer + controller->Write32(HDAC_DMA_POSITION_BASE_LOWER, 0); + controller->Write32(HDAC_DMA_POSITION_BASE_UPPER, 0); + + control = controller->Read32(HDAC_GLOBAL_CONTROL); } - if (corbControl != 0 || rirbControl != 0) { - dprintf("hda: unable to stop dma\n"); - return B_BUSY; - } - - // 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++) { @@ -417,6 +422,9 @@ reset_controller(hda_controller* controller) return B_BUSY; } + // Wait for codec PLL to lock at least 100us, section 5.5.1.2 + snooze(1000); + // Unset reset bit control = controller->Read32(HDAC_GLOBAL_CONTROL);