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 <device/pci_def.h>
8 #include <arch/io.h>
9 #include <device/pci_ops.h>
10 #include <delay.h>
11 #include "i82801gx.h"
12 
13 #define NAMBAR 0x10
14 #define MASTER_VOL 0x02
15 #define PAGING 0x24
16 #define EXT_AUDIO 0x28
17 #define FUNC_SEL 0x66
18 #define INFO_IO 0x68
19 #define CONNECTOR 0x6a
20 #define VENDOR_ID1 0x7c
21 #define VENDOR_ID2 0x7e
22 #define SEC_VENDOR_ID1 0xfc
23 #define SEC_VENDOR_ID2 0xfe
24 
25 #define NABMBAR 0x14
26 #define GLOB_CNT 0x2c
27 #define GLOB_STA 0x30
28 #define CAS 0x34
29 
30 #define MMBAR 0x10
31 #define EXT_MODEM_ID1 0x3c
32 #define EXT_MODEM_ID2 0xbc
33 
34 #define MBAR 0x14
35 #define SEC_CODEC 0x40
36 
37 /* FIXME. This table is probably mainboard specific */
38 static u16 ac97_function[16*2][4] = {
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  { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }
71 };
72 
73 static u16 nabmbar;
74 static u16 nambar;
75 
76 static int ac97_semaphore(void)
77 {
78  int timeout;
79  u8 reg8;
80 
81  timeout = 0xffff;
82  do {
83  reg8 = inb(nabmbar + CAS);
84  timeout--;
85  } while ((reg8 & 1) && timeout);
86  if (!timeout)
87  printk(BIOS_DEBUG, "Timeout!\n");
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 {
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  .init = ac97_audio_init,
241  .enable = i82801gx_enable,
242  .ops_pci = &pci_dev_ops_pci,
243 };
244 
245 static struct device_operations ac97_modem_ops = {
247  .set_resources = pci_dev_set_resources,
248  .enable_resources = pci_dev_enable_resources,
249  .init = ac97_modem_init,
250  .enable = i82801gx_enable,
251  .ops_pci = &pci_dev_ops_pci,
252 };
253 
254 /* 82801GB/GR/GDH/GBM/GHM (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH) */
255 /* Note: 82801GU (ICH7-U) doesn't have AC97 audio. */
256 static const struct pci_driver i82801gx_ac97_audio __pci_driver = {
257  .ops = &ac97_audio_ops,
258  .vendor = PCI_VID_INTEL,
259  .device = 0x27de,
260 };
261 
262 /* 82801GB/GR/GDH/GBM/GHM (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH) */
263 /* Note: 82801GU (ICH7-U) doesn't have AC97 modem. */
264 static const struct pci_driver i82801gx_ac97_modem __pci_driver = {
265  .ops = &ac97_modem_ops,
266  .vendor = PCI_VID_INTEL,
267  .device = 0x27dd,
268 };
#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:21
static void program_sigid(struct device *dev, u32 id)
Definition: ac97.c:97
#define MMBAR
Definition: ac97.c:30
static void ac97_audio_init(struct device *dev)
Definition: ac97.c:102
#define FUNC_SEL
Definition: ac97.c:17
static const struct pci_driver i82801gx_ac97_audio __pci_driver
Definition: ac97.c:256
#define INFO_IO
Definition: ac97.c:18
#define SEC_CODEC
Definition: ac97.c:35
#define CONNECTOR
Definition: ac97.c:19
static u16 ac97_function[16 *2][4]
Definition: ac97.c:38
static struct device_operations ac97_modem_ops
Definition: ac97.c:245
#define VENDOR_ID1
Definition: ac97.c:20
static int ac97_semaphore(void)
Definition: ac97.c:76
#define MBAR
Definition: ac97.c:34
static void ac97_modem_init(struct device *dev)
Definition: ac97.c:199
#define GLOB_STA
Definition: ac97.c:27
#define EXT_AUDIO
Definition: ac97.c:16
static u16 nambar
Definition: ac97.c:74
static u16 nabmbar
Definition: ac97.c:73
#define SEC_VENDOR_ID2
Definition: ac97.c:23
static void init_cnr(void)
Definition: ac97.c:92
#define GLOB_CNT
Definition: ac97.c:26
#define NABMBAR
Definition: ac97.c:25
#define MASTER_VOL
Definition: ac97.c:14
#define EXT_MODEM_ID2
Definition: ac97.c:32
#define SEC_VENDOR_ID1
Definition: ac97.c:22
static struct device_operations ac97_audio_ops
Definition: ac97.c:236
#define CAS
Definition: ac97.c:28
#define EXT_MODEM_ID1
Definition: ac97.c:31
#define NAMBAR
Definition: ac97.c:13
#define PAGING
Definition: ac97.c:15
void i82801gx_enable(struct device *dev)
Definition: i82801gx.c:54
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
#define PCI_SUBSYSTEM_VENDOR_ID
Definition: pci_def.h:83
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
struct pci_operations pci_dev_ops_pci
Default device operation for PCI devices.
Definition: pci_device.c:911
void pci_dev_set_resources(struct device *dev)
Definition: pci_device.c:691
#define PCI_VID_INTEL
Definition: pci_ids.h:2157
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