diff --git a/sys/dev/sound/pci/via8233.c b/sys/dev/sound/pci/via8233.c index 883012c0435f..f8f136e9ab23 100644 --- a/sys/dev/sound/pci/via8233.c +++ b/sys/dev/sound/pci/via8233.c @@ -653,33 +653,56 @@ dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) static int via_chip_init(device_t dev) { - int i, s; + u_int32_t data, cnt; - pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 0, 1); - DELAY(100); + /* Wake up and reset AC97 if necessary */ + data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1); - /* assert ACLink reset */ - pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_NRST, 1); - DELAY(2); + if ((data & VIA_PCI_ACLINK_C00_READY) == 0) { + /* Cold reset per ac97r2.3 spec (page 95) */ + /* Assert low */ + pci_write_config(dev, VIA_PCI_ACLINK_CTRL, + VIA_PCI_ACLINK_EN, 1); + /* Wait T_rst_low */ + DELAY(100); + /* Assert high */ + pci_write_config(dev, VIA_PCI_ACLINK_CTRL, + VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_NRST, 1); + /* Wait T_rst2clk */ + DELAY(5); + /* Assert low */ + pci_write_config(dev, VIA_PCI_ACLINK_CTRL, + VIA_PCI_ACLINK_EN, 1); + } else { + /* Warm reset */ + /* Force no sync */ + pci_write_config(dev, VIA_PCI_ACLINK_CTRL, + VIA_PCI_ACLINK_EN, 1); + DELAY(100); + /* Sync */ + pci_write_config(dev, VIA_PCI_ACLINK_CTRL, + VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_SYNC, 1); + /* Wait T_sync_high */ + DELAY(5); + /* Force no sync */ + pci_write_config(dev, VIA_PCI_ACLINK_CTRL, + VIA_PCI_ACLINK_EN, 1); + /* Wait T_sync2clk */ + DELAY(5); + } - /* deassert ACLink reset, force SYNC (warm AC'97 reset) */ - pci_write_config(dev, VIA_PCI_ACLINK_CTRL, - VIA_PCI_ACLINK_NRST | VIA_PCI_ACLINK_SYNC, 1); + /* Power everything up */ + pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_DESIRED, 1); - /* ACLink on, deassert ACLink reset, VSR, SGD data out */ - pci_write_config(dev, VIA_PCI_ACLINK_CTRL, - VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_NRST - | VIA_PCI_ACLINK_VRATE | VIA_PCI_ACLINK_SGD, 1); - - for (i = 0; i < 100; i++) { - s = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1); - if (s & VIA_PCI_ACLINK_C00_READY) { - s = pci_read_config(dev, VIA_PCI_ACLINK_CTRL, 1); + /* Wait for codec to become ready (largest reported delay 310ms) */ + for (cnt = 0; cnt < 2000; cnt++) { + data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1); + if (data & VIA_PCI_ACLINK_C00_READY) { return 0; } - DELAY(10); + DELAY(5000); } - device_printf(dev, "primary codec not ready (s = 0x%02x)\n", s); + device_printf(dev, "primary codec not ready (cnt = 0x%02x)\n", cnt); return ENXIO; } diff --git a/sys/dev/sound/pci/via8233.h b/sys/dev/sound/pci/via8233.h index f0caca5ea0d6..bc6f57aa6208 100644 --- a/sys/dev/sound/pci/via8233.h +++ b/sys/dev/sound/pci/via8233.h @@ -72,6 +72,10 @@ # define VIA_PCI_ACLINK_SERIAL 0x10 # define VIA_PCI_ACLINK_VRATE 0x08 # define VIA_PCI_ACLINK_SGD 0x04 +# define VIA_PCI_ACLINK_DESIRED (VIA_PCI_ACLINK_EN | \ + VIA_PCI_ACLINK_NRST | \ + VIA_PCI_ACLINK_VRATE | \ + VIA_PCI_ACLINK_SGD) #define VIA_MC_SGD_STATUS 0x40 #define VIA_WR0_SGD_STATUS 0x60