This is so that people can see it. This is the sb600 for v3. It almost
[coreboot.git] / src / southbridge / amd / sb600 / hda.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include <types.h>
21 #include <lib.h>
22 #include <console.h>
23 #include <device/pci.h>
24 #include <msr.h>
25 #include <legacy.h>
26 #include <device/pci_ids.h>
27 #include <statictree.h>
28 #include <config.h>
29 #include "sb600.h"
30
31 static int set_bits(u8 * port, u32 mask, u32 val)
32 {
33         u32 dword;
34         int count;
35
36         val &= mask;
37         dword = readl(port);
38         dword &= ~mask;
39         dword |= val;
40         writel(dword, port);
41
42         count = 50;
43         do {
44                 dword = readl(port);
45                 dword &= mask;
46                 udelay(100);
47         } while ((dword != val) && --count);
48
49         if (!count)
50                 return -1;
51
52         udelay(540);
53         return 0;
54 }
55
56 static int codec_detect(u8 * base)
57 {
58         u32 dword;
59
60         /* 1 */
61         set_bits(base + 0x08, 1, 1);
62
63         /* 2 */
64         dword = readl(base + 0x0e);
65         dword |= 7;
66         writel(dword, base + 0x0e);
67
68         /* 3 */
69         set_bits(base + 0x08, 1, 0);
70
71         /* 4 */
72         set_bits(base + 0x08, 1, 1);
73
74         /* 5 */
75         dword = readl(base + 0xe);
76         dword &= 7;
77
78         /* 6 */
79         if (!dword) {
80                 set_bits(base + 0x08, 1, 0);
81                 printk(BIOS_DEBUG, "No codec!\n");
82                 return 0;
83         }
84         return dword;
85
86 }
87
88 static u32 cim_verb_data[] = {
89         0x01471c10,
90         0x01471d40,
91         0x01471e01,
92         0x01471f01,
93 /* 1 */
94         0x01571c12,
95         0x01571d10,
96         0x01571e01,
97         0x01571f01,
98 /* 2 */
99         0x01671c11,
100         0x01671d60,
101         0x01671e01,
102         0x01671f01,
103 /* 3 */
104         0x01771c14,
105         0x01771d20,
106         0x01771e01,
107         0x01771f01,
108 /* 4 */
109         0x01871c30,
110         0x01871d90,
111         0x01871ea1,
112         0x01871f01,
113 /* 5 */
114         0x01971cf0,
115         0x01971d11,
116         0x01971e11,
117         0x01971f41,
118 /* 6 */
119         0x01a71c80,
120         0x01a71d30,
121         0x01a71e81,
122         0x01a71f01,
123 /* 7 */
124         0x01b71cf0,
125         0x01b71d11,
126         0x01b71e11,
127         0x01b71f41,
128 /* 8 */
129         0x01c71cf0,
130         0x01c71d11,
131         0x01c71e11,
132         0x01c71f41,
133 /* 9 */
134         0x01d71cf0,
135         0x01d71d11,
136         0x01d71e11,
137         0x01d71f41,
138 /* 10 */
139         0x01e71c50,
140         0x01e71d11,
141         0x01e71e44,
142         0x01e71f01,
143 /* 11 */
144         0x01f71c60,
145         0x01f71d61,
146         0x01f71ec4,
147         0x01f71f01,
148 };
149 static unsigned find_verb(u32 viddid, u32 ** verb)
150 {
151         struct device * azalia_dev = dev_find_slot(0, PCI_DEVFN(0x14, 2));
152         struct southbridge_amd_sb600_dts_config *cfg =
153             (struct southbridge_amd_sb600_config *)azalia_dev->chip_info;
154         printk(BIOS_DEBUG, "Dev=%s\n", dev_path(azalia_dev));
155         printk(BIOS_DEBUG, "Default viddid=%x\n", cfg->hda_viddid);
156         printk(BIOS_DEBUG, "Reading viddid=%x\n", viddid);
157         if (!cfg)
158                 return 0;
159         if (viddid != cfg->hda_viddid)
160                 return 0;
161         *verb = (u32 *) cim_verb_data;
162         return sizeof(cim_verb_data) / sizeof(u32);
163 }
164
165 static void codec_init(u8 * base, int addr)
166 {
167         u32 dword;
168         u32 *verb;
169         u32 verb_size;
170         int i;
171
172         /* 1 */
173         do {
174                 dword = readl(base + 0x68);
175         } while (dword & 1);
176
177         dword = (addr << 28) | 0x000f0000;
178         writel(dword, base + 0x60);
179
180         do {
181                 dword = readl(base + 0x68);
182         } while ((dword & 3) != 2);
183
184         dword = readl(base + 0x64);
185
186         /* 2 */
187         printk(BIOS_DEBUG, "codec viddid: %08x\n", dword);
188         verb_size = find_verb(dword, &verb);
189
190         if (!verb_size) {
191                 printk(BIOS_DEBUG, "No verb!\n");
192                 return;
193         }
194
195         printk(BIOS_DEBUG, "verb_size: %d\n", verb_size);
196         /* 3 */
197         for (i = 0; i < verb_size; i++) {
198                 do {
199                         dword = readl(base + 0x68);
200                 } while (dword & 1);
201
202                 writel(verb[i], base + 0x60);
203
204                 do {
205                         dword = readl(base + 0x68);
206                 } while ((dword & 3) != 2);
207         }
208         printk(BIOS_DEBUG, "verb loaded!\n");
209 }
210
211 static void codecs_init(u8 * base, u32 codec_mask)
212 {
213         int i;
214         for (i = 2; i >= 0; i--) {
215                 if (codec_mask & (1 << i))
216                         codec_init(base, i);
217         }
218 }
219
220 static void hda_init(struct device *dev)
221 {
222         u8 *base;
223         struct resource *res;
224         u32 codec_mask;
225
226         /* SM Setting */
227         struct device * hda_dev;
228         hda_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
229         /* Set routing pin */
230         pci_write_config32(dev, 0xf8, 0x0);
231         pci_write_config8(dev, 0xfc, 0xAA);
232         /* Set INTA */
233         pci_write_config8(dev, 0x63, 0x0);
234         /* Enable azalia, disable ac97 */
235         pm_iowrite(0x59, 0xB);
236
237         res = find_resource(dev, 0x10);
238         if (!res)
239                 return;
240
241         base = (u8 *) ((u32)res->base);
242         printk(BIOS_DEBUG, "base = %08x\n", base);
243         codec_mask = codec_detect(base);
244
245         if (codec_mask) {
246                 printk(BIOS_DEBUG, "codec_mask = %02x\n", codec_mask);
247                 codecs_init(base, codec_mask);
248         }
249 }
250
251 static struct pci_operations lops_pci = {
252         .set_subsystem = pci_dev_set_subsystem,
253 };
254
255 struct device_operations sb600_hda = {
256         .id = {.type = DEVICE_ID_PCI,
257                 {.pci = {.vendor = PCI_VENDOR_ID_ATI,
258                               .device = PCI_DEVICE_ID_ATI_SB600_HDA}}},
259         .constructor             = default_device_constructor,
260         .phase4_read_resources   = pci_dev_read_resources,
261         .phase4_set_resources    = pci_dev_set_resources,
262         .phase5_enable_resources = pci_dev_enable_resources,
263         .phase6_init             = hda_init,
264         .ops_pci          = &lops_pci
265 };