1dc91ae45d47b65d0b983969db09fc2a0804633b
[coreboot.git] / src / southbridge / sis / sis966 / sis966_aza.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2004 Tyan Computer
5  * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer.
6  * Copyright (C) 2006,2007 AMD
7  * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD.
8  * Copyright (C) 2007 Silicon Integrated Systems Corp. (SiS)
9  * Written by Morgan Tsai <my_tsai@sis.com> for SiS.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
24  */
25
26 #include <console/console.h>
27 #include <device/device.h>
28 #include <device/pci.h>
29 #include <device/pci_ids.h>
30 #include <device/pci_ops.h>
31 #include <arch/io.h>
32 #include <delay.h>
33 #include "sis966.h"
34
35 uint8_t SiS_SiS7502_init[7][3]={
36 {0x04, 0xFF, 0x07},
37 {0x2C, 0xFF, 0x39},
38 {0x2D, 0xFF, 0x10},
39 {0x2E, 0xFF, 0x91},
40 {0x2F, 0xFF, 0x01},
41 {0x04, 0xFF, 0x06},
42 {0x00, 0x00, 0x00}                                      //End of table
43 };
44
45 static int set_bits(uint8_t *port, uint32_t mask, uint32_t val)
46 {
47         uint32_t dword;
48         int count;
49
50         val &= mask;
51         dword = read32(port);
52         dword &= ~mask;
53         dword |= val;
54         write32(port, dword);
55
56         count = 50;
57         do {
58                 dword = read32(port);
59                 dword &= mask;
60                 udelay(100);
61         } while ((dword != val) && --count);
62
63         if(!count) return -1;
64
65         udelay(500);
66         return 0;
67
68 }
69
70  uint32_t send_verb(uint8_t *base, uint32_t verb)
71 {
72
73
74      uint32_t dword;
75
76      dword = read32(base + 0x68);
77      dword=dword|(unsigned long)0x0002;
78      write32(base + 0x68, dword);
79      do {
80                 dword = read32(base + 0x68);
81      }  while ((dword & 1)!=0);
82      write32(base + 0x60, verb);
83      udelay(500);
84      dword = read32(base + 0x68);
85      dword =(dword |0x1);
86      write32(base + 0x68, dword);
87      do {
88                 udelay(100);
89                 dword = read32(base + 0x68);
90      } while ((dword & 3) != 2);
91
92      dword = read32(base + 0x64);
93      return dword;
94
95 }
96
97
98 static int codec_detect(uint8_t *base)
99 {
100         uint32_t dword;
101         int idx=0;
102
103         /* 1 */ // controller reset
104         printk_debug("controller reset\n");
105
106         set_bits(base + 0x08, 1, 1);
107
108       do{
109                 dword = read32(base + 0x08)&0x1;
110                 if(idx++>1000) { printk_debug("controller reset fail !!! \n"); break;}
111            } while (dword !=1);
112
113        dword=send_verb(base,0x000F0000); // get codec VendorId and DeviceId
114
115        if(dword==0) {
116                 printk_debug("No codec!\n");
117                 return 0;
118        }
119
120          printk_debug("Codec ID = %lx\n", dword);
121
122        dword=0x1;
123         return dword;
124
125 }
126
127
128 static uint32_t verb_data[] = {
129
130 //14
131         0x01471c10,
132         0x01471d40,
133         0x01471e01,
134         0x01471f01,
135 //15
136         0x01571c12,
137         0x01571d10,
138         0x01571e01,
139         0x01571f01,
140 //16
141         0x01671c11,
142         0x01671d60,
143         0x01671e01,
144         0x01671f01,
145 //17
146         0x01771c14,
147         0x01771d20,
148         0x01771e01,
149         0x01771f01,
150 //18
151         0x01871c40,
152         0x01871d98,
153         0x01871ea1,
154         0x01871f01,
155 //19
156         0x01971c50,
157         0x01971d98,
158         0x01971ea1,
159         0x01971f02,
160 //1a
161         0x01a71c4f,
162         0x01a71d30,
163         0x01a71e81,
164         0x01a71f01,
165 //1b
166         0x01b71c20,
167         0x01b71d40,
168         0x01b71e01,
169         0x01b71f02,
170 //1c
171         0x01c71cf0,
172         0x01c71d01,
173         0x01c71e33,
174         0x01c71f59,
175 //1d
176         0x01d71c01,
177         0x01d71de6,
178         0x01d71e05,
179         0x01d71f40,
180 //1e
181         0x01e71c30,
182         0x01e71d11,
183         0x01e71e44,
184         0x01e71f01,
185 //1f
186         0x01f71c60,
187         0x01f71d61,
188         0x01f71ec4,
189         0x01f71f01,
190 };
191
192 static unsigned find_verb(uint32_t viddid, uint32_t **verb)
193 {
194         if((viddid == 0x10ec0883) || (viddid == 0x10ec0882) || (viddid == 0x10ec0880)) return 0;
195         *verb =  (uint32_t *)verb_data;
196         return sizeof(verb_data)/sizeof(uint32_t);
197 }
198
199
200 static void codec_init(uint8_t *base, int addr)
201 {
202         uint32_t dword;
203         uint32_t *verb;
204         unsigned verb_size;
205         int i;
206
207         /* 1 */
208         do {
209                 dword = read32(base + 0x68);
210         } while (dword & 1);
211
212         dword = (addr<<28) | 0x000f0000;
213         write32(base + 0x60, dword);
214
215         do {
216                 dword = read32(base + 0x68);
217         } while ((dword & 3)!=2);
218
219         dword = read32(base + 0x64);
220
221         /* 2 */
222         printk_debug("codec viddid: %08x\n", dword);
223         verb_size = find_verb(dword, &verb);
224
225         if(!verb_size) {
226                 printk_debug("No verb!\n");
227                 return;
228         }
229
230         printk_debug("verb_size: %d\n", verb_size);
231         /* 3 */
232         for(i=0; i<verb_size; i++) {
233                 send_verb(base,verb[i]);
234         }
235         printk_debug("verb loaded!\n");
236 }
237
238 static void codecs_init(uint8_t *base, uint32_t codec_mask)
239 {
240         codec_init(base, 0);
241         return;
242 }
243
244 static void aza_init(struct device *dev)
245 {
246         uint8_t *base;
247         struct resource *res;
248         uint32_t codec_mask;
249
250         print_debug("AZALIA_INIT:---------->\n");
251
252 //-------------- enable AZA (SiS7502) -------------------------
253 {
254         uint8_t  temp8;
255         int i=0;
256         while(SiS_SiS7502_init[i][0] != 0)
257         {
258                 temp8 = pci_read_config8(dev, SiS_SiS7502_init[i][0]);
259                 temp8 &= SiS_SiS7502_init[i][1];
260                 temp8 |= SiS_SiS7502_init[i][2];
261                 pci_write_config8(dev, SiS_SiS7502_init[i][0], temp8);
262                 i++;
263         };
264 }
265 //-----------------------------------------------------------
266
267
268         // put audio to D0 state
269         pci_write_config8(dev, 0x54,0x00);
270
271 #if DEBUG_AZA
272 {
273         int i;
274
275         print_debug("****** Azalia PCI config ******");
276         print_debug("\n    03020100  07060504  0B0A0908  0F0E0D0C");
277
278         for(i=0;i<0xff;i+=4){
279                 if((i%16)==0){
280                         print_debug("\r\n");
281                         print_debug_hex8(i);
282                         print_debug(": ");
283                 }
284                 print_debug_hex32(pci_read_config32(dev,i));
285                 print_debug("  ");
286         }
287         print_debug("\r\n");
288 }
289 #endif
290
291         res = find_resource(dev, 0x10);
292         if(!res)
293                 return;
294
295         base =(uint8_t *) res->base;
296         printk_debug("base = %08x\n", base);
297
298         codec_mask = codec_detect(base);
299
300         if(codec_mask) {
301                 printk_debug("codec_mask = %02x\n", codec_mask);
302                 codecs_init(base, codec_mask);
303         }
304
305         print_debug("AZALIA_INIT:<----------\n");
306 }
307
308 static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
309 {
310         pci_write_config32(dev, 0x40,
311                 ((device & 0xffff) << 16) | (vendor & 0xffff));
312 }
313
314 static struct pci_operations lops_pci = {
315         .set_subsystem  = lpci_set_subsystem,
316 };
317
318 static struct device_operations aza_audio_ops  = {
319         .read_resources = pci_dev_read_resources,
320         .set_resources  = pci_dev_set_resources,
321         .enable_resources       = pci_dev_enable_resources,
322 //      .enable         = sis966_enable,
323         .init           = aza_init,
324         .scan_bus       = 0,
325         .ops_pci        = &lops_pci,
326 };
327
328 static const struct pci_driver azaaudio_driver __pci_driver = {
329         .ops    = &aza_audio_ops,
330         .vendor = PCI_VENDOR_ID_SIS,
331         .device = PCI_DEVICE_ID_SIS_SIS966_HD_AUDIO,
332 };
333