From bf68bb95f9774127a026845e286822ca83bcaa37 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Thu, 15 Feb 2024 21:05:51 +0100 Subject: [PATCH] stm32/network_lan: Add the phy_type=x keyword option to network.LAN(). With LAN8742, LAN8720, LAN83825 and DP83848 as possible options, and the symbols PHY_LAN8720, PHY_LAN8742, PHY_DP83825 and PHY_DP8348. The default is PHY_LAN8742 which is the existing behaviour. The eth_init() parameters for the Portenta H7 board are set to phy_addr=0 and phy_type=LAN8742, which matches the previous defaults and the schematics. Tested with LAN8720 and DP83848 breakout boards at 10M Duplex and 100M Duplex modes. Signed-off-by: robert-hh --- ports/stm32/Makefile | 1 + .../boards/ARDUINO_PORTENTA_H7/board_init.c | 2 +- ports/stm32/eth.c | 52 +++++++------- ports/stm32/eth.h | 9 ++- ports/stm32/eth_phy.c | 59 ++++++++++++++++ ports/stm32/eth_phy.h | 67 +++++++++++++++++++ ports/stm32/network_lan.c | 12 +++- 7 files changed, 171 insertions(+), 31 deletions(-) create mode 100644 ports/stm32/eth_phy.c create mode 100644 ports/stm32/eth_phy.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 19f6f420e1..d1694426d3 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -251,6 +251,7 @@ SRC_C += \ pyb_can.c \ usb.c \ eth.c \ + eth_phy.c \ gccollect.c \ help.c \ machine_bitstream.c \ diff --git a/ports/stm32/boards/ARDUINO_PORTENTA_H7/board_init.c b/ports/stm32/boards/ARDUINO_PORTENTA_H7/board_init.c index ad275ef87c..04fa3b9bc3 100644 --- a/ports/stm32/boards/ARDUINO_PORTENTA_H7/board_init.c +++ b/ports/stm32/boards/ARDUINO_PORTENTA_H7/board_init.c @@ -115,7 +115,7 @@ void PORTENTA_board_early_init(void) { mp_hal_pin_write(pyb_pin_ETH_RST, 1); // Put Eth in low-power mode - eth_init(ð_instance, MP_HAL_MAC_ETH0, 0); + eth_init(ð_instance, MP_HAL_MAC_ETH0, 0, ETH_PHY_LAN8742); eth_low_power_mode(ð_instance, true); #if MICROPY_HW_USB_HS_ULPI3320 diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c index f5bdcc1524..fd46bde23c 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -32,6 +32,7 @@ #include "extmod/modnetwork.h" #include "mpu.h" #include "eth.h" +#include "eth_phy.h" #if defined(MICROPY_HW_ETH_MDC) @@ -40,26 +41,6 @@ #include "lwip/dhcp.h" #include "netif/ethernet.h" -// ETH PHY register definitions (for LAN8742 and LAN8720/LAN8710) -#undef PHY_BCR -#define PHY_BCR (0x0000) -#define PHY_BCR_SOFT_RESET (0x8000) -#define PHY_BCR_AUTONEG_EN (0x1000) -#define PHY_BCR_POWER_DOWN (0x0800U) - -#undef PHY_BSR -#define PHY_BSR (0x0001) -#define PHY_BSR_LINK_STATUS (0x0004) -#define PHY_BSR_AUTONEG_DONE (0x0020) - -#define PHY_SCSR (0x001f) -#define PHY_SCSR_SPEED_Pos (2) -#define PHY_SCSR_SPEED_Msk (7 << PHY_SCSR_SPEED_Pos) -#define PHY_SCSR_SPEED_10HALF (1 << PHY_SCSR_SPEED_Pos) -#define PHY_SCSR_SPEED_10FULL (5 << PHY_SCSR_SPEED_Pos) -#define PHY_SCSR_SPEED_100HALF (2 << PHY_SCSR_SPEED_Pos) -#define PHY_SCSR_SPEED_100FULL (6 << PHY_SCSR_SPEED_Pos) - // ETH DMA RX and TX descriptor definitions #if defined(STM32H5) #define RX_DESCR_3_OWN_Pos (31) @@ -137,6 +118,7 @@ typedef struct _eth_t { struct netif netif; struct dhcp dhcp_struct; uint32_t phy_addr; + int16_t (*phy_get_link_status)(uint32_t phy_addr); } eth_t; static eth_dma_t eth_dma __attribute__((aligned(16384))); @@ -146,7 +128,7 @@ eth_t eth_instance; static void eth_mac_deinit(eth_t *self); static void eth_process_frame(eth_t *self, size_t len, const uint8_t *buf); -static void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) { +void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) { #if defined(STM32H5) || defined(STM32H7) while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) { } @@ -174,7 +156,7 @@ static void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) { #endif } -static uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) { +uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) { #if defined(STM32H5) || defined(STM32H7) while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) { } @@ -202,10 +184,17 @@ static uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) { #endif } -void eth_init(eth_t *self, int mac_idx, uint32_t phy_addr) { +int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) { mp_hal_get_mac(mac_idx, &self->netif.hwaddr[0]); self->netif.hwaddr_len = 6; self->phy_addr = phy_addr; + if (phy_type == ETH_PHY_DP83825 || phy_type == ETH_PHY_DP83848) { + self->phy_get_link_status = eth_phy_dp838xx_get_link_status; + } else if (phy_type == ETH_PHY_LAN8720 || phy_type == ETH_PHY_LAN8742) { + self->phy_get_link_status = eth_phy_lan87xx_get_link_status; + } else { + return -1; + } // Configure GPIO mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDC); @@ -230,6 +219,7 @@ void eth_init(eth_t *self, int mac_idx, uint32_t phy_addr) { #else __HAL_RCC_ETH_CLK_ENABLE(); #endif + return 0; } void eth_set_trace(eth_t *self, uint32_t value) { @@ -381,6 +371,14 @@ static int eth_mac_init(eth_t *self) { break; case 1: if (bsr & PHY_BSR_LINK_STATUS) { + // Announce all modes + eth_phy_write(self->phy_addr, PHY_ANAR, + PHY_ANAR_SPEED_10HALF | + PHY_ANAR_SPEED_10FULL | + PHY_ANAR_SPEED_100HALF | + PHY_ANAR_SPEED_100FULL | + PHY_ANAR_IEEE802_3); + // Start autonegotiate. eth_phy_write(self->phy_addr, PHY_BCR, PHY_BCR_AUTONEG_EN); phy_state = 2; } @@ -396,7 +394,7 @@ static int eth_mac_init(eth_t *self) { } // Get register with link status - uint16_t phy_scsr = eth_phy_read(self->phy_addr, PHY_SCSR); + uint16_t phy_scsr = self->phy_get_link_status(self->phy_addr); // Burst mode configuration #if defined(STM32H5) || defined(STM32H7) @@ -505,9 +503,9 @@ static int eth_mac_init(eth_t *self) { // Set main MAC control register ETH->MACCR = - (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_10FULL ? ETH_MACCR_DM - : (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_100HALF ? ETH_MACCR_FES - : (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_100FULL ? (ETH_MACCR_FES | ETH_MACCR_DM) + phy_scsr == PHY_SPEED_10FULL ? ETH_MACCR_DM + : phy_scsr == PHY_SPEED_100HALF ? ETH_MACCR_FES + : phy_scsr == PHY_SPEED_100FULL ? (ETH_MACCR_FES | ETH_MACCR_DM) : 0 ; mp_hal_delay_ms(2); diff --git a/ports/stm32/eth.h b/ports/stm32/eth.h index 45c385a252..5647449690 100644 --- a/ports/stm32/eth.h +++ b/ports/stm32/eth.h @@ -26,10 +26,17 @@ #ifndef MICROPY_INCLUDED_STM32_ETH_H #define MICROPY_INCLUDED_STM32_ETH_H +enum { + ETH_PHY_LAN8742 = 0, + ETH_PHY_LAN8720, + ETH_PHY_DP83848, + ETH_PHY_DP83825 +}; + typedef struct _eth_t eth_t; extern eth_t eth_instance; -void eth_init(eth_t *self, int mac_idx, uint32_t phy_addr); +int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type); void eth_set_trace(eth_t *self, uint32_t value); struct netif *eth_netif(eth_t *self); int eth_link_status(eth_t *self); diff --git a/ports/stm32/eth_phy.c b/ports/stm32/eth_phy.c new file mode 100644 index 0000000000..56cddba9c5 --- /dev/null +++ b/ports/stm32/eth_phy.c @@ -0,0 +1,59 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * Copyright (c) 2024 Robert Hammelrath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "eth_phy.h" + +#if defined(MICROPY_HW_ETH_MDC) + +#define PHY_SCSR_LAN87XX (0x001f) +#define PHY_SCSR_LAN87XX_SPEED_Pos (2) +#define PHY_SCSR_LAN87XX_SPEED_Msk (7) + +#define PHY_SCSR_DP838XX (0x0010) +#define PHY_RECR_DP838XX (0x0015) +#define PHY_SCSR_DP838XX_DUPLEX_Msk (4) +#define PHY_SCSR_DP838XX_10M_Msk (2) + +int16_t eth_phy_lan87xx_get_link_status(uint32_t phy_addr) { + // Get the link mode & speed + int16_t scsr = eth_phy_read(phy_addr, PHY_SCSR_LAN87XX); + return (scsr >> PHY_SCSR_LAN87XX_SPEED_Pos) & PHY_SCSR_LAN87XX_SPEED_Msk; +} + +int16_t eth_phy_dp838xx_get_link_status(uint32_t phy_addr) { + int16_t scsr = 0; + // Get the link mode & speed + uint16_t temp = eth_phy_read(phy_addr, PHY_SCSR_DP838XX); + scsr = (temp & PHY_SCSR_DP838XX_10M_Msk) ? PHY_SPEED_10HALF : PHY_SPEED_100HALF; + if (temp & PHY_SCSR_DP838XX_DUPLEX_Msk) { + scsr |= PHY_DUPLEX; + } + return scsr; +} + +#endif diff --git a/ports/stm32/eth_phy.h b/ports/stm32/eth_phy.h new file mode 100644 index 0000000000..5036905c1f --- /dev/null +++ b/ports/stm32/eth_phy.h @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * Copyright (c) 2024 Robert Hammelrath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_STM32_PHY_H +#define MICROPY_INCLUDED_STM32_PYH_H + +#if defined(MICROPY_HW_ETH_MDC) + +// Common ETH PHY register definitions +#undef PHY_BCR +#define PHY_BCR (0x0000) +#define PHY_BCR_SOFT_RESET (0x8000) +#define PHY_BCR_AUTONEG_EN (0x1000) +#define PHY_BCR_POWER_DOWN (0x0800U) + +#undef PHY_BSR +#define PHY_BSR (0x0001) +#define PHY_BSR_LINK_STATUS (0x0004) +#define PHY_BSR_AUTONEG_DONE (0x0020) + +#undef PHY_ANAR +#define PHY_ANAR (0x0004) +#define PHY_ANAR_SPEED_10HALF (0x0020) +#define PHY_ANAR_SPEED_10FULL (0x0040) +#define PHY_ANAR_SPEED_100HALF (0x0080) +#define PHY_ANAR_SPEED_100FULL (0x0100) +#define PHY_ANAR_IEEE802_3 (0x0001) + +#define PHY_SPEED_10HALF (1) +#define PHY_SPEED_10FULL (5) +#define PHY_SPEED_100HALF (2) +#define PHY_SPEED_100FULL (6) +#define PHY_DUPLEX (4) + +uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg); +void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val); + +int16_t eth_phy_lan87xx_get_link_status(uint32_t phy_addr); +int16_t eth_phy_dp838xx_get_link_status(uint32_t phy_addr); + +#endif + +#endif // MICROPY_INCLUDED_STM32_PHY_H diff --git a/ports/stm32/network_lan.c b/ports/stm32/network_lan.c index efdd354fb3..27f3e1337e 100644 --- a/ports/stm32/network_lan.c +++ b/ports/stm32/network_lan.c @@ -54,16 +54,19 @@ static void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_prin } static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_phy_addr}; + enum { ARG_phy_addr, ARG_phy_type}; static const mp_arg_t allowed_args[] = { { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ETH_PHY_LAN8742} }, }; // Parse args. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); const network_lan_obj_t *self = &network_lan_eth0; - eth_init(self->eth, MP_HAL_MAC_ETH0, args[ARG_phy_addr].u_int); + if (eth_init(self->eth, MP_HAL_MAC_ETH0, args[ARG_phy_addr].u_int, args[ARG_phy_type].u_int) != 0) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid phy_type")); + } return MP_OBJ_FROM_PTR(self); } @@ -162,6 +165,11 @@ static const mp_rom_map_elem_t network_lan_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_lan_ifconfig_obj) }, { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_lan_status_obj) }, { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_lan_config_obj) }, + + { MP_ROM_QSTR(MP_QSTR_PHY_LAN8742), MP_ROM_INT(ETH_PHY_LAN8742) }, + { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(ETH_PHY_LAN8720) }, + { MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(ETH_PHY_DP83848) }, + { MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(ETH_PHY_DP83825) }, }; static MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table);