More AC97 work, including 48 KHz sample rate cap

This commit is contained in:
RichardG867
2021-07-29 00:47:39 -03:00
parent 8cf651db57
commit 89d6a67e86
3 changed files with 54 additions and 52 deletions

View File

@@ -124,13 +124,13 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
if (val & 0x40) { /* dispatch command if START is set */ if (val & 0x40) { /* dispatch command if START is set */
timer_bytes++; /* address */ timer_bytes++; /* address */
smbus_addr = (dev->addr >> 1); smbus_addr = dev->addr >> 1;
read = dev->addr & 0x01; read = dev->addr & 0x01;
cmd = (dev->ctl >> 2) & 0xf; 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); 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)) { if (!i2c_start(i2c_smbus, smbus_addr, read)) {
dev->next_stat = 0x04; dev->next_stat = 0x04;
break; break;

View File

@@ -106,11 +106,17 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val)
/* Read-only registers. */ /* Read-only registers. */
return; 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 0x03: /* Master Volume MSB */
case 0x05: /* Aux Out Volume MSB */ case 0x05: /* Aux Out Volume MSB */
val &= 0xbf; val &= 0xbf;
/* Convert 6-bit level 1xxxxx to 011111. */ /* Limit level to a maximum of 011111. */
if (val & 0x20) { if (val & 0x20) {
val &= ~0x20; val &= ~0x20;
val |= 0x1f; val |= 0x1f;
@@ -123,18 +129,6 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val)
val &= 0x80; val &= 0x80;
break; 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 */ case 0x0a: /* PC Beep Volume LSB */
val &= 0x1e; val &= 0x1e;
break; break;
@@ -177,9 +171,12 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val)
break; break;
case 0x2a: /* Extended Audio Status/Control LSB */ case 0x2a: /* Extended Audio Status/Control LSB */
#ifdef AC97_CODEC_FULL_RATE_RANGE /* enable DRA (double rate) support */
val &= 0x0b; val &= 0x0b;
#else
/* Reset DAC sample rates to 48 KHz if VRA is being cleared. */ val &= 0x09;
#endif
/* Reset DAC sample rates to 48 KHz (96 KHz with DRA) if VRA is being cleared. */
if (!(val & 0x01)) { if (!(val & 0x01)) {
for (i = 0x2c; i <= 0x30; i += 2) for (i = 0x2c; i <= 0x30; i += 2)
*((uint16_t *) &dev->regs[i]) = 48000; *((uint16_t *) &dev->regs[i]) = 48000;
@@ -192,16 +189,19 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val)
} }
break; break;
case 0x2c ... 0x31: /* DAC Rates */ case 0x2c ... 0x35: /* DAC/ADC Rates */
/* Writable only if VRA is set. */ /* Writable only if VRA/VRM is set. */
if (!(dev->regs[0x2a] & 0x01)) i = (reg >= 0x32) ? 0x08 : 0x01;
if (!(dev->regs[0x2a] & i))
return; return;
break;
case 0x32 ... 0x35: /* ADC Rates */ #ifndef AC97_CODEC_FULL_RATE_RANGE
/* Writable only if VRM is set. */ /* Limit to 48 KHz on MSB write. */
if (!(dev->regs[0x2a] & 0x08)) if ((reg & 1) && (((val << 8) | dev->regs[reg & 0x7e]) > 48000)) {
*((uint16_t *) &dev->regs[reg & 0x7e]) = 48000;
return; return;
}
#endif
break; break;
} }
@@ -232,10 +232,14 @@ ac97_codec_reset(void *priv)
dev->regs[0x26] = 0x0f; dev->regs[0x26] = 0x0f;
/* Set up variable sample rate support. */ /* Set up variable sample rate support. */
#ifdef AC97_CODEC_FULL_RATE_RANGE /* enable DRA (double rate) support */
dev->regs[0x28] = 0x0b; dev->regs[0x28] = 0x0b;
#else
dev->regs[0x28] = 0x09;
#endif
ac97_codec_write(dev, 0x2a, 0x00); /* reset DAC/ADC sample rates */ 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[0x29] = (dev->codec_id << 6) | 0x02;
dev->regs[0x7c] = dev->vendor_id >> 16; dev->regs[0x7c] = dev->vendor_id >> 16;
dev->regs[0x7d] = dev->vendor_id >> 24; 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. */ /* Get configured sample rate, which is always 48000 if VRA/VRM is not set. */
uint32_t ret = *((uint16_t *) &dev->regs[reg]); 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 this is a DAC, double sample rate if DRA is set. */
if ((reg < 0x32) && (dev->regs[0x2a] & 0x02)) if ((reg < 0x32) && (dev->regs[0x2a] & 0x02))
ret <<= 1; ret <<= 1;
#endif
ac97_codec_log("AC97 Codec %d: getrate(%02X) = %d\n", dev->codec_id, reg, ret); ac97_codec_log("AC97 Codec %d: getrate(%02X) = %d\n", dev->codec_id, reg, ret);

View File

@@ -85,7 +85,7 @@ ac97_via_log(const char *fmt, ...)
static void ac97_via_sgd_process(void *priv); 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); 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); ac97_via_log("AC97 VIA %d: write_control(%02X)\n", modem, val);
if (!modem) { /* Reset codecs if requested. */
/* Set the variable sample rate flag now, so that the upcoming if (!(val & 0x40)) {
update_codec can properly update the poller timer interval. */ for (i = 0; i <= 1; i++) {
dev->vsr_enabled = !!(val & 0x08); if (dev->codec[modem][i])
} ac97_codec_reset(dev->codec[modem][i]);
}
/* 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]);
} }
if (!modem) { if (!modem) {
/* Set the variable sample rate flag. */
dev->vsr_enabled = (val & 0xf8) == 0xc8;
/* Start or stop PCM playback. */ /* Start or stop PCM playback. */
i = (val & 0xf4) == 0xc4; i = (val & 0xf4) == 0xc4;
if (i && !dev->pcm_enabled) 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) if (i && !dev->fm_enabled)
timer_advance_u64(&dev->timer_count_fm, dev->timer_latch); timer_advance_u64(&dev->timer_count_fm, dev->timer_latch);
dev->fm_enabled = i; 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) ac97_via_update_irqs(ac97_via_t *dev)
{ {
/* Check interrupt flags in all SGDs. */ /* Check interrupt flags in all SGDs. */
uint8_t i, sgd_id; for (uint8_t i = 0x00; i < ((sizeof(dev->sgd) / sizeof(dev->sgd[0])) << 4); i += 0x10) {
for (i = 0; i < (sizeof(dev->sgd) / sizeof(dev->sgd[0])); i++) {
sgd_id = i << 4;
/* Stop immediately if any flag is set. Doing it this way optimizes /* Stop immediately if any flag is set. Doing it this way optimizes
rising edges for the playback SGD (0 - first to be checked). */ 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); pci_set_irq(dev->slot, dev->irq_pin);
return; return;
} }
@@ -183,13 +176,16 @@ ac97_via_update_irqs(ac97_via_t *dev)
static void 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. */ /* Update volumes according to codec registers. */
ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); 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, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r);
ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_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); ac97_via_speed_changed(dev);
} }
@@ -388,9 +384,9 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv)
val |= 1; val |= 1;
ac97_codec_write(codec, val, dev->codec_shadow[modem].regs_codec[i][val] = dev->sgd_regs[0x81]); 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) if (!modem && !i)
ac97_via_update_codec(dev, codec); ac97_via_update_codec(dev);
} }
/* Flag data/status/index for this codec as valid. */ /* Flag data/status/index for this codec as valid. */