I too have done a few boards where the MAC address has been stored in the flash device. The idea was to save on cost, the same as yours Ron. This matter of board design is exactly that, board specific. The CK804 has a specific place in flash that the MAC(s) should be placed anyways, in the ROMSTRAP+0x30. I noticed you knew that YH. As the CK804 area is chipset specific, it shouldn't be board specific. So what I did is placed a define for your TYAN board, at least until you take your stuff out. In the code, it reads the ROMSTRAP offset + 0x30. Each MAC address is an +0x8 from there if you have more than one. This is exactly how the CK804 BIOS Porting guides state to do it. Now do you have to listen to me or the guide, no. It's just my $0.02.
On a side note YH, you have a bug in the ck804_nic.c. I hope it's OK to point this out. But the MAC address is supposed to be placed into the Memmory Mapped IO (MMIO) area at offset 0xA8, and not in the device configuration space...
My recommendation... // set that into NIC MMIO write32(mac_l, base + 0xA8); write32(mac_h, base + 0xAC);
your code... // set that into NIC pci_write_config32(dev, 0xa8, mac_l); pci_write_config32(dev, 0xac, mac_h);
Here is the code I recommend(or at least something close to it)...
#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 "ck804.h"
#define MAC_DBG 1 #define TYANs2895 0
uint8_t read8(unsigned long addr) { return *((volatile uint8_t *)(addr)); }
uint16_t read16(unsigned long addr) { return *((volatile uint16_t *)(addr)); }
uint32_t read32(unsigned long addr) { return *((volatile uint32_t *)(addr)); }
void write8(unsigned long addr, uint8_t value) { *((volatile uint8_t *)(addr)) = value; }
void write16(unsigned long addr, uint16_t value) { *((volatile uint16_t *)(addr)) = value; }
void write32(unsigned long addr, uint32_t value) { *((volatile uint32_t *)(addr)) = value; }
static void nic_init(struct device *dev) { uint32_t dword, old; uint32_t mac_h, mac_l; static uint32_t nic_index = 0; unsigned long mac_pos; uint32_t base; struct resource *res; #define NvRegPhyInterface 0xC0 #define PHY_RGMII 0x10000000
res = find_resource(dev, 0x10); base = res->base; write32(base + NvRegPhyInterface, PHY_RGMII);
old = dword = pci_read_config32(dev, 0x30); dword &= ~(0xf); dword |= 0xf; if(old != dword) { pci_write_config32(dev, 0x30 , dword); }
#if TYAN int eeprom_valid = 0; struct southbridge_nvidia_ck804_config *conf;
conf = dev->chip_info;
if(conf->mac_eeprom_smbus != 0) { // read MAC address from EEPROM at first struct device *dev_eeprom; dev_eeprom = dev_find_slot_on_smbus(conf->mac_eeprom_smbus, conf->mac_eeprom_addr);
if(dev_eeprom) { // if that is valid we will use that unsigned char dat[6]; int status; int i; for(i=0;i<6;i++) { status = smbus_read_byte(dev_eeprom, i); if(status < 0) break; dat[i] = status & 0xff; } if(status >= 0) { mac_l = 0; for(i=3;i>=0;i--) { mac_l <<= 8; mac_l += dat[i]; } if(mac_l != 0xffffffff) { mac_l += nic_index; mac_h = 0; for(i=5;i>=4;i--) { mac_h <<= 8; mac_h += dat[i]; } eeprom_valid = 1; } } } } // if that is invalid we will read that from romstrap if(!eeprom_valid) { mac_pos = 0xffffffd0; // refer to romstrap.inc and romstrap.lds mac_l = read32(mac_pos) + nic_index; mac_h = read32(mac_pos + 4); } #else // read directly from rom_strap mac_pos = read8(0xffffffe0); // refer to romstrap.inc mac_pos |= (read8(0xffffffe1)<<8); mac_pos |= (read8(0xffffffe2)<<16); mac_pos |= (read8(0xffffffe3)<<24);
mac_pos += 0x30; for ( dword = nic_index ; dword > 0 ; dword-- ) { mac_pos += 8; }
mac_l = read32(mac_pos); mac_h = read32(mac_pos + 4); #endif
// set that into NIC MMIO write32(mac_l, base + 0xA8); write32(mac_h, base + 0xAC);
#if MAC_DBG printk_info("MAC:\tMAC Address is: %02x:%02x:%02x:%02x:%02x:%02x\n", read8(base + 0xAD), read8(base + 0xAC), read8(base + 0xAB), read8(base + 0xAA), read8(base + 0xA9), read8(base + 0xA8)); #endif
nic_index++;
#if CONFIG_PCI_ROM_RUN == 1 pci_dev_init(dev);// it will init option rom #endif
}
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 = ck804_enable, .ops_pci = &lops_pci, }; static struct pci_driver nic_driver __pci_driver = { .ops = &nic_ops, .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_CK804_NIC, }; static struct pci_driver nic_bridge_driver __pci_driver = { .ops = &nic_ops, .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_CK804_NIC_BRIDGE, };
Peter,
1. About MAC set, that is according to Nvidia DOC, I guess MMIO is some better thatn PCI config. the reason is BIOS set that in PCI Config, and NIC controller will fill that into MMIO. The side effects is if the CK804 DEV start from 0, it works well. but if it is from 1, the NIC may fail to get MAC from the PCI Config.... timing...? I will try MMIO to see if it can use dev num from 1. 2. You don't like SEEPROM? the code should try the SMBUS at first, and if you do not set that (SMBUS num in Config.lb), it will be skipped. 3. readl.... has been defined in arch/io.h
YH