blob: b40adb5e4bfe7a490777456f63ef17de8428e754 [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]={
38{0x04, 0xFF, 0x07},
39{0x2C, 0xFF, 0x39},
40{0x2D, 0xFF, 0x10},
41{0x2E, 0xFF, 0x91},
42{0x2F, 0xFF, 0x01},
43{0x00, 0x00, 0x00} //End of table
44};
45
46#if 1
47#define StatusReg 0x1
48#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);
59 outb(value,0x79);
60}
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
75 outl(0x80001048,0xcf8);
76 outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data
77
78 printk_debug("MAC addr in APC = ");
79 for(i = 0x9 ; i <=0xe ; i++)
80 {
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);
88
89 /* disable APC in south bridge */
90 outl(0x80001048,0xcf8);
91 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 */
103 outl(0x80001048,0xcf8);
104 outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data
105
106 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);
117
118 /* disable APC in south bridge */
119 outl(0x80001048,0xcf8);
120 outl(inl(0xcfc)&0xffffffbf,0xcfc);
121
122 // CFG reg0x73 bit=1, tell driver MAC Address load to APC
123 bTmp = pci_read_config8(dev, 0x73);
124 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;
145
146
147 ulValue = (0x80 | (0x2 << 8) | (Reg << 10)); //BIT_7
148
149 writel( ulValue,base+0x3c);
150
151 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 }
162
163 mdelay(50);
164
165 if(i==LoopNum) data=0x10000;
166 else{
167 ulValue=readl(base+0x3c);
168 data = (uint16_t)((ulValue & 0xffff0000) >> 16);
169 }
170
171 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;
182
183
184 Read_Cmd = ((phy_reg << 11) |
185 (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);
192
193 // 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);
199 ulValue = readl(base+0x44);
200 //ulValue = inl(tmp+0x44);
201 } while((ulValue & SMI_REQUEST) != 0);
202 //printk_debug("base %x cmd %lx ret val %lx\n", tmp,Read_Cmd,ulValue);
203 usData=(ulValue>>16);
204
205
206
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;
219
220
221 // Scan all PHY address(0 ~ 31) to find a valid PHY
222 for(PhyAddress = 0; PhyAddress < 32; PhyAddress++)
223 {
224 usData=phy_read(base,PhyAddress,StatusReg); // Status register is a PHY's register(offset 01h)
225
226 // Found a valid PHY
227
228 if((usData != 0x0) && (usData != 0xffff))
229 {
230 bFoundPhy = TRUE;
231 break;
232 }
233 }
234// printk_debug(" PHY_Addr=%x\n",PhyAddress);
235
236 //usData=phy_read(base,PhyAddress,0x0);
237 //printk_debug("PHY=%x\n",usData);
238
239 if(!bFoundPhy)
240 {
241 printk_debug("PHY not found !!!! \n");
242 // DisableMac();
243 }
244
245 *PhyAddr=PhyAddress;
246
247 return bFoundPhy;
248}
249
250
251static void nic_init(struct device *dev)
252{
253 uint32_t dword, old;
254 uint32_t mac_h, mac_l;
255 int eeprom_valid = 0;
256 int val;
257 uint16_t PhyAddr;
258 struct southbridge_sis_sis966_config *conf;
259
260 static uint32_t nic_index = 0;
261
262 uint32_t base;
263 struct resource *res;
264 uint32_t reg;
265
266
267printk_debug("SIS NIC init-------->\r\n");
268
269
270//-------------- enable NIC (SiS19x) -------------------------
271{
272 uint8_t temp8;
273 int i=0;
274 while(SiS_SiS191_init[i][0] != 0)
275 { temp8 = pci_read_config8(dev, SiS_SiS191_init[i][0]);
276 temp8 &= SiS_SiS191_init[i][1];
277 temp8 |= SiS_SiS191_init[i][2];
278 pci_write_config8(dev, SiS_SiS191_init[i][0], temp8);
279 i++;
280 };
281}
282//-----------------------------------------------------------
283
284
285
286
287{
288unsigned long i;
289unsigned long ulValue;
290
291#if 0
292for(i=0;i<0xFF;i+=4)
293{ if((i%16)==0)
294 {print_debug("\r\n");print_debug_hex8(i);print_debug(" ");}
295 print_debug_hex32(pci_read_config32(dev,i));
296 print_debug(" ");
297}
298print_debug("\r\n");
299#endif
300 res = find_resource(dev, 0x10);
301
302 if(!res) return;
303
304 base = res->base;
305printk_debug("NIC base address %lx\n",base);
306 if(!(val=phy_detect(base,&PhyAddr)))
307 {
308 printk_debug("PHY detect fail !!!!\r\n");
309 return;
310 }
311
312#if 0
313//------------ show op registers ----------------------
314{
315//device_t dev;
316int i;
317//dev = pci_locate_device(PCI_ID(0x1039, 0x5513), 0);
318printk_debug("NIC OP Registers \n");
319for(i=0;i<0xFF;i+=4)
320{ if((i%16)==0)
321 {print_debug("\r\n");print_debug_hex8(i);print_debug(" ");}
322 print_debug_hex32(readl(base+i));
323 print_debug(" ");
324}
325
326}
327
328//----------------------------------------------------
329#endif
330
331 ulValue=readl(base + 0x38L); // check EEPROM existing
332
333 if((ulValue & 0x0002))
334 {
335
336 // read MAC address from EEPROM at first
337
338 // if that is valid we will use that
339
340 printk_debug("EEPROM contents %x \n",ReadEEprom( dev, base, 0LL));
341 for(i=0;i<3;i++) {
342 //status = smbus_read_byte(dev_eeprom, i);
343 ulValue=ReadEEprom( dev, base, i+3L);
344 if (ulValue ==0x10000) break; // error
345
346 MacAddr[i] =ulValue & 0xFFFF;
347
348 }
349
350 }else{
351 // read MAC address from firmware
352 printk_debug("EEPROM invalid!!\nReg 0x38h=%.8lx \n",ulValue);
353 MacAddr[0]=readw(0xffffffc0); // mac address store at here
354 MacAddr[1]=readw(0xffffffc2);
355 MacAddr[2]=readw(0xffffffc4);
356 }
357
358
359#if 0
360// read MAC address from EEPROM at first
361printk_debug("MAC address in firmware trap \n");
362 for( i=0;i<3;i++)
363 printk_debug(" %4x\n",MacAddr[i]);
364 printk_debug("\n");
365#endif
366
367set_apc(dev);
368
369readApcMacAddr();
370
371#if 0
372{
373//device_t dev;
374int i;
375//dev = pci_locate_device(PCI_ID(0x1039, 0x5513), 0);
376printk_debug("NIC PCI config \n");
377for(i=0;i<0xFF;i+=4)
378{ if((i%16)==0)
379 {print_debug("\r\n");print_debug_hex8(i);print_debug(" ");}
380 print_debug_hex32(pci_read_config32(dev,i));
381 print_debug(" ");
382}
383
384}
385#endif
386
387}
388
389printk_debug("nic_init<--------\r\n");
390return;
391
392#define RegStationMgtInf 0x44
393#define PHY_RGMII 0x10000000
394
395 writel(PHY_RGMII, base + RegStationMgtInf);
396 conf = dev->chip_info;
397
398 if(conf->mac_eeprom_smbus != 0) {
399// read MAC address from EEPROM at first
400
401 struct device *dev_eeprom;
402 dev_eeprom = dev_find_slot_on_smbus(conf->mac_eeprom_smbus, conf->mac_eeprom_addr);
403
404 if(dev_eeprom) {
405 // if that is valid we will use that
406 unsigned char dat[6];
407 int status;
408 int i;
409 for(i=0;i<6;i++) {
410 status = smbus_read_byte(dev_eeprom, i);
411 if(status < 0) break;
412 dat[i] = status & 0xff;
413 }
414 if(status >= 0) {
415 mac_l = 0;
416 for(i=3;i>=0;i--) {
417 mac_l <<= 8;
418 mac_l += dat[i];
419 }
420 if(mac_l != 0xffffffff) {
421 mac_l += nic_index;
422 mac_h = 0;
423 for(i=5;i>=4;i--) {
424 mac_h <<= 8;
425 mac_h += dat[i];
426 }
427 eeprom_valid = 1;
428 }
429 }
430 }
431 }
432// if that is invalid we will read that from romstrap
433 if(!eeprom_valid) {
434 unsigned long mac_pos;
435 mac_pos = 0xffffffd0; // refer to romstrap.inc and romstrap.lds
436 mac_l = readl(mac_pos) + nic_index; // overflow?
437 mac_h = readl(mac_pos + 4);
438
439 }
440#if 1
441// set that into NIC MMIO
442#define NvRegMacAddrA 0xA8
443#define NvRegMacAddrB 0xAC
444 writel(mac_l, base + NvRegMacAddrA);
445 writel(mac_h, base + NvRegMacAddrB);
446#else
447// set that into NIC
448 pci_write_config32(dev, 0xa8, mac_l);
449 pci_write_config32(dev, 0xac, mac_h);
450#endif
451
452 nic_index++;
453
454#if CONFIG_PCI_ROM_RUN == 1
455 pci_dev_init(dev);// it will init option rom
456#endif
457
458}
459
460
461
462#else // orginal code
463
464tatic int phy_read(uint8_t *base, unsigned phy_addr, unsigned phy_reg)
465{
466 uint32_t dword;
467 unsigned loop = 0x100;
468 writel(0x8000, base+0x190); //Clear MDIO lock bit
469 mdelay(1);
470 dword = readl(base+0x190);
471 if(dword & (1<<15)) return -1;
472
473 writel(1, base+0x180);
474 writel((phy_addr<<5) | (phy_reg),base + 0x190);
475 do{
476 dword = readl(base + 0x190);
477 if(--loop==0) return -4;
478 } while ((dword & (1<<15)) );
479
480 dword = readl(base + 0x180);
481 if(dword & 1) return -3;
482
483 dword = readl(base + 0x194);
484
485 return dword;
486
487}
488
489static int phy_detect(uint8_t *base)
490{
491 uint32_t dword;
492 int i;
493 int val;
494 unsigned id;
495 dword = readl(base+0x188);
496 dword &= ~(1<<20);
497 writel(dword, base+0x188);
498
499 phy_read(base, 0, 1);
500
501 for(i=1; i<=32; i++) {
502 int phyaddr = i & 0x1f;
503 val = phy_read(base, phyaddr, 1);
504 if(val<0) continue;
505 if((val & 0xffff) == 0xfffff) continue;
506 if((val & 0xffff) == 0) continue;
507 if(!(val & 1)) {
508 break; // Ethernet PHY
509 }
510 val = phy_read(base, phyaddr, 3);
511 if (val < 0 || val == 0xffff) continue;
512 id = val & 0xfc00;
513 val = phy_read(base, phyaddr, 2);
514 if (val < 0 || val == 0xffff) continue;
515 id |= ((val & 0xffff)<<16);
516 printk_debug("SIS966 MAC PHY ID 0x%08x PHY ADDR %d\n", id, i);
517// if((id == 0xe0180000) || (id==0x0032cc00))
518 break;
519 }
520
521 if(i>32) {
522 printk_debug("SIS966 MAC PHY not found\n");
523 }
524
525}
526static void nic_init(struct device *dev)
527{
528 uint32_t dword, old;
529 uint32_t mac_h, mac_l;
530 int eeprom_valid = 0;
531 struct southbridge_sis_sis966_config *conf;
532
533 static uint32_t nic_index = 0;
534
535 uint8_t *base;
536 struct resource *res;
537
538 res = find_resource(dev, 0x10);
539
540 if(!res) return;
541
542 base = res->base;
543
544 phy_detect(base);
545
546#define NvRegPhyInterface 0xC0
547#define PHY_RGMII 0x10000000
548
549 writel(PHY_RGMII, base + NvRegPhyInterface);
550
551 conf = dev->chip_info;
552
553 if(conf->mac_eeprom_smbus != 0) {
554// read MAC address from EEPROM at first
555 struct device *dev_eeprom;
556 dev_eeprom = dev_find_slot_on_smbus(conf->mac_eeprom_smbus, conf->mac_eeprom_addr);
557
558 if(dev_eeprom) {
559 // if that is valid we will use that
560 unsigned char dat[6];
561 int status;
562 int i;
563 for(i=0;i<6;i++) {
564 status = smbus_read_byte(dev_eeprom, i);
565 if(status < 0) break;
566 dat[i] = status & 0xff;
567 }
568 if(status >= 0) {
569 mac_l = 0;
570 for(i=3;i>=0;i--) {
571 mac_l <<= 8;
572 mac_l += dat[i];
573 }
574 if(mac_l != 0xffffffff) {
575 mac_l += nic_index;
576 mac_h = 0;
577 for(i=5;i>=4;i--) {
578 mac_h <<= 8;
579 mac_h += dat[i];
580 }
581 eeprom_valid = 1;
582 }
583 }
584 }
585 }
586// if that is invalid we will read that from romstrap
587 if(!eeprom_valid) {
588 unsigned long mac_pos;
589 mac_pos = 0xffffffd0; // refer to romstrap.inc and romstrap.lds
590 mac_l = readl(mac_pos) + nic_index; // overflow?
591 mac_h = readl(mac_pos + 4);
592
593 }
594#if 1
595// set that into NIC MMIO
596#define NvRegMacAddrA 0xA8
597#define NvRegMacAddrB 0xAC
598 writel(mac_l, base + NvRegMacAddrA);
599 writel(mac_h, base + NvRegMacAddrB);
600#else
601// set that into NIC
602 pci_write_config32(dev, 0xa8, mac_l);
603 pci_write_config32(dev, 0xac, mac_h);
604#endif
605
606 nic_index++;
607
608#if CONFIG_PCI_ROM_RUN == 1
609 pci_dev_init(dev);// it will init option rom
610#endif
611
612}
613
614#endif
615static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
616{
617 pci_write_config32(dev, 0x40,
618 ((device & 0xffff) << 16) | (vendor & 0xffff));
619}
620
621static struct pci_operations lops_pci = {
622 .set_subsystem = lpci_set_subsystem,
623};
624
625static struct device_operations nic_ops = {
626 .read_resources = pci_dev_read_resources,
627 .set_resources = pci_dev_set_resources,
628 .enable_resources = pci_dev_enable_resources,
629 .init = nic_init,
630 .scan_bus = 0,
631// .enable = sis966_enable,
632 .ops_pci = &lops_pci,
633};
634static struct pci_driver nic_driver __pci_driver = {
635 .ops = &nic_ops,
636 .vendor = PCI_VENDOR_ID_SIS,
637 .device = PCI_DEVICE_ID_SIS_SIS966_NIC1,
638};
639static struct pci_driver nic_bridge_driver __pci_driver = {
640 .ops = &nic_ops,
641 .vendor = PCI_VENDOR_ID_SIS,
642 .device = PCI_DEVICE_ID_SIS_SIS966_NIC_BRIDGE,
643};