hda: fixes

This commit is contained in:
Matheus
2026-07-29 00:47:42 -03:00
parent d1b499c43e
commit 8a72152c21
+54 -11
View File
@@ -16,6 +16,10 @@
#define HDA_BDL_FLAGS_IOC 1
#define INTEL_HDA_TCSEL 0x44
#define INTEL_HDA_DEVC 0x78
#define INTEL_HDA_DEVC_NOSNOOP (1 << 11)
typedef struct {
uint64_t address;
uint32_t length;
@@ -59,6 +63,9 @@ typedef struct {
#define SIZE_16 1
#define SIZE_2 0
#define CORBRP_RST (1 << 15)
#define CORBCTL_DMA_ENABLE (1 << 1)
typedef struct {
uint16_t gcap;
uint8_t vmin;
@@ -198,6 +205,11 @@ typedef struct {
hda_stream_t **streams;
} hda_t;
static uint32_t hda_stream_mask(hda_t *hda) {
size_t count = hda->input_stream_count + hda->output_stream_count + hda->bi_stream_count;
return count >= 30 ? 0x3fffffff : ((1u << count) - 1);
}
static bool hda_sd_set_reset(volatile hda_sd_t *sd, bool set) {
if (set)
sd->ctl[0] |= HDA_SD_CTL_BYTE0_RESET;
@@ -500,7 +512,7 @@ static void hda_stream_fill_data(hda_stream_t *stream) {
}
static void stream_irq(hda_t *hda) {
uint32_t status = hda->regs->intsts & 0x3f;
uint32_t status = hda->regs->intsts & hda_stream_mask(hda);
for (int i = 0; i < 30; ++i) {
if ((status & (1 << i)) == 0)
@@ -548,7 +560,7 @@ static void hda_isr(isr_t *isr, context_t *) {
if (hda->regs->rirbsts)
rirb_irq(hda);
if (hda->regs->intsts & 0x3f)
if (hda->regs->intsts & hda_stream_mask(hda))
stream_irq(hda);
}
@@ -776,6 +788,27 @@ static void get_sizes(uint8_t reg, uint8_t *size_reg, size_t *size_count) {
}
}
static bool corb_reset_read_pointer(volatile hda_regs_t *regs, size_t timeoutms) {
regs->corbrp = CORBRP_RST;
int loops = 0;
while ((regs->corbrp & CORBRP_RST) == 0) {
if (loops++ >= timeoutms * 10)
return false;
sched_sleep_us(100);
}
regs->corbrp = 0;
loops = 0;
while (regs->corbrp & CORBRP_RST) {
if (loops++ >= timeoutms * 10)
return false;
sched_sleep_us(100);
}
return true;
}
static void init_function_group(hda_t *hda, int codec, hda_fg_t *function_group) {
function_group->type = hda_get_parameter(hda, codec, function_group->nid, HDA_PARAM_FUNCTION_GROUP_TYPE) & 0xff;
if (function_group->type != HDA_FUNCTION_GROUP_TYPE_AFG)
@@ -875,6 +908,9 @@ static void initcontroller(pcienum_t *e) {
pci_setcommand(e, PCI_COMMAND_IRQDISABLE, 1);
pci_setcommand(e, PCI_COMMAND_BUSMASTER, 1);
PCI_WRITE8(e, INTEL_HDA_TCSEL, PCI_READ8(e, INTEL_HDA_TCSEL) & ~0x7);
PCI_WRITE16(e, INTEL_HDA_DEVC, PCI_READ16(e, INTEL_HDA_DEVC) & ~INTEL_HDA_DEVC_NOSNOOP);
// enable interrupts
if (e->msix.exists) {
pci_initmsix(e);
@@ -923,9 +959,12 @@ static void initcontroller(pcienum_t *e) {
regs->corblbase = (uint64_t)corb_phys & 0xffffffff;
regs->corbhbase = ((uint64_t)corb_phys >> 32) & 0xffffffff;
regs->corbsize = (regs->corbsize & 0xfc) | corbsize;
regs->corbrp = 0x8000 | (regs->corbrp & 0x7fff);
regs->corbwp = regs->corbwp & 0xff00;
regs->corbctl = (regs->corbctl & 0xfc) | 2;
if (!corb_reset_read_pointer(regs, 1)) {
printf("hda: resetting CORB read pointer timed out\n");
return;
}
regs->corbwp = 0;
regs->corbctl = (regs->corbctl & ~CORBCTL_DMA_ENABLE) | CORBCTL_DMA_ENABLE;
uint8_t rirbsize;
size_t rirb_entries;
@@ -990,12 +1029,16 @@ static void initcontroller(pcienum_t *e) {
}
void hda_init() {
int i = 0;
for (;;) {
pcienum_t *e = pci_getenum(-1, -1, -1, 0x8086, 0x2668, -1, i++);
if (e == NULL)
break;
initcontroller(e);
static const int device_ids[] = {0x2668, 0x8c20};
for (size_t device = 0; device < sizeof(device_ids) / sizeof(device_ids[0]); ++device) {
int i = 0;
for (;;) {
pcienum_t *e = pci_getenum(-1, -1, -1, 0x8086, device_ids[device], -1, i++);
if (e == NULL)
break;
initcontroller(e);
}
}
}