coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
ac97.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <device/device.h>
5 #include <device/pci.h>
6 #include <device/pci_ids.h>
7 #include <arch/io.h>
8 #include <device/pci_ops.h>
9 #include <delay.h>
10 #include "i82801dx.h"
11 
12 #define NAMBAR 0x10
13 #define MASTER_VOL 0x02
14 #define PAGING 0x24
15 #define EXT_AUDIO 0x28
16 #define FUNC_SEL 0x66
17 #define INFO_IO 0x68
18 #define CONNECTOR 0x6a
19 #define VENDOR_ID1 0x7c
20 #define VENDOR_ID2 0x7e
21 #define SEC_VENDOR_ID1 0xfc
22 #define SEC_VENDOR_ID2 0xfe
23 
24 #define NABMBAR 0x14
25 #define GLOB_CNT 0x2c
26 #define GLOB_STA 0x30
27 #define CAS 0x34
28 
29 #define MMBAR 0x10
30 #define EXT_MODEM_ID1 0x3c
31 #define EXT_MODEM_ID2 0xbc
32 
33 #define MBAR 0x14
34 #define SEC_CODEC 0x40
35 
36 /* FIXME. This table is probably mainboard specific */
37 static u16 ac97_function[16*2][4] = {
38  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
39  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
40  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
41  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
42  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
43  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
44  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
45  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
46  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
47  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
48  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
49  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
50  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
51  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
52  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
53  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
54  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
55  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
56  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
57  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
58  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
59  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
60  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
61  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
62  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
63  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
64  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
65  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
66  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
67  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
68  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
69  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }
70 };
71 
72 static u16 nabmbar;
73 static u16 nambar;
74 
75 static int ac97_semaphore(void)
76 {
77  int timeout;
78  u8 reg8;
79 
80  timeout = 0xffff;
81  do {
82  reg8 = inb(nabmbar + CAS);
83  timeout--;
84  } while ((reg8 & 1) && timeout);
85  if (! timeout) {
86  printk(BIOS_DEBUG, "Timeout!\n");
87  }
88 
89  return (!timeout);
90 }
91 
92 static void init_cnr(void)
93 {
94  // TODO
95 }
96 
97 static void program_sigid(struct device *dev, u32 id)
98 {
99  pci_write_config32(dev, 0x2c, id);
100 }
101 
102 static void ac97_audio_init(struct device *dev)
103 {
104  u16 reg16;
105  u32 reg32;
106  int i;
107 
108  printk(BIOS_DEBUG, "Initializing AC'97 Audio.\n");
109 
110  /* top 16 bits are zero, so don't read them */
111  nabmbar = pci_read_config16(dev, NABMBAR) & 0xfffe;
112  nambar = pci_read_config16(dev, NAMBAR) & 0xfffe;
113 
114  reg16 = inw(nabmbar + GLOB_CNT);
115  reg16 |= (1 << 1); /* Remove AC_RESET# */
116  outw(reg16, nabmbar + GLOB_CNT);
117 
118  /* Wait 600ms. Ouch. */
119  udelay(600 * 1000);
120 
121  init_cnr();
122 
123  /* Detect Primary AC'97 Codec */
124  reg32 = inl(nabmbar + GLOB_STA);
125  if ((reg32 & ((1 << 28) | (1 << 9) | (1 << 8))) == 0) {
126  /* Primary Codec not found */
127  printk(BIOS_DEBUG, "No primary codec. Disabling AC'97 Audio.\n");
128  return;
129  }
130 
131  ac97_semaphore();
132 
133  /* Detect if codec is programmable */
134  outw(0x8000, nambar + MASTER_VOL);
135  ac97_semaphore();
136  if (inw(nambar + MASTER_VOL) != 0x8000) {
137  printk(BIOS_DEBUG, "Codec not programmable. Disabling AC'97 Audio.\n");
138  return;
139  }
140 
141  /* Program Vendor IDs */
142  reg32 = inw(nambar + VENDOR_ID1);
143  reg32 <<= 16;
144  reg32 |= (u16)inw(nambar + VENDOR_ID2);
145 
146  program_sigid(dev, reg32);
147 
148  /* Is Codec AC'97 2.3 compliant? */
149  reg16 = inw(nambar + EXT_AUDIO);
150  /* [11:10] = 10b -> AC'97 2.3 */
151  if ((reg16 & 0x0c00) != 0x0800) {
152  /* No 2.3 Codec. We're done */
153  return;
154  }
155 
156  /* Select Page 1 */
157  reg16 = inw(nambar + PAGING);
158  reg16 &= 0xfff0;
159  reg16 |= 0x0001;
160  outw(reg16, nambar + PAGING);
161 
162  for (i = 0x0a * 2; i > 0; i--) {
163  outw(i, nambar + FUNC_SEL);
164 
165  /* Function could not be selected. Next one */
166  if (inw(nambar + FUNC_SEL) != i)
167  continue;
168 
169  reg16 = inw(nambar + INFO_IO);
170 
171  /* Function Information present? */
172  if (!(reg16 & (1 << 0)))
173  continue;
174 
175  /* Function Information valid? */
176  if (!(reg16 & (1 << 4)))
177  continue;
178 
179  /* Program Buffer Delay [9:5] */
180  reg16 &= 0x03e0;
181  reg16 |= ac97_function[i][0];
182 
183  /* Program Gain [15:11] */
184  reg16 |= ac97_function[i][1];
185 
186  /* Program Inversion [10] */
187  reg16 |= ac97_function[i][2];
188 
189  outw(reg16, nambar + INFO_IO);
190 
191  /* Program Connector / Jack Location */
192  reg16 = inw(nambar + CONNECTOR);
193  reg16 &= 0x1fff;
194  reg16 |= ac97_function[i][3];
195  outw(reg16, nambar + CONNECTOR);
196  }
197 }
198 
199 static void ac97_modem_init(struct device *dev)
200 {
201  u16 reg16;
202  u32 reg32;
203  u16 mmbar, mbar;
204 
205  mmbar = pci_read_config16(dev, MMBAR) & 0xfffe;
206  mbar = pci_read_config16(dev, MBAR) & 0xfffe;
207 
208  reg16 = inw(mmbar + EXT_MODEM_ID1);
209  if ((reg16 & 0xc000) != 0xc000) {
210  if (reg16 & (1 << 0)) {
211  reg32 = inw(mmbar + VENDOR_ID2);
212  reg32 <<= 16;
213  reg32 |= (u16)inw(mmbar + VENDOR_ID1);
214  program_sigid(dev, reg32);
215  return;
216  }
217  }
218 
219  /* Secondary codec? */
220  reg16 = inw(mbar + SEC_CODEC);
221  if ((reg16 & (1 << 9)) == 0)
222  return;
223 
224  reg16 = inw(mmbar + EXT_MODEM_ID2);
225  if ((reg16 & 0xc000) == 0x4000) {
226  if (reg16 & (1 << 0)) {
227  reg32 = inw(mmbar + SEC_VENDOR_ID2);
228  reg32 <<= 16;
229  reg32 |= (u16)inw(mmbar + SEC_VENDOR_ID1);
230  program_sigid(dev, reg32);
231  return;
232  }
233  }
234 }
235 
236 static struct device_operations ac97_audio_ops = {
238  .set_resources = pci_dev_set_resources,
239  .enable_resources = pci_dev_enable_resources,
240  .enable = i82801dx_enable,
241  .init = ac97_audio_init,
242 };
243 
244 static struct device_operations ac97_modem_ops = {
246  .set_resources = pci_dev_set_resources,
247  .enable_resources = pci_dev_enable_resources,
248  .enable = i82801dx_enable,
249  .init = ac97_modem_init,
250 };
251 
252 /* 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) */
253 static const struct pci_driver i82801db_ac97_audio __pci_driver = {
254  .ops = &ac97_audio_ops,
255  .vendor = PCI_VID_INTEL,
257 };
258 
259 static const struct pci_driver i82801db_ac97_modem __pci_driver = {
260  .ops = &ac97_modem_ops,
261  .vendor = PCI_VID_INTEL,
263 };
#define printk(level,...)
Definition: stdlib.h:16
u8 inb(u16 port)
u16 inw(u16 port)
u32 inl(u16 port)
void outw(u16 val, u16 port)
#define VENDOR_ID2
Definition: ac97.c:20
static void program_sigid(struct device *dev, u32 id)
Definition: ac97.c:97
#define MMBAR
Definition: ac97.c:29
static void ac97_audio_init(struct device *dev)
Definition: ac97.c:102
static const struct pci_driver i82801db_ac97_audio __pci_driver
Definition: ac97.c:253
#define FUNC_SEL
Definition: ac97.c:16
#define INFO_IO
Definition: ac97.c:17
#define SEC_CODEC
Definition: ac97.c:34
#define CONNECTOR
Definition: ac97.c:18
static u16 ac97_function[16 *2][4]
Definition: ac97.c:37
static struct device_operations ac97_modem_ops
Definition: ac97.c:244
#define VENDOR_ID1
Definition: ac97.c:19
static int ac97_semaphore(void)
Definition: ac97.c:75
#define MBAR
Definition: ac97.c:33
static void ac97_modem_init(struct device *dev)
Definition: ac97.c:199
#define GLOB_STA
Definition: ac97.c:26
#define EXT_AUDIO
Definition: ac97.c:15
static u16 nambar
Definition: ac97.c:73
static u16 nabmbar
Definition: ac97.c:72
#define SEC_VENDOR_ID2
Definition: ac97.c:22
static void init_cnr(void)
Definition: ac97.c:92
#define GLOB_CNT
Definition: ac97.c:25
#define NABMBAR
Definition: ac97.c:24
#define MASTER_VOL
Definition: ac97.c:13
#define EXT_MODEM_ID2
Definition: ac97.c:31
#define SEC_VENDOR_ID1
Definition: ac97.c:21
static struct device_operations ac97_audio_ops
Definition: ac97.c:236
#define CAS
Definition: ac97.c:27
#define EXT_MODEM_ID1
Definition: ac97.c:30
#define NAMBAR
Definition: ac97.c:12
#define PAGING
Definition: ac97.c:14
void i82801dx_enable(struct device *dev)
Definition: i82801dx.c:8
static __always_inline void pci_write_config32(const struct device *dev, u16 reg, u32 val)
Definition: pci_ops.h:76
static __always_inline u16 pci_read_config16(const struct device *dev, u16 reg)
Definition: pci_ops.h:52
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
void pci_dev_enable_resources(struct device *dev)
Definition: pci_device.c:721
void pci_dev_read_resources(struct device *dev)
Definition: pci_device.c:534
void pci_dev_set_resources(struct device *dev)
Definition: pci_device.c:691
#define PCI_VID_INTEL
Definition: pci_ids.h:2157
#define PCI_DID_INTEL_82801DB_AC97_MODEM
Definition: pci_ids.h:2280
#define PCI_DID_INTEL_82801DB_AC97_AUDIO
Definition: pci_ids.h:2279
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
void(* read_resources)(struct device *dev)
Definition: device.h:39
Definition: device.h:107
void udelay(uint32_t us)
Definition: udelay.c:15