且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

I.MX6 Ar8031 device register hacking

更新时间:2022-08-12 20:37:06

/*****************************************************************************
 *                   I.MX6 Ar8031 device register hacking
 * 声明:
 *   主要是为了知道网卡的注册流程,如果需要对网卡中的一些需求进行修改时,能够
 *   能够快速的对需求进行分析、修改。
 *
 *                                   2015-8-15 雨 深圳 南山区平山村 曾剑锋
 ****************************************************************************/

/*
 * initialize __mach_desc_MX6Q_SABRESD data structure.
 */
MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")
    /* 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); -----------------------------------------------+
    ......           |                                                      |
}                    +-------------+                                        |
                                   |                                        |
/*SBC-7112 NET Driver*/            V                                        |
static struct fec_platform_data fec_data __initdata = {                     |
        .init                   = mx6q_sabresd_fec_phy_init,   -----+       |
        .power_hibernate        = mx6_sabresd_fec_power_hibernate,--*------+|
        .phy                    = PHY_INTERFACE_MODE_RGMII,         |      ||
#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO                                  |      ||
        .gpio_irq = MX6_ENET_IRQ,                                   |      ||
#endif                                                              |      ||
};                                                                  |      ||
                                                                    |      ||
static int mx6q_sabresd_fec_phy_init(struct phy_device *phydev) <---+      ||
{                                                                          ||
    unsigned short val;                                                    ||
    gpio_request(SABRESD_FEC_PHY_RESET,"phy-rst");                         ||
    gpio_direction_output(SABRESD_FEC_PHY_RESET, 1);                       ||
    mdelay(1);                                                             ||
    gpio_direction_output(SABRESD_FEC_PHY_RESET, 0);                       ||
    mdelay(20);                                                            ||
    gpio_direction_output(SABRESD_FEC_PHY_RESET, 1);                       ||
    mdelay(5);                                                             ||
                                                                           ||
    /* Ar8031 phy SmartEEE feature cause link status generates glitch,     ||
     * which cause ethernet link down/up issue, so disable SmartEEE        ||
     */                                                                    ||
    phy_write(phydev, 0xd, 0x3);                                           ||
    phy_write(phydev, 0xe, 0x805d);                                        ||
    phy_write(phydev, 0xd, 0x4003);                                        ||
    val = phy_read(phydev, 0xe);                                           ||
    val &= ~(0x1 << 8);                                                    ||
    phy_write(phydev, 0xe, val);                                           ||
                                                                           ||
    /* To enable AR8031 ouput a 125MHz clk from CLK_25M */                 ||
    phy_write(phydev, 0xd, 0x7);                                           ||
    phy_write(phydev, 0xe, 0x8016);                                        ||
    phy_write(phydev, 0xd, 0x4007);                                        ||
    val = phy_read(phydev, 0xe);                                           ||
                                                                           ||
    val &= 0xffe3;                                                         ||
    val |= 0x18;                                                           ||
    phy_write(phydev, 0xe, val);                                           ||
                                                                           ||
    /* introduce tx clock delay */                                         ||
    phy_write(phydev, 0x1d, 0x5);                                          ||
    val = phy_read(phydev, 0x1e);                                          ||
    val |= 0x0100;                                                         ||
    phy_write(phydev, 0x1e, val);                                          ||
                                                                           ||
    /*check phy power*/                                                    ||
    val = phy_read(phydev, 0x0);                                           ||
    if (val & BMCR_PDOWN)                                                  ||
        phy_write(phydev, 0x0, (val & ~BMCR_PDOWN)); --------+             ||
    return 0;                                                |             ||
}                       +------------------------------------+             ||
                        V                                                  ||
static inline void phy_write(struct mii_phy *phy, int reg, int val)        ||
{                                                                          ||
    phy->mdio_write(phy->dev, phy->address, reg, val);                     ||
}                                                                          ||
                                                                           ||
static int mx6_sabresd_fec_power_hibernate(struct phy_device *phydev)  <---+|
{                                                                           |
    unsigned short val;                                                     |
                                                                            |
    /*set AR8031 debug reg 0xb to hibernate power*/                         |
    phy_write(phydev, 0x1d, 0xb);                                           |
    val = phy_read(phydev, 0x1e);                                           |
                                                                            |
    val |= 0x8000;                                                          |
    phy_write(phydev, 0x1e, val);                                           |
                                                                            |
    return 0;                                                               |
}                                                                           |
                                                                            |
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);            --------*---------------------+||
}                                                    |                     |||
                                                     |                     |||
static int fec_get_mac_addr(unsigned char *mac) <----+                     |||
{                                                                          |||
    unsigned int value;                                                    |||
                                                                           |||
    value = readl(MX6_IO_ADDRESS(OCOTP_BASE_ADDR) + HW_OCOTP_MACn(0));     |||
    printk("<danny debug> vaule = %x\n",value);                            |||
    value = 0x03040506;                                                    |||
    mac[5] = value & 0xff;                                                 |||
    mac[4] = (value >> 8) & 0xff;                                          ||| 
    mac[3] = (value >> 16) & 0xff;                                         |||
    mac[2] = (value >> 24) & 0xff;                                         |||
    value = readl(MX6_IO_ADDRESS(OCOTP_BASE_ADDR) + HW_OCOTP_MACn(1));     |||
    printk("<danny debug> vaule = %x\n",value);                            |||
    value = 0x0102;                                                        |||
    mac[1] = value & 0xff;                                                 |||
    mac[0] = (value >> 8) & 0xff;                                          |||
                                                                           |||
    return 0;                                                              |||
}                                                                          |||
                                                                           |||
static inline int is_valid_ether_addr(const u8 *addr)         <------------**+
{                                                                          ||  
    /* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to        ||
     * explicitly check for it here. */                                    ||
    return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);    ||
}                          ^                                  V            ||
                           V                                  |            ||
static inline int is_multicast_ether_addr(const u8 *addr)     |            ||
{                                                             |            ||  
    return 0x01 & addr[0];                                    |            ||
}                                                             |            ||
                                                              |            ||
static inline int is_zero_ether_addr(const u8 *addr)    <-----+            ||
{                                                                          ||
    return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);   ||
}                                                                          ||
                                                                           ||
static inline void random_ether_addr(u8 *addr)        <--------------------*+
{                                                                          |
    get_random_bytes (addr, ETH_ALEN);      -----------------------+       |
    addr [0] &= 0xfe;   /* clear multicast bit */                  |       |
    addr [0] |= 0x02;   /* set local assignment bit (IEEE802) */   |       |
}                                                                  |       |
                                                                   |       |
void get_random_bytes(void *buf, int nbytes)        <--------------+       |
{                                                                          |
    extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);  -----------+   |
}                                                                      |   |
EXPORT_SYMBOL(get_random_bytes);                                       |   |
                                                                       |   |
/********************************************************************* |   |
 *                                                                     |   |
 * Entropy extraction routines                                         |   |
 *                                                                     |   |
 ********************************************************************/ |   |
                                                                       |   |
static ssize_t extract_entropy(struct entropy_store *r, void *buf,  <--+   |
                   size_t nbytes, int min, int rsvd);                      |
                                                                           |
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                                                        |         |
                                                              |         |
#define imx_fec_data_entry_single(soc, _devid)  \        <----+         |
    {                                           \                       |
        .iobase = soc ## _FEC_BASE_ADDR,        \                       |
        .irq = soc ## _INT_FEC,                 \                       |
        .devid = _devid,                        \                       |
    }                                                                   |
                                                                        |
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));        |     |
}                                                            |     |
                                                             |     |
int fuse_dev_is_available(enum mxc_dev_type dev)       <-----+     |
{                                                                  |
    ......                                                         |
    if (!cpu_is_mx6())                                             |
        return 1;                                                  |
                                                                   |
    /* mx6sl is still not supported */                             |
    if (cpu_is_mx6sl())                                            |
        return 1;                                                  |
                                                                   |
    switch (dev) {                                                 |
    case MXC_DEV_PXP:                                              |
        if (cpu_is_mx6q())                                         |
            return 0;                                              |
                                                                   |
        if (cpu_is_mx6dl()) {                                      |
            reg = HW_OCOTP_CFGn(2);                                |
            mask = 0x80000000;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_OVG:                                              |
        if (cpu_is_mx6dl())                                        |
            return 0;                                              |
                                                                   |
        if (cpu_is_mx6q()) {                                       |
            reg = HW_OCOTP_CFGn(2);                                |
            mask = 0x40000000;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_DSI_CSI2:                                         |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(2);                                |
            mask = 0x10000000;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_ENET:                                             |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(2);                                |
            mask = 0x08000000;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_MLB:                                              |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(2);                                |
            mask = 0x04000000;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_EPDC:                                             |
        if (cpu_is_mx6q())                                         |
            return 0;                                              |
                                                                   |
        if (cpu_is_mx6dl()) {                                      |
            reg = HW_OCOTP_CFGn(2);                                |
            mask = 0x02000000;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_HDMI:                                             |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000080;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_PCIE:                                             |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000040;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_SATA:                                             |
        if (cpu_is_mx6dl())                                        |
            return 0;                                              |
                                                                   |
        if (cpu_is_mx6q()) {                                       |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000020;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_DTCP:                                             |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000010;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_2D:                                               |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000008;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_3D:                                               |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000004;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_VPU:                                              |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00008000;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_DIVX3:                                            |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000400;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_RV:                                               |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000200;                                     |
        }                                                          |
        break;                                                     |
    case MXC_DEV_SORENSEN:                                         |
        if (cpu_is_mx6dl() || cpu_is_mx6q()) {                     |
            reg = HW_OCOTP_CFGn(3);                                |
            mask = 0x00000100;                                     |
        }                                                          |
        break;                                                     |
    default:                                                       |
        /* we treat the unkown device is avaiable by default */    |
        return 1;                                                  |
    }                                                              |
                                                                   |
    ret = readl(MX6_IO_ADDRESS(OCOTP_BASE_ADDR) + reg) & mask;     |
    pr_debug("fuse_check: %s is %s\n", names[dev], ret ?           |
                    "unavailable" : "available");                  |
                                                                   |
    return !ret;                                                   |
}                                        +-------------------------+
                                         V
struct platform_device *__init imx_add_platform_device_dmamask(
        const char *name, int id,
        const struct resource *res, unsigned int num_resources,
        const void *data, size_t size_data, u64 dmamask)
{
    int ret = -ENOMEM;
    struct platform_device *pdev;

    pdev = platform_device_alloc(name, id);
    if (!pdev)
        goto err;

    if (dmamask) {
        /*
         * This memory isn't freed when the device is put,
         * I don't have a nice idea for that though.  Conceptually
         * dma_mask in struct device should not be a pointer.
         * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
         */
        pdev->dev.dma_mask =
            kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
        if (!pdev->dev.dma_mask)
            /* ret is still -ENOMEM; */
            goto err;

        *pdev->dev.dma_mask = dmamask;
        pdev->dev.coherent_dma_mask = dmamask;
    }

    if (res) {
        ret = platform_device_add_resources(pdev, res, num_resources);
        if (ret)
            goto err;
    }

    if (data) {
        ret = platform_device_add_data(pdev, data, size_data);
        if (ret)
            goto err;
    }

    ret = platform_device_add(pdev);
    if (ret) {
err:
        if (dmamask)
            kfree(pdev->dev.dma_mask);
        platform_device_put(pdev);
        return ERR_PTR(ret);
    }

    return pdev;
}