From 89d6a67e86d05c00dd245e4a07d6f104e727fd7a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 29 Jul 2021 00:47:39 -0300 Subject: [PATCH] More AC97 work, including 48 KHz sample rate cap --- src/device/smbus_piix4.c | 4 +-- src/sound/snd_ac97_codec.c | 52 +++++++++++++++++++++----------------- src/sound/snd_ac97_via.c | 50 +++++++++++++++++------------------- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index 91ee5566e..271747d92 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -124,13 +124,13 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) if (val & 0x40) { /* dispatch command if START is set */ timer_bytes++; /* address */ - smbus_addr = (dev->addr >> 1); + smbus_addr = dev->addr >> 1; read = dev->addr & 0x01; cmd = (dev->ctl >> 2) & 0xf; smbus_piix4_log("SMBus PIIX4: addr=%02X read=%d protocol=%X cmd=%02X data0=%02X data1=%02X\n", smbus_addr, read, cmd, dev->cmd, dev->data0, dev->data1); - /* Raise DEV_ERR if no device is at this address, or if the device returned NAK when starting the transfer. */ + /* Raise DEV_ERR if no device is at this address, or if the device returned NAK. */ if (!i2c_start(i2c_smbus, smbus_addr, read)) { dev->next_stat = 0x04; break; diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 02ae9cbe9..2ae310465 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -106,11 +106,17 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val) /* Read-only registers. */ return; + case 0x02: /* Master Volume LSB */ + case 0x04: /* Aux Out Volume LSB */ + case 0x06: /* Mono Volume LSB */ + val &= 0x3f; + /* fall-through */ + case 0x03: /* Master Volume MSB */ case 0x05: /* Aux Out Volume MSB */ val &= 0xbf; - /* Convert 6-bit level 1xxxxx to 011111. */ + /* Limit level to a maximum of 011111. */ if (val & 0x20) { val &= ~0x20; val |= 0x1f; @@ -123,18 +129,6 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val) val &= 0x80; break; - case 0x02: /* Master Volume LSB */ - case 0x04: /* Aux Out Volume LSB */ - case 0x06: /* Mono Volume LSB */ - val &= 0x3f; - - /* Convert 6-bit level 1xxxxx to 011111. */ - if (val & 0x20) { - val &= ~0x20; - val |= 0x1f; - } - break; - case 0x0a: /* PC Beep Volume LSB */ val &= 0x1e; break; @@ -177,9 +171,12 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val) break; case 0x2a: /* Extended Audio Status/Control LSB */ +#ifdef AC97_CODEC_FULL_RATE_RANGE /* enable DRA (double rate) support */ val &= 0x0b; - - /* Reset DAC sample rates to 48 KHz if VRA is being cleared. */ +#else + val &= 0x09; +#endif + /* Reset DAC sample rates to 48 KHz (96 KHz with DRA) if VRA is being cleared. */ if (!(val & 0x01)) { for (i = 0x2c; i <= 0x30; i += 2) *((uint16_t *) &dev->regs[i]) = 48000; @@ -192,16 +189,19 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val) } break; - case 0x2c ... 0x31: /* DAC Rates */ - /* Writable only if VRA is set. */ - if (!(dev->regs[0x2a] & 0x01)) + case 0x2c ... 0x35: /* DAC/ADC Rates */ + /* Writable only if VRA/VRM is set. */ + i = (reg >= 0x32) ? 0x08 : 0x01; + if (!(dev->regs[0x2a] & i)) return; - break; - case 0x32 ... 0x35: /* ADC Rates */ - /* Writable only if VRM is set. */ - if (!(dev->regs[0x2a] & 0x08)) +#ifndef AC97_CODEC_FULL_RATE_RANGE + /* Limit to 48 KHz on MSB write. */ + if ((reg & 1) && (((val << 8) | dev->regs[reg & 0x7e]) > 48000)) { + *((uint16_t *) &dev->regs[reg & 0x7e]) = 48000; return; + } +#endif break; } @@ -232,10 +232,14 @@ ac97_codec_reset(void *priv) dev->regs[0x26] = 0x0f; /* Set up variable sample rate support. */ +#ifdef AC97_CODEC_FULL_RATE_RANGE /* enable DRA (double rate) support */ dev->regs[0x28] = 0x0b; +#else + dev->regs[0x28] = 0x09; +#endif ac97_codec_write(dev, 0x2a, 0x00); /* reset DAC/ADC sample rates */ - /* Set Codec and Vendor IDs. */ + /* Set codec and vendor IDs. */ dev->regs[0x29] = (dev->codec_id << 6) | 0x02; dev->regs[0x7c] = dev->vendor_id >> 16; dev->regs[0x7d] = dev->vendor_id >> 24; @@ -277,9 +281,11 @@ ac97_codec_getrate(void *priv, uint8_t reg) /* Get configured sample rate, which is always 48000 if VRA/VRM is not set. */ uint32_t ret = *((uint16_t *) &dev->regs[reg]); +#ifdef AC97_CODEC_FULL_RATE_RANGE /* If this is a DAC, double sample rate if DRA is set. */ if ((reg < 0x32) && (dev->regs[0x2a] & 0x02)) ret <<= 1; +#endif ac97_codec_log("AC97 Codec %d: getrate(%02X) = %d\n", dev->codec_id, reg, ret); diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index 476d05474..262872e5e 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -85,7 +85,7 @@ ac97_via_log(const char *fmt, ...) static void ac97_via_sgd_process(void *priv); -static void ac97_via_update_codec(ac97_via_t *dev, ac97_codec_t *codec); +static void ac97_via_update_codec(ac97_via_t *dev); static void ac97_via_speed_changed(void *priv); @@ -127,27 +127,18 @@ ac97_via_write_control(void *priv, uint8_t modem, uint8_t val) ac97_via_log("AC97 VIA %d: write_control(%02X)\n", modem, val); - if (!modem) { - /* Set the variable sample rate flag now, so that the upcoming - update_codec can properly update the poller timer interval. */ - dev->vsr_enabled = !!(val & 0x08); - } - - /* Reset and/or update volumes on all codecs. */ - for (i = 0; i <= 1; i++) { - if (!dev->codec[modem][i]) - continue; - - /* Reset codec if requested. */ - if (!(val & 0x40)) - ac97_codec_reset(dev->codec[modem][i]); - - /* Update primary codec state. */ - if (!modem && !i) - ac97_via_update_codec(dev, dev->codec[modem][i]); + /* Reset codecs if requested. */ + if (!(val & 0x40)) { + for (i = 0; i <= 1; i++) { + if (dev->codec[modem][i]) + ac97_codec_reset(dev->codec[modem][i]); + } } if (!modem) { + /* Set the variable sample rate flag. */ + dev->vsr_enabled = (val & 0xf8) == 0xc8; + /* Start or stop PCM playback. */ i = (val & 0xf4) == 0xc4; if (i && !dev->pcm_enabled) @@ -159,6 +150,10 @@ ac97_via_write_control(void *priv, uint8_t modem, uint8_t val) if (i && !dev->fm_enabled) timer_advance_u64(&dev->timer_count_fm, dev->timer_latch); dev->fm_enabled = i; + + /* Update primary audio codec state. */ + if (dev->codec[0][0]) + ac97_via_update_codec(dev); } } @@ -167,12 +162,10 @@ static void ac97_via_update_irqs(ac97_via_t *dev) { /* Check interrupt flags in all SGDs. */ - uint8_t i, sgd_id; - for (i = 0; i < (sizeof(dev->sgd) / sizeof(dev->sgd[0])); i++) { - sgd_id = i << 4; + for (uint8_t i = 0x00; i < ((sizeof(dev->sgd) / sizeof(dev->sgd[0])) << 4); i += 0x10) { /* Stop immediately if any flag is set. Doing it this way optimizes rising edges for the playback SGD (0 - first to be checked). */ - if (dev->sgd_regs[sgd_id] & (dev->sgd_regs[sgd_id | 0x2] & 0x03)) { + if (dev->sgd_regs[i] & (dev->sgd_regs[i | 0x2] & 0x03)) { pci_set_irq(dev->slot, dev->irq_pin); return; } @@ -183,13 +176,16 @@ ac97_via_update_irqs(ac97_via_t *dev) static void -ac97_via_update_codec(ac97_via_t *dev, ac97_codec_t *codec) { +ac97_via_update_codec(ac97_via_t *dev) { + /* Get primary audio codec. */ + ac97_codec_t *codec = dev->codec[0][0]; + /* Update volumes according to codec registers. */ ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); ac97_codec_getattn(codec, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r); ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r); - /* Update sample rate according to codec registers and the variable sample rate bit. */ + /* Update sample rate according to codec registers and the variable sample rate flag. */ ac97_via_speed_changed(dev); } @@ -388,9 +384,9 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) val |= 1; ac97_codec_write(codec, val, dev->codec_shadow[modem].regs_codec[i][val] = dev->sgd_regs[0x81]); - /* Update primary codec state. */ + /* Update primary audio codec state if that codec was written to. */ if (!modem && !i) - ac97_via_update_codec(dev, codec); + ac97_via_update_codec(dev); } /* Flag data/status/index for this codec as valid. */