1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #![allow(dead_code)] 6 7 // Audio Mixer Registers 8 // 00h Reset 9 // 02h Master Volume Mute 10 // 04h Headphone Volume Mute 11 // 06h Master Volume Mono Mute 12 // 08h Master Tone (R & L) 13 // 0Ah PC_BEEP Volume Mute 14 // 0Ch Phone Volume Mute 15 // 0Eh Mic Volume Mute 16 // 10h Line In Volume Mute 17 // 12h CD Volume Mute 18 // 14h Video Volume Mute 19 // 16h Aux Volume Mute 20 // 18h PCM Out Volume Mute 21 // 1Ah Record Select 22 // 1Ch Record Gain Mute 23 // 1Eh Record Gain Mic Mute 24 // 20h General Purpose 25 // 22h 3D Control 26 // 24h AC’97 RESERVED 27 // 26h Powerdown Ctrl/Stat 28 // 28h Extended Audio ID 29 // 2Ah Extended Audio Status and Control 30 // 2CH PCM Front DAC Rate 31 // 2Eh PCM Surr DAC Rate 32 // 30h PCM LFE DAC Rate 33 // 32h PCM L/R ADC Rate 34 // 34h PCM MIC ADC Rate 35 36 // Size of IO register regions 37 pub const MIXER_REGS_SIZE: u64 = 0x100; 38 pub const MASTER_REGS_SIZE: u64 = 0x400; 39 40 pub const MIXER_RESET_00: u64 = 0x00; 41 pub const MIXER_MASTER_VOL_MUTE_02: u64 = 0x02; 42 pub const MIXER_MIC_VOL_MUTE_0E: u64 = 0x0e; 43 pub const MIXER_PCM_OUT_VOL_MUTE_18: u64 = 0x18; 44 pub const MIXER_REC_VOL_MUTE_1C: u64 = 0x1c; 45 pub const MIXER_POWER_DOWN_CONTROL_26: u64 = 0x26; 46 pub const MIXER_EXTENDED_AUDIO_ID_28: u64 = 0x28; 47 pub const MIXER_EXTENDED_AUDIO_STATUS_CONTROL_28: u64 = 0x2a; 48 pub const MIXER_PCM_FRONT_DAC_RATE_2C: u64 = 0x2c; 49 pub const MIXER_PCM_SURR_DAC_RATE_2E: u64 = 0x2e; 50 pub const MIXER_PCM_LFE_DAC_RATE_30: u64 = 0x30; 51 pub const MIXER_VENDOR_ID1_7C: u64 = 0x7c; 52 pub const MIXER_VENDOR_ID2_7E: u64 = 0x7e; 53 54 // Extended Audio ID Bits. 55 pub const MIXER_EI_VRA: u16 = 0x0001; // Variable Rate Audio mode is available. 56 pub const MIXER_EI_CDAC: u16 = 0x0040; // PCM Center DAC is available. 57 pub const MIXER_EI_SDAC: u16 = 0x0080; // PCM Surround DAC is available. 58 pub const MIXER_EI_LDAC: u16 = 0x0100; // PCM LFE DAC is available. 59 60 // Basic capabilities for MIXER_RESET_00 61 pub const BC_DEDICATED_MIC: u16 = 0x0001; /* Dedicated Mic PCM In Tube */ 62 63 // Bus Master regs from ICH spec: 64 // 00h PI_BDBAR PCM In Buffer Descriptor list Base Address Register 65 // 04h PI_CIV PCM In Current Index Value 66 // 05h PI_LVI PCM In Last Valid Index 67 // 06h PI_SR PCM In Status Register 68 // 08h PI_PICB PCM In Position In Current Buffer 69 // 0Ah PI_PIV PCM In Prefetched Index Value 70 // 0Bh PI_CR PCM In Control Register 71 // 10h PO_BDBAR PCM Out Buffer Descriptor list Base Address Register 72 // 14h PO_CIV PCM Out Current Index Value 73 // 15h PO_LVI PCM Out Last Valid Index 74 // 16h PO_SR PCM Out Status Register 75 // 18h PO_PICB PCM Out Position In Current Buffer 76 // 1Ah PO_PIV PCM Out Prefetched Index Value 77 // 1Bh PO_CR PCM Out Control Register 78 // 20h MC_BDBAR Mic. In Buffer Descriptor list Base Address Register 79 // 24h PM_CIV Mic. In Current Index Value 80 // 25h MC_LVI Mic. In Last Valid Index 81 // 26h MC_SR Mic. In Status Register 82 // 28h MC_PICB Mic In Position In Current Buffer 83 // 2Ah MC_PIV Mic. In Prefetched Index Value 84 // 2Bh MC_CR Mic. In Control Register 85 // 2Ch GLOB_CNT Global Control 86 // 30h GLOB_STA Global Status 87 // 34h ACC_SEMA Codec Write Semaphore Register 88 89 // Global Control 90 pub const GLOB_CNT_2C: u64 = 0x2C; 91 pub const GLOB_CNT_COLD_RESET: u32 = 0x0000_0002; 92 pub const GLOB_CNT_WARM_RESET: u32 = 0x0000_0004; 93 pub const GLOB_CNT_STABLE_BITS: u32 = 0x0000_007f; // Bits not affected by reset. 94 95 // PCM 4/6 Enable bits 96 pub const GLOB_CNT_PCM_2: u32 = 0x0000_0000; // 2 tubes 97 pub const GLOB_CNT_PCM_4: u32 = 0x0010_0000; // 4 tubes 98 pub const GLOB_CNT_PCM_6: u32 = 0x0020_0000; // 6 tubes 99 pub const GLOB_CNT_PCM_246_MASK: u32 = GLOB_CNT_PCM_4 | GLOB_CNT_PCM_6; // tube mask 100 101 // Global status 102 pub const GLOB_STA_30: u64 = 0x30; 103 // Primary codec ready set and turn on D20:21 to support 4 and 6 tubes on PCM out. 104 pub const GLOB_STA_RESET_VAL: u32 = 0x0030_0100; 105 106 // glob_sta bits 107 pub const GS_MD3: u32 = 1 << 17; 108 pub const GS_AD3: u32 = 1 << 16; 109 pub const GS_RCS: u32 = 1 << 15; 110 pub const GS_B3S12: u32 = 1 << 14; 111 pub const GS_B2S12: u32 = 1 << 13; 112 pub const GS_B1S12: u32 = 1 << 12; 113 pub const GS_S1R1: u32 = 1 << 11; 114 pub const GS_S0R1: u32 = 1 << 10; 115 pub const GS_S1CR: u32 = 1 << 9; 116 pub const GS_S0CR: u32 = 1 << 8; 117 pub const GS_MINT: u32 = 1 << 7; 118 pub const GS_POINT: u32 = 1 << 6; 119 pub const GS_PIINT: u32 = 1 << 5; 120 pub const GS_RSRVD: u32 = 1 << 4 | 1 << 3; 121 pub const GS_MOINT: u32 = 1 << 2; 122 pub const GS_MIINT: u32 = 1 << 1; 123 pub const GS_GSCI: u32 = 1; 124 pub const GS_RO_MASK: u32 = GS_B3S12 125 | GS_B2S12 126 | GS_B1S12 127 | GS_S1CR 128 | GS_S0CR 129 | GS_MINT 130 | GS_POINT 131 | GS_PIINT 132 | GS_RSRVD 133 | GS_MOINT 134 | GS_MIINT; 135 pub const GS_VALID_MASK: u32 = 0x0003_ffff; 136 pub const GS_WCLEAR_MASK: u32 = GS_RCS | GS_S1R1 | GS_S0R1 | GS_GSCI; 137 138 pub const ACC_SEMA_34: u64 = 0x34; 139 140 // Audio funciton registers. 141 pub const CIV_OFFSET: u64 = 0x04; 142 pub const LVI_OFFSET: u64 = 0x05; 143 pub const SR_OFFSET: u64 = 0x06; 144 pub const PICB_OFFSET: u64 = 0x08; 145 pub const PIV_OFFSET: u64 = 0x0a; 146 pub const CR_OFFSET: u64 = 0x0b; 147 148 // Capture 149 pub const PI_BASE_00: u64 = 0x00; 150 pub const PI_BDBAR_00: u64 = PI_BASE_00; 151 pub const PI_CIV_04: u64 = PI_BASE_00 + CIV_OFFSET; 152 pub const PI_LVI_05: u64 = PI_BASE_00 + LVI_OFFSET; 153 pub const PI_SR_06: u64 = PI_BASE_00 + SR_OFFSET; 154 pub const PI_PICB_08: u64 = PI_BASE_00 + PICB_OFFSET; 155 pub const PI_PIV_0A: u64 = PI_BASE_00 + PIV_OFFSET; 156 pub const PI_CR_0B: u64 = PI_BASE_00 + CR_OFFSET; 157 158 // Play Out 159 pub const PO_BASE_10: u64 = 0x10; 160 pub const PO_BDBAR_10: u64 = PO_BASE_10; 161 pub const PO_CIV_14: u64 = PO_BASE_10 + CIV_OFFSET; 162 pub const PO_LVI_15: u64 = PO_BASE_10 + LVI_OFFSET; 163 pub const PO_SR_16: u64 = PO_BASE_10 + SR_OFFSET; 164 pub const PO_PICB_18: u64 = PO_BASE_10 + PICB_OFFSET; 165 pub const PO_PIV_1A: u64 = PO_BASE_10 + PIV_OFFSET; 166 pub const PO_CR_1B: u64 = PO_BASE_10 + CR_OFFSET; 167 168 // Microphone 169 pub const MC_BASE_20: u64 = 0x20; 170 pub const MC_BDBAR_20: u64 = MC_BASE_20; 171 pub const MC_CIV_24: u64 = MC_BASE_20 + CIV_OFFSET; 172 pub const MC_LVI_25: u64 = MC_BASE_20 + LVI_OFFSET; 173 pub const MC_SR_26: u64 = MC_BASE_20 + SR_OFFSET; 174 pub const MC_PICB_28: u64 = MC_BASE_20 + PICB_OFFSET; 175 pub const MC_PIV_2A: u64 = MC_BASE_20 + PIV_OFFSET; 176 pub const MC_CR_2B: u64 = MC_BASE_20 + CR_OFFSET; 177 178 // Status Register Bits. 179 pub const SR_DCH: u16 = 0x01; 180 pub const SR_CELV: u16 = 0x02; 181 pub const SR_LVBCI: u16 = 0x04; 182 pub const SR_BCIS: u16 = 0x08; 183 pub const SR_FIFOE: u16 = 0x10; 184 pub const SR_VALID_MASK: u16 = 0x1f; 185 pub const SR_WCLEAR_MASK: u16 = SR_FIFOE | SR_BCIS | SR_LVBCI; 186 pub const SR_RO_MASK: u16 = SR_DCH | SR_CELV; 187 pub const SR_INT_MASK: u16 = SR_BCIS | SR_LVBCI; 188 189 // Control Register Bits. 190 pub const CR_RPBM: u8 = 0x01; 191 pub const CR_RR: u8 = 0x02; 192 pub const CR_LVBIE: u8 = 0x04; 193 pub const CR_FEIE: u8 = 0x08; 194 pub const CR_IOCE: u8 = 0x10; 195 pub const CR_VALID_MASK: u8 = 0x1f; 196 pub const CR_DONT_CLEAR_MASK: u8 = CR_IOCE | CR_FEIE | CR_LVBIE; 197 198 // Mixer register bits 199 pub const MUTE_REG_BIT: u16 = 0x8000; 200 pub const VOL_REG_MASK: u16 = 0x003f; 201 pub const MIXER_VOL_MASK: u16 = 0x001f; 202 pub const MIXER_VOL_LEFT_SHIFT: usize = 8; 203 pub const MIXER_MIC_20DB: u16 = 0x0040; 204 // Powerdown reg 205 pub const PD_REG_STATUS_MASK: u16 = 0x000f; 206 pub const PD_REG_OUTPUT_MUTE_MASK: u16 = 0xb200; 207 pub const PD_REG_INPUT_MUTE_MASK: u16 = 0x0d00; 208 209 // Buffer descriptors are four bytes of pointer and 4 bytes of control/length. 210 pub const DESCRIPTOR_LENGTH: usize = 8; 211 pub const BD_IOC: u32 = 1 << 31; 212 213 /// The functions that are supported by the Ac97 subsystem. 214 #[derive(Debug, Copy, Clone, PartialEq)] 215 pub enum Ac97Function { 216 Input, 217 Output, 218 Microphone, 219 } 220 221 /// Registers for individual audio functions. 222 /// Each audio function in Ac97 gets a set of these registers. 223 #[derive(Clone, Default)] 224 pub struct Ac97FunctionRegs { 225 pub bdbar: u32, 226 pub civ: u8, 227 pub lvi: u8, 228 pub sr: u16, 229 pub picb: u16, 230 pub piv: u8, 231 pub cr: u8, 232 } 233 234 impl Ac97FunctionRegs { 235 /// Creates a new set of function registers, these can be used for the capture, playback, or 236 /// microphone functions. new() -> Self237 pub fn new() -> Self { 238 let mut regs = Ac97FunctionRegs { 239 sr: SR_DCH, 240 ..Default::default() 241 }; 242 regs.do_reset(); 243 regs 244 } 245 246 /// Reset all the registers to the PoR defaults. `sr` should be updated by `update_sr`. do_reset(&mut self)247 pub fn do_reset(&mut self) { 248 self.bdbar = 0; 249 self.civ = 0; 250 self.lvi = 0; 251 self.picb = 0; 252 self.piv = 0; 253 self.cr &= CR_DONT_CLEAR_MASK; 254 } 255 256 /// Read register 4, 5, and 6 as one 32 bit word. 257 /// According to the ICH spec, reading these three with one 32 bit access is allowed. atomic_status_regs(&self) -> u32258 pub fn atomic_status_regs(&self) -> u32 { 259 u32::from(self.civ) | u32::from(self.lvi) << 8 | u32::from(self.sr) << 16 260 } 261 262 /// Returns the mask for enabled interrupts. The returned mask represents the bits in the status 263 /// register that should trigger and interrupt. int_mask(&self) -> u16264 pub fn int_mask(&self) -> u16 { 265 let mut int_mask = 0; 266 if self.cr & CR_LVBIE != 0 { 267 int_mask |= SR_LVBCI; 268 } 269 if self.cr & CR_IOCE != 0 { 270 int_mask |= SR_BCIS; 271 } 272 int_mask 273 } 274 275 /// Sets the current buffer to the next buffer by updating CIV to PIV, and 276 /// updates related fields. move_to_next_buffer(&mut self)277 pub fn move_to_next_buffer(&mut self) { 278 self.civ = self.piv; 279 self.piv = (self.piv + 1) % 32; // move piv to the next buffer. 280 } 281 282 /// Returns irq status. has_irq(&self) -> bool283 pub fn has_irq(&self) -> bool { 284 self.sr & self.int_mask() != 0 285 } 286 } 287