blob: a7c33194a4f8de23386fa0ca5982ae181aa1b829 [file] [log] [blame]
Morgan Tsai1602dd52007-10-29 21:00:14 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Morgan Tsai1602dd52007-10-29 21:00:14 +00003 *
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.
Morgan Tsai1602dd52007-10-29 21:00:14 +000020 */
21
22#include <console/console.h>
23#include <device/device.h>
24#include <device/pci.h>
25#include <device/pci_ids.h>
26#include <device/pci_ops.h>
27#include <arch/io.h>
Carl-Daniel Hailfingera3588922007-11-05 22:21:27 +000028#include <delay.h>
Morgan Tsai1602dd52007-10-29 21:00:14 +000029#include "sis966.h"
30
Stefan Reinauereea66b72010-04-07 15:32:52 +000031u8 SiS_SiS7502_init[7][3]={
Morgan Tsai218c2652007-11-02 16:09:58 +000032{0x04, 0xFF, 0x07},
33{0x2C, 0xFF, 0x39},
34{0x2D, 0xFF, 0x10},
35{0x2E, 0xFF, 0x91},
Morgan Tsai1602dd52007-10-29 21:00:14 +000036{0x2F, 0xFF, 0x01},
37{0x04, 0xFF, 0x06},
38{0x00, 0x00, 0x00} //End of table
39};
40
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080041static int set_bits(void *port, u32 mask, u32 val)
Morgan Tsai1602dd52007-10-29 21:00:14 +000042{
Stefan Reinauereea66b72010-04-07 15:32:52 +000043 u32 dword;
Morgan Tsai1602dd52007-10-29 21:00:14 +000044 int count;
45
46 val &= mask;
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000047 dword = read32(port);
Morgan Tsai1602dd52007-10-29 21:00:14 +000048 dword &= ~mask;
49 dword |= val;
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000050 write32(port, dword);
Morgan Tsai1602dd52007-10-29 21:00:14 +000051
52 count = 50;
53 do {
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000054 dword = read32(port);
Morgan Tsai1602dd52007-10-29 21:00:14 +000055 dword &= mask;
56 udelay(100);
57 } while ((dword != val) && --count);
58
59 if(!count) return -1;
60
Morgan Tsai218c2652007-11-02 16:09:58 +000061 udelay(500);
Morgan Tsai1602dd52007-10-29 21:00:14 +000062 return 0;
63
64}
65
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080066static u32 send_verb(u8 *base, u32 verb)
Morgan Tsai1602dd52007-10-29 21:00:14 +000067{
Stefan Reinauereea66b72010-04-07 15:32:52 +000068 u32 dword;
Morgan Tsai218c2652007-11-02 16:09:58 +000069
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000070 dword = read32(base + 0x68);
Morgan Tsai1602dd52007-10-29 21:00:14 +000071 dword=dword|(unsigned long)0x0002;
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000072 write32(base + 0x68, dword);
Morgan Tsai218c2652007-11-02 16:09:58 +000073 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080074 dword = read32(base + 0x68);
Morgan Tsai1602dd52007-10-29 21:00:14 +000075 } while ((dword & 1)!=0);
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000076 write32(base + 0x60, verb);
Morgan Tsai218c2652007-11-02 16:09:58 +000077 udelay(500);
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000078 dword = read32(base + 0x68);
Morgan Tsai218c2652007-11-02 16:09:58 +000079 dword =(dword |0x1);
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000080 write32(base + 0x68, dword);
Morgan Tsai1602dd52007-10-29 21:00:14 +000081 do {
Morgan Tsai218c2652007-11-02 16:09:58 +000082 udelay(100);
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000083 dword = read32(base + 0x68);
Morgan Tsai1602dd52007-10-29 21:00:14 +000084 } while ((dword & 3) != 2);
85
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000086 dword = read32(base + 0x64);
Morgan Tsai1602dd52007-10-29 21:00:14 +000087 return dword;
Morgan Tsai1602dd52007-10-29 21:00:14 +000088}
89
90
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080091static int codec_detect(u8 *base)
Morgan Tsai1602dd52007-10-29 21:00:14 +000092{
Stefan Reinauereea66b72010-04-07 15:32:52 +000093 u32 dword;
Morgan Tsai1602dd52007-10-29 21:00:14 +000094 int idx=0;
95
96 /* 1 */ // controller reset
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000097 printk(BIOS_DEBUG, "controller reset\n");
Morgan Tsai218c2652007-11-02 16:09:58 +000098
Morgan Tsai1602dd52007-10-29 21:00:14 +000099 set_bits(base + 0x08, 1, 1);
Morgan Tsai218c2652007-11-02 16:09:58 +0000100
Morgan Tsai1602dd52007-10-29 21:00:14 +0000101 do{
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000102 dword = read32(base + 0x08)&0x1;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000103 if(idx++>1000) { printk(BIOS_DEBUG, "controller reset fail !!! \n"); break;}
Morgan Tsai1602dd52007-10-29 21:00:14 +0000104 } while (dword !=1);
Morgan Tsai218c2652007-11-02 16:09:58 +0000105
Morgan Tsai1602dd52007-10-29 21:00:14 +0000106 dword=send_verb(base,0x000F0000); // get codec VendorId and DeviceId
Morgan Tsai218c2652007-11-02 16:09:58 +0000107
Morgan Tsai1602dd52007-10-29 21:00:14 +0000108 if(dword==0) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000109 printk(BIOS_DEBUG, "No codec!\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000110 return 0;
111 }
112
Myles Watson08e0fb82010-03-22 16:33:25 +0000113 printk(BIOS_DEBUG, "Codec ID = %x\n", dword);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000114
Morgan Tsai1602dd52007-10-29 21:00:14 +0000115 dword=0x1;
116 return dword;
117
118}
119
Morgan Tsai1602dd52007-10-29 21:00:14 +0000120
Stefan Reinauereea66b72010-04-07 15:32:52 +0000121static u32 verb_data[] = {
Morgan Tsai218c2652007-11-02 16:09:58 +0000122
Morgan Tsai1602dd52007-10-29 21:00:14 +0000123//14
124 0x01471c10,
125 0x01471d40,
126 0x01471e01,
127 0x01471f01,
128//15
129 0x01571c12,
130 0x01571d10,
131 0x01571e01,
132 0x01571f01,
133//16
134 0x01671c11,
135 0x01671d60,
136 0x01671e01,
137 0x01671f01,
138//17
139 0x01771c14,
140 0x01771d20,
141 0x01771e01,
142 0x01771f01,
143//18
144 0x01871c40,
145 0x01871d98,
146 0x01871ea1,
147 0x01871f01,
148//19
149 0x01971c50,
150 0x01971d98,
151 0x01971ea1,
152 0x01971f02,
153//1a
154 0x01a71c4f,
155 0x01a71d30,
156 0x01a71e81,
157 0x01a71f01,
158//1b
159 0x01b71c20,
160 0x01b71d40,
161 0x01b71e01,
162 0x01b71f02,
163//1c
164 0x01c71cf0,
165 0x01c71d01,
166 0x01c71e33,
167 0x01c71f59,
168//1d
169 0x01d71c01,
170 0x01d71de6,
171 0x01d71e05,
172 0x01d71f40,
173//1e
174 0x01e71c30,
175 0x01e71d11,
176 0x01e71e44,
177 0x01e71f01,
178//1f
179 0x01f71c60,
180 0x01f71d61,
181 0x01f71ec4,
182 0x01f71f01,
183};
184
Stefan Reinauereea66b72010-04-07 15:32:52 +0000185static unsigned find_verb(u32 viddid, u32 **verb)
Morgan Tsai1602dd52007-10-29 21:00:14 +0000186{
187 if((viddid == 0x10ec0883) || (viddid == 0x10ec0882) || (viddid == 0x10ec0880)) return 0;
Stefan Reinauereea66b72010-04-07 15:32:52 +0000188 *verb = (u32 *)verb_data;
189 return sizeof(verb_data)/sizeof(u32);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000190}
191
192
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800193static void codec_init(u8 *base, int addr)
Morgan Tsai1602dd52007-10-29 21:00:14 +0000194{
Stefan Reinauereea66b72010-04-07 15:32:52 +0000195 u32 dword;
196 u32 *verb;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000197 unsigned verb_size;
198 int i;
199
200 /* 1 */
201 do {
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000202 dword = read32(base + 0x68);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000203 } while (dword & 1);
204
205 dword = (addr<<28) | 0x000f0000;
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000206 write32(base + 0x60, dword);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000207
208 do {
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000209 dword = read32(base + 0x68);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000210 } while ((dword & 3)!=2);
211
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000212 dword = read32(base + 0x64);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000213
214 /* 2 */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000215 printk(BIOS_DEBUG, "codec viddid: %08x\n", dword);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000216 verb_size = find_verb(dword, &verb);
217
218 if(!verb_size) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000219 printk(BIOS_DEBUG, "No verb!\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000220 return;
221 }
222
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000223 printk(BIOS_DEBUG, "verb_size: %d\n", verb_size);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000224 /* 3 */
225 for(i=0; i<verb_size; i++) {
226 send_verb(base,verb[i]);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000227 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000228 printk(BIOS_DEBUG, "verb loaded!\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000229}
230
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800231static void codecs_init(u8 *base, u32 codec_mask)
Morgan Tsai1602dd52007-10-29 21:00:14 +0000232{
Morgan Tsai1602dd52007-10-29 21:00:14 +0000233 codec_init(base, 0);
234 return;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000235}
236
237static void aza_init(struct device *dev)
238{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800239 u8 *base;
Morgan Tsai218c2652007-11-02 16:09:58 +0000240 struct resource *res;
Stefan Reinauereea66b72010-04-07 15:32:52 +0000241 u32 codec_mask;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000242
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800243 printk(BIOS_DEBUG, "AZALIA_INIT:---------->\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000244
245//-------------- enable AZA (SiS7502) -------------------------
246{
Stefan Reinauereea66b72010-04-07 15:32:52 +0000247 u8 temp8;
Morgan Tsai218c2652007-11-02 16:09:58 +0000248 int i=0;
249 while(SiS_SiS7502_init[i][0] != 0)
250 {
251 temp8 = pci_read_config8(dev, SiS_SiS7502_init[i][0]);
252 temp8 &= SiS_SiS7502_init[i][1];
253 temp8 |= SiS_SiS7502_init[i][2];
254 pci_write_config8(dev, SiS_SiS7502_init[i][0], temp8);
255 i++;
256 };
Morgan Tsai1602dd52007-10-29 21:00:14 +0000257}
258//-----------------------------------------------------------
259
260
Morgan Tsai218c2652007-11-02 16:09:58 +0000261 // put audio to D0 state
262 pci_write_config8(dev, 0x54,0x00);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000263
Morgan Tsai218c2652007-11-02 16:09:58 +0000264#if DEBUG_AZA
Morgan Tsai1602dd52007-10-29 21:00:14 +0000265{
Morgan Tsai218c2652007-11-02 16:09:58 +0000266 int i;
267
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800268 printk(BIOS_DEBUG, "****** Azalia PCI config ******");
269 printk(BIOS_DEBUG, "\n 03020100 07060504 0B0A0908 0F0E0D0C");
Morgan Tsai218c2652007-11-02 16:09:58 +0000270
271 for(i=0;i<0xff;i+=4){
272 if((i%16)==0){
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800273 printk(BIOS_DEBUG, "\n%02x: ", i);
Morgan Tsai218c2652007-11-02 16:09:58 +0000274 }
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800275 printk(BIOS_DEBUG, "%08x ", pci_read_config32(dev,i));
Morgan Tsai1602dd52007-10-29 21:00:14 +0000276 }
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800277 printk(BIOS_DEBUG, "\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000278}
Morgan Tsai218c2652007-11-02 16:09:58 +0000279#endif
Morgan Tsai1602dd52007-10-29 21:00:14 +0000280
281 res = find_resource(dev, 0x10);
282 if(!res)
283 return;
284
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800285 base = res2mmio(res, 0, 0);
286 printk(BIOS_DEBUG, "base = 0x%p\n", base);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000287
288 codec_mask = codec_detect(base);
289
290 if(codec_mask) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000291 printk(BIOS_DEBUG, "codec_mask = %02x\n", codec_mask);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000292 codecs_init(base, codec_mask);
293 }
294
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800295 printk(BIOS_DEBUG, "AZALIA_INIT:<----------\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000296}
297
298static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
299{
300 pci_write_config32(dev, 0x40,
301 ((device & 0xffff) << 16) | (vendor & 0xffff));
302}
303
304static struct pci_operations lops_pci = {
305 .set_subsystem = lpci_set_subsystem,
306};
307
308static struct device_operations aza_audio_ops = {
309 .read_resources = pci_dev_read_resources,
310 .set_resources = pci_dev_set_resources,
311 .enable_resources = pci_dev_enable_resources,
312// .enable = sis966_enable,
313 .init = aza_init,
314 .scan_bus = 0,
315 .ops_pci = &lops_pci,
316};
317
Stefan Reinauer83b52e72007-10-30 02:17:49 +0000318static const struct pci_driver azaaudio_driver __pci_driver = {
Morgan Tsai1602dd52007-10-29 21:00:14 +0000319 .ops = &aza_audio_ops,
320 .vendor = PCI_VENDOR_ID_SIS,
Morgan Tsai31e805d2007-11-14 01:34:02 +0000321 .device = PCI_DEVICE_ID_SIS_SIS966_HD_AUDIO,
Morgan Tsai1602dd52007-10-29 21:00:14 +0000322};