Skip to content

Commit 18277b4

Browse files
marwaiehm-stkartben
authored andcommitted
drivers: ethernet: Add API_V2 auto-negotiation support
- Added definitions for LAN8742 PHY registers and bit masks to support auto-negotiation. - The function `eth_init_api_v2` 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 7e39286 commit 18277b4

File tree

1 file changed

+217
-62
lines changed

1 file changed

+217
-62
lines changed

drivers/ethernet/eth_stm32_hal.c

Lines changed: 217 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)
@@ -924,7 +944,6 @@ static int eth_initialize(const struct device *dev)
924944
struct eth_stm32_hal_dev_data *dev_data;
925945
const struct eth_stm32_hal_dev_cfg *cfg;
926946
ETH_HandleTypeDef *heth;
927-
HAL_StatusTypeDef hal_ret = HAL_OK;
928947
int ret = 0;
929948

930949
__ASSERT_NO_MSG(dev != NULL);
@@ -972,11 +991,8 @@ static int eth_initialize(const struct device *dev)
972991

973992
heth->Init.MACAddr = dev_data->mac_addr;
974993

975-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
976-
heth->Init.TxDesc = dma_tx_desc_tab;
977-
heth->Init.RxDesc = dma_rx_desc_tab;
978-
heth->Init.RxBuffLen = ETH_STM32_RX_BUF_SIZE;
979-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
994+
#if !defined(CONFIG_ETH_STM32_HAL_API_V2)
995+
HAL_StatusTypeDef hal_ret = HAL_OK;
980996

981997
hal_ret = HAL_ETH_Init(heth);
982998
if (hal_ret == HAL_TIMEOUT) {
@@ -989,75 +1005,22 @@ static int eth_initialize(const struct device *dev)
9891005
return -EINVAL;
9901006
}
9911007

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

10151010
/* Initialize semaphores */
10161011
k_mutex_init(&dev_data->tx_mutex);
10171012
k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
1018-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1019-
k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT);
1020-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1021-
1022-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1023-
/* Adjust MDC clock range depending on HCLK frequency: */
1024-
HAL_ETH_SetMDIOClockRange(heth);
1025-
1026-
/* @TODO: read duplex mode and speed from PHY and set it to ETH */
10271013

1028-
ETH_MACConfigTypeDef mac_config;
1029-
1030-
HAL_ETH_GetMACConfig(heth, &mac_config);
1031-
mac_config.DuplexMode = IS_ENABLED(CONFIG_ETH_STM32_MODE_HALFDUPLEX) ?
1032-
ETH_HALFDUPLEX_MODE : ETH_FULLDUPLEX_MODE;
1033-
mac_config.Speed = IS_ENABLED(CONFIG_ETH_STM32_SPEED_10M) ?
1034-
ETH_SPEED_10M : ETH_SPEED_100M;
1035-
hal_ret = HAL_ETH_SetMACConfig(heth, &mac_config);
1036-
if (hal_ret != HAL_OK) {
1037-
LOG_ERR("HAL_ETH_SetMACConfig: failed: %d", hal_ret);
1038-
}
1039-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1040-
1041-
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1042-
1043-
/* prepare tx buffer header */
1044-
for (uint16_t i = 0; i < ETH_TXBUFNB; ++i) {
1045-
dma_tx_buffer_header[i].tx_buff.buffer = dma_tx_buffer[i];
1046-
}
1047-
1048-
hal_ret = HAL_ETH_Start_IT(heth);
1049-
#else
10501014
HAL_ETH_DMATxDescListInit(heth, dma_tx_desc_tab,
10511015
&dma_tx_buffer[0][0], ETH_TXBUFNB);
10521016
HAL_ETH_DMARxDescListInit(heth, dma_rx_desc_tab,
10531017
&dma_rx_buffer[0][0], ETH_RXBUFNB);
10541018

10551019
hal_ret = HAL_ETH_Start(heth);
1056-
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1057-
10581020
if (hal_ret != HAL_OK) {
10591021
LOG_ERR("HAL_ETH_Start{_IT} failed");
10601022
}
1023+
#endif /* !CONFIG_ETH_STM32_HAL_API_V2 */
10611024

10621025
setup_mac_filter(heth);
10631026

@@ -1120,6 +1083,190 @@ static void eth_stm32_mcast_filter(const struct device *dev, const struct ethern
11201083

11211084
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
11221085

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

11511298
ethernet_init(iface);
11521299

1300+
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
1301+
/* This function requires the Ethernet interface to be
1302+
* properly initialized. In auto-negotiation mode, it reads the speed
1303+
* and duplex settings to configure the driver accordingly.
1304+
*/
1305+
eth_init_api_v2(dev);
1306+
#endif
1307+
11531308
net_if_carrier_off(iface);
11541309

11551310
net_lldp_set_lldpdu(iface);

0 commit comments

Comments
 (0)