blob: 632c5133ccee60e3bb6362d7c8f929e0cc5ba930 [file] [log] [blame]
Morgan Tsai1602dd52007-10-29 21:00:14 +00001/*
2 * This file is part of the LinuxBIOS 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/smbus.h>
29#include <device/pci.h>
30#include <device/pci_ids.h>
31#include <device/pci_ops.h>
32#include <arch/io.h>
33#include <delay.h>
34#include "sis966.h"
35
36
37uint8_t SiS_SiS191_init[6][3]={
Morgan Tsai218c2652007-11-02 16:09:58 +000038{0x04, 0xFF, 0x07},
39{0x2C, 0xFF, 0x39},
40{0x2D, 0xFF, 0x10},
41{0x2E, 0xFF, 0x91},
Morgan Tsai1602dd52007-10-29 21:00:14 +000042{0x2F, 0xFF, 0x01},
43{0x00, 0x00, 0x00} //End of table
44};
45
Morgan Tsai218c2652007-11-02 16:09:58 +000046
47#define StatusReg 0x1
Morgan Tsai1602dd52007-10-29 21:00:14 +000048#define SMI_READ 0x0
49#define SMI_REQUEST 0x10
50#define TRUE 1
51#define FALSE 0
52
53uint16_t MacAddr[3];
54
55
56void writeApcByte(int addr, uint8_t value)
57{
58 outb(addr,0x78);
Morgan Tsai218c2652007-11-02 16:09:58 +000059 outb(value,0x79);
Morgan Tsai1602dd52007-10-29 21:00:14 +000060}
61uint8_t readApcByte(int addr)
62{
63 uint8_t value;
64 outb(addr,0x78);
65 value=inb(0x79);
66 return(value);
67}
68
69static void readApcMacAddr(void)
70{
71 uint8_t i;
72
73// enable APC in south bridge sis966 D2F0
74
Morgan Tsai218c2652007-11-02 16:09:58 +000075 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +000076 outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data
77
78 printk_debug("MAC addr in APC = ");
Morgan Tsai218c2652007-11-02 16:09:58 +000079 for(i = 0x9 ; i <=0xe ; i++)
Morgan Tsai1602dd52007-10-29 21:00:14 +000080 {
81 printk_debug("%2.2x",readApcByte(i));
82 }
83 printk_debug("\n");
84
85 /* Set APC Reload */
86 writeApcByte(0x7,readApcByte(0x7)&0xf7);
87 writeApcByte(0x7,readApcByte(0x7)|0x0a);
Morgan Tsai218c2652007-11-02 16:09:58 +000088
Morgan Tsai1602dd52007-10-29 21:00:14 +000089 /* disable APC in south bridge */
Morgan Tsai218c2652007-11-02 16:09:58 +000090 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +000091 outl(inl(0xcfc)&0xffffffbf,0xcfc);
92}
93
94static void set_apc(struct device *dev)
95{
96 uint32_t tmp;
97 uint16_t addr;
98 uint32_t idx;
99 uint16_t i;
100 uint8_t bTmp;
101
102 /* enable APC in south bridge sis966 D2F0 */
Morgan Tsai218c2652007-11-02 16:09:58 +0000103 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000104 outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data
Morgan Tsai218c2652007-11-02 16:09:58 +0000105
Morgan Tsai1602dd52007-10-29 21:00:14 +0000106 for(i = 0 ; i <3; i++)
107 {
108 addr=0x9+2*i;
109 writeApcByte(addr,(uint8_t)(MacAddr[i]&0xFF));
110 writeApcByte(addr+1L,(uint8_t)((MacAddr[i]>>8)&0xFF));
111 // printf("%x - ",readMacAddrByte(0x59+i));
112 }
113
114 /* Set APC Reload */
115 writeApcByte(0x7,readApcByte(0x7)&0xf7);
116 writeApcByte(0x7,readApcByte(0x7)|0x0a);
Morgan Tsai218c2652007-11-02 16:09:58 +0000117
Morgan Tsai1602dd52007-10-29 21:00:14 +0000118 /* disable APC in south bridge */
Morgan Tsai218c2652007-11-02 16:09:58 +0000119 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000120 outl(inl(0xcfc)&0xffffffbf,0xcfc);
121
Morgan Tsai218c2652007-11-02 16:09:58 +0000122 // CFG reg0x73 bit=1, tell driver MAC Address load to APC
123 bTmp = pci_read_config8(dev, 0x73);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000124 bTmp|=0x1;
125 pci_write_config8(dev, 0x73, bTmp);
126}
127
128//-----------------------------------------------------------------------------
129// Procedure: ReadEEprom
130//
131// Description: This routine serially reads one word out of the EEPROM.
132//
133// Arguments:
134// Reg - EEPROM word to read.
135//
136// Returns:
137// Contents of EEPROM word (Reg).
138//-----------------------------------------------------------------------------
139#define LoopNum 200
140static unsigned long ReadEEprom( struct device *dev, uint32_t base, uint32_t Reg)
141{
142 uint16_t data;
143 uint32_t i;
144 uint32_t ulValue;
Morgan Tsai218c2652007-11-02 16:09:58 +0000145
146
Morgan Tsai1602dd52007-10-29 21:00:14 +0000147 ulValue = (0x80 | (0x2 << 8) | (Reg << 10)); //BIT_7
148
149 writel( ulValue,base+0x3c);
Morgan Tsai218c2652007-11-02 16:09:58 +0000150
Morgan Tsai1602dd52007-10-29 21:00:14 +0000151 mdelay(10);
152
153 for(i=0 ; i <= LoopNum; i++)
154 {
155 ulValue=readl(base+0x3c);
156
157 if(!(ulValue & 0x0080)) //BIT_7
158 break;
159
160 mdelay(100);
161 }
Morgan Tsai218c2652007-11-02 16:09:58 +0000162
Morgan Tsai1602dd52007-10-29 21:00:14 +0000163 mdelay(50);
164
165 if(i==LoopNum) data=0x10000;
166 else{
167 ulValue=readl(base+0x3c);
168 data = (uint16_t)((ulValue & 0xffff0000) >> 16);
Morgan Tsai218c2652007-11-02 16:09:58 +0000169 }
170
Morgan Tsai1602dd52007-10-29 21:00:14 +0000171 return data;
172}
173
174static int phy_read(uint32_t base, unsigned phy_addr, unsigned phy_reg)
175{
176 uint32_t ulValue;
177 unsigned loop = 0x100;
178 uint32_t Read_Cmd;
179 uint16_t usData;
180
181 uint16_t tmp;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000182
Morgan Tsai218c2652007-11-02 16:09:58 +0000183
184 Read_Cmd = ((phy_reg << 11) |
Morgan Tsai1602dd52007-10-29 21:00:14 +0000185 (phy_addr << 6) |
186 SMI_READ |
187 SMI_REQUEST);
188
189 // SmiMgtInterface Reg is the SMI management interface register(offset 44h) of MAC
190 writel( Read_Cmd,base+0x44);
191 //outl( Read_Cmd,tmp+0x44);
Morgan Tsai218c2652007-11-02 16:09:58 +0000192
Morgan Tsai1602dd52007-10-29 21:00:14 +0000193 // Polling SMI_REQ bit to be deasserted indicated read command completed
194 do
195 {
196 // Wait 20 usec before checking status
197 //StallAndWait(20);
198 mdelay(20);
Morgan Tsai218c2652007-11-02 16:09:58 +0000199 ulValue = readl(base+0x44);
200 //ulValue = inl(tmp+0x44);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000201 } while((ulValue & SMI_REQUEST) != 0);
Morgan Tsai218c2652007-11-02 16:09:58 +0000202 //printk_debug("base %x cmd %lx ret val %lx\n", tmp,Read_Cmd,ulValue);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000203 usData=(ulValue>>16);
204
Morgan Tsai218c2652007-11-02 16:09:58 +0000205
Morgan Tsai1602dd52007-10-29 21:00:14 +0000206
207 return usData;
208
209}
210
211// Detect a valid PHY
212// If there exist a valid PHY then return TRUE, else return FALSE
213static int phy_detect(uint32_t base,uint16_t *PhyAddr) //BOOL PHY_Detect()
214{
215 int bFoundPhy = FALSE;
216 uint32_t Read_Cmd;
217 uint16_t usData;
218 int PhyAddress = 0;
Morgan Tsai218c2652007-11-02 16:09:58 +0000219
220
Morgan Tsai1602dd52007-10-29 21:00:14 +0000221 // Scan all PHY address(0 ~ 31) to find a valid PHY
222 for(PhyAddress = 0; PhyAddress < 32; PhyAddress++)
Morgan Tsai218c2652007-11-02 16:09:58 +0000223 {
224 usData=phy_read(base,PhyAddress,StatusReg); // Status register is a PHY's register(offset 01h)
225
226 // Found a valid PHY
227
Morgan Tsai1602dd52007-10-29 21:00:14 +0000228 if((usData != 0x0) && (usData != 0xffff))
229 {
230 bFoundPhy = TRUE;
231 break;
232 }
233 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000234
Morgan Tsai1602dd52007-10-29 21:00:14 +0000235
236 if(!bFoundPhy)
237 {
238 printk_debug("PHY not found !!!! \n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000239 }
240
241 *PhyAddr=PhyAddress;
Morgan Tsai218c2652007-11-02 16:09:58 +0000242
Morgan Tsai1602dd52007-10-29 21:00:14 +0000243 return bFoundPhy;
244}
245
246
247static void nic_init(struct device *dev)
248{
Morgan Tsai218c2652007-11-02 16:09:58 +0000249 uint32_t dword, old;
250 uint32_t mac_h, mac_l;
251 int eeprom_valid = 0;
252 int val;
253 uint16_t PhyAddr;
254 struct southbridge_sis_sis966_config *conf;
255 static uint32_t nic_index = 0;
256 uint32_t base;
257 struct resource *res;
258 uint32_t reg;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000259
Morgan Tsai1602dd52007-10-29 21:00:14 +0000260
Morgan Tsai218c2652007-11-02 16:09:58 +0000261 print_debug("NIC_INIT:---------->\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000262
263
264//-------------- enable NIC (SiS19x) -------------------------
265{
266 uint8_t temp8;
267 int i=0;
268 while(SiS_SiS191_init[i][0] != 0)
Morgan Tsai218c2652007-11-02 16:09:58 +0000269 {
270 temp8 = pci_read_config8(dev, SiS_SiS191_init[i][0]);
271 temp8 &= SiS_SiS191_init[i][1];
272 temp8 |= SiS_SiS191_init[i][2];
273 pci_write_config8(dev, SiS_SiS191_init[i][0], temp8);
274 i++;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000275 };
276}
277//-----------------------------------------------------------
278
Morgan Tsai1602dd52007-10-29 21:00:14 +0000279{
Morgan Tsai218c2652007-11-02 16:09:58 +0000280 unsigned long i;
281 unsigned long ulValue;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000282
Morgan Tsai1602dd52007-10-29 21:00:14 +0000283 res = find_resource(dev, 0x10);
284
Morgan Tsai218c2652007-11-02 16:09:58 +0000285 if(!res)
286 {
287 printk_debug("NIC Cannot find resource..\r\n");
288 return;
289 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000290 base = res->base;
Morgan Tsai218c2652007-11-02 16:09:58 +0000291 printk_debug("NIC base address %lx\n",base);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000292
Morgan Tsai218c2652007-11-02 16:09:58 +0000293 if(!(val=phy_detect(base,&PhyAddr)))
294 {
295 printk_debug("PHY detect fail !!!!\r\n");
296 return;
297 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000298
Morgan Tsai218c2652007-11-02 16:09:58 +0000299 ulValue=readl(base + 0x38L); // check EEPROM existing
Morgan Tsai1602dd52007-10-29 21:00:14 +0000300
Morgan Tsai218c2652007-11-02 16:09:58 +0000301 if((ulValue & 0x0002))
302 {
Morgan Tsai1602dd52007-10-29 21:00:14 +0000303
Morgan Tsai218c2652007-11-02 16:09:58 +0000304 // read MAC address from EEPROM at first
305
Morgan Tsai1602dd52007-10-29 21:00:14 +0000306 // if that is valid we will use that
Morgan Tsai218c2652007-11-02 16:09:58 +0000307
Morgan Tsai1602dd52007-10-29 21:00:14 +0000308 printk_debug("EEPROM contents %x \n",ReadEEprom( dev, base, 0LL));
309 for(i=0;i<3;i++) {
310 //status = smbus_read_byte(dev_eeprom, i);
311 ulValue=ReadEEprom( dev, base, i+3L);
Morgan Tsai218c2652007-11-02 16:09:58 +0000312 if (ulValue ==0x10000) break; // error
313
314 MacAddr[i] =ulValue & 0xFFFF;
315
Morgan Tsai1602dd52007-10-29 21:00:14 +0000316 }
Morgan Tsai218c2652007-11-02 16:09:58 +0000317 }else{
318 // read MAC address from firmware
Morgan Tsai1602dd52007-10-29 21:00:14 +0000319 printk_debug("EEPROM invalid!!\nReg 0x38h=%.8lx \n",ulValue);
320 MacAddr[0]=readw(0xffffffc0); // mac address store at here
321 MacAddr[1]=readw(0xffffffc2);
322 MacAddr[2]=readw(0xffffffc4);
Morgan Tsai218c2652007-11-02 16:09:58 +0000323 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000324
Morgan Tsai218c2652007-11-02 16:09:58 +0000325 set_apc(dev);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000326
Morgan Tsai218c2652007-11-02 16:09:58 +0000327 readApcMacAddr();
Morgan Tsai1602dd52007-10-29 21:00:14 +0000328
Morgan Tsai218c2652007-11-02 16:09:58 +0000329#if DEBUG_NIC
Morgan Tsai1602dd52007-10-29 21:00:14 +0000330{
Morgan Tsai218c2652007-11-02 16:09:58 +0000331 int i;
332
333 print_debug("****** NIC PCI config ******");
334 print_debug("\n 03020100 07060504 0B0A0908 0F0E0D0C");
335
336 for(i=0;i<0xff;i+=4){
337 if((i%16)==0){
338 print_debug("\r\n");
339 print_debug_hex8(i);
340 print_debug(": ");
341 }
342 print_debug_hex32(pci_read_config32(dev,i));
343 print_debug(" ");
344 }
345 print_debug("\r\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000346}
347
Morgan Tsai218c2652007-11-02 16:09:58 +0000348
Morgan Tsai1602dd52007-10-29 21:00:14 +0000349#endif
350
351}
352
Morgan Tsai218c2652007-11-02 16:09:58 +0000353print_debug("NIC_INIT:<----------\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000354return;
355
356#define RegStationMgtInf 0x44
357#define PHY_RGMII 0x10000000
358
359 writel(PHY_RGMII, base + RegStationMgtInf);
360 conf = dev->chip_info;
361
362 if(conf->mac_eeprom_smbus != 0) {
363// read MAC address from EEPROM at first
364
365 struct device *dev_eeprom;
366 dev_eeprom = dev_find_slot_on_smbus(conf->mac_eeprom_smbus, conf->mac_eeprom_addr);
367
368 if(dev_eeprom) {
369 // if that is valid we will use that
370 unsigned char dat[6];
371 int status;
372 int i;
373 for(i=0;i<6;i++) {
374 status = smbus_read_byte(dev_eeprom, i);
375 if(status < 0) break;
376 dat[i] = status & 0xff;
377 }
378 if(status >= 0) {
379 mac_l = 0;
380 for(i=3;i>=0;i--) {
381 mac_l <<= 8;
382 mac_l += dat[i];
383 }
384 if(mac_l != 0xffffffff) {
385 mac_l += nic_index;
386 mac_h = 0;
387 for(i=5;i>=4;i--) {
388 mac_h <<= 8;
389 mac_h += dat[i];
390 }
391 eeprom_valid = 1;
392 }
393 }
394 }
395 }
Morgan Tsai218c2652007-11-02 16:09:58 +0000396
397// if that is invalid we will read that from romstrap
Morgan Tsai1602dd52007-10-29 21:00:14 +0000398 if(!eeprom_valid) {
399 unsigned long mac_pos;
400 mac_pos = 0xffffffd0; // refer to romstrap.inc and romstrap.lds
401 mac_l = readl(mac_pos) + nic_index; // overflow?
402 mac_h = readl(mac_pos + 4);
403
404 }
Morgan Tsai218c2652007-11-02 16:09:58 +0000405
406// set that into NIC MMIO
Morgan Tsai1602dd52007-10-29 21:00:14 +0000407#define NvRegMacAddrA 0xA8
408#define NvRegMacAddrB 0xAC
409 writel(mac_l, base + NvRegMacAddrA);
410 writel(mac_h, base + NvRegMacAddrB);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000411
412 nic_index++;
413
414#if CONFIG_PCI_ROM_RUN == 1
415 pci_dev_init(dev);// it will init option rom
416#endif
417
418}
419
Morgan Tsai1602dd52007-10-29 21:00:14 +0000420static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
421{
422 pci_write_config32(dev, 0x40,
423 ((device & 0xffff) << 16) | (vendor & 0xffff));
424}
425
426static struct pci_operations lops_pci = {
427 .set_subsystem = lpci_set_subsystem,
428};
429
430static struct device_operations nic_ops = {
431 .read_resources = pci_dev_read_resources,
432 .set_resources = pci_dev_set_resources,
433 .enable_resources = pci_dev_enable_resources,
434 .init = nic_init,
435 .scan_bus = 0,
436// .enable = sis966_enable,
437 .ops_pci = &lops_pci,
438};
Stefan Reinauer83b52e72007-10-30 02:17:49 +0000439static const struct pci_driver nic_driver __pci_driver = {
Morgan Tsai1602dd52007-10-29 21:00:14 +0000440 .ops = &nic_ops,
441 .vendor = PCI_VENDOR_ID_SIS,
442 .device = PCI_DEVICE_ID_SIS_SIS966_NIC1,
443};