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,
};