/*********************************************************************
* I.MX6 Ethernet MAC (ENET) MAC Address hacking
* 说明:
* Lee对相关的一些代码进行了修改,所以这边跟一下这边相关的设置原理,
* 主要是为了知道MAC address在Uboot、Linux kernel阶段的的设置,获取的
* 工作机制。
*
* 2016-7-27 深圳 南山平山村 曾剑锋
********************************************************************/
参考文档:
Freescale i.MX6 Linux Ethernet Driver驱动源码分析
http://blog.163.com/thinki_cao/blog/static/8394487520146308450620/
cat lib_arm/board.c
void start_armboot (void)
{
......
stdio_init (); /* get the devices list going. */ ---------+
...... |
eth_initialize(gd->bd); ----------------*-+
...... | |
} | |
| |
int stdio_init (void) <-----------------------------+ |
{ |
...... |
#ifdef CONFIG_LCD |
drv_lcd_init (); ------------+ |
#endif | |
...... | |
| |
return (); | |
} | |
| |
int drv_lcd_init (void) <------------+ |
{ |
...... |
lcd_init (lcd_base); /* LCD initialization */ --------+ |
...... | |
} | |
| |
static int lcd_init (void *lcdbase) <--------+ |
{ |
...... |
lcd_enable (); --------+ |
...... | |
} | |
| |
#ifdef CONFIG_LCD | |
void lcd_enable(void) <--------+ |
{ |
...... |
setenv("ethaddr",buffer); |
...... |
} |
|
int eth_initialize(bd_t *bis) <----------------------+
{
......
/* Try board-specific initialization first. If it fails or isn't
* present, try the cpu-specific initialization */
if (board_eth_init(bis) < )
cpu_eth_init(bis); -------+
|
...... |
} |
|
|
int cpu_eth_init(bd_t *bis) <------+
{
int rc = -ENODEV;
#if defined(CONFIG_MXC_FEC)
rc = mxc_fec_initialize(bis); -------+
|
/* Board level init */ |
enet_board_init(); |
|
#endif |
return rc; |
} |
|
int mxc_fec_initialize(bd_t *bis) <-------+
{
struct eth_device *dev;
int i;
unsigned char ethaddr[];
for (i = ; i < sizeof(fec_info) / sizeof(fec_info[]); i++) {
#ifdef CONFIG_ARCH_MMU
int j;
#endif
dev =
(struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE,
sizeof *dev);
if (dev == NULL)
hang();
memset(dev, , sizeof(*dev));
sprintf(dev->name, "FEC%d", fec_info[i].index);
dev->priv = &fec_info[i]; ----------+
dev->init = fec_init; |
dev->halt = fec_halt; |
dev->send = fec_send; |
dev->recv = fec_recv; |
...... |
|
if (fec_get_hwaddr(dev, ethaddr) == ) { ------*-----+
printf("got MAC address from IIM: %pM\n", ethaddr); | |
memcpy(dev->enetaddr, ethaddr, ); | |
fec_set_hwaddr(dev); ------*-----*-+
} | | |
} | | |
| | |
return ; | | |
} | | |
| | |
struct fec_info_s fec_info[] = { <----------+ | |
{ | | |
, /* index */ | | |
CONFIG_FEC0_IOBASE, /* io base */ --------+-*-----*-*-+
CONFIG_FEC0_PHY_ADDR, /* phy_addr */ | | | | |
, /* duplex and speed */ | | | | |
, /* phy name */ | | | | |
, /* phyname init */ | | | | |
, /* RX BD */ | | | | |
, /* TX BD */ | | | | |
, /* rx Index */ | | | | |
, /* tx Index */ | | | | |
, /* tx buffer */ | | | | |
#ifdef CONFIG_ARCH_MMU | | | | |
{ }, /* rx buffer */ | | | | |
#endif | | | | |
, /* initialized flag */ | | | | |
}, | | | | |
}; | | | | |
| | | | |
/* FEC private information */ | | | | |
struct fec_info_s { <----------*-+ | | |
int index; | | | |
u32 iobase; | | | |
int phy_addr; | | | |
int dup_spd; | | | |
char *phy_name; | | | |
int phyname_init; | | | |
cbd_t *rxbd; /* Rx BD */ | | | |
cbd_t *txbd; /* Tx BD */ | | | |
uint rxIdx; | | | |
uint txIdx; | | | |
char *txbuf; | | | |
#ifdef CONFIG_ARCH_MMU | | | |
char *rxbuf[PKTBUFSRX]; | | | |
#endif | | | |
int initialized; | | | |
struct fec_info_s *next; | | | |
}; | | | |
| | | |
#define CONFIG_FEC0_IOBASE ENET_BASE_ADDR <------------+ | | |
#define ENET_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x8000) | | |
#define AIPS2_OFF_BASE_ADDR (ATZ2_BASE_ADDR + 0x80000) | | |
#define ATZ2_BASE_ADDR AIPS2_ARB_BASE_ADDR | | |
#define AIPS2_ARB_BASE_ADDR 0x02100000 | | |
| | |
extern int fec_get_mac_addr(unsigned char *mac); | | |
static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac) <-+ | |
{ | |
#ifdef CONFIG_GET_FEC_MAC_ADDR_FROM_IIM | |
fec_get_mac_addr(mac); ----------+ | |
| | |
return ; | | |
#else | | |
return -; | | |
#endif | | |
} | | |
| | |
#ifdef CONFIG_GET_FEC_MAC_ADDR_FROM_IIM | | |
int fec_get_mac_addr(unsigned char *mac) <----------+ | |
{ | |
#if 0 | |
unsigned int value; | |
| |
value = readl(OCOTP_BASE_ADDR + HW_OCOTP_MACn()); | |
mac[] = value & 0xff; | |
mac[] = (value >> ) & 0xff; | |
mac[] = (value >> ) & 0xff; | |
mac[] = (value >> ) & 0xff; | |
value = readl(OCOTP_BASE_ADDR + HW_OCOTP_MACn()); | |
mac[] = value & 0xff; | |
mac[] = (value >> ) & 0xff; | |
#else | |
eth_getenv_enetaddr("ethaddr", mac); ----------+ | |
#endif | | |
return ; | | |
} | | |
#endif | | |
| | |
static int fec_set_hwaddr(struct eth_device *dev) <----|-----------+ |
{ | |
uchar *mac = dev->enetaddr; | |
struct fec_info_s *info = dev->priv; | |
volatile fec_t *fecp = (fec_t *)(info->iobase); | |
| |
writel(, &fecp->iaur); | |
writel(, &fecp->ialr); | |
writel(, &fecp->gaur); | |
writel(, &fecp->galr); | |
| |
/* | |
* Set physical address | |
*/ V |
writel((mac[] << ) + (mac[] << ) + (mac[] << ) + mac[], ------*-+
&fecp->palr); | |
writel((mac[] << ) + (mac[] << ) + 0x8808, &fecp->paur); | |
| |
return ; | |
} | |
| |
| |
cat arch/arm/mach-mx6/board-mx6q_sabresd.c | |
MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Boa|"|)
/* Maintainer: Freescale Semiconductor, Inc. */ | |
.boot_params = MX6_PHYS_OFFSET + 0x100, | |
.fixup = fixup_mxc_board, | |
.map_io = mx6_map_io, | |
.init_irq = mx6_init_irq, | |
.init_machine = mx6_sabresd_board_init, ----------+ | |
.timer = &mx6_sabresd_timer, | | |
.reserve = mx6q_sabresd_reserve, | | |
MACHINE_END | | |
| | |
/*! | | |
* Board specific initialization. | | |
*/ | | |
static void __init mx6_sabresd_board_init(void) <---------+ | |
{ | |
...... | |
imx6_init_fec(fec_data); | |
...... | | |
} | | |
V | |
void __init imx6_init_fec(struct fec_platform_data fec_data) ---------+ | |
{ | | |
fec_get_mac_addr(fec_data.mac); | | |
/* | | |
if (!is_valid_ether_addr(fec_data.mac)) | | |
random_ether_addr(fec_data.mac); | | |
*/ | | |
| | |
if (cpu_is_mx6sl()) | | |
imx6sl_add_fec(&fec_data); | | |
else | | |
imx6q_add_fec(&fec_data); | | |
} | | |
| | |
extern const struct imx_fec_data imx6q_fec_data __initconst; | | |
#define imx6q_add_fec(pdata) \ <--------------------+ | |
imx_add_fec(&imx6q_fec_data, pdata) ---------------------+ | |
| | |
#ifdef CONFIG_SOC_IMX6Q | | |
const struct imx_fec_data imx6q_fec_data __initconst = | | |
imx_fec_data_entry_single(MX6Q, "enet"); | | |
| | |
const struct imx_fec_data imx6sl_fec_data __initconst = <----------+ | |
imx_fec_data_entry_single(MX6DL, "fec"); ----------+ | | |
#endif | | | |
| | | |
struct platform_device *__init imx_add_fec( <------------------*-+ | |
const struct imx_fec_data *data, | | |
const struct fec_platform_data *pdata) | | |
{ | | |
struct resource res[] = { | | |
{ | | |
.start = data->iobase, | | |
.end = data->iobase + SZ_4K - , | | |
.flags = IORESOURCE_MEM, | | |
}, { | | |
.start = data->irq, | | |
.end = data->irq, | | |
.flags = IORESOURCE_IRQ, | | |
}, | | |
}; | | |
| | |
if (!fuse_dev_is_available(MXC_DEV_ENET)) | | |
return ERR_PTR(-ENODEV); | | |
| | |
return imx_add_platform_device_dmamask(data->devid, , | | |
res, ARRAY_SIZE(res), | | |
pdata, sizeof(*pdata), DMA_BIT_MASK()); | | |
} | | |
| | |
#define imx_fec_data_entry_single(soc, _devid) \ <----+ | |
{ \ | |
.iobase = soc ## _FEC_BASE_ADDR, \ --------+ | |
.irq = soc ## _INT_FEC, \ | | |
.devid = _devid, \ | | |
} | | |
| | |
#define MX6DL_FEC_BASE_ADDR ENET_BASE_ADDR <-------+------+ |
#define ENET_BASE_ADDR (AIPS2_OFF_BASE_ADDR+0x8000) |
#define AIPS2_OFF_BASE_ADDR (ATZ2_BASE_ADDR + 0x80000) |
#define ATZ2_BASE_ADDR AIPS2_ARB_BASE_ADDR |
#define AIPS2_ARB_BASE_ADDR 0x02100000 |
|
cat drivers/net/fec.c |
static int __init |
fec_enet_module_init(void) |
{ |
printk(KERN_INFO "FEC Ethernet Driver\n"); |
|
return platform_driver_register(&fec_driver); ------+ |
} | |
| |
static void __exit | |
fec_enet_cleanup(void) | |
{ | |
platform_driver_unregister(&fec_driver); | |
} | |
| |
module_exit(fec_enet_cleanup); | |
module_init(fec_enet_module_init); | |
| |
MODULE_LICENSE("GPL"); | |
| |
static struct platform_driver fec_driver = { <-----+ |
.driver = { |
.name = DRIVER_NAME, |
.owner = THIS_MODULE, |
#ifdef CONFIG_PM |
.pm = &fec_pm_ops, |
#endif |
}, |
.id_table = fec_devtype, |
.probe = fec_probe, ------+ |
.remove = __devexit_p(fec_drv_remove), | |
}; | |
| |
static int __devinit | |
fec_probe(struct platform_device *pdev) <-----+ |
{ |
...... |
fep->hwp = ioremap(r->start, resource_size(r)); ---------------+ |
...... | |
ret = fec_enet_init(ndev); ------+ | |
if (ret) | | |
goto failed_init; | | |
...... | | |
} | | |
| | |
static int fec_enet_init(struct net_device *ndev) <-----+ | |
{ | |
...... | |
/* Get the Ethernet address */ | |
fec_get_mac(ndev); ----------------+ | |
...... | | |
} | | |
| | |
static void __inline__ fec_get_mac(struct net_device *ndev) <-----+ | |
{ | |
struct fec_enet_private *fep = netdev_priv(ndev); | |
struct fec_platform_data *pdata = fep->pdev->dev.platform_data; | |
unsigned char *iap, tmpaddr[ETH_ALEN]; | |
| |
/* | |
* try to get mac address in following order: | |
* | |
* 1) module parameter via kernel command line in form | |
* fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0 | |
*/ | |
iap = macaddr; | |
| |
/* | |
* 2) from flash or fuse (via platform data) | |
*/ | |
if (!is_valid_ether_addr(iap)) { | |
#ifdef CONFIG_M5272 | |
if (FEC_FLASHMAC) | |
iap = (unsigned char *)FEC_FLASHMAC; | |
#else | |
if (pdata) | |
memcpy(iap, pdata->mac, ETH_ALEN); | |
#endif | |
} | |
| |
/* | |
* 3) FEC mac registers set by bootloader | |
*/ | |
if (!is_valid_ether_addr(iap)) { | |
*((unsigned long *) &tmpaddr[]) = | |
be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW)); <----------+-----+
*((unsigned short *) &tmpaddr[]) =
be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> );
iap = &tmpaddr[];
}
memcpy(ndev->dev_addr, iap, ETH_ALEN);
/* Adjust MAC if using macaddr */
if (iap == macaddr)
ndev->dev_addr[ETH_ALEN-] = macaddr[ETH_ALEN-] + fep->pdev->id;
}