123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- /*
- * Copyright (c) 2006-2023, 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>
- #define BSP_USING_IMX6ULL_ART_PI
- #if (defined(RT_USING_ENET1)) || (defined(RT_USING_ENET2))
- #ifdef BSP_USING_IMX6ULL_ART_PI
- static struct imx6ull_iomuxc mdio_gpio[2] =
- {
- {IOMUXC_GPIO1_IO06_ENET1_MDIO,0U,0xB029},
- {IOMUXC_GPIO1_IO07_ENET1_MDC,0U,0xB0E9}
- };
- #else
- static struct imx6ull_iomuxc mdio_gpio[2] =
- {
- {IOMUXC_GPIO1_IO06_ENET2_MDIO,0U,0xB029},
- {IOMUXC_GPIO1_IO07_ENET2_MDC,0U,0xB0E9},
- };
- #endif
- enum
- {
- #ifdef RT_USING_ENET1
- DEV_ENET1,
- #endif
- #ifdef RT_USING_ENET2
- DEV_ENET2,
- #endif
- DEV_ENET_MAX,
- };
- 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
- },
- .gpio =
- {
- {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}
- }
- },
- #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
- },
- .gpio =
- {
- {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}
- }
- },
- #endif
- };
- void imx6ul_eth_link_change(struct rt_imx6ul_ethps *imx6ul_device,rt_bool_t up)
- {
- if(up)
- {
- LOG_D("enet%d link up",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",imx6ul_device->mac_num);
- eth_device_linkchange(&imx6ul_device->parent, RT_FALSE);
- 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");
- 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");
- 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");
- 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");
- 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");
- 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;
- }
- /* 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;
- rt_uint32_t reg_value;
- imx6ul_device->enet_virtual_base_addr = (ENET_Type *)rt_ioremap((void *)imx6ul_device->enet_phy_base_addr,SYS_PAGE_SIZE);
- base_addr = imx6ul_device->enet_virtual_base_addr;
- config = &imx6ul_device->config;
- handle = &imx6ul_device->handle;
- buffConfig = &imx6ul_device->buffConfig;
- for (int i=0; i<GET_ARRAY_NUM(imx6ul_device->gpio); i++)
- {
- imx6ull_gpio_init(&imx6ul_device->gpio[i]);
- }
- IOMUXC_GPR_Type *GPR1 = (IOMUXC_GPR_Type *)rt_ioremap((void *)IOMUXC_GPR,0x1000);
- if(imx6ul_device->mac_num == 1)
- {
- 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;
- }
- else if(imx6ul_device->mac_num == 2)
- {
- 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();
- 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_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)
- {
- OCOTP_Type *ocotp_base;
- rt_uint32_t uid[2];
- rt_uint32_t uid_crc = 0;
- ocotp_base = (OCOTP_Type *)rt_ioremap((void*)OCOTP_BASE, 0x1000);
- uid[0] = ocotp_base->CFG0;
- uid[1] = ocotp_base->CFG1;
- rt_iounmap(ocotp_base);
- LOG_D("UNIQUE_ID is %x%x",uid[0], uid[1]);
- uid_crc = uid[0] - uid[1];
- LOG_D("UNIQUE_ID change to 32 bits %x", uid_crc);
- if (imx6ul_device->enet_phy_base_addr == ENET1)
- {
- imx6ul_device->dev_addr[0] = 0xa8;
- imx6ul_device->dev_addr[1] = 0x5e;
- imx6ul_device->dev_addr[2] = 0x45;
- imx6ul_device->dev_addr[3] = (uid_crc>>16) & 0x7f;
- imx6ul_device->dev_addr[4] = (uid_crc>>8) & 0xff;
- imx6ul_device->dev_addr[5] = uid_crc & 0xff;
- }
- else /*if (imx6ul_device->enet_phy_base_addr == ENET2)*/
- {
- imx6ul_device->dev_addr[0] = 0xa8;
- imx6ul_device->dev_addr[1] = 0x5e;
- imx6ul_device->dev_addr[2] = 0x46;
- imx6ul_device->dev_addr[3] = (uid_crc >> 16) & 0x7f;
- imx6ul_device->dev_addr[4] = (uid_crc >> 8) & 0xff;
- imx6ul_device->dev_addr[5] = uid_crc & 0xff;
- }
- 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",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",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");
- 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)
- {
- bool link = false;
- phy_speed_t speed;
- phy_duplex_t duplex;
- 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;
- phy_reset(imx6ul_device->phy_base_addr,imx6ul_device->phy_gpio_pin);
- PHY_Init(base_addr, imx6ul_device->phy_num, SYS_CLOCK_HZ,imx6ul_device->phy_id);
- PHY_GetLinkStatus(base_addr, imx6ul_device->phy_num, &link);
- if (link)
- {
- /* Get the actual PHY link speed. */
- PHY_GetLinkSpeedDuplex(base_addr, imx6ul_device->phy_num, &speed, &duplex);
- /* Change the MII speed and duplex for actual link status. */
- imx6ul_device->config.miiSpeed = (enet_mii_speed_t)speed;
- imx6ul_device->config.miiDuplex = (enet_mii_duplex_t)duplex;
- }
- else
- {
- LOG_W("PHY Link down, please check the cable connection and link partner setting.");
- }
- while(1)
- {
- PHY_GetLinkStatus(base_addr, imx6ul_device->phy_num, &link);
- if(link != imx6ul_device->phy_link_status)
- {
- if(link == true)
- {
- PHY_StartNegotiation(base_addr,imx6ul_device->phy_num);
- }
- imx6ul_eth_link_change(imx6ul_device,link);
- }
- rt_thread_delay(DETECT_DELAY_ONE_SECOND);
- }
- }
- _internal_ro struct rt_device_ops _k_enet_ops =
- {
- .init = rt_imx6ul_eth_init,
- .control = rt_imx6ul_eth_control,
- };
- static int imx6ul_eth_init(void)
- {
- rt_err_t state = RT_EOK;
- char link_detect[10];
- imx6ull_gpio_init(&mdio_gpio[0]);
- imx6ull_gpio_init(&mdio_gpio[1]);
- for (int idx=0; idx<GET_ARRAY_NUM(_imx6ul_eth_device); idx++)
- {
- _imx6ul_eth_device[idx].parent.parent.ops = &_k_enet_ops;
- _imx6ul_eth_device[idx].parent.eth_rx = rt_imx6ul_eth_rx;
- _imx6ul_eth_device[idx].parent.eth_tx = rt_imx6ul_eth_tx;
- _imx6ul_eth_device[idx].phy_link_status = RT_FALSE;
- /* register eth device */
- state = eth_device_init(&(_imx6ul_eth_device[idx].parent), _imx6ul_eth_device[idx].mac_name);
- if (RT_EOK == state)
- {
- LOG_I("emac device init success");
- }
- else
- {
- LOG_E("emac device init faild: %d", state);
- state = -RT_ERROR;
- }
- rt_sprintf(link_detect,"link_d%d",_imx6ul_eth_device[idx].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[idx],
- 4096,
- RT_THREAD_PRIORITY_MAX - 2,
- 2);
- if (phy_link_tid != RT_NULL)
- {
- rt_thread_startup(phy_link_tid);
- }
- memset(link_detect,0,sizeof(link_detect));
- }
- return state;
- }
- INIT_DEVICE_EXPORT(imx6ul_eth_init);
- #endif
|