diff options
Diffstat (limited to 'src/southbridge/sis/sis966/nic.c')
-rw-r--r-- | src/southbridge/sis/sis966/nic.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/src/southbridge/sis/sis966/nic.c b/src/southbridge/sis/sis966/nic.c new file mode 100644 index 0000000000..a7aeec37ed --- /dev/null +++ b/src/southbridge/sis/sis966/nic.c @@ -0,0 +1,365 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * Copyright (C) 2007 Silicon Integrated Systems Corp. (SiS) + * Written by Morgan Tsai <my_tsai@sis.com> for SiS. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/smbus.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <arch/io.h> +#include <delay.h> +#include "sis966.h" + + +u8 SiS_SiS191_init[6][3]={ +{0x04, 0xFF, 0x07}, +{0x2C, 0xFF, 0x39}, +{0x2D, 0xFF, 0x10}, +{0x2E, 0xFF, 0x91}, +{0x2F, 0xFF, 0x01}, +{0x00, 0x00, 0x00} //End of table +}; + + +#define StatusReg 0x1 +#define SMI_READ 0x0 +#define SMI_REQUEST 0x10 +#define TRUE 1 +#define FALSE 0 + +u16 MacAddr[3]; + + +static void writeApcByte(int addr, u8 value) +{ + outb(addr,0x78); + outb(value,0x79); +} + +static u8 readApcByte(int addr) +{ + u8 value; + outb(addr,0x78); + value=inb(0x79); + return(value); +} + +static void readApcMacAddr(void) +{ + u8 i; + +// enable APC in south bridge sis966 D2F0 + + outl(0x80001048,0xcf8); + outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data + + printk(BIOS_DEBUG, "MAC addr in APC = "); + for(i = 0x9 ; i <=0xe ; i++) + { + printk(BIOS_DEBUG, "%2.2x",readApcByte(i)); + } + printk(BIOS_DEBUG, "\n"); + + /* Set APC Reload */ + writeApcByte(0x7,readApcByte(0x7)&0xf7); + writeApcByte(0x7,readApcByte(0x7)|0x0a); + + /* disable APC in south bridge */ + outl(0x80001048,0xcf8); + outl(inl(0xcfc)&0xffffffbf,0xcfc); +} + +static void set_apc(struct device *dev) +{ + u16 addr; + u16 i; + u8 bTmp; + + /* enable APC in south bridge sis966 D2F0 */ + outl(0x80001048,0xcf8); + outl((inl(0xcfc) & 0xfffffffd),0xcfc ); // enable IO78/79h for APC Index/Data + + for(i = 0 ; i <3; i++) + { + addr=0x9+2*i; + writeApcByte(addr,(u8)(MacAddr[i]&0xFF)); + writeApcByte(addr+1L,(u8)((MacAddr[i]>>8)&0xFF)); + // printf("%x - ",readMacAddrByte(0x59+i)); + } + + /* Set APC Reload */ + writeApcByte(0x7,readApcByte(0x7)&0xf7); + writeApcByte(0x7,readApcByte(0x7)|0x0a); + + /* disable APC in south bridge */ + outl(0x80001048,0xcf8); + outl(inl(0xcfc)&0xffffffbf,0xcfc); + + // CFG reg0x73 bit=1, tell driver MAC Address load to APC + bTmp = pci_read_config8(dev, 0x73); + bTmp|=0x1; + pci_write_config8(dev, 0x73, bTmp); +} + +/** + * Read one word out of the serial EEPROM. + * + * @param dev TODO + * @param base TODO + * @param Reg EEPROM word to read. + * @return Contents of EEPROM word (Reg). + */ +#define LoopNum 200 +static unsigned long ReadEEprom( struct device *dev, u32 base, u32 Reg) +{ + u32 data; + u32 i; + u32 ulValue; + + + ulValue = (0x80 | (0x2 << 8) | (Reg << 10)); //BIT_7 + + write32(base+0x3c, ulValue); + + mdelay(10); + + for(i=0 ; i <= LoopNum; i++) + { + ulValue=read32(base+0x3c); + + if(!(ulValue & 0x0080)) //BIT_7 + break; + + mdelay(100); + } + + mdelay(50); + + if(i==LoopNum) data=0x10000; + else{ + ulValue=read32(base+0x3c); + data = ((ulValue & 0xffff0000) >> 16); + } + + return data; +} + +static int phy_read(u32 base, unsigned phy_addr, unsigned phy_reg) +{ + u32 ulValue; + u32 Read_Cmd; + u16 usData; + + + + Read_Cmd = ((phy_reg << 11) | + (phy_addr << 6) | + SMI_READ | + SMI_REQUEST); + + // SmiMgtInterface Reg is the SMI management interface register(offset 44h) of MAC + write32(base+0x44, Read_Cmd); + + // Polling SMI_REQ bit to be deasserted indicated read command completed + do + { + // Wait 20 usec before checking status + mdelay(20); + ulValue = read32(base+0x44); + } while((ulValue & SMI_REQUEST) != 0); + //printk(BIOS_DEBUG, "base %x cmd %lx ret val %lx\n", tmp,Read_Cmd,ulValue); + usData=(ulValue>>16); + + + + return usData; + +} + +// Detect a valid PHY +// If there exist a valid PHY then return TRUE, else return FALSE +static int phy_detect(u32 base,u16 *PhyAddr) //BOOL PHY_Detect() +{ + int bFoundPhy = FALSE; + u16 usData; + int PhyAddress = 0; + + + // Scan all PHY address(0 ~ 31) to find a valid PHY + for(PhyAddress = 0; PhyAddress < 32; PhyAddress++) + { + usData=phy_read(base,PhyAddress,StatusReg); // Status register is a PHY's register(offset 01h) + + // Found a valid PHY + + if((usData != 0x0) && (usData != 0xffff)) + { + bFoundPhy = TRUE; + break; + } + } + + + if(!bFoundPhy) + { + printk(BIOS_DEBUG, "PHY not found !!!! \n"); + } + + *PhyAddr=PhyAddress; + + return bFoundPhy; +} + + +static void nic_init(struct device *dev) +{ + int val; + u16 PhyAddr; + u32 base; + struct resource *res; + + print_debug("NIC_INIT:---------->\n"); + +//-------------- enable NIC (SiS19x) ------------------------- +{ + u8 temp8; + int i=0; + while(SiS_SiS191_init[i][0] != 0) + { + temp8 = pci_read_config8(dev, SiS_SiS191_init[i][0]); + temp8 &= SiS_SiS191_init[i][1]; + temp8 |= SiS_SiS191_init[i][2]; + pci_write_config8(dev, SiS_SiS191_init[i][0], temp8); + i++; + }; +} +//----------------------------------------------------------- + +{ + unsigned long i; + unsigned long ulValue; + + res = find_resource(dev, 0x10); + + if(!res) + { + printk(BIOS_DEBUG, "NIC Cannot find resource..\n"); + return; + } + base = res->base; + printk(BIOS_DEBUG, "NIC base address %x\n",base); + + if(!(val=phy_detect(base,&PhyAddr))) + { + printk(BIOS_DEBUG, "PHY detect fail !!!!\n"); + return; + } + + ulValue=read32(base + 0x38L); // check EEPROM existing + + if((ulValue & 0x0002)) + { + + // read MAC address from EEPROM at first + + // if that is valid we will use that + + printk(BIOS_DEBUG, "EEPROM contents %lx \n",ReadEEprom( dev, base, 0LL)); + for(i=0;i<3;i++) { + //status = smbus_read_byte(dev_eeprom, i); + ulValue=ReadEEprom( dev, base, i+3L); + if (ulValue ==0x10000) break; // error + + MacAddr[i] =ulValue & 0xFFFF; + + } + }else{ + // read MAC address from firmware + printk(BIOS_DEBUG, "EEPROM invalid!!\nReg 0x38h=%.8lx \n",ulValue); + MacAddr[0]=read16(0xffffffc0); // mac address store at here + MacAddr[1]=read16(0xffffffc2); + MacAddr[2]=read16(0xffffffc4); + } + + set_apc(dev); + + readApcMacAddr(); + +#if DEBUG_NIC +{ + int i; + + print_debug("****** NIC PCI config ******"); + print_debug("\n 03020100 07060504 0B0A0908 0F0E0D0C"); + + for(i=0;i<0xff;i+=4){ + if((i%16)==0){ + print_debug("\n"); + print_debug_hex8(i); + print_debug(": "); + } + print_debug_hex32(pci_read_config32(dev,i)); + print_debug(" "); + } + print_debug("\n"); +} + + +#endif + +} + +print_debug("NIC_INIT:<----------\n"); +return; + + +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations nic_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = nic_init, + .scan_bus = 0, +// .enable = sis966_enable, + .ops_pci = &lops_pci, +}; + +static const struct pci_driver nic_driver __pci_driver = { + .ops = &nic_ops, + .vendor = PCI_VENDOR_ID_SIS, + .device = PCI_DEVICE_ID_SIS_SIS966_NIC, +}; |