珀耳塞福建 发表于 2017-7-6 14:28:12

I.MX6 Ethernet MAC (ENET) MAC Address hacking

/*********************************************************************
*      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 (0);                                    |                |         
}                                                |                |         
|                |         
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) < 0)                                                
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 = 0; 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, 0, sizeof(*dev));                                          
sprintf(dev->name, "FEC%d", fec_info.index);                        
dev->priv = &fec_info;                     ----------+            
dev->init = fec_init;                                     |            
dev->halt = fec_halt;                                     |            
dev->send = fec_send;                                     |            
dev->recv = fec_recv;                                     |            
......                                                    |            
|            
if (fec_get_hwaddr(dev, ethaddr) == 0) {            ------*-----+      
printf("got MAC address from IIM: %pM\n", ethaddr);   |   |      
memcpy(dev->enetaddr, ethaddr, 6);                  |   |      
fec_set_hwaddr(dev);                            ------*-----*-+   
}                                                         |   | |   
}                                                             |   | |   
|   | |   
return 1;                                                   |   | |   
}                                                               |   | |   
|   | |   
struct fec_info_s fec_info[] = {                     <----------+   | |   
{                                                             |   | |   
0,            /* index */                                    |   | |   
CONFIG_FEC0_IOBASE,    /* io base */               --------+-*-----*-*-+   
CONFIG_FEC0_PHY_ADDR,    /* phy_addr */                  | |   | | |   
0,            /* duplex and speed */                     | |   | | |   
0,            /* phy name */                               | |   | | |   
0,            /* phyname init */                           | |   | | |   
0,            /* RX BD */                                  | |   | | |   
0,            /* TX BD */                                  | |   | | |   
0,            /* rx Index */                               | |   | | |   
0,            /* tx Index */                               | |   | | |   
0,            /* tx buffer */                              | |   | | |   
#ifdef CONFIG_ARCH_MMU                                          | |   | | |   
{ 0 },            /* rx buffer */                        | |   | | |   
#endif                                                          | |   | | |   
0,            /* 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;                                     |       | | |   
#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 0;                                                 |         | |   
#else                                                         |         | |   
return -1;                                                |         | |   
#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(0));                  | |   
mac = value & 0xff;                                                | |   
mac = (value >> 8) & 0xff;                                       | |   
mac = (value >> 16) & 0xff;                                        | |   
mac = (value >> 24) & 0xff;                                        | |   
value = readl(OCOTP_BASE_ADDR + HW_OCOTP_MACn(1));                  | |   
mac = value & 0xff;                                                | |   
mac = (value >> 8) & 0xff;                                       | |   
#else                                                                     | |   
eth_getenv_enetaddr("ethaddr", mac);            ----------+         | |   
#endif                                                      |         | |   
return 0;                                                 |         | |   
}                                                             |         | |   
#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(0, &fecp->iaur);                                 |             |   
writel(0, &fecp->ialr);                                 |             |   
writel(0, &fecp->gaur);                                 |             |   
writel(0, &fecp->galr);                                 |             |   
|             |   
/*                                                      |             |   
* Set physical address                                 |             |   
*/                                                       V             |   
writel((mac << 24) + (mac << 16) + (mac << 8) + mac,------*-+
&fecp->palr);                                                   | |
writel((mac << 24) + (mac << 16) + 0x8808, &fecp->paur);          | |
| |
return 0;                                                               | |
}                                                                           | |
| |
| |
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 - 1,                         |      | |
.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, 0,         |      | |
res, ARRAY_SIZE(res),                                    |      | |
pdata, sizeof(*pdata), DMA_BIT_MASK(32));                |      | |
}                                                                  |      | |
|      | |
#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;                              |   |
|   |
/*                                                                  |   |
* 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) >> 16);               
iap = &tmpaddr;                                                      
}                                                                           
memcpy(ndev->dev_addr, iap, ETH_ALEN);                                    
/* Adjust MAC if using macaddr */                                          
if (iap == macaddr)                                                         
ndev->dev_addr = macaddr + fep->pdev->id;      
}
页: [1]
查看完整版本: I.MX6 Ethernet MAC (ENET) MAC Address hacking