From 2e224b30ad68e934205467721ac2385d7d66676d Mon Sep 17 00:00:00 2001 From: flyingcys Date: Sun, 18 Aug 2024 13:29:02 +0800 Subject: [PATCH] [bsp/cvitek] eth driver support phy link detect Signed-off-by: flyingcys --- bsp/cvitek/drivers/drv_eth.c | 64 +++++++++++-- .../drivers/libraries/eth/cvi_eth_phy.c | 91 ++++++++++++------ .../drivers/libraries/eth/cvi_eth_phy.h | 48 +++------- bsp/cvitek/drivers/libraries/eth/dw_eth_mac.c | 42 +++++--- bsp/cvitek/drivers/libraries/eth/dw_eth_mac.h | 95 ++++++++++++++++++- .../drivers/libraries/eth/eth_phy_cvitek.c | 27 +++--- 6 files changed, 266 insertions(+), 101 deletions(-) diff --git a/bsp/cvitek/drivers/drv_eth.c b/bsp/cvitek/drivers/drv_eth.c index b4e03fa4c8..d25b395a11 100644 --- a/bsp/cvitek/drivers/drv_eth.c +++ b/bsp/cvitek/drivers/drv_eth.c @@ -27,6 +27,8 @@ // #define ETH_RX_DUMP #define MAX_ADDR_LEN 6 +#define DETECT_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 2 +#define DETECT_THREAD_STACK_SIZE 4096 struct _dw_eth { @@ -109,7 +111,7 @@ static int cvi_eth_mac_phy_enable(uint32_t enable) } /* set mac address */ - memcpy(addr.b, g_mac_addr, sizeof(g_mac_addr)); + rt_memcpy(addr.b, g_mac_addr, sizeof(g_mac_addr)); ret = cvi_eth_mac_set_macaddr(g_mac_handle, &addr); if (ret != 0) { @@ -174,6 +176,36 @@ static void dw_gmac_handler_irq(int vector, void *param) } } +static void phy_link_detect(void *param) +{ + int link_status = -1; + int link_status_old = -1; + int ret = -1; + + while (1) + { + link_status = eth_phy_update_link(g_phy_handle); + LOG_D("eth link status: %d", link_status); + + if (link_status_old != link_status) + { + if (link_status == 0) + { + LOG_I("eth link up"); + eth_device_linkchange(&(dw_eth_device.parent), RT_TRUE); + } + else + { + LOG_I("eth link down"); + eth_device_linkchange(&(dw_eth_device.parent), RT_FALSE); + } + + link_status_old = link_status; + } + rt_thread_delay(RT_TICK_PER_SECOND); + } +} + static rt_err_t rt_dw_eth_init(rt_device_t dev) { struct _dw_eth *dw_eth; @@ -209,8 +241,23 @@ static rt_err_t rt_dw_eth_init(rt_device_t dev) rt_hw_interrupt_install(dw_eth->irq, dw_gmac_handler_irq, g_mac_handle, "e0"); rt_hw_interrupt_umask(dw_eth->irq); - /* change device link status */ - eth_device_linkchange(&(dw_eth_device.parent), RT_TRUE); + LOG_D("PHY MAC init success"); + + rt_thread_t link_detect; + link_detect = rt_thread_create("link_detect", + phy_link_detect, + (void *)&dw_eth_device, + DETECT_THREAD_STACK_SIZE, + DETECT_THREAD_PRIORITY, + 2); + if (link_detect != RT_NULL) + { + rt_thread_startup(link_detect); + } + else + { + err = -RT_ERROR; + } return RT_EOK; } @@ -275,7 +322,7 @@ struct pbuf* rt_dw_eth_rx(rt_device_t dev) uint32_t i = 0; int32_t len = cvi_eth_mac_read_frame(g_mac_handle, RecvDataBuf, GMAC_BUF_LEN); - if((len <= 0) || (len > GMAC_BUF_LEN)) + if ((len <= 0) || (len > GMAC_BUF_LEN)) { return NULL; } @@ -308,11 +355,11 @@ struct pbuf* rt_dw_eth_rx(rt_device_t dev) * actually received size. In this case, ensure the tot_len member of the * pbuf is the sum of the chained pbuf len members. */ - memcpy((u8_t*)q->payload, (u8_t*)&RecvDataBuf[i], q->len); + rt_memcpy((u8_t*)q->payload, (u8_t*)&RecvDataBuf[i], q->len); i = i + q->len; } - if((i != p->tot_len) || (i > len)) + if ((i != p->tot_len) || (i > len)) { return NULL; } @@ -348,14 +395,14 @@ rt_err_t rt_dw_eth_tx(rt_device_t dev, struct pbuf* p) variable. */ MEMCPY((uint8_t *)&SendDataBuf[len], (uint8_t *)q->payload, q->len); len = len + q->len; - if((len > GMAC_BUF_LEN) || (len > p->tot_len)) + if ((len > GMAC_BUF_LEN) || (len > p->tot_len)) { LOG_E("rt_dw_eth_tx: error, len=%d, tot_len=%d", len, p->tot_len); return -RT_ERROR; } } - if(len == p->tot_len) + if (len == p->tot_len) { if (cvi_eth_mac_send_frame(g_mac_handle, SendDataBuf, len) < 0) ret = -RT_ERROR; @@ -405,7 +452,6 @@ static int rthw_eth_init(void) LOG_E("eth_device_init failed: %d", ret); return ret; } - return RT_EOK; } INIT_DEVICE_EXPORT(rthw_eth_init); diff --git a/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.c b/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.c index 38cc8de343..c52596763c 100644 --- a/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.c +++ b/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.c @@ -1,6 +1,18 @@ /* -* Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. -*/ + * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include "cvi_eth_phy.h" @@ -88,6 +100,51 @@ static int32_t eth_read_phy_id(eth_phy_priv_t *priv, uint8_t phy_addr, uint32_t return 0; } +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ +static inline int32_t ffs(int32_t x) +{ + int32_t r = 1; + + if (!x) + return 0; + + if (!(x & 0xffff)) + { + x >>= 16; + r += 16; + } + + if (!(x & 0xff)) + { + x >>= 8; + r += 8; + } + + if (!(x & 0xf)) + { + x >>= 4; + r += 4; + } + + if (!(x & 3)) + { + x >>= 2; + r += 2; + } + + if (!(x & 1)) + { + x >>= 1; + r += 1; + } + + return r; +} + static eth_phy_dev_t * eth_get_phy_by_mask(eth_phy_priv_t *priv, uint32_t phy_mask, phy_if_mode_t interface) { uint32_t phy_id = 0xffffffff; @@ -283,33 +340,9 @@ int32_t genphy_update_link(eth_phy_dev_t *phy_dev) if ((phy_dev->priv->link_info.autoneg == CSI_ETH_AUTONEG_ENABLE) && !(mii_reg & CVI_BMSR_ANEGCOMPLETE)) { - int i = 0; - rt_kprintf("%s waiting for PHY auto negotiation to complete...\n", - phy_dev->name); - while (!(mii_reg & CVI_BMSR_ANEGCOMPLETE)) { - /* - * Timeout reached ? - */ - if (i > CVI_PHY_ANEG_TIMEOUT) { - rt_kprintf("TIMEOUT!\n"); - phy_dev->link_state = ETH_LINK_DOWN; - return -1; - } - - // if ((i++ % 1000) == 0) - // rt_kprintf("."); - i ++; - - rt_hw_us_delay(1000); /* 1 ms */ - - ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg); - if (ret != 0) { - return ret; - } - } - rt_kprintf("auto negotiation Done!\n"); - phy_dev->link_state = ETH_LINK_UP; + phy_dev->link_state = ETH_LINK_DOWN; + return -1; } else { /* Read the link a second time to clear the latched state */ @@ -590,7 +623,7 @@ eth_phy_handle_t cvi_eth_phy_init(csi_eth_phy_read_t fn_read, csi_eth_phy_write phy_dev = eth_connect_phy(priv, phy_mask, interface); if (phy_dev == NULL) { rt_kprintf("No phy device found!\n"); - return; + return NULL; } rt_kprintf("connect phy id: 0x%X\n", phy_dev->phy_id); diff --git a/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.h b/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.h index 222accea00..4494ac9d7f 100644 --- a/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.h +++ b/bsp/cvitek/drivers/libraries/eth/cvi_eth_phy.h @@ -1,5 +1,17 @@ /* - * Copyright (C) 2019-2020 AlibabaGroup Holding Limited + * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /****************************************************************************** * @file phy.h @@ -359,40 +371,10 @@ int32_t eth_phy_update_link(eth_phy_handle_t handle); int32_t genphy_config(eth_phy_dev_t *phy_dev); int32_t genphy_update_link(eth_phy_dev_t *phy_dev); -/* - * ffs: find first bit set. This is defined the same way as - * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). - */ +int32_t cvi_eth_phy_power_control(eth_phy_handle_t handle, eth_power_state_t state); -// static inline int32_t ffs(int32_t x) -// { -// int32_t r = 1; +eth_phy_handle_t cvi_eth_phy_init(csi_eth_phy_read_t fn_read, csi_eth_phy_write_t fn_write); -// if (!x) -// return 0; -// if (!(x & 0xffff)) { -// x >>= 16; -// r += 16; -// } -// if (!(x & 0xff)) { -// x >>= 8; -// r += 8; -// } -// if (!(x & 0xf)) { -// x >>= 4; -// r += 4; -// } -// if (!(x & 3)) { -// x >>= 2; -// r += 2; -// } -// if (!(x & 1)) { -// x >>= 1; -// r += 1; -// } -// return r; -// } #ifdef __cplusplus } diff --git a/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.c b/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.c index 61895837db..dad7fb3ff3 100644 --- a/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.c +++ b/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.c @@ -1,10 +1,23 @@ /* -* Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. -*/ + * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include "dw_eth_mac.h" #include "cache.h" +#include "string.h" #define roundup(x, y) ( \ { \ @@ -91,7 +104,7 @@ static void tx_descs_init(eth_mac_handle_t handle) desc_p->dmamac_next = (unsigned long)&desc_table_p[0]; /* Flush all Tx buffer descriptors at once */ - rt_hw_cpu_dcache_clean((unsigned long)priv->tx_mac_descrtable, sizeof(priv->tx_mac_descrtable)); + rt_hw_cpu_dcache_clean((void *)priv->tx_mac_descrtable, sizeof(priv->tx_mac_descrtable)); dma_reg->txdesclistaddr = (unsigned long)&desc_table_p[0]; @@ -114,7 +127,7 @@ static void rx_descs_init(eth_mac_handle_t handle) * Otherwise there's a chance to get some of them flushed in RAM when * GMAC is already pushing data to RAM via DMA. This way incoming from * GMAC data will be corrupted. */ - rt_hw_cpu_dcache_clean((unsigned long)rxbuffs, CVI_RX_TOTAL_BUFSIZE); + rt_hw_cpu_dcache_clean((void *)rxbuffs, CVI_RX_TOTAL_BUFSIZE); for (idx = 0; idx < CVI_CONFIG_RX_DESCR_NUM; idx++) { desc_p = &desc_table_p[idx]; @@ -132,7 +145,7 @@ static void rx_descs_init(eth_mac_handle_t handle) desc_p->dmamac_next = (unsigned long)&desc_table_p[0]; /* Flush all Rx buffer descriptors at once */ - rt_hw_cpu_dcache_clean((unsigned long)priv->rx_mac_descrtable, sizeof(priv->rx_mac_descrtable)); + rt_hw_cpu_dcache_clean((void *)priv->rx_mac_descrtable, sizeof(priv->rx_mac_descrtable)); dma_reg->rxdesclistaddr = (unsigned long)&desc_table_p[0]; @@ -238,8 +251,8 @@ static int32_t designware_eth_enable(eth_mac_handle_t handle, int32_t control) struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p; eth_link_state_t link_state = mac_dev->phy_dev->link_state; - if (link_state == ETH_LINK_DOWN) - return -1; + // if (link_state == ETH_LINK_DOWN) + // return -1; switch (control) { case CSI_ETH_MAC_CONTROL_TX: @@ -320,7 +333,7 @@ static int32_t designware_eth_send(eth_mac_handle_t handle, const uint8_t *frame /* Check if the descriptor is owned by CPU */ while (1) { - rt_hw_cpu_dcache_invalidate(desc_start, desc_end - desc_start); + rt_hw_cpu_dcache_invalidate((void *)desc_start, desc_end - desc_start); if (!(desc_p->txrx_status & CVI_DESC_TXSTS_OWNBYDMA)) { break; } @@ -335,7 +348,7 @@ static int32_t designware_eth_send(eth_mac_handle_t handle, const uint8_t *frame memcpy((void *)data_start, frame, length); /* Flush data to be sent */ - rt_hw_cpu_dcache_clean(data_start, data_end - data_start); + rt_hw_cpu_dcache_clean((void *)data_start, data_end - data_start); #if defined(CONFIG_DW_ALTDESCRIPTOR) desc_p->txrx_status |= CVI_DESC_TXSTS_TXFIRST | CVI_DESC_TXSTS_TXLAST; @@ -355,7 +368,7 @@ static int32_t designware_eth_send(eth_mac_handle_t handle, const uint8_t *frame #endif /* Flush modified buffer descriptor */ - rt_hw_cpu_dcache_clean(desc_start, desc_end - desc_start); + rt_hw_cpu_dcache_clean((void *)desc_start, desc_end - desc_start); /* Test the wrap-around condition. */ if (++desc_num >= CVI_CONFIG_TX_DESCR_NUM) @@ -383,7 +396,7 @@ static int32_t designware_eth_recv(eth_mac_handle_t handle, uint8_t **packetp) uint64_t data_end; /* Invalidate entire buffer descriptor */ - rt_hw_cpu_dcache_invalidate(desc_start, desc_end - desc_start); + rt_hw_cpu_dcache_invalidate((void *)desc_start, desc_end - desc_start); status = desc_p->txrx_status; /* Check if the owner is the CPU */ if (!(status & CVI_DESC_RXSTS_OWNBYDMA)) { @@ -391,7 +404,7 @@ static int32_t designware_eth_recv(eth_mac_handle_t handle, uint8_t **packetp) CVI_DESC_RXSTS_FRMLENSHFT; /* Invalidate received data */ data_end = data_start + roundup(length, DW_GMAC_DMA_ALIGN); - rt_hw_cpu_dcache_invalidate(data_start, data_end - data_start); + rt_hw_cpu_dcache_invalidate((void *)data_start, data_end - data_start); *packetp = (uint8_t *)((uint64_t)desc_p->dmamac_addr); } @@ -415,7 +428,7 @@ static int32_t designware_free_pkt(eth_mac_handle_t handle) desc_p->txrx_status |= CVI_DESC_RXSTS_OWNBYDMA; /* Flush only status field - others weren't changed */ - rt_hw_cpu_dcache_clean(desc_start, desc_end - desc_start); + rt_hw_cpu_dcache_clean((void *)desc_start, desc_end - desc_start); /* Test the wrap-around condition. */ if (++desc_num >= CVI_CONFIG_RX_DESCR_NUM) @@ -619,10 +632,9 @@ int32_t cvi_eth_mac_set_macaddr(eth_mac_handle_t handle, const eth_mac_addr_t *m \param[in] handle ethernet handle \param[in] frame Pointer to frame buffer with data to send \param[in] len Frame buffer length in bytes - \param[in] flags Frame transmit flags (see CSI_ETH_MAC_TX_FRAME_...) \return error code */ -int32_t cvi_eth_mac_send_frame(eth_mac_handle_t handle, const uint8_t *frame, uint32_t len, uint32_t flags) +int32_t cvi_eth_mac_send_frame(eth_mac_handle_t handle, const uint8_t *frame, uint32_t len) { RT_ASSERT(handle); RT_ASSERT(frame); diff --git a/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.h b/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.h index 0947de346f..275159ea9f 100644 --- a/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.h +++ b/bsp/cvitek/drivers/libraries/eth/dw_eth_mac.h @@ -1,7 +1,18 @@ /* -* Copyright (C) Cvitek Co., Ltd. 2019-2022. All rights reserved. -*/ - + * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef _DW_GMAC_182x_H_ #define _DW_GMAC_182x_H_ @@ -327,6 +338,84 @@ static inline void *memalign(uint32_t align, uint32_t size, void **mem_unalign) } return mem; } +/** + \brief Write Ethernet PHY Register through Management Interface. + \param[in] handle ethernet handle + \param[in] phy_addr 5-bit device address + \param[in] reg_addr 5-bit register address + \param[in] data 16-bit data to write + \return error code +*/ +int32_t dw_eth_mac_phy_write(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t data); + +/** + \brief Control Ethernet Interface. + \param[in] handle ethernet handle + \param[in] control Operation + \param[in] arg Argument of operation (optional) + \return error code +*/ +int32_t cvi_eth_mac_control(eth_mac_handle_t handle, uint32_t control, uint32_t arg); +/** + \brief Get Ethernet MAC Address. + \param[in] handle ethernet handle + \param[in] mac Pointer to address + \return error code +*/ +int32_t cvi_eth_mac_get_macaddr(eth_mac_handle_t handle, eth_mac_addr_t *mac); + +/** + \brief Set Ethernet MAC Address. + \param[in] handle ethernet handle + \param[in] mac Pointer to address + \return error code +*/ +int32_t cvi_eth_mac_set_macaddr(eth_mac_handle_t handle, const eth_mac_addr_t *mac); + +/** + \brief Connect phy device to mac device. + \param[in] handle_mac mac handle + \param[in] handle_phy phy handle +*/ +void dw_eth_mac_connect_phy(eth_mac_handle_t handle_mac, eth_phy_handle_t handle_phy); + +/** + \brief Read Ethernet PHY Register through Management Interface. + \param[in] handle ethernet handle + \param[in] phy_addr 5-bit device address + \param[in] reg_addr 5-bit register address + \param[out] data Pointer where the result is written to + \return error code +*/ +int32_t dw_eth_mac_phy_read(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data); + +/** + \brief Send Ethernet frame. + \param[in] handle ethernet handle + \param[in] frame Pointer to frame buffer with data to send + \param[in] len Frame buffer length in bytes + \return error code +*/ +int32_t cvi_eth_mac_send_frame(eth_mac_handle_t handle, const uint8_t *frame, uint32_t len); + +/** + \brief Read data of received Ethernet frame. + \param[in] handle ethernet handle + \param[in] frame Pointer to frame buffer for data to read into + \param[in] len Frame buffer length in bytes + \return number of data bytes read or execution status + - value >= 0: number of data bytes read + - value < 0: error occurred, value is execution status as defined with execution_status +*/ +int32_t cvi_eth_mac_read_frame(eth_mac_handle_t handle, uint8_t *frame, uint32_t len); + +/** + \brief This function is used to initialize Ethernet device and register an event callback. + \param[in] idx device id + \param[in] cb callback to handle ethernet event + \return return ethernet handle if success + */ +eth_mac_handle_t cvi_eth_mac_init(unsigned int *base); #ifdef __cplusplus } diff --git a/bsp/cvitek/drivers/libraries/eth/eth_phy_cvitek.c b/bsp/cvitek/drivers/libraries/eth/eth_phy_cvitek.c index 989cd4b6a6..0d6383b006 100644 --- a/bsp/cvitek/drivers/libraries/eth/eth_phy_cvitek.c +++ b/bsp/cvitek/drivers/libraries/eth/eth_phy_cvitek.c @@ -1,18 +1,26 @@ /* -* Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. -*/ + * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include #include #include -// #include - #include "cvi_eth_phy.h" #include "mii.h" - - // #define CVI_ETH_PHY_LOOPBACK #define LOOPBACK_XMII2MAC 0x8000 #define LOOPBACK_PCS2MAC 0x2000 @@ -334,14 +342,9 @@ int32_t cv181x_start(eth_phy_handle_t handle) assert(handle); eth_phy_dev_t *dev = (eth_phy_dev_t *)handle; - int32_t ret; /* Read the Status (2x to make sure link is right) */ - ret = genphy_update_link(dev); - - if (ret) { - return ret; - } + genphy_update_link(dev); return cv181x_parse_status(dev); }