Skip to content

Commit 6f93ec2

Browse files
committed
drivers: ethernet: Add API_V2 auto-negotiation support
- Added definitions for LAN8742 PHY registers and bit masks to support auto-negotiation. - The function `eth_enable_api_v2(dev)` requires the Ethernet interface to be properly initialized. In auto-negotiation mode, it reads the speed and duplex settings to configure the driver accordingly. - Implemented functions to get link state and configure speed and duplex mode based on auto-negotiation results. - Ensured proper initialization of semaphores and MAC configuration for both auto-negotiation enabled and disabled scenarios. Signed-off-by: IBEN EL HADJ MESSAOUD Marwa <[email protected]>
1 parent d8edd78 commit 6f93ec2

File tree

1 file changed

+218
-62
lines changed

1 file changed

+218
-62
lines changed

drivers/ethernet/eth_stm32_hal.c

Lines changed: 218 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
5656

5757
#define PHY_ADDR CONFIG_ETH_STM32_HAL_PHY_ADDRESS
5858

59+
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
60+
#define PHY_SCSR ((uint16_t)0x001FU) /*!< PHY Special Control/Status */
61+
#define PHY_SCSR_AUTONEGO_DONE ((uint16_t)0x1000U) /*!< Auto-Negotiation Done Status */
62+
#define PHY_HCDSPEEDMASK ((uint16_t)0x001CU) /*!< High Capability Speed Mask */
63+
#define PHY_10BT_HD ((uint16_t)0x0004U) /*!< 10Base-T half-duplex */
64+
#define PHY_10BT_FD ((uint16_t)0x0014U) /*!< 10Base-T full-duplex */
65+
#define PHY_100BTX_HD ((uint16_t)0x0008U) /*!< 100Base-TX half-duplex */
66+
#define PHY_100BTX_FD ((uint16_t)0x0018U) /*!< 100Base-TX full-duplex */
67+
#define PHY_AUTONEGO_ENABLE ((uint16_t)0x1000U) /*!< Auto-negotiation enable bit */
68+
#define PHY_TIMEOUT (5000U) /*!< PHY operation timeout in msec */
69+
70+
#define PHY_STATUS_LINK_DOWN ((int32_t)1) /*!< Link down status */
71+
#define PHY_STATUS_100MBITS_FULLDUPLEX ((int32_t)2) /*!< 100 Mbps full-duplex status */
72+
#define PHY_STATUS_100MBITS_HALFDUPLEX ((int32_t)3) /*!< 100 Mbps half-duplex status */
73+
#define PHY_STATUS_10MBITS_FULLDUPLEX ((int32_t)4) /*!< 10 Mbps full-duplex status */
74+
#define PHY_STATUS_10MBITS_HALFDUPLEX ((int32_t)5) /*!< 10 Mbps half-duplex status */
75+
#define PHY_STATUS_AUTONEGO_NOTDONE ((int32_t)6) /*!< Auto-negotiation not done */
76+
#endif
77+
5978
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_mdio)
6079

6180
#define DEVICE_PHY_BY_NAME(n) \
@@ -67,8 +86,9 @@ static const struct device *eth_stm32_phy_dev = DEVICE_PHY_BY_NAME(0);
6786

6887
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
6988

70-
#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */
71-
#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */
89+
#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */
90+
#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */
91+
#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */
7292

7393
#define IS_ETH_DMATXDESC_OWN(dma_tx_desc) (dma_tx_desc->DESC3 & \
7494
ETH_DMATXNDESCRF_OWN)
@@ -918,7 +938,6 @@ static int eth_initialize(const struct device *dev)
918938
struct eth_stm32_hal_dev_data *dev_data;
919939
const struct eth_stm32_hal_dev_cfg *cfg;
920940
ETH_HandleTypeDef *heth;
921-
HAL_StatusTypeDef hal_ret = HAL_OK;
922941
int ret = 0;
923942

924943
__ASSERT_NO_MSG(dev != NULL);
@@ -966,11 +985,8 @@ static int eth_initialize(const struct device *dev)
966985

967986
heth->Init.MACAddr = dev_data->mac_addr;
968987

969-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
970-
heth->Init.TxDesc = dma_tx_desc_tab;
971-
heth->Init.RxDesc = dma_rx_desc_tab;
972-
heth->Init.RxBuffLen = ETH_STM32_RX_BUF_SIZE;
973-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
988+
#if !defined(CONFIG_ETH_STM32_HAL_API_V2)
989+
HAL_StatusTypeDef hal_ret = HAL_OK;
974990

975991
hal_ret = HAL_ETH_Init(heth);
976992
if (hal_ret == HAL_TIMEOUT) {
@@ -983,75 +999,22 @@ static int eth_initialize(const struct device *dev)
983999
return -EINVAL;
9841000
}
9851001

986-
#if defined(CONFIG_PTP_CLOCK_STM32_HAL)
987-
/* Enable timestamping of RX packets. We enable all packets to be
988-
* timestamped to cover both IEEE 1588 and gPTP.
989-
*/
990-
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
991-
heth->Instance->MACTSCR |= ETH_MACTSCR_TSENALL;
992-
#else
993-
heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSARFE;
994-
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
995-
#endif /* CONFIG_PTP_CLOCK_STM32_HAL */
996-
997-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
998-
/* Tx config init: */
999-
memset(&tx_config, 0, sizeof(ETH_TxPacketConfig));
1000-
tx_config.Attributes = ETH_TX_PACKETS_FEATURES_CSUM |
1001-
ETH_TX_PACKETS_FEATURES_CRCPAD;
1002-
tx_config.ChecksumCtrl = IS_ENABLED(CONFIG_ETH_STM32_HW_CHECKSUM) ?
1003-
ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC : ETH_CHECKSUM_DISABLE;
1004-
tx_config.CRCPadCtrl = ETH_CRC_PAD_INSERT;
1005-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1006-
10071002
dev_data->link_up = false;
10081003

10091004
/* Initialize semaphores */
10101005
k_mutex_init(&dev_data->tx_mutex);
10111006
k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
1012-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1013-
k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT);
1014-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1015-
1016-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1017-
/* Adjust MDC clock range depending on HCLK frequency: */
1018-
HAL_ETH_SetMDIOClockRange(heth);
1019-
1020-
/* @TODO: read duplex mode and speed from PHY and set it to ETH */
10211007

1022-
ETH_MACConfigTypeDef mac_config;
1023-
1024-
HAL_ETH_GetMACConfig(heth, &mac_config);
1025-
mac_config.DuplexMode = IS_ENABLED(CONFIG_ETH_STM32_MODE_HALFDUPLEX) ?
1026-
ETH_HALFDUPLEX_MODE : ETH_FULLDUPLEX_MODE;
1027-
mac_config.Speed = IS_ENABLED(CONFIG_ETH_STM32_SPEED_10M) ?
1028-
ETH_SPEED_10M : ETH_SPEED_100M;
1029-
hal_ret = HAL_ETH_SetMACConfig(heth, &mac_config);
1030-
if (hal_ret != HAL_OK) {
1031-
LOG_ERR("HAL_ETH_SetMACConfig: failed: %d", hal_ret);
1032-
}
1033-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1034-
1035-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1036-
1037-
/* prepare tx buffer header */
1038-
for (uint16_t i = 0; i < ETH_TXBUFNB; ++i) {
1039-
dma_tx_buffer_header[i].tx_buff.buffer = dma_tx_buffer[i];
1040-
}
1041-
1042-
hal_ret = HAL_ETH_Start_IT(heth);
1043-
#else
10441008
HAL_ETH_DMATxDescListInit(heth, dma_tx_desc_tab,
10451009
&dma_tx_buffer[0][0], ETH_TXBUFNB);
10461010
HAL_ETH_DMARxDescListInit(heth, dma_rx_desc_tab,
10471011
&dma_rx_buffer[0][0], ETH_RXBUFNB);
10481012

10491013
hal_ret = HAL_ETH_Start(heth);
1050-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1051-
10521014
if (hal_ret != HAL_OK) {
10531015
LOG_ERR("HAL_ETH_Start{_IT} failed");
10541016
}
1017+
#endif /* !CONFIG_ETH_STM32_HAL_API_V2 */
10551018

10561019
setup_mac_filter(heth);
10571020

@@ -1114,6 +1077,191 @@ static void eth_stm32_mcast_filter(const struct device *dev, const struct ethern
11141077

11151078
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
11161079

1080+
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1081+
#if defined(CONFIG_ETH_STM32_AUTO_NEGOTIATION_ENABLE)
1082+
static uint32_t eth_phy_get_link_state(ETH_HandleTypeDef *heth)
1083+
{
1084+
uint32_t readval = 0;
1085+
uint32_t tickstart = 0U;
1086+
1087+
tickstart = HAL_GetTick();
1088+
1089+
/* Wait for linked status */
1090+
do {
1091+
HAL_ETH_ReadPHYRegister(heth, PHY_ADDR, PHY_BSR, (uint32_t *)&readval);
1092+
1093+
/* Check for the Timeout */
1094+
if ((HAL_GetTick() - tickstart) > 5000U) {
1095+
LOG_INF("Check for the Timeout");
1096+
return HAL_TIMEOUT;
1097+
}
1098+
} while (((readval & PHY_LINKED_STATUS) != PHY_LINKED_STATUS));
1099+
1100+
if ((readval & PHY_LINKED_STATUS) == 0) {
1101+
LOG_ERR("Link Down");
1102+
return PHY_STATUS_LINK_DOWN;
1103+
}
1104+
1105+
/* Check Auto negotiation */
1106+
if (HAL_ETH_ReadPHYRegister(heth, PHY_ADDR, PHY_BCR, (uint32_t *)&readval) != HAL_OK) {
1107+
LOG_INF("Error reading BCR register\n");
1108+
return HAL_ERROR;
1109+
}
1110+
1111+
if ((readval & PHY_AUTONEGO_ENABLE) != PHY_AUTONEGO_ENABLE) {
1112+
/* Enable Auto-Negotiation */
1113+
if ((HAL_ETH_WritePHYRegister(heth, PHY_ADDR, PHY_BCR, PHY_AUTONEGO_ENABLE)) !=
1114+
HAL_OK) {
1115+
return HAL_ERROR;
1116+
}
1117+
}
1118+
1119+
/* Auto Nego enabled */
1120+
LOG_DBG("Auto nego enabled");
1121+
if (HAL_ETH_ReadPHYRegister(heth, PHY_ADDR, PHY_SCSR, &readval) != HAL_OK) {
1122+
return HAL_ERROR;
1123+
}
1124+
1125+
/* Check if auto nego not done */
1126+
if ((readval & PHY_SCSR_AUTONEGO_DONE) == 0) {
1127+
return PHY_STATUS_AUTONEGO_NOTDONE;
1128+
}
1129+
1130+
if ((readval & PHY_HCDSPEEDMASK) == PHY_100BTX_FD) {
1131+
return PHY_STATUS_100MBITS_FULLDUPLEX;
1132+
} else if ((readval & PHY_HCDSPEEDMASK) == PHY_100BTX_HD) {
1133+
return PHY_STATUS_100MBITS_HALFDUPLEX;
1134+
} else if ((readval & PHY_HCDSPEEDMASK) == PHY_10BT_FD) {
1135+
return PHY_STATUS_10MBITS_FULLDUPLEX;
1136+
} else {
1137+
return PHY_STATUS_10MBITS_HALFDUPLEX;
1138+
}
1139+
}
1140+
1141+
static void get_auto_nego_speed_duplex(ETH_HandleTypeDef *heth, ETH_MACConfigTypeDef *mac_config)
1142+
{
1143+
uint32_t phyLinkState;
1144+
uint32_t tickstart = HAL_GetTick();
1145+
1146+
do {
1147+
phyLinkState = eth_phy_get_link_state(heth);
1148+
} while ((phyLinkState <= PHY_STATUS_LINK_DOWN) &&
1149+
((HAL_GetTick() - tickstart) < PHY_TIMEOUT));
1150+
1151+
/* Get link state */
1152+
if (phyLinkState <= PHY_STATUS_LINK_DOWN) {
1153+
return;
1154+
}
1155+
1156+
switch (phyLinkState) {
1157+
case PHY_STATUS_100MBITS_FULLDUPLEX:
1158+
mac_config->DuplexMode = ETH_FULLDUPLEX_MODE;
1159+
mac_config->Speed = ETH_SPEED_100M;
1160+
break;
1161+
case PHY_STATUS_100MBITS_HALFDUPLEX:
1162+
mac_config->DuplexMode = ETH_HALFDUPLEX_MODE;
1163+
mac_config->Speed = ETH_SPEED_100M;
1164+
break;
1165+
case PHY_STATUS_10MBITS_FULLDUPLEX:
1166+
mac_config->DuplexMode = ETH_FULLDUPLEX_MODE;
1167+
mac_config->Speed = ETH_SPEED_10M;
1168+
break;
1169+
case PHY_STATUS_10MBITS_HALFDUPLEX:
1170+
mac_config->DuplexMode = ETH_HALFDUPLEX_MODE;
1171+
mac_config->Speed = ETH_SPEED_10M;
1172+
break;
1173+
default:
1174+
mac_config->DuplexMode = ETH_FULLDUPLEX_MODE;
1175+
mac_config->Speed = ETH_SPEED_100M;
1176+
break;
1177+
}
1178+
}
1179+
#endif /* CONFIG_ETH_STM32_AUTO_NEGOTIATION_ENABLE */
1180+
1181+
static int eth_enable_api_v2(const struct device *dev)
1182+
{
1183+
HAL_StatusTypeDef hal_ret = HAL_OK;
1184+
struct eth_stm32_hal_dev_data *dev_data;
1185+
ETH_HandleTypeDef *heth;
1186+
ETH_MACConfigTypeDef mac_config;
1187+
1188+
dev_data = dev->data;
1189+
heth = &dev_data->heth;
1190+
1191+
heth->Init.TxDesc = dma_tx_desc_tab;
1192+
heth->Init.RxDesc = dma_rx_desc_tab;
1193+
heth->Init.RxBuffLen = ETH_STM32_RX_BUF_SIZE;
1194+
1195+
hal_ret = HAL_ETH_Init(heth);
1196+
if (hal_ret == HAL_TIMEOUT) {
1197+
/* HAL Init time out. This could be linked to */
1198+
/* a recoverable error. Log the issue and continue */
1199+
/* driver initialisation */
1200+
LOG_ERR("HAL_ETH_Init Timed out");
1201+
} else if (hal_ret != HAL_OK) {
1202+
LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
1203+
return -EINVAL;
1204+
}
1205+
1206+
#if defined(CONFIG_PTP_CLOCK_STM32_HAL)
1207+
/* Enable timestamping of RX packets. We enable all packets to be
1208+
* timestamped to cover both IEEE 1588 and gPTP.
1209+
*/
1210+
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1211+
heth->Instance->MACTSCR |= ETH_MACTSCR_TSENALL;
1212+
#else
1213+
heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSARFE;
1214+
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1215+
#endif /* CONFIG_PTP_CLOCK_STM32_HAL */
1216+
1217+
dev_data->link_up = false;
1218+
1219+
/* Initialize semaphores */
1220+
k_mutex_init(&dev_data->tx_mutex);
1221+
k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
1222+
k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT);
1223+
1224+
/* Tx config init: */
1225+
memset(&tx_config, 0, sizeof(ETH_TxPacketConfig));
1226+
tx_config.Attributes = ETH_TX_PACKETS_FEATURES_CSUM |
1227+
ETH_TX_PACKETS_FEATURES_CRCPAD;
1228+
tx_config.ChecksumCtrl = IS_ENABLED(CONFIG_ETH_STM32_HW_CHECKSUM) ?
1229+
ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC : ETH_CHECKSUM_DISABLE;
1230+
tx_config.CRCPadCtrl = ETH_CRC_PAD_INSERT;
1231+
1232+
HAL_ETH_SetMDIOClockRange(heth);
1233+
1234+
HAL_ETH_GetMACConfig(heth, &mac_config);
1235+
1236+
#if defined(CONFIG_ETH_STM32_AUTO_NEGOTIATION_ENABLE)
1237+
/* Auto Nego enabled */
1238+
get_auto_nego_speed_duplex(heth, &mac_config);
1239+
1240+
#else /* Auto Nego disabled */
1241+
mac_config.DuplexMode = IS_ENABLED(CONFIG_ETH_STM32_MODE_HALFDUPLEX) ? ETH_HALFDUPLEX_MODE
1242+
: ETH_FULLDUPLEX_MODE;
1243+
mac_config.Speed = IS_ENABLED(CONFIG_ETH_STM32_SPEED_10M) ? ETH_SPEED_10M : ETH_SPEED_100M;
1244+
#endif
1245+
1246+
hal_ret = HAL_ETH_SetMACConfig(heth, &mac_config);
1247+
if (hal_ret != HAL_OK) {
1248+
LOG_ERR("HAL_ETH_SetMACConfig: failed: %d", hal_ret);
1249+
}
1250+
1251+
/* prepare tx buffer header */
1252+
for (uint16_t i = 0; i < ETH_TXBUFNB; ++i) {
1253+
dma_tx_buffer_header[i].tx_buff.buffer = dma_tx_buffer[i];
1254+
}
1255+
1256+
hal_ret = HAL_ETH_Start_IT(heth);
1257+
if (hal_ret != HAL_OK) {
1258+
LOG_ERR("HAL_ETH_Start{_IT} failed");
1259+
}
1260+
1261+
return 0;
1262+
}
1263+
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1264+
11171265
static void eth_iface_init(struct net_if *iface)
11181266
{
11191267
const struct device *dev;
@@ -1144,6 +1292,14 @@ static void eth_iface_init(struct net_if *iface)
11441292

11451293
ethernet_init(iface);
11461294

1295+
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1296+
/* This function requires the Ethernet interface to be
1297+
* properly initialized. In auto-negotiation mode, it reads the speed
1298+
* and duplex settings to configure the driver accordingly.
1299+
*/
1300+
eth_enable_api_v2(dev);
1301+
#endif
1302+
11471303
net_if_carrier_off(iface);
11481304

11491305
net_lldp_set_lldpdu(iface);

0 commit comments

Comments
 (0)