[bsp/cvitek] eth driver support phy link detect

Signed-off-by: flyingcys <flyingcys@163.com>
This commit is contained in:
flyingcys 2024-08-18 13:29:02 +08:00 committed by Meco Man
parent cf56227000
commit 2e224b30ad
6 changed files with 266 additions and 101 deletions

View File

@ -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);

View File

@ -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 <rtthread.h>
#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);

View File

@ -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
}

View File

@ -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 <rtthread.h>
#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);

View File

@ -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
}

View File

@ -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 <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
// #include <mmio.h>
#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);
}