soem主站移植到rt thread smart操作系统

2021年花了两个月时间捣鼓了rt thread smart操作系统,其是一款国产开源操作系统,用起来的感觉和linux、freertos很像。其支持带mmu的芯片,理论上是支持linux端的程序移植的,因此可以取代一部分的嵌入式linux系统。下图摘自rt thread smart官网。
在这里插入图片描述
rt smart是2020年新推出的操作系统,目前支持的板子不多,想学习的话只能拿imx6ull板子来练练手了。我测试了art-pi samrt开发板、韦东山imx6ull和野火的imx6ull,都可以成功运行。
在linux上开发ethercat主站,需要配合xenomai。我想用rt thread smart操作系统来替换掉Linux,由于rt smart本身就是实时操作系统,因此也就不需要xenomai了。把之前基于linux开发的运动控制器程序,移植一下,理论上应该能在rt thread smart系统上跑起来。我打算先移植一下soem主站试试。
大概捣鼓了两周,终于跑起来了。imx6ull的网卡感觉存在bug,其芯片本身是内置enet1和enet0外设的,但是mdio只能访问一个phy外设,没法实时检测两个phy,一开启就会出错,所以只好都关了。这部分折腾了我好久,也没找到更好的解决办法。
调试后的效果就是,一个网口可以进行tcp/ip通讯,一个网口进行ethercat通讯。实验效果如下:

soem主站移植到rt thread smart操作系统

整个移植步骤和移植到stm32上的步骤差不多,主要就是网卡驱动部分比较繁琐。tcp/ip网口我是保留了rt smart的驱动框架,ethercat那个网口基本就是裸机程序。然后把ethercat网卡初始化代码嵌入tcp/ip网口驱动代码中。
驱动部分代码如下:

drv_eth.h

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-06-16     songchao   first version
 * 2021-08-13     songchao   add more device info
 */

#ifndef __DRV_ETH_H__
#define __DRV_ETH_H__

#include <rtthread.h>
#include <netif/ethernetif.h>
#include "fsl_phy.h"
#include "imx6ull.h"
#include "drv_common.h"

#ifdef __cplusplus
extern "C" {
#endif

#define MAX_ADDR_LEN 6
struct rt_imx6ul_ethps
{
    /* inherit from ethernet device */
    struct eth_device parent;
    /* interface address info, hw address */
    rt_uint8_t  dev_addr[MAX_ADDR_LEN];
    /* ETH_Speed */
    uint32_t    ETH_Speed;
    /* ETH_Duplex_Mode */
    uint32_t    ETH_Mode;
    rt_bool_t phy_link_status;
    const char *mac_name;
    const char *irq_name;
    enum _imx_interrupts irq_num;
    uint8_t phy_num;
    const ENET_Type *enet_phy_base_addr;
    ENET_Type *enet_virtual_base_addr;
    uint32_t mac_num;
    enet_buffer_config_t buffConfig;
    enet_config_t config;
    enet_handle_t handle;
    GPIO_Type *phy_base_addr;
    uint32_t phy_gpio_pin;
    uint32_t phy_id;
};

struct rt_imx6ul_lan8720
{
    /* interface address info, hw address */
    rt_uint8_t  dev_addr[MAX_ADDR_LEN];
    /* ETH_Speed */
    uint32_t    ETH_Speed;
    /* ETH_Duplex_Mode */
    uint32_t    ETH_Mode;
    rt_bool_t phy_link_status;
    const char *mac_name;
    uint8_t phy_num;
    const ENET_Type *enet_phy_base_addr;
    ENET_Type *enet_virtual_base_addr;
    uint32_t mac_num;
    enet_buffer_config_t buffConfig;
    enet_config_t config;
    enet_handle_t handle;
    GPIO_Type *phy_base_addr;
    uint32_t phy_gpio_pin;
    uint32_t phy_id;
};

int32_t get_instance_by_base(void *base);
void enable_mdio_enet1(void);
void enable_mdio_enet2(void);
void enable_enet_gpio(void);
rt_err_t rt_imx6ul_lan8720_init(void);

#ifdef __cplusplus
}
#endif

#endif /* __DRV_ETH_H__ */

drv_eth.c

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-06-16     songchao   support emac driver
 * 2021-06-29     songchao   add phy link detect
 * 2021-08-13     songchao   support dual mac and reduse copy
 */

#include "drv_eth.h"
#define DBG_TAG "drv.enet"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#if (defined(RT_USING_ENET1)) || (defined(RT_USING_ENET2))

static struct imx6ull_iomuxc mdio_gpio_enet1[2] = 
{
    {IOMUXC_GPIO1_IO06_ENET1_MDIO,0U,0xB029},
    {IOMUXC_GPIO1_IO07_ENET1_MDC,0U,0xB0E9}
};

static struct imx6ull_iomuxc mdio_gpio_enet2[2] = 
{
    {IOMUXC_GPIO1_IO06_ENET2_MDIO,0U,0xB029},
    {IOMUXC_GPIO1_IO07_ENET2_MDC,0U,0xB0E9},
};

static struct imx6ull_iomuxc enet1_gpio[9] = 
{
    {IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09,0U,0x110B0},
    {IOMUXC_ENET1_RX_DATA0_ENET1_RDATA00,0U,0xB0E9},
    {IOMUXC_ENET1_RX_DATA1_ENET1_RDATA01,0U,0xB0E9},
    {IOMUXC_ENET1_RX_EN_ENET1_RX_EN,0U,0xB0E9},
    {IOMUXC_ENET1_RX_ER_ENET1_RX_ER,0U,0xB0E9},
    {IOMUXC_ENET1_TX_CLK_ENET1_REF_CLK1,1U,0x00F0},
    {IOMUXC_ENET1_TX_DATA0_ENET1_TDATA00,0U,0xB0E9},
    {IOMUXC_ENET1_TX_DATA1_ENET1_TDATA01,0U,0xB0E9},
    {IOMUXC_ENET1_TX_EN_ENET1_TX_EN,0U,0xB0E9}
};

static struct imx6ull_iomuxc lan8720_gpio[9] = 
{
    {IOMUXC_SNVS_SNVS_TAMPER6_GPIO5_IO06,0U,0x110B0},
    {IOMUXC_ENET2_RX_DATA0_ENET2_RDATA00,0U,0xB0E9},
    {IOMUXC_ENET2_RX_DATA1_ENET2_RDATA01,0U,0xB0E9},
    {IOMUXC_ENET2_RX_EN_ENET2_RX_EN,0U,0xB0E9},
    {IOMUXC_ENET2_RX_ER_ENET2_RX_ER,0U,0xB0E9},
    {IOMUXC_ENET2_TX_CLK_ENET2_REF_CLK2,1U,0x00F0},
    {IOMUXC_ENET2_TX_DATA0_ENET2_TDATA00,0U,0xB0E9},
    {IOMUXC_ENET2_TX_DATA1_ENET2_TDATA01,0U,0xB0E9},
    {IOMUXC_ENET2_TX_EN_ENET2_TX_EN,0U,0xB0E9}
};

static struct rt_imx6ul_lan8720 _imx6ul_lan8720_device =
{
    .dev_addr = {0xa8,0x5e,0x45,0x01,0x02,0x03},
    .mac_name = "e2",
    .enet_phy_base_addr = ENET2,
    .phy_num = ENET_PHY2,
    .mac_num = 2,
    .phy_base_addr = GPIO5,
    .phy_gpio_pin = 6,
    .phy_id = 7,
    .buffConfig =
    {
        ENET_RXBD_NUM,
        ENET_TXBD_NUM,
        ENET_RXBUFF_ALIGN_SIZE,
        ENET_TXBUFF_ALIGN_SIZE,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        ENET_RXBUFF_TOTAL_SIZE,
        ENET_TXBUFF_TOTAL_SIZE
    },
};


#define DEV_ENET_MAX 1

static struct rt_imx6ul_ethps _imx6ul_eth_device[DEV_ENET_MAX] = 
{
#ifdef RT_USING_ENET1
    {
        .dev_addr = {0xa8,0x5e,0x45,0x91,0x92,0x93},
        .mac_name = "e1",
        .irq_name = "emac1_intr",
        .enet_phy_base_addr = ENET1,
        .irq_num = IMX_INT_ENET1,
        .phy_num = ENET_PHY1,
        .mac_num = 1,
        .phy_base_addr = GPIO5,
        .phy_gpio_pin = 9,
        .phy_id = 7,
        .buffConfig =
        {
            ENET_RXBD_NUM,
            ENET_TXBD_NUM,
            ENET_RXBUFF_ALIGN_SIZE,
            ENET_TXBUFF_ALIGN_SIZE,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            ENET_RXBUFF_TOTAL_SIZE,
            ENET_TXBUFF_TOTAL_SIZE
        },
    },
#endif

#ifdef RT_USING_ENET2
    {
        .dev_addr = {0xa8,0x5e,0x45,0x01,0x02,0x03},
        .mac_name = "e2",
        .irq_name = "emac2_intr",
        .enet_phy_base_addr = ENET2,
        .irq_num = IMX_INT_ENET2,
        .phy_num = ENET_PHY2,
        .mac_num = 2,
        .phy_base_addr = GPIO5,
        .phy_gpio_pin = 6,
        .phy_id = 7,
        .buffConfig =
        {
            ENET_RXBD_NUM,
            ENET_TXBD_NUM,
            ENET_RXBUFF_ALIGN_SIZE,
            ENET_TXBUFF_ALIGN_SIZE,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            RT_NULL,
            ENET_RXBUFF_TOTAL_SIZE,
            ENET_TXBUFF_TOTAL_SIZE
        },
    },
#endif
};

void imx6ul_eth_link_change(struct rt_imx6ul_ethps *imx6ul_device,rt_bool_t up)
{
    if(up)
    {
        LOG_D("enet%d link up\n",imx6ul_device->mac_num);
        eth_device_linkchange(&imx6ul_device->parent, RT_TRUE);
        imx6ul_device->phy_link_status = RT_TRUE;
    }
    else
    {
        LOG_D("enet%d link down\n",imx6ul_device->mac_num);
        eth_device_linkchange(&imx6ul_device->parent, RT_FALSE);
        imx6ul_device->phy_link_status = RT_FALSE;
    }
}

void imx6ul_lan8720_link_change(struct rt_imx6ul_lan8720 *imx6ul_device,rt_bool_t up)
{
    if(up)
    {
        LOG_D("enet%d link up\n",imx6ul_device->mac_num);
        imx6ul_device->phy_link_status = RT_TRUE;
    }
    else
    {
        LOG_D("enet%d link down\n",imx6ul_device->mac_num);
        imx6ul_device->phy_link_status = RT_FALSE;
    }
}

void ENET_InitModuleClock(void)
{
    const clock_enet_pll_config_t config = {true, true, false, 1, 1};
    CLOCK_InitEnetPll(&config);
}

rt_err_t enet_buffer_init(enet_buffer_config_t *buffConfig)
{
    void *tx_buff_addr = RT_NULL;
    void *rx_buff_addr = RT_NULL;
    void *tx_bd_addr = RT_NULL;
    void *rx_bd_addr = RT_NULL;

    if(((SYS_PAGE_SIZE<<RX_BUFFER_INDEX_NUM)<buffConfig->rxBufferTotalSize)||
       ((SYS_PAGE_SIZE<<TX_BUFFER_INDEX_NUM)<buffConfig->txBufferTotalSize))
    {
        LOG_E("ERROR: alloc mem not enough for enet driver\n");
        return RT_ERROR;
    }
    rx_buff_addr = rt_pages_alloc(RX_BUFFER_INDEX_NUM);
    if(!rx_buff_addr)
    {
        LOG_E("ERROR: rx buff page alloc failed\n");
        return RT_ERROR;
    }
    buffConfig->rxBufferAlign = (void *)rt_ioremap_nocache(virtual_to_physical(rx_buff_addr), (SYS_PAGE_SIZE<<RX_BUFFER_INDEX_NUM));
    buffConfig->rxPhyBufferAlign = (void *)virtual_to_physical(rx_buff_addr);

    tx_buff_addr = rt_pages_alloc(TX_BUFFER_INDEX_NUM);
    if(!tx_buff_addr)
    {
        LOG_E("ERROR: tx buff page alloc failed\n");
        return RT_ERROR;
    }
    buffConfig->txBufferAlign = (void *)rt_ioremap_nocache(virtual_to_physical(tx_buff_addr), (SYS_PAGE_SIZE<<TX_BUFFER_INDEX_NUM));
    buffConfig->txPhyBufferAlign = (void *)virtual_to_physical(tx_buff_addr);

    rx_bd_addr = rt_pages_alloc(RX_BD_INDEX_NUM);
    if(!rx_bd_addr)
    {
        LOG_E("ERROR: rx bd page alloc failed\n");
        return RT_ERROR;
    }
    buffConfig->rxBdStartAddrAlign = (void *)rt_ioremap_nocache(virtual_to_physical(rx_bd_addr), (SYS_PAGE_SIZE<<RX_BD_INDEX_NUM));
    buffConfig->rxPhyBdStartAddrAlign = virtual_to_physical(rx_bd_addr);

    tx_bd_addr = rt_pages_alloc(TX_BD_INDEX_NUM);
    if(!tx_bd_addr)
    {
        LOG_E("ERROR: tx bd page alloc failed\n");
        return RT_ERROR;
    }
    buffConfig->txBdStartAddrAlign = (void *)rt_ioremap_nocache(virtual_to_physical(tx_bd_addr), (SYS_PAGE_SIZE<<TX_BD_INDEX_NUM));
    buffConfig->txPhyBdStartAddrAlign = virtual_to_physical(tx_bd_addr);

    return RT_EOK;
}

rt_err_t rt_imx6ul_lan8720_init(void)
{
    rt_kprintf("\r\nrt_imx6ul_lan8720_init\r\n");
    rt_err_t state;
    struct rt_imx6ul_lan8720 *lan8720_device = &_imx6ul_lan8720_device;
    ENET_Type *base_addr = RT_NULL;
    enet_config_t *config;
    enet_handle_t *handle;
    enet_buffer_config_t *buffConfig;
    
    base_addr = lan8720_device->enet_virtual_base_addr;
    config = &lan8720_device->config;
    handle = &lan8720_device->handle;
    buffConfig = &lan8720_device->buffConfig;
    
    ENET_GetDefaultConfig(config);
    state = enet_buffer_init(buffConfig);
    if(state != RT_EOK)
    {
        return state;
    }
    ENET_Init_lan8720(base_addr, handle, config, buffConfig, &lan8720_device->dev_addr[0], SYS_CLOCK_HZ);
    ENET_ActiveRead(base_addr);
    rt_kprintf("\r\nrt_imx6ul_lan8720_init end\r\n");
    return RT_EOK;
}

/* EMAC initialization function */
static rt_err_t rt_imx6ul_eth_init(rt_device_t dev)
{
    rt_err_t state;
    struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
    ENET_Type *base_addr = RT_NULL;
    enet_config_t *config;
    enet_handle_t *handle;
    enet_buffer_config_t *buffConfig;
    
    base_addr = imx6ul_device->enet_virtual_base_addr;
    config = &imx6ul_device->config;
    handle = &imx6ul_device->handle;
    buffConfig = &imx6ul_device->buffConfig;
    
    ENET_GetDefaultConfig(config);
    config->interrupt |= (ENET_RX_INTERRUPT);
    state = enet_buffer_init(buffConfig);
    if(state != RT_EOK)
    {
        return state;
    }
    ENET_Init(base_addr, handle, config, buffConfig, &imx6ul_device->dev_addr[0], SYS_CLOCK_HZ);
    ENET_ActiveRead(base_addr);
    rt_hw_interrupt_install(imx6ul_device->irq_num, (rt_isr_handler_t)ENET_DriverIRQHandler, (void *)base_addr,imx6ul_device->irq_name);
    rt_hw_interrupt_umask(imx6ul_device->irq_num);

    return RT_EOK;
}


static rt_err_t rt_imx6ul_eth_open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

static rt_err_t rt_imx6ul_eth_close(rt_device_t dev)
{
    return RT_EOK;
}

static rt_size_t rt_imx6ul_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    return 0;
}

static rt_size_t rt_imx6ul_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    return 0;
}

static rt_err_t rt_imx6ul_eth_control(rt_device_t dev, int cmd, void *args)
{
    struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
    switch (cmd)
    {
    case NIOCTL_GADDR:
        /* get MAC address */
        if (args)
        {
            rt_memcpy(args, imx6ul_device->dev_addr, MAX_ADDR_LEN);
        }
        else
        {
            return -RT_ERROR;
        }
        break;

    default :
        break;
    }
    return RT_EOK;
}

static status_t read_data_from_eth(rt_device_t dev,void *read_data,uint16_t *read_length)
{
    status_t status = 0;
    uint16_t length = 0;
    ENET_Type *base_addr = RT_NULL;
    enet_config_t *config;
    enet_handle_t *handle;
    enet_buffer_config_t *buffConfig;
    struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
    base_addr = imx6ul_device->enet_virtual_base_addr;
    config = &imx6ul_device->config;
    handle = &imx6ul_device->handle;
    buffConfig = &imx6ul_device->buffConfig;
    /* Get the Frame size */
    status = ENET_ReadFrame(base_addr,handle,config,read_data,&length);
    if((status == kStatus_ENET_RxFrameEmpty)||(status == kStatus_ENET_RxFrameError))
    {
        ENET_EnableInterrupts(base_addr,ENET_RX_INTERRUPT);
        if(status == kStatus_ENET_RxFrameError)
        {
            /*recv error happend reinitialize mac*/
            ENET_Init(base_addr, handle, config, buffConfig, &imx6ul_device->dev_addr[0], SYS_CLOCK_HZ);
            ENET_ActiveRead(base_addr);
            return kStatus_ENET_RxFrameError;
        }
        else if(status == kStatus_ENET_RxFrameEmpty)
        {
            return kStatus_ENET_RxFrameEmpty;
        }
    }
    *read_length = length;
    return status;
}

/* transmit data*/
rt_err_t rt_imx6ul_eth_tx(rt_device_t dev, struct pbuf *p)
{
    rt_err_t ret = RT_ERROR;
    struct pbuf *q = RT_NULL;
    uint16_t offset = 0;
    uint32_t last_flag = 0;
    status_t status;
    ENET_Type *base_addr = RT_NULL;
    enet_handle_t *handle;
    struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
    base_addr = imx6ul_device->enet_virtual_base_addr;
    handle = &imx6ul_device->handle;
    RT_ASSERT(p);

    for(q = p;q != RT_NULL;q=q->next)
    {
        if(q->next == RT_NULL)
        {
            last_flag = 1;
        }
        else
        {
            last_flag = 0;
        }
        status = ENET_SendFrame(base_addr, handle, q->payload, q->len,last_flag);
        offset = offset + q->len;
        if(status == kStatus_Success)
        {
        }
        else
        {
            return RT_ERROR;
        }
    }
    if(offset > ENET_FRAME_MAX_FRAMELEN)
    {
        LOG_E("net error send length %d exceed max length\n",offset);
    }
    return ret;
}

struct pbuf *rt_imx6ul_eth_rx(rt_device_t dev)
{
    static struct pbuf *p_s = RT_NULL;
    struct pbuf *p = RT_NULL;
    status_t status;
    uint16_t length = 0;

    if(p_s == RT_NULL)
    {
        p_s = pbuf_alloc(PBUF_RAW, ENET_FRAME_MAX_FRAMELEN, PBUF_POOL);
        if(p_s == RT_NULL)
        {
            return RT_NULL;
        }
    }
    p = p_s;
    status = read_data_from_eth(dev,p->payload,&length);
    if(status == kStatus_ENET_RxFrameEmpty)
    {
        return RT_NULL;
    }
    else if(status == kStatus_ENET_RxFrameError)
    {
        return RT_NULL;
    }
    if(length > ENET_FRAME_MAX_FRAMELEN)
    {
        LOG_E("net error recv length %d exceed max length\n",length);
        return RT_NULL;
    }
    pbuf_realloc(p, length);
    p_s = RT_NULL;
    return p;
}

int32_t get_instance_by_base(void *base)
{
    int32_t i = 0;
    int32_t instance = 0;
    for(i = 0; i < DEV_ENET_MAX; i ++)
    {
        if((void *)_imx6ul_eth_device[i].enet_virtual_base_addr == base)
        {
            break;
        }
    }
    if(i == DEV_ENET_MAX)
    {
        return -1;
    }
    return instance;
    
}
void rx_enet_callback(void *base)
{
    int32_t instance = 0;
    instance = get_instance_by_base(base);
    if(instance == -1)
    {
        LOG_E("interrput match base addr error \n");
        return;
    }
    eth_device_ready(&(_imx6ul_eth_device[instance].parent));
    ENET_DisableInterrupts(base,ENET_RX_INTERRUPT);
}

void tx_enet_callback(void *base)
{
    ENET_DisableInterrupts(base,ENET_TX_INTERRUPT);
}

/*phy link detect thread*/
static void phy_detect_thread_entry(void *param)
{
    rt_kprintf("phy_detect_thread_entry!\n");
    bool link = false;
    ENET_Type *base_addr = RT_NULL;
    struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)param;
    base_addr = imx6ul_device->enet_virtual_base_addr;

    while(1)
    {
        PHY_GetLinkStatus(base_addr, imx6ul_device->phy_num, &link);
        if(link != imx6ul_device->phy_link_status)
        {          
            imx6ul_eth_link_change(imx6ul_device,link);
        }
        rt_thread_delay(DETECT_DELAY_ONE_SECOND);
    }
}

/*phy link detect thread*/
static void lan8720_detect_thread_entry(void *param)
{
    rt_kprintf("lan8720_detect_thread_entry!\n");
    bool link_lan8720 = false;
    ENET_Type *lan8720_addr = RT_NULL;
    struct rt_imx6ul_lan8720 *lan8720_device =  (struct rt_imx6ul_lan8720 *)param;
    lan8720_addr = lan8720_device->enet_virtual_base_addr;

    while(1)
    {     
        PHY_GetLinkStatus(lan8720_addr, lan8720_device->phy_num, &link_lan8720);
        if(link_lan8720 != lan8720_device->phy_link_status)
        {         
            imx6ul_lan8720_link_change(lan8720_device,link_lan8720);
        }
        rt_thread_delay(DETECT_DELAY_ONE_SECOND);
    }
}


_internal_ro struct rt_device_ops _k_enet_ops =
{
    rt_imx6ul_eth_init,
    rt_imx6ul_eth_open,
    rt_imx6ul_eth_close,
    rt_imx6ul_eth_read,
    rt_imx6ul_eth_write,
    rt_imx6ul_eth_control,
};

void enable_mdio_enet1(void)
{
    imx6ull_gpio_init(&mdio_gpio_enet1[0]);
    imx6ull_gpio_init(&mdio_gpio_enet1[1]);
}

void enable_mdio_enet2(void)
{
    imx6ull_gpio_init(&mdio_gpio_enet2[0]);
    imx6ull_gpio_init(&mdio_gpio_enet2[1]);
}

void enable_enet_gpio(void)
{
    for (int i=0; i<GET_ARRAY_NUM(enet1_gpio); i++)
    {
        imx6ull_gpio_init(&enet1_gpio[i]);
    }

    for (int i=0; i<GET_ARRAY_NUM(lan8720_gpio); i++)
    {
        imx6ull_gpio_init(&lan8720_gpio[i]);
    }
}

static int imx6ul_eth_init(void)
{
    rt_err_t state = RT_EOK;
    rt_uint32_t init_flag;
    phy_speed_t speed;
    phy_duplex_t duplex;
    bool link = false;
    bool link_lan8720 = false;

    // enable_mdio_enet2();
    enable_enet_gpio();
    phy_reset_all();

    rt_uint32_t reg_value;
    IOMUXC_GPR_Type *GPR1 = (IOMUXC_GPR_Type *)rt_ioremap((void *)IOMUXC_GPR,0x1000);
    reg_value = GPR1->GPR1;
    reg_value &= ~(IOMUXC_GPR_GPR1_ENET1_CLK_SEL_MASK
                | IOMUXC_GPR_GPR1_ENET1_CLK_SEL_MASK);
    reg_value |=  IOMUXC_GPR_GPR1_ENET1_TX_CLK_DIR(1);
    reg_value |=  IOMUXC_GPR_GPR1_ENET1_CLK_SEL(0);
    GPR1->GPR1 = reg_value;

    reg_value = GPR1->GPR1;
    reg_value &= ~(IOMUXC_GPR_GPR1_ENET2_CLK_SEL_MASK
                | IOMUXC_GPR_GPR1_ENET2_CLK_SEL_MASK);
    reg_value |=  IOMUXC_GPR_GPR1_ENET2_TX_CLK_DIR(1);
    reg_value |=  IOMUXC_GPR_GPR1_ENET2_CLK_SEL(0);
    GPR1->GPR1 = reg_value;
    
    ENET_InitModuleClock();

    _imx6ul_eth_device[0].enet_virtual_base_addr = (ENET_Type *)rt_ioremap((void *)ENET1,SYS_PAGE_SIZE);
    _imx6ul_lan8720_device.enet_virtual_base_addr = (ENET_Type *)rt_ioremap((void *)ENET2,SYS_PAGE_SIZE);
    _imx6ul_eth_device[0].phy_link_status   = RT_FALSE;
    _imx6ul_lan8720_device.phy_link_status = RT_FALSE;

    /****************************************************************************************/

    _imx6ul_eth_device[0].parent.parent.ops = &_k_enet_ops;
    _imx6ul_eth_device[0].parent.eth_rx     = rt_imx6ul_eth_rx;
    _imx6ul_eth_device[0].parent.eth_tx     = rt_imx6ul_eth_tx;
    

    /* register eth device */
    state = eth_device_init(&(_imx6ul_eth_device[0].parent), _imx6ul_eth_device[0].mac_name);
    if (RT_EOK == state)
    {
        LOG_E("emac device init success\n");
    }
    else
    {
        LOG_E("emac device init faild: %d", state);
        state = -RT_ERROR;
    }
    
    /****************************************************************************************/
    enable_mdio_enet1();

    init_flag = PHY_Init_enet1(_imx6ul_eth_device[0].enet_virtual_base_addr,_imx6ul_eth_device[0].phy_num, SYS_CLOCK_HZ);
    if(init_flag == 0)
    {
        rt_kprintf("PHY_Init enet1 success!\n");
    }

    PHY_GetLinkStatus(_imx6ul_eth_device[0].enet_virtual_base_addr,_imx6ul_eth_device[0].phy_num, &link);
    if (link)
    {
        /* Get the actual PHY link speed. */
        PHY_GetLinkSpeedDuplex(_imx6ul_eth_device[0].enet_virtual_base_addr, _imx6ul_eth_device[0].phy_num, &speed, &duplex);
        /* Change the MII speed and duplex for actual link status. */
        _imx6ul_eth_device[0].config.miiSpeed = (enet_mii_speed_t)speed;
        _imx6ul_eth_device[0].config.miiDuplex = (enet_mii_duplex_t)duplex;
        rt_kprintf("\r\nenet1 Link up.\r\n");
    }
    else
    {
        rt_kprintf("\r\nenet1 Link down, please check the cable connection and link partner setting.\r\n");
    }

    if(link != _imx6ul_eth_device[0].phy_link_status)
    {       
        imx6ul_eth_link_change(&_imx6ul_eth_device[0],link);
    }

    /****************************************************************************************/
    enable_mdio_enet2();
    rt_imx6ul_lan8720_init();

    init_flag = PHY_Init_enet2(_imx6ul_lan8720_device.enet_virtual_base_addr,_imx6ul_lan8720_device.phy_num, SYS_CLOCK_HZ);
    if(init_flag == 0)
    {
        rt_kprintf("PHY_Init enet2 success!\n");
    }

    PHY_GetLinkStatus(_imx6ul_lan8720_device.enet_virtual_base_addr,_imx6ul_lan8720_device.phy_num, &link_lan8720);
    if (link_lan8720)
    {
        /* Get the actual PHY link speed. */
        PHY_GetLinkSpeedDuplex(_imx6ul_lan8720_device.enet_virtual_base_addr,_imx6ul_lan8720_device.phy_num, &speed, &duplex);
        /* Change the MII speed and duplex for actual link status. */
        _imx6ul_lan8720_device.config.miiSpeed = (enet_mii_speed_t)speed;
        _imx6ul_lan8720_device.config.miiDuplex = (enet_mii_duplex_t)duplex;
        rt_kprintf("\r\nenet1 Link up.\r\n");
    }
    else
    {
        rt_kprintf("\r\nenet2 Link down, please check the cable connection and link partner setting.\r\n");
    }

    if(link_lan8720 != _imx6ul_lan8720_device.phy_link_status)
    {       
        imx6ul_lan8720_link_change(&_imx6ul_lan8720_device,link_lan8720);
    }












    // char link_detect[10];
    // rt_sprintf(link_detect,"link_d%d",_imx6ul_eth_device[0].mac_num);
    // /* start phy link detect */
    // rt_thread_t phy_link_tid;
    // phy_link_tid = rt_thread_create(link_detect,
    //                         phy_detect_thread_entry,
    //                         &_imx6ul_eth_device[0],
    //                         4096,
    //                         21,
    //                         2);
    // if (phy_link_tid != RT_NULL)
    // {
    //     rt_thread_startup(phy_link_tid);
    // }
    // memset(link_detect,0,sizeof(link_detect));



    // char lan8720_detect[10];
    // rt_sprintf(lan8720_detect,"link_d%d",_imx6ul_lan8720_device.mac_num);
    // /* start phy link detect */
    // rt_thread_t lan8720_link_tid;
    // lan8720_link_tid = rt_thread_create(lan8720_detect,
    //                         lan8720_detect_thread_entry,
    //                         &_imx6ul_lan8720_device,
    //                         4096,
    //                         21,
    //                         2);
    // if (lan8720_link_tid != RT_NULL)
    // {
    //     rt_thread_startup(lan8720_link_tid);
    // }
    // memset(lan8720_detect,0,sizeof(lan8720_detect));



    return state;
}
INIT_DEVICE_EXPORT(imx6ul_eth_init);
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值