blob: cd376ab781aa026fd2a635970ee4c269fe46b687 [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/smbus.h>
25#include <device/pci.h>
26#include <device/pci_ids.h>
27#include <device/pci_ops.h>
28#include <arch/io.h>
29#include <delay.h>
30#include "sis966.h"
31
32
Stefan Reinauereea66b72010-04-07 15:32:52 +000033u8 SiS_SiS191_init[6][3]={
Morgan Tsai218c2652007-11-02 16:09:58 +000034{0x04, 0xFF, 0x07},
35{0x2C, 0xFF, 0x39},
36{0x2D, 0xFF, 0x10},
37{0x2E, 0xFF, 0x91},
Morgan Tsai1602dd52007-10-29 21:00:14 +000038{0x2F, 0xFF, 0x01},
39{0x00, 0x00, 0x00} //End of table
40};
41
Morgan Tsai218c2652007-11-02 16:09:58 +000042
43#define StatusReg 0x1
Morgan Tsai1602dd52007-10-29 21:00:14 +000044#define SMI_READ 0x0
45#define SMI_REQUEST 0x10
46#define TRUE 1
47#define FALSE 0
48
Stefan Reinauereea66b72010-04-07 15:32:52 +000049u16 MacAddr[3];
Morgan Tsai1602dd52007-10-29 21:00:14 +000050
51
Stefan Reinauereea66b72010-04-07 15:32:52 +000052static void writeApcByte(int addr, u8 value)
Morgan Tsai1602dd52007-10-29 21:00:14 +000053{
54 outb(addr,0x78);
Morgan Tsai218c2652007-11-02 16:09:58 +000055 outb(value,0x79);
Morgan Tsai1602dd52007-10-29 21:00:14 +000056}
Stefan Reinauereea66b72010-04-07 15:32:52 +000057
58static u8 readApcByte(int addr)
Morgan Tsai1602dd52007-10-29 21:00:14 +000059{
Stefan Reinauereea66b72010-04-07 15:32:52 +000060 u8 value;
Morgan Tsai1602dd52007-10-29 21:00:14 +000061 outb(addr,0x78);
62 value=inb(0x79);
63 return(value);
64}
65
66static void readApcMacAddr(void)
67{
Stefan Reinauereea66b72010-04-07 15:32:52 +000068 u8 i;
Morgan Tsai1602dd52007-10-29 21:00:14 +000069
70// enable APC in south bridge sis966 D2F0
71
Morgan Tsai218c2652007-11-02 16:09:58 +000072 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +000073 outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data
74
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000075 printk(BIOS_DEBUG, "MAC addr in APC = ");
Morgan Tsai218c2652007-11-02 16:09:58 +000076 for(i = 0x9 ; i <=0xe ; i++)
Morgan Tsai1602dd52007-10-29 21:00:14 +000077 {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000078 printk(BIOS_DEBUG, "%2.2x",readApcByte(i));
Morgan Tsai1602dd52007-10-29 21:00:14 +000079 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000080 printk(BIOS_DEBUG, "\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +000081
82 /* Set APC Reload */
83 writeApcByte(0x7,readApcByte(0x7)&0xf7);
84 writeApcByte(0x7,readApcByte(0x7)|0x0a);
Morgan Tsai218c2652007-11-02 16:09:58 +000085
Morgan Tsai1602dd52007-10-29 21:00:14 +000086 /* disable APC in south bridge */
Morgan Tsai218c2652007-11-02 16:09:58 +000087 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +000088 outl(inl(0xcfc)&0xffffffbf,0xcfc);
89}
90
91static void set_apc(struct device *dev)
92{
Stefan Reinauereea66b72010-04-07 15:32:52 +000093 u16 addr;
94 u16 i;
95 u8 bTmp;
Morgan Tsai1602dd52007-10-29 21:00:14 +000096
97 /* enable APC in south bridge sis966 D2F0 */
Morgan Tsai218c2652007-11-02 16:09:58 +000098 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +000099 outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data
Morgan Tsai218c2652007-11-02 16:09:58 +0000100
Morgan Tsai1602dd52007-10-29 21:00:14 +0000101 for(i = 0 ; i <3; i++)
102 {
103 addr=0x9+2*i;
Stefan Reinauereea66b72010-04-07 15:32:52 +0000104 writeApcByte(addr,(u8)(MacAddr[i]&0xFF));
105 writeApcByte(addr+1L,(u8)((MacAddr[i]>>8)&0xFF));
Morgan Tsai1602dd52007-10-29 21:00:14 +0000106 // printf("%x - ",readMacAddrByte(0x59+i));
107 }
108
109 /* Set APC Reload */
110 writeApcByte(0x7,readApcByte(0x7)&0xf7);
111 writeApcByte(0x7,readApcByte(0x7)|0x0a);
Morgan Tsai218c2652007-11-02 16:09:58 +0000112
Morgan Tsai1602dd52007-10-29 21:00:14 +0000113 /* disable APC in south bridge */
Morgan Tsai218c2652007-11-02 16:09:58 +0000114 outl(0x80001048,0xcf8);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000115 outl(inl(0xcfc)&0xffffffbf,0xcfc);
116
Morgan Tsai218c2652007-11-02 16:09:58 +0000117 // CFG reg0x73 bit=1, tell driver MAC Address load to APC
118 bTmp = pci_read_config8(dev, 0x73);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000119 bTmp|=0x1;
120 pci_write_config8(dev, 0x73, bTmp);
121}
122
Uwe Hermannb69cb5a2010-10-26 22:46:43 +0000123/**
124 * Read one word out of the serial EEPROM.
125 *
126 * @param dev TODO
127 * @param base TODO
128 * @param Reg EEPROM word to read.
129 * @return Contents of EEPROM word (Reg).
130 */
Morgan Tsai1602dd52007-10-29 21:00:14 +0000131#define LoopNum 200
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800132static unsigned long ReadEEprom( struct device *dev, u8 *base, u32 Reg)
Morgan Tsai1602dd52007-10-29 21:00:14 +0000133{
Stefan Reinauereea66b72010-04-07 15:32:52 +0000134 u32 data;
135 u32 i;
136 u32 ulValue;
Morgan Tsai218c2652007-11-02 16:09:58 +0000137
138
Morgan Tsai1602dd52007-10-29 21:00:14 +0000139 ulValue = (0x80 | (0x2 << 8) | (Reg << 10)); //BIT_7
140
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800141 write32(base + 0x3c, ulValue);
Morgan Tsai218c2652007-11-02 16:09:58 +0000142
Morgan Tsai1602dd52007-10-29 21:00:14 +0000143 mdelay(10);
144
145 for(i=0 ; i <= LoopNum; i++)
146 {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800147 ulValue=read32(base + 0x3c);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000148
149 if(!(ulValue & 0x0080)) //BIT_7
150 break;
151
152 mdelay(100);
153 }
Morgan Tsai218c2652007-11-02 16:09:58 +0000154
Morgan Tsai1602dd52007-10-29 21:00:14 +0000155 mdelay(50);
156
157 if(i==LoopNum) data=0x10000;
158 else{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800159 ulValue=read32(base + 0x3c);
Carl-Daniel Hailfingera3588922007-11-05 22:21:27 +0000160 data = ((ulValue & 0xffff0000) >> 16);
Morgan Tsai218c2652007-11-02 16:09:58 +0000161 }
162
Morgan Tsai1602dd52007-10-29 21:00:14 +0000163 return data;
164}
165
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800166static int phy_read(u8 *base, unsigned phy_addr, unsigned phy_reg)
Morgan Tsai1602dd52007-10-29 21:00:14 +0000167{
Stefan Reinauereea66b72010-04-07 15:32:52 +0000168 u32 ulValue;
169 u32 Read_Cmd;
170 u16 usData;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000171
Morgan Tsai1602dd52007-10-29 21:00:14 +0000172
Morgan Tsai218c2652007-11-02 16:09:58 +0000173
174 Read_Cmd = ((phy_reg << 11) |
Morgan Tsai1602dd52007-10-29 21:00:14 +0000175 (phy_addr << 6) |
176 SMI_READ |
177 SMI_REQUEST);
178
179 // SmiMgtInterface Reg is the SMI management interface register(offset 44h) of MAC
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800180 write32(base + 0x44, Read_Cmd);
Morgan Tsai218c2652007-11-02 16:09:58 +0000181
Morgan Tsai1602dd52007-10-29 21:00:14 +0000182 // Polling SMI_REQ bit to be deasserted indicated read command completed
183 do
184 {
185 // Wait 20 usec before checking status
Morgan Tsai1602dd52007-10-29 21:00:14 +0000186 mdelay(20);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800187 ulValue = read32(base + 0x44);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000188 } while((ulValue & SMI_REQUEST) != 0);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000189 //printk(BIOS_DEBUG, "base %x cmd %lx ret val %lx\n", tmp,Read_Cmd,ulValue);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000190 usData=(ulValue>>16);
191
Morgan Tsai218c2652007-11-02 16:09:58 +0000192
Morgan Tsai1602dd52007-10-29 21:00:14 +0000193
194 return usData;
195
196}
197
198// Detect a valid PHY
199// If there exist a valid PHY then return TRUE, else return FALSE
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800200static int phy_detect(u8 *base,u16 *PhyAddr) //BOOL PHY_Detect()
Morgan Tsai1602dd52007-10-29 21:00:14 +0000201{
202 int bFoundPhy = FALSE;
Stefan Reinauereea66b72010-04-07 15:32:52 +0000203 u16 usData;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000204 int PhyAddress = 0;
Morgan Tsai218c2652007-11-02 16:09:58 +0000205
206
Morgan Tsai1602dd52007-10-29 21:00:14 +0000207 // Scan all PHY address(0 ~ 31) to find a valid PHY
208 for(PhyAddress = 0; PhyAddress < 32; PhyAddress++)
Morgan Tsai218c2652007-11-02 16:09:58 +0000209 {
210 usData=phy_read(base,PhyAddress,StatusReg); // Status register is a PHY's register(offset 01h)
211
212 // Found a valid PHY
213
Morgan Tsai1602dd52007-10-29 21:00:14 +0000214 if((usData != 0x0) && (usData != 0xffff))
215 {
216 bFoundPhy = TRUE;
217 break;
218 }
219 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000220
Morgan Tsai1602dd52007-10-29 21:00:14 +0000221
222 if(!bFoundPhy)
223 {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000224 printk(BIOS_DEBUG, "PHY not found !!!! \n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000225 }
226
227 *PhyAddr=PhyAddress;
Morgan Tsai218c2652007-11-02 16:09:58 +0000228
Morgan Tsai1602dd52007-10-29 21:00:14 +0000229 return bFoundPhy;
230}
231
232
233static void nic_init(struct device *dev)
234{
Morgan Tsai218c2652007-11-02 16:09:58 +0000235 int val;
Stefan Reinauereea66b72010-04-07 15:32:52 +0000236 u16 PhyAddr;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800237 u8 *base;
Morgan Tsai218c2652007-11-02 16:09:58 +0000238 struct resource *res;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000239
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800240 printk(BIOS_DEBUG, "NIC_INIT:---------->\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000241
Morgan Tsai1602dd52007-10-29 21:00:14 +0000242//-------------- enable NIC (SiS19x) -------------------------
243{
Stefan Reinauereea66b72010-04-07 15:32:52 +0000244 u8 temp8;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000245 int i=0;
246 while(SiS_SiS191_init[i][0] != 0)
Morgan Tsai218c2652007-11-02 16:09:58 +0000247 {
248 temp8 = pci_read_config8(dev, SiS_SiS191_init[i][0]);
249 temp8 &= SiS_SiS191_init[i][1];
250 temp8 |= SiS_SiS191_init[i][2];
251 pci_write_config8(dev, SiS_SiS191_init[i][0], temp8);
252 i++;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000253 };
254}
255//-----------------------------------------------------------
256
Morgan Tsai1602dd52007-10-29 21:00:14 +0000257{
Morgan Tsai218c2652007-11-02 16:09:58 +0000258 unsigned long i;
259 unsigned long ulValue;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000260
Morgan Tsai1602dd52007-10-29 21:00:14 +0000261 res = find_resource(dev, 0x10);
262
Morgan Tsai218c2652007-11-02 16:09:58 +0000263 if(!res)
264 {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000265 printk(BIOS_DEBUG, "NIC Cannot find resource..\n");
Morgan Tsai218c2652007-11-02 16:09:58 +0000266 return;
267 }
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800268 base = res2mmio(res, 0, 0);
269 printk(BIOS_DEBUG, "NIC base address %p\n",base);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000270
Morgan Tsai218c2652007-11-02 16:09:58 +0000271 if(!(val=phy_detect(base,&PhyAddr)))
272 {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000273 printk(BIOS_DEBUG, "PHY detect fail !!!!\n");
Morgan Tsai218c2652007-11-02 16:09:58 +0000274 return;
275 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000276
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000277 ulValue=read32(base + 0x38L); // check EEPROM existing
Morgan Tsai1602dd52007-10-29 21:00:14 +0000278
Morgan Tsai218c2652007-11-02 16:09:58 +0000279 if((ulValue & 0x0002))
280 {
Morgan Tsai1602dd52007-10-29 21:00:14 +0000281
Morgan Tsai218c2652007-11-02 16:09:58 +0000282 // read MAC address from EEPROM at first
283
Morgan Tsai1602dd52007-10-29 21:00:14 +0000284 // if that is valid we will use that
Morgan Tsai218c2652007-11-02 16:09:58 +0000285
Myles Watson08e0fb82010-03-22 16:33:25 +0000286 printk(BIOS_DEBUG, "EEPROM contents %lx \n",ReadEEprom( dev, base, 0LL));
Morgan Tsai1602dd52007-10-29 21:00:14 +0000287 for(i=0;i<3;i++) {
288 //status = smbus_read_byte(dev_eeprom, i);
289 ulValue=ReadEEprom( dev, base, i+3L);
Morgan Tsai218c2652007-11-02 16:09:58 +0000290 if (ulValue ==0x10000) break; // error
291
292 MacAddr[i] =ulValue & 0xFFFF;
293
Morgan Tsai1602dd52007-10-29 21:00:14 +0000294 }
Morgan Tsai218c2652007-11-02 16:09:58 +0000295 }else{
296 // read MAC address from firmware
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000297 printk(BIOS_DEBUG, "EEPROM invalid!!\nReg 0x38h=%.8lx \n",ulValue);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800298 MacAddr[0]=read16((u16 *)0xffffffc0); // mac address store at here
299 MacAddr[1]=read16((u16 *)0xffffffc2);
300 MacAddr[2]=read16((u16 *)0xffffffc4);
Morgan Tsai218c2652007-11-02 16:09:58 +0000301 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000302
Morgan Tsai218c2652007-11-02 16:09:58 +0000303 set_apc(dev);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000304
Morgan Tsai218c2652007-11-02 16:09:58 +0000305 readApcMacAddr();
Morgan Tsai1602dd52007-10-29 21:00:14 +0000306
Morgan Tsai218c2652007-11-02 16:09:58 +0000307#if DEBUG_NIC
Morgan Tsai1602dd52007-10-29 21:00:14 +0000308{
Morgan Tsai218c2652007-11-02 16:09:58 +0000309 int i;
310
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800311 printk(BIOS_DEBUG, "****** NIC PCI config ******");
312 printk(BIOS_DEBUG, "\n 03020100 07060504 0B0A0908 0F0E0D0C");
Morgan Tsai218c2652007-11-02 16:09:58 +0000313
314 for(i=0;i<0xff;i+=4){
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800315 if((i%16)==0)
316 printk(BIOS_DEBUG, "\n%02x: ", i);
317 printk(BIOS_DEBUG, "%08x ", pci_read_config32(dev,i));
Morgan Tsai218c2652007-11-02 16:09:58 +0000318 }
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800319 printk(BIOS_DEBUG, "\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000320}
321
Morgan Tsai218c2652007-11-02 16:09:58 +0000322
Morgan Tsai1602dd52007-10-29 21:00:14 +0000323#endif
324
325}
326
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800327printk(BIOS_DEBUG, "NIC_INIT:<----------\n");
Morgan Tsai1602dd52007-10-29 21:00:14 +0000328return;
329
Morgan Tsai1602dd52007-10-29 21:00:14 +0000330
331}
332
Morgan Tsai1602dd52007-10-29 21:00:14 +0000333static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
334{
335 pci_write_config32(dev, 0x40,
336 ((device & 0xffff) << 16) | (vendor & 0xffff));
337}
338
339static struct pci_operations lops_pci = {
340 .set_subsystem = lpci_set_subsystem,
341};
342
343static struct device_operations nic_ops = {
344 .read_resources = pci_dev_read_resources,
345 .set_resources = pci_dev_set_resources,
346 .enable_resources = pci_dev_enable_resources,
347 .init = nic_init,
348 .scan_bus = 0,
349// .enable = sis966_enable,
350 .ops_pci = &lops_pci,
351};
Carl-Daniel Hailfingera3588922007-11-05 22:21:27 +0000352
Stefan Reinauer83b52e72007-10-30 02:17:49 +0000353static const struct pci_driver nic_driver __pci_driver = {
Morgan Tsai1602dd52007-10-29 21:00:14 +0000354 .ops = &nic_ops,
355 .vendor = PCI_VENDOR_ID_SIS,
Morgan Tsai31e805d2007-11-14 01:34:02 +0000356 .device = PCI_DEVICE_ID_SIS_SIS966_NIC,
Morgan Tsai1602dd52007-10-29 21:00:14 +0000357};