// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * James Courtier-Dutton <James@superbug.co.uk> * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * Creative Labs, Inc. * * Routines for control of EMU10K1 chips
*/
/* Setup SPDIF Out Audio Enable */ /* The Audigy 2 Value has a separate SPDIF out, * so no need for a mixer switch
*/
snd_emu10k1_ptr20_write(emu, P17V_MIXER_SPDIF_ENABLE, 0, 0xFF000000);
tmp = inw(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */
outw(tmp, emu->port + A_IOCFG);
} if (emu->card_capabilities->spi_dac) { /* Audigy 2 ZS Notebook with DAC Wolfson WM8768/WM8568 */ int size, n;
size = ARRAY_SIZE(spi_dac_init); for (n = 0; n < size; n++)
snd_emu10k1_spi_write(emu, spi_dac_init[n]);
snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f);
tmp = inw(emu->port + A_IOCFG);
outw(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */
tmp = inw(emu->port + A_IOCFG);
size = ARRAY_SIZE(i2c_adc_init); for (n = 0; n < size; n++)
snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); for (n = 0; n < 4; n++) {
emu->i2c_capture_volume[n][0] = 0xcf;
emu->i2c_capture_volume[n][1] = 0xcf;
}
}
snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */
snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_256K); /* taken from original driver */
if (enable_ir) { /* enable IR for SB Live */ if (emu->card_capabilities->emu_model) {
; /* Disable all access to A_IOCFG for the emu1010 */
} elseif (emu->card_capabilities->i2c_adc) {
; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} elseif (emu->audigy) {
u16 reg = inw(emu->port + A_IOCFG);
outw(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
udelay(500);
outw(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
udelay(100);
outw(reg, emu->port + A_IOCFG);
} else { unsignedint reg = inl(emu->port + HCFG);
outl(reg | HCFG_GPOUT2, emu->port + HCFG);
udelay(500);
outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG);
udelay(100);
outl(reg, emu->port + HCFG);
}
}
if (emu->card_capabilities->emu_model) {
; /* Disable all access to A_IOCFG for the emu1010 */
} elseif (emu->card_capabilities->i2c_adc) {
; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} elseif (emu->audigy) { /* enable analog output */
u16 reg = inw(emu->port + A_IOCFG);
outw(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
}
if (emu->address_mode == 0) { /* use 16M in 4G */
outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG);
}
return 0;
}
staticvoid snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
{ /* * Enable the audio bit
*/
outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
/* Enable analog/digital outs on audigy */ if (emu->card_capabilities->emu_model) {
; /* Disable all access to A_IOCFG for the emu1010 */
} elseif (emu->card_capabilities->i2c_adc) {
; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} elseif (emu->audigy) {
outw(inw(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Unmute Analog now. Set GPO6 to 1 for Apollo. * This has to be done after init ALice3 I2SOut beyond 48KHz.
* So, sequence is important. */
outw(inw(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG);
} elseif (emu->card_capabilities->ca0108_chip) { /* audigy2 value */ /* Unmute Analog now. */
outw(inw(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG);
} else { /* Disable routing from AC97 line out to Front speakers */
outw(inw(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG);
}
}
#define EC_SPDIF0_SEL_SHIFT 15 #define EC_SPDIF1_SEL_SHIFT 17 #define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT) #define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT) #define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK) #define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK) #define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should * be incremented any time the EEPROM's
* format is changed. */
#define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */
/* Addresses for special values stored in to EEPROM */ #define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */ #define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */ #define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */
#define EC_LAST_PROMFILE_ADDR 0x2f
#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The * can be up to 30 characters in length * and is stored as a NULL-terminated * ASCII string. Any unused bytes must be
* filled with zeros */ #define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */
/* Most of this stuff is pretty self-evident. According to the hardware * dudes, we need to leave the ADCCAL bit low in order to avoid a DC * offset problem. Weird.
*/ #define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \
EC_TRIM_CSN)
/************************************************************************** * @func Clock bits into the Ecard's control latch. The Ecard uses a * control latch will is loaded bit-serially by toggling the Modem control * lines from function 2 on the E8010. This function hides these details * and presents the illusion that we are actually writing to a distinct * register.
*/
/************************************************************************** * @func Set the gain of the ECARD's CS3310 Trim/gain controller. The * trim value consists of a 16bit value which is composed of two * 8 bit gain/trim values, one for the left channel and one for the * right channel. The following table maps from the Gain/Attenuation * value in decibels into the corresponding bit pattern for a single * channel.
*/
/* Set up the initial settings */
emu->ecard_ctrl = EC_RAW_RUN_MODE |
EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) |
EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL);
/* Step 0: Set the codec type in the hardware control register
* and enable audio output */
hc_value = inl(emu->port + HCFG);
outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG);
inl(emu->port + HCFG);
/* Step 1: Turn off the led and deassert TRIM_CS */
snd_emu10k1_ecard_write(emu, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
/* Step 2: Calibrate the ADC and DAC */
snd_emu10k1_ecard_write(emu, EC_DACCAL | EC_LEDN | EC_TRIM_CSN);
/* Step 3: Wait for awhile; XXX We can't get away with this * under a real operating system; we'll need to block and wait that
* way. */
snd_emu10k1_wait(emu, 48000);
/* Step 4: Switch off the DAC and ADC calibration. Note * That ADC_CAL is actually an inverted signal, so we assert
* it here to stop calibration. */
snd_emu10k1_ecard_write(emu, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
/* Step 4: Switch into run mode */
snd_emu10k1_ecard_write(emu, emu->ecard_ctrl);
/* Step 5: Set the analog input gain */
snd_emu10k1_ecard_setadcgain(emu, EC_DEFAULT_ADC_GAIN);
/* Special initialisation routine * before the rest of the IO-Ports become active.
*/
special_port = emu->port + 0x38;
value = inl(special_port);
outl(0x00d00000, special_port);
value = inl(special_port);
outl(0x00d00001, special_port);
value = inl(special_port);
outl(0x00d0005f, special_port);
value = inl(special_port);
outl(0x00d0007f, special_port);
value = inl(special_port);
outl(0x0090007f, special_port);
value = inl(special_port);
snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */ /* Delay to give time for ADC chip to switch on. It needs 113ms */
msleep(200); return 0;
}
staticvoid snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
{
u32 tmp, tmp2; int err;
// The docking events clearly arrive prematurely - while the // Dock's FPGA seems to be successfully programmed, the Dock // fails to initialize subsequently if we don't give it some // time to "warm up" here.
msleep(200);
dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); if (err < 0) return;
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); if ((tmp & 0x1f) != 0x15) { /* FPGA failed to be programmed */
dev_err(emu->card->dev, "emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n",
tmp); return;
}
dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n");
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { /* Audio Dock attached */
snd_emu1010_load_dock_firmware(emu); /* Unmute all. Default is muted after a firmware load */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
} elseif (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) { /* Audio Dock removed */
dev_info(emu->card->dev, "emu1010: Audio Dock detached\n"); /* The hardware auto-mutes all, so we unmute again */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
}
}
spin_lock_irq(&emu->reg_lock); // This is the only thing that can actually happen.
emu->emu1010.clock_source = emu->emu1010.clock_fallback;
emu->emu1010.wclock = 1 - emu->emu1010.clock_source;
snd_emu1010_update_clock(emu);
spin_unlock_irq(&emu->reg_lock);
snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0);
snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
}
// The distinction of the IRQ status bits is unreliable, // so we dispatch later based on option card status. if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
emu1010_dock_event(emu);
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
emu1010_clock_event(emu);
snd_emu1010_fpga_unlock(emu);
}
staticvoid emu1010_interrupt(struct snd_emu10k1 *emu)
{ // We get an interrupt on each GPIO input pin change, but we // care only about the ones triggered by the dedicated pin.
u16 sts = inw(emu->port + A_GPIO);
u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000; if (!(sts & bit)) return;
schedule_work(&emu->emu1010.work);
}
/* * Current status of the driver: * ---------------------------- * * only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz) * * PCM device nb. 2: * 16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops * 16 x 32-bit capture - snd_emu10k1_capture_efx_ops
*/ staticint snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
{
u32 tmp, tmp2, reg; int err;
dev_info(emu->card->dev, "emu1010: Special config.\n");
/* Mute, and disable audio and lock cache, just in case.
* Proper init follows in snd_emu10k1_init(). */
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
emu->gpio_interrupt = emu1010_interrupt; // Note: The Audigy INTE is set later
snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE,
EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST | EMU_HANA_IRQ_WCLK_CHANGED);
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); // Clear pending IRQs
// The routes are all set to EMU_SRC_SILENCE due to the reset, // so it is safe to simply enable the outputs.
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
/* * The chip (at least the Audigy 2 CA0102 chip, but most likely others, too) * has a problem that from time to time it likes to do few DMA reads a bit * beyond its normal allocation and gets very confused if these reads get * blocked by a IOMMU. * * This behaviour has been observed for the first (reserved) page * (for which it happens multiple times at every playback), often for various * synth pages and sometimes for PCM playback buffers and the page table * memory itself. * * As a workaround let's widen these DMA allocations by an extra page if we * detect that the device is behind a non-passthrough IOMMU.
*/ staticvoid snd_emu10k1_detect_iommu(struct snd_emu10k1 *emu)
{ struct iommu_domain *domain;
emu->iommu_workaround = false;
domain = iommu_get_domain_for_dev(emu->card->dev); if (!domain || domain->type == IOMMU_DOMAIN_IDENTITY) return;
// The masks are not used for Audigy. // FIXME: these should come from the card_capabilites table. if (extin_mask == 0)
extin_mask = 0x3fcf; // EXTIN_* if (extout_mask == 0)
extout_mask = 0x7fff; // EXTOUT_*
emu->fx8010.extin_mask = extin_mask;
emu->fx8010.extout_mask = extout_mask;
emu->enable_ir = enable_ir;
if (emu->card_capabilities->ca_cardbus_chip) {
err = snd_emu10k1_cardbus_init(emu); if (err < 0) return err;
} if (emu->card_capabilities->ecard) {
err = snd_emu10k1_ecard_init(emu); if (err < 0) return err;
} elseif (emu->card_capabilities->emu_model) {
err = snd_emu10k1_emu1010_init(emu); if (err < 0) return err;
} else { /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version
does not support this, it shouldn't do any harm */
snd_emu10k1_ptr_write(emu, AC97SLOT, 0,
AC97SLOT_CNTR|AC97SLOT_LFE);
}
/* resore for spdif */ if (emu->audigy)
outw(emu->saved_a_iocfg, emu->port + A_IOCFG);
outl(emu->saved_hcfg, emu->port + HCFG);
val = emu->saved_ptr; for (reg = saved_regs; *reg != 0xff; reg++) for (i = 0; i < NUM_G; i++, val++)
snd_emu10k1_ptr_write(emu, *reg, i, *val); if (emu->audigy) { for (reg = saved_regs_audigy; *reg != 0xff; reg++) for (i = 0; i < NUM_G; i++, val++)
snd_emu10k1_ptr_write(emu, *reg, i, *val);
}
} #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.