mimxrt: Support selection of PHY type and address.

Useful for boards without a PHY interface, where that has to be
attached. Like the Seed ARCH MIX board or Vision SOM. Phy drivers
supported so far are:

- KSZ8081
- DP83825
- LAN8720

More to come. Usage e.g.:
lan = LAN(phy_type=LAN.PHY_LAN8720, phy_addr=1)

The default values are those set in mpconfigboard.h.
This commit is contained in:
robert-hh 2021-11-04 21:54:44 +01:00
parent bc1b0fd2c1
commit bbe25f4704
4 changed files with 70 additions and 13 deletions

View File

@ -33,7 +33,6 @@
#if defined(MICROPY_HW_ETH_MDC) #if defined(MICROPY_HW_ETH_MDC)
#include "eth.h"
#include "pin.h" #include "pin.h"
#include "shared/netutils/netutils.h" #include "shared/netutils/netutils.h"
#include "extmod/modnetwork.h" #include "extmod/modnetwork.h"
@ -46,6 +45,7 @@
#include "hal/phy/device/phydp83825/fsl_phydp83825.h" #include "hal/phy/device/phydp83825/fsl_phydp83825.h"
#include "hal/phy/device/phylan8720/fsl_phylan8720.h" #include "hal/phy/device/phylan8720/fsl_phylan8720.h"
#include "eth.h"
#include "lwip/etharp.h" #include "lwip/etharp.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "lwip/dhcp.h" #include "lwip/dhcp.h"
@ -167,22 +167,24 @@ void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event,
if (event == kENET_RxEvent) { if (event == kENET_RxEvent) {
do { do {
status = ENET_GetRxFrameSize(&g_handle, &length); status = ENET_GetRxFrameSize(handle, &length);
if (status == kStatus_Success) { if (status == kStatus_Success) {
// Get the data // Get the data
ENET_ReadFrame(ENET, &g_handle, g_rx_frame, length); ENET_ReadFrame(base, handle, g_rx_frame, length);
eth_process_frame(self, g_rx_frame, length); eth_process_frame(self, g_rx_frame, length);
} else if (status == kStatus_ENET_RxFrameError) { } else if (status == kStatus_ENET_RxFrameError) {
ENET_ReadFrame(ENET, &g_handle, NULL, 0); ENET_ReadFrame(base, handle, NULL, 0);
} }
} while (status != kStatus_ENET_RxFrameEmpty); } while (status != kStatus_ENET_RxFrameEmpty);
} else { } else {
ENET_ClearInterruptStatus(ENET, kENET_TxFrameInterrupt); ENET_ClearInterruptStatus(base, kENET_TxFrameInterrupt);
} }
} }
// eth_init: Set up GPIO and the transceiver // eth_init: Set up GPIO and the transceiver
void eth_init(eth_t *self, int mac_idx) { void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr) {
self->netif.num = mac_idx; // Set the interface number
CLOCK_EnableClock(kCLOCK_Iomuxc); CLOCK_EnableClock(kCLOCK_Iomuxc);
@ -242,6 +244,8 @@ void eth_init(eth_t *self, int mac_idx) {
mp_hal_get_mac(0, hw_addr); mp_hal_get_mac(0, hw_addr);
phyHandle.ops = phy_ops;
phyConfig.phyAddr = phy_addr;
phyConfig.autoNeg = true; phyConfig.autoNeg = true;
mdioHandle.resource.base = ENET; mdioHandle.resource.base = ENET;
mdioHandle.resource.csrClock_Hz = CLOCK_GetFreq(kCLOCK_IpgClk); mdioHandle.resource.csrClock_Hz = CLOCK_GetFreq(kCLOCK_IpgClk);
@ -252,7 +256,6 @@ void eth_init(eth_t *self, int mac_idx) {
phy_speed_t speed = kENET_MiiSpeed100M; phy_speed_t speed = kENET_MiiSpeed100M;
phy_duplex_t duplex = kENET_MiiFullDuplex; phy_duplex_t duplex = kENET_MiiFullDuplex;
phyConfig.phyAddr = ENET_PHY_ADDRESS;
status_t status = PHY_Init(&phyHandle, &phyConfig); status_t status = PHY_Init(&phyHandle, &phyConfig);
if (status == kStatus_Success) { if (status == kStatus_Success) {

View File

@ -30,7 +30,7 @@
typedef struct _eth_t eth_t; typedef struct _eth_t eth_t;
extern eth_t eth_instance; extern eth_t eth_instance;
void eth_init(eth_t *self, int mac_idx); void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr);
void eth_set_trace(eth_t *self, uint32_t value); void eth_set_trace(eth_t *self, uint32_t value);
struct netif *eth_netif(eth_t *self); struct netif *eth_netif(eth_t *self);
int eth_link_status(eth_t *self); int eth_link_status(eth_t *self);
@ -38,4 +38,10 @@ int eth_start(eth_t *self);
int eth_stop(eth_t *self); int eth_stop(eth_t *self);
void eth_low_power_mode(eth_t *self, bool enable); void eth_low_power_mode(eth_t *self, bool enable);
enum {
PHY_KSZ8081 = 0,
PHY_DP83825,
PHY_LAN8720,
};
#endif // MICROPY_INCLUDED_MIMXRT_ETH_H #endif // MICROPY_INCLUDED_MIMXRT_ETH_H

View File

@ -97,6 +97,7 @@ enum {
MP_HAL_MAC_WLAN1, MP_HAL_MAC_WLAN1,
MP_HAL_MAC_BDADDR, MP_HAL_MAC_BDADDR,
MP_HAL_MAC_ETH0, MP_HAL_MAC_ETH0,
MP_HAL_MAC_ETH1,
}; };
void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]); void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);

View File

@ -27,10 +27,15 @@
#include "py/runtime.h" #include "py/runtime.h"
#include "py/mphal.h" #include "py/mphal.h"
#include "extmod/modnetwork.h" #include "extmod/modnetwork.h"
#include "eth.h"
#if defined(MICROPY_HW_ETH_MDC) #if defined(MICROPY_HW_ETH_MDC)
#include "fsl_phy.h"
#include "eth.h"
#include "hal/phy/device/phyksz8081/fsl_phyksz8081.h"
#include "hal/phy/device/phydp83825/fsl_phydp83825.h"
#include "hal/phy/device/phylan8720/fsl_phylan8720.h"
#include "lwip/netif.h" #include "lwip/netif.h"
typedef struct _network_lan_obj_t { typedef struct _network_lan_obj_t {
@ -53,10 +58,48 @@ 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 *args) { 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) {
mp_arg_check_num(n_args, n_kw, 0, 0, false); enum { ARG_id, ARG_phy_type, ARG_phy_addr};
const network_lan_obj_t *self = &network_lan_eth0; static const mp_arg_t allowed_args[] = {
eth_init(self->eth, MP_HAL_MAC_ETH0); { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_PHY_ADDRESS} },
};
// 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 phy_operations_t *phy_ops = &ENET_PHY_OPS;
// Select PHY driver
int phy_type = args[ARG_phy_type].u_int;
if (phy_type != -1) {
if (phy_type == PHY_KSZ8081) {
phy_ops = &phyksz8081_ops;
} else if (phy_type == PHY_DP83825) {
phy_ops = &phydp83825_ops;
} else if (phy_type == PHY_LAN8720) {
phy_ops = &phylan8720_ops;
} else {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid value %d for phy"), phy_type);
}
}
int phy_addr = args[ARG_phy_addr].u_int;
// Prepare for two ETH interfaces.
const network_lan_obj_t *self;
int mac_id = args[ARG_id].u_int;
if (mac_id == 0) {
self = &network_lan_eth0;
mac_id = MP_HAL_MAC_ETH0;
} else if (mac_id == 1) {
self = &network_lan_eth0;
mac_id = MP_HAL_MAC_ETH1;
} else {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid LAN interface %d"), mac_id);
}
eth_init(self->eth, mac_id, phy_ops, phy_addr);
// register with network module // register with network module
mod_network_register_nic((mp_obj_t *)self); mod_network_register_nic((mp_obj_t *)self);
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
@ -157,6 +200,10 @@ 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_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_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_config), MP_ROM_PTR(&network_lan_config_obj) },
{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8081), MP_ROM_INT(PHY_KSZ8081) },
{ MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(PHY_DP83825) },
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
}; };
STATIC MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table);