I.MX6 Ethernet MAC (ENET) MAC Address hacking

时间:2021-11-26 09:25:03
/*********************************************************************
 *        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[6];                                                   
                                                                                
    for (i = 0; i < sizeof(fec_info) / sizeof(fec_info[0]); 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[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) == 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[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 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[5] = value & 0xff;                                                | |   
    mac[4] = (value >> 8) & 0xff;                                         | |   
    mac[3] = (value >> 16) & 0xff;                                        | |   
    mac[2] = (value >> 24) & 0xff;                                        | |   
    value = readl(OCOTP_BASE_ADDR + HW_OCOTP_MACn(1));                    | |   
    mac[1] = value & 0xff;                                                | |   
    mac[0] = (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[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],  ------*-+ 
            &fecp->palr);                                                   | | 
    writel((mac[4] << 24) + (mac[5] << 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[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[0]) =                              |     | 
            be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW));     <----------+-----+ 
        *((unsigned short *) &tmpaddr[4]) =                                     
            be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16);                 
        iap = &tmpaddr[0];                                                      
    }                                                                           
                                                                                
    memcpy(ndev->dev_addr, iap, ETH_ALEN);                                      
                                                                                
    /* Adjust MAC if using macaddr */                                           
    if (iap == macaddr)                                                         
         ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->pdev->id;      
}