summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/mimxrt/Makefile48
-rw-r--r--ports/mimxrt/board_init.c3
-rw-r--r--ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h21
-rw-r--r--ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk4
-rw-r--r--ports/mimxrt/boards/MIMXRT1021.ld1
-rw-r--r--ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h23
-rw-r--r--ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk7
-rw-r--r--ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h21
-rw-r--r--ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk4
-rw-r--r--ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h21
-rw-r--r--ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk4
-rw-r--r--ports/mimxrt/boards/TEENSY41/mpconfigboard.h21
-rwxr-xr-xports/mimxrt/boards/TEENSY41/mpconfigboard.mk4
-rw-r--r--ports/mimxrt/eth.c448
-rw-r--r--ports/mimxrt/eth.h41
-rw-r--r--ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c281
-rw-r--r--ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h163
-rw-r--r--ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c284
-rw-r--r--ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h163
-rw-r--r--ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c271
-rw-r--r--ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h163
-rw-r--r--ports/mimxrt/hal/phy/fsl_mdio.h125
-rw-r--r--ports/mimxrt/hal/phy/fsl_phy.h258
-rw-r--r--ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c128
-rw-r--r--ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h21
-rw-r--r--ports/mimxrt/lwip_inc/arch/cc.h10
-rw-r--r--ports/mimxrt/lwip_inc/arch/sys_arch.h1
-rw-r--r--ports/mimxrt/lwip_inc/lwipopts.h59
-rw-r--r--ports/mimxrt/main.c26
-rw-r--r--ports/mimxrt/mbedtls/mbedtls_config.h99
-rw-r--r--ports/mimxrt/mbedtls/mbedtls_port.c93
-rw-r--r--ports/mimxrt/moduos.c18
-rw-r--r--ports/mimxrt/mpconfigport.h69
-rw-r--r--ports/mimxrt/mphalport.c42
-rw-r--r--ports/mimxrt/mphalport.h12
-rw-r--r--ports/mimxrt/mpnetworkport.c64
-rw-r--r--ports/mimxrt/network_lan.c171
-rw-r--r--ports/mimxrt/pendsv.c73
-rw-r--r--ports/mimxrt/pendsv.h44
-rw-r--r--ports/mimxrt/pin.c15
-rw-r--r--ports/mimxrt/systick.c60
-rw-r--r--ports/mimxrt/systick.h60
42 files changed, 3436 insertions, 8 deletions
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 1b83f36ab..16aac389d 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -43,7 +43,7 @@ MICROPY_VFS_FAT ?= 1
# Include py core make definitions
include $(TOP)/py/py.mk
-GIT_SUBMODULES = lib/tinyusb lib/nxp_driver
+GIT_SUBMODULES = lib/tinyusb lib/nxp_driver lib/lwip lib/mbedtls
MCU_DIR = lib/nxp_driver/sdk/devices/$(MCU_SERIES)
LD_FILES = boards/$(MCU_SERIES).ld boards/common.ld
@@ -79,7 +79,7 @@ INC += -I$(TOP)/lib/tinyusb/src
CFLAGS_MCU = -mtune=cortex-m7 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16
CFLAGS += $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 -nostdlib -mthumb $(CFLAGS_MCU)
-CFLAGS += -DCPU_$(MCU_SERIES) -DCPU_$(MCU_VARIANT)
+CFLAGS += -DCPU_$(MCU_SERIES) -DCPU_$(MCU_VARIANT) -DBOARD_$(BOARD)
CFLAGS += -DXIP_EXTERNAL_FLASH=1 \
-DXIP_BOOT_HEADER_ENABLE=1 \
-DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \
@@ -134,6 +134,34 @@ LDFLAGS += --gc-sections
CFLAGS += -fdata-sections -ffunction-sections
endif
+# All settings for Ethernet support are controller by the value of MICROPY_PY_LWIP
+ifeq ($(MICROPY_PY_LWIP), 1)
+
+INC += -Ilwip_inc
+INC += -Ihal/phy
+
+SRC_MOD := $(filter-out %/mbedtls/library/error.c, $(SRC_MOD))
+
+SRC_ETH_C += \
+ hal/phy/mdio/enet/fsl_enet_mdio.c \
+ hal/phy/device/phydp83825/fsl_phydp83825.c \
+ hal/phy/device/phyksz8081/fsl_phyksz8081.c \
+ hal/phy/device/phylan8720/fsl_phylan8720.c \
+ lib/mbedtls_errors/mp_mbedtls_errors.c \
+ $(MCU_DIR)/drivers/fsl_enet.c \
+
+SRC_QSTR += \
+ extmod/modlwip.c \
+ extmod/modnetwork.c \
+ extmod/moduwebsocket.c \
+ extmod/modusocket.c \
+ network_lan.c \
+
+CFLAGS += -DFSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE=1 \
+ -DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"'
+
+endif
+
# TinyUSB Stack source
SRC_TINYUSB_C += \
lib/tinyusb/src/class/cdc/cdc_device.c \
@@ -164,6 +192,7 @@ SRC_HAL_IMX_C += \
$(MCU_DIR)/drivers/fsl_lpspi.c \
$(MCU_DIR)/drivers/fsl_lpspi_edma.c \
$(MCU_DIR)/drivers/fsl_lpuart.c \
+ $(MCU_DIR)/drivers/fsl_ocotp.c \
$(MCU_DIR)/drivers/fsl_pit.c \
$(MCU_DIR)/drivers/fsl_snvs_lp.c \
$(MCU_DIR)/drivers/fsl_trng.c \
@@ -183,7 +212,11 @@ SRC_C += \
board_init.c \
dma_channel.c \
drivers/bus/softspi.c \
+ eth.c \
+ extmod/modnetwork.c \
extmod/modonewire.c \
+ extmod/modusocket.c \
+ extmod/uos_dupterm.c \
fatfs_port.c \
led.c \
machine_adc.c \
@@ -197,6 +230,7 @@ SRC_C += \
machine_timer.c \
machine_uart.c \
main.c \
+ mbedtls/mbedtls_port.c \
mimxrt_flash.c \
mimxrt_sdram.c \
modmachine.c \
@@ -204,10 +238,16 @@ SRC_C += \
moduos.c \
modutime.c \
mphalport.c \
+ mpnetworkport.c \
+ network_lan.c \
+ pendsv.c \
pin.c \
sdcard.c \
shared/libc/printf.c \
shared/libc/string0.c \
+ shared/netutils/netutils.c \
+ shared/netutils/trace.c \
+ shared/netutils/dhcpserver.c \
shared/readline/readline.c \
shared/runtime/gchelper_native.c \
shared/runtime/mpirq.c \
@@ -215,10 +255,13 @@ SRC_C += \
shared/runtime/stdout_helpers.c \
shared/runtime/sys_stdio_mphal.c \
shared/timeutils/timeutils.c \
+ systick.c \
ticks.c \
tusb_port.c \
$(SRC_TINYUSB_C) \
$(SRC_HAL_IMX_C) \
+ $(SRC_ETH_C) \
+
ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor)
SRC_C += \
@@ -334,6 +377,7 @@ SRC_S += shared/runtime/gchelper_m3.s \
# List of sources for qstr extraction
SRC_QSTR += \
extmod/modonewire.c \
+ extmod/uos_dupterm.c \
machine_adc.c \
machine_led.c \
machine_pin.c \
diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c
index e37ed1f14..d96645fef 100644
--- a/ports/mimxrt/board_init.c
+++ b/ports/mimxrt/board_init.c
@@ -56,6 +56,9 @@ void board_init(void) {
mimxrt_sdram_init();
#endif
+ // 1ms tick timer
+ SysTick_Config(SystemCoreClock / 1000);
+
// ------------- USB0 ------------- //
// Clock
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index 4f33bb208..b546700e7 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -117,3 +117,24 @@
#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_09_SEMC_WE
#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_12_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address
+#define ENET_PHY_ADDRESS (2)
+#define ENET_PHY_OPS phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN pin_GPIO_AD_B0_04
+#define ENET_INT_PIN pin_GPIO_AD_B1_06
+
+#define IOMUX_TABLE_ENET \
+ { IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 1, 0xB0E9u }, \
+ { IOMUXC_GPIO_AD_B0_09_ENET_RDATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_AD_B0_10_ENET_RDATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_AD_B0_11_ENET_RX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_AD_B0_12_ENET_RX_ER, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_AD_B0_13_ENET_TX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_AD_B0_14_ENET_TDATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_40_ENET_MDIO, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_41_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
index e08b3357f..c1e1678e5 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
@@ -9,6 +9,10 @@ MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB
MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
JLINK_PATH ?= /media/RT1020-EVK/
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld
index 8d981a7c6..64f4e537e 100644
--- a/ports/mimxrt/boards/MIMXRT1021.ld
+++ b/ports/mimxrt/boards/MIMXRT1021.ld
@@ -42,6 +42,7 @@ _gc_heap_start = ORIGIN(m_sdram);
_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
#else
/* Use second OCRAM bank for GC heap. */
+/* Use all OCRAM for the GC heap. */
_gc_heap_start = ORIGIN(m_ocrm);
_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
#endif
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index f6021ac78..3837315f7 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -1,4 +1,4 @@
-#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVK"
+#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVKB-A1"
#define MICROPY_HW_MCU_NAME "MIMXRT1052DVL6B"
// MIMXRT1050_EVKB has 1 user LED
@@ -108,3 +108,24 @@
#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address & Type
+#define ENET_PHY_ADDRESS (2)
+#define ENET_PHY_OPS phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN pin_GPIO_AD_B0_09
+#define ENET_INT_PIN pin_GPIO_AD_B0_10
+
+#define IOMUX_TABLE_ENET \
+ { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+ { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
index 4165b72c2..65e3d3096 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
@@ -9,7 +9,6 @@ MICROPY_HW_FLASH_SIZE ?= 0x4000000 # 64MB
MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
-JLINK_PATH ?= /media/RT1050-EVKB/
-
-deploy: $(BUILD)/firmware.bin
- cp $< $(JLINK_PATH)
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index af4401048..a66fcf9ae 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -107,3 +107,24 @@
#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address
+#define ENET_PHY_ADDRESS (2)
+#define ENET_PHY_OPS phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN pin_GPIO_AD_B0_09
+#define ENET_INT_PIN pin_GPIO_AD_B0_10
+
+#define IOMUX_TABLE_ENET \
+ { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+ { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
index 4c4a2ff98..56ccba6e5 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
@@ -9,6 +9,10 @@ MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB
MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
JLINK_PATH ?= /media/RT1060-EVK/
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index 17268b0a5..1dcdd378a 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -107,3 +107,24 @@
#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address
+#define ENET_PHY_ADDRESS (2)
+#define ENET_PHY_OPS phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN pin_GPIO_AD_B0_09
+#define ENET_INT_PIN pin_GPIO_AD_B0_10
+
+#define IOMUX_TABLE_ENET \
+ { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+ { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
index 8bc35dd0d..5cd7d49ab 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
@@ -9,6 +9,10 @@ MICROPY_HW_FLASH_SIZE ?= 0x4000000 # 64MB
MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
JLINK_PATH ?= /media/RT1064-EVK/
deploy: $(BUILD)/firmware.bin
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
index 7890ba762..4ca82d4b6 100644
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
@@ -65,3 +65,24 @@
.data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
.data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
}
+
+// Network definitions
+// Transceiver Phy Address & Type
+#define ENET_PHY_ADDRESS (0)
+#define ENET_PHY_OPS phydp83825_ops
+
+// Ethernet PIN definitions
+#define ENET_RESET_PIN pin_GPIO_B0_14
+#define ENET_INT_PIN pin_GPIO_B0_15
+
+#define IOMUX_TABLE_ENET \
+ { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+ { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_15_ENET_MDIO, 0, 0xB0E9u }, \
+ { IOMUXC_GPIO_B1_14_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
index 27039648b..a012444ca 100755
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
@@ -7,5 +7,9 @@ MICROPY_HW_FLASH_TYPE ?= qspi_nor
MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB
MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
deploy: $(BUILD)/firmware.hex
teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c
new file mode 100644
index 000000000..414e8d51f
--- /dev/null
+++ b/ports/mimxrt/eth.c
@@ -0,0 +1,448 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2021 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 <string.h>
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/mperrno.h"
+#include "ticks.h"
+
+#if defined(MICROPY_HW_ETH_MDC)
+
+#include "eth.h"
+#include "pin.h"
+#include "shared/netutils/netutils.h"
+#include "extmod/modnetwork.h"
+
+#include "fsl_iomuxc.h"
+#include "fsl_enet.h"
+#include "fsl_phy.h"
+#include "hal/phy/mdio/enet/fsl_enet_mdio.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/etharp.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+#include "netif/ethernet.h"
+
+#include "ticks.h"
+
+// Configuration values
+enet_config_t enet_config;
+phy_config_t phyConfig = {0};
+
+// Prepare the buffer configuration.
+
+#define ENET_RXBD_NUM (5)
+#define ENET_TXBD_NUM (5)
+
+AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT);
+AT_NONCACHEABLE_SECTION_ALIGN(enet_tx_bd_struct_t g_txBuffDescrip[ENET_TXBD_NUM], ENET_BUFF_ALIGNMENT);
+SDK_ALIGN(uint8_t g_rxDataBuff[ENET_RXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+ ENET_BUFF_ALIGNMENT);
+SDK_ALIGN(uint8_t g_txDataBuff[ENET_TXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+ ENET_BUFF_ALIGNMENT);
+
+// ENET Handles & Buffers
+enet_handle_t g_handle;
+
+static mdio_handle_t mdioHandle = {.ops = &enet_ops};
+static phy_handle_t phyHandle = {.phyAddr = ENET_PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &ENET_PHY_OPS};
+
+enet_buffer_config_t buffConfig[] = {{
+ ENET_RXBD_NUM,
+ ENET_TXBD_NUM,
+ SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+ SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+ &g_rxBuffDescrip[0],
+ &g_txBuffDescrip[0],
+ &g_rxDataBuff[0][0],
+ &g_txDataBuff[0][0],
+ }};
+
+static uint8_t hw_addr[6]; // The MAC address field
+eth_t eth_instance;
+
+#define PHY_INIT_TIMEOUT_MS (10000)
+#define PHY_AUTONEGO_TIMEOUT_US (5000000)
+
+typedef struct _eth_t {
+ uint32_t trace_flags;
+ struct netif netif;
+ struct dhcp dhcp_struct;
+} eth_t;
+
+typedef struct _iomux_table_t {
+ uint32_t muxRegister;
+ uint32_t muxMode;
+ uint32_t inputRegister;
+ uint32_t inputDaisy;
+ uint32_t configRegister;
+ uint32_t inputOnfield;
+ uint32_t configValue;
+} iomux_table_t;
+
+static const iomux_table_t iomux_table_enet[] = {
+ IOMUX_TABLE_ENET
+};
+
+#define IOTE (iomux_table_enet[i])
+#ifndef ENET_TX_CLK_OUTPUT
+#define ENET_TX_CLK_OUTPUT true
+#endif
+
+#define TRACE_ASYNC_EV (0x0001)
+#define TRACE_ETH_TX (0x0002)
+#define TRACE_ETH_RX (0x0004)
+#define TRACE_ETH_FULL (0x0008)
+
+
+STATIC void eth_trace(eth_t *self, size_t len, const void *data, unsigned int flags) {
+ if (((flags & NETUTILS_TRACE_IS_TX) && (self->trace_flags & TRACE_ETH_TX))
+ || (!(flags & NETUTILS_TRACE_IS_TX) && (self->trace_flags & TRACE_ETH_RX))) {
+ const uint8_t *buf;
+ if (len == (size_t)-1) {
+ // data is a pbuf
+ const struct pbuf *pbuf = data;
+ buf = pbuf->payload;
+ len = pbuf->len; // restricted to print only the first chunk of the pbuf
+ } else {
+ // data is actual data buffer
+ buf = data;
+ }
+ if (self->trace_flags & TRACE_ETH_FULL) {
+ flags |= NETUTILS_TRACE_PAYLOAD;
+ }
+ netutils_ethernet_trace(MP_PYTHON_PRINTER, len, buf, flags);
+ }
+}
+
+STATIC void eth_process_frame(eth_t *self, uint8_t *buf, size_t length) {
+
+ struct netif *netif = &self->netif;
+ if (netif->flags & NETIF_FLAG_LINK_UP) {
+ struct pbuf *p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
+ if (p != NULL) {
+ // Need to create a local copy first, since ENET_ReadFrame does not
+ // provide a pointer to the buffer.
+ pbuf_take(p, buf, length);
+ if (netif->input(p, netif) != ERR_OK) {
+ pbuf_free(p);
+ }
+ }
+ }
+}
+
+void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *userData) {
+ eth_t *self = (eth_t *)userData;
+ uint8_t g_rx_frame[ENET_FRAME_MAX_FRAMELEN + 14];
+ uint32_t length = 0;
+ status_t status;
+
+ if (event == kENET_RxEvent) {
+ do {
+ status = ENET_GetRxFrameSize(&g_handle, &length);
+ if (status == kStatus_Success) {
+ // Get the data
+ ENET_ReadFrame(ENET, &g_handle, g_rx_frame, length);
+ eth_process_frame(self, g_rx_frame, length);
+ } else if (status == kStatus_ENET_RxFrameError) {
+ ENET_ReadFrame(ENET, &g_handle, NULL, 0);
+ }
+ } while (status != kStatus_ENET_RxFrameEmpty);
+ } else {
+ ENET_ClearInterruptStatus(ENET, kENET_TxFrameInterrupt);
+ }
+}
+
+// eth_init: Set up GPIO and the transceiver
+void eth_init(eth_t *self, int mac_idx) {
+
+ CLOCK_EnableClock(kCLOCK_Iomuxc);
+
+ gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
+ (void)gpio_config;
+
+ #ifdef ENET_RESET_PIN
+ // Configure the Reset Pin
+ const machine_pin_obj_t *reset_pin = &ENET_RESET_PIN;
+ const machine_pin_af_obj_t *af_obj = pin_find_af(reset_pin, PIN_AF_MODE_ALT5);
+
+ IOMUXC_SetPinMux(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0U);
+ IOMUXC_SetPinConfig(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0xB0A9U);
+ GPIO_PinInit(reset_pin->gpio, reset_pin->pin, &gpio_config);
+ #endif
+
+ #ifdef ENET_INT_PIN
+ // Configure the Int Pin
+ const machine_pin_obj_t *int_pin = &ENET_INT_PIN;
+ af_obj = pin_find_af(int_pin, PIN_AF_MODE_ALT5);
+
+ IOMUXC_SetPinMux(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0U);
+ IOMUXC_SetPinConfig(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0xB0A9U);
+ GPIO_PinInit(int_pin->gpio, int_pin->pin, &gpio_config);
+ #endif
+
+ // Configure the Transceiver Pins, Settings except for CLK:
+ // Slew Rate Field: Fast Slew Rate, Drive Strength, R0/5, Speed max(200MHz)
+ // Open Drain Disabled, Pull Enabled, Pull 100K Ohm Pull Up
+ // Hysteresis Disabled
+
+ for (int i = 0; i < ARRAY_SIZE(iomux_table_enet); i++) {
+ IOMUXC_SetPinMux(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.inputOnfield);
+ IOMUXC_SetPinConfig(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.configValue);
+ }
+
+ const clock_enet_pll_config_t config = {
+ .enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1
+ };
+ CLOCK_InitEnetPll(&config);
+
+ IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); // Drive ENET_REF_CLK from PAD
+ IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, ENET_TX_CLK_OUTPUT); // Enable output driver
+
+ // Reset transceiver
+ // pull up the ENET_INT before RESET.
+ #ifdef ENET_INT_PIN
+ GPIO_WritePinOutput(int_pin->gpio, int_pin->pin, 1);
+ #endif
+
+ #ifdef ENET_RESET_PIN
+ GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 0);
+ mp_hal_delay_us(1000);
+ GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 1);
+ mp_hal_delay_us(1000);
+ #endif
+
+ mp_hal_get_mac(0, hw_addr);
+
+ phyConfig.autoNeg = true;
+ mdioHandle.resource.base = ENET;
+ mdioHandle.resource.csrClock_Hz = CLOCK_GetFreq(kCLOCK_IpgClk);
+
+ // Init the PHY interface & negotiate the speed
+ bool link = false;
+ bool autonego = false;
+ phy_speed_t speed = kENET_MiiSpeed100M;
+ phy_duplex_t duplex = kENET_MiiFullDuplex;
+
+ phyConfig.phyAddr = ENET_PHY_ADDRESS;
+
+ status_t status = PHY_Init(&phyHandle, &phyConfig);
+ if (status == kStatus_Success) {
+ if (phyConfig.autoNeg) {
+ uint64_t t = ticks_us64() + PHY_AUTONEGO_TIMEOUT_US;
+ // Wait for auto-negotiation success and link up
+ do {
+ PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
+ PHY_GetLinkStatus(&phyHandle, &link);
+ if (autonego && link) {
+ break;
+ }
+ } while (ticks_us64() < t);
+ if (!autonego) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Auto-negotiation failed."));
+ }
+ PHY_GetLinkSpeedDuplex(&phyHandle, &speed, &duplex);
+ } else {
+ PHY_SetLinkSpeedDuplex(&phyHandle, speed, duplex);
+ }
+ } else {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Init failed."));
+ }
+
+ ENET_GetDefaultConfig(&enet_config);
+ enet_config.miiSpeed = (enet_mii_speed_t)speed;
+ enet_config.miiDuplex = (enet_mii_duplex_t)duplex;
+ enet_config.miiMode = kENET_RmiiMode;
+ // Enable checksum generation by the ENET controller
+ // Note: Disabled due to problems with the checksum on ICMP requests
+ // Maybe caused by LWIP inserting 0xffff instead of 0x0000
+ // Keep the code for now until it may be fixed.
+ // enet_config.txAccelerConfig = kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled;
+ // Set interrupt
+ enet_config.interrupt |= ENET_TX_INTERRUPT | ENET_RX_INTERRUPT;
+
+ ENET_Init(ENET, &g_handle, &enet_config, &buffConfig[0], hw_addr, CLOCK_GetFreq(kCLOCK_IpgClk));
+ ENET_SetCallback(&g_handle, eth_irq_handler, (void *)self);
+ ENET_EnableInterrupts(ENET, ENET_RX_INTERRUPT);
+ ENET_ClearInterruptStatus(ENET, ENET_TX_INTERRUPT | ENET_RX_INTERRUPT | ENET_ERR_INTERRUPT);
+ ENET_ActiveRead(ENET);
+}
+
+// Initialize the phy interface
+STATIC int eth_mac_init(eth_t *self) {
+ return 0;
+}
+
+// Deinit the interface
+STATIC void eth_mac_deinit(eth_t *self) {
+}
+
+void eth_set_trace(eth_t *self, uint32_t value) {
+ self->trace_flags = value;
+}
+
+/*******************************************************************************/
+// ETH-LwIP bindings
+
+STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
+ // This function should always be called from a context where PendSV-level IRQs are disabled
+ status_t status;
+
+ LINK_STATS_INC(link.xmit);
+ eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE);
+
+ if (p->next == NULL) {
+ status = ENET_SendFrame(ENET, &g_handle, p->payload, p->len);
+ } else {
+ // frame consists of several parts. Copy them together and send them
+ size_t length = 0;
+ uint8_t tx_frame[ENET_FRAME_MAX_FRAMELEN + 14];
+
+ while (p) {
+ memcpy(&tx_frame[length], p->payload, p->len);
+ length += p->len;
+ p = p->next;
+ }
+ status = ENET_SendFrame(ENET, &g_handle, tx_frame, length);
+ }
+ return status == kStatus_Success ? ERR_OK : ERR_BUF;
+}
+
+STATIC err_t eth_netif_init(struct netif *netif) {
+ netif->linkoutput = eth_netif_output;
+ netif->output = etharp_output;
+ netif->mtu = 1500;
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
+ // Checksums only need to be checked on incoming frames, not computed on outgoing frames
+ NETIF_SET_CHECKSUM_CTRL(netif,
+ NETIF_CHECKSUM_CHECK_IP
+ | NETIF_CHECKSUM_CHECK_UDP
+ | NETIF_CHECKSUM_CHECK_TCP
+ | NETIF_CHECKSUM_CHECK_ICMP
+ | NETIF_CHECKSUM_CHECK_ICMP6
+ | NETIF_CHECKSUM_GEN_IP
+ | NETIF_CHECKSUM_GEN_UDP
+ | NETIF_CHECKSUM_GEN_TCP
+ | NETIF_CHECKSUM_GEN_ICMP
+ | NETIF_CHECKSUM_GEN_ICMP6
+ );
+ return ERR_OK;
+}
+
+STATIC void eth_lwip_init(eth_t *self) {
+ ip_addr_t ipconfig[4];
+ IP4_ADDR(&ipconfig[0], 192, 168, 0, 2);
+ IP4_ADDR(&ipconfig[1], 255, 255, 255, 0);
+ IP4_ADDR(&ipconfig[2], 192, 168, 0, 1);
+ IP4_ADDR(&ipconfig[3], 8, 8, 8, 8);
+
+ self->netif.hwaddr_len = 6;
+ memcpy(self->netif.hwaddr, hw_addr, 6);
+
+ MICROPY_PY_LWIP_ENTER
+
+ struct netif *n = &self->netif;
+ n->name[0] = 'e';
+ n->name[1] = '0';
+ netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, eth_netif_init, ethernet_input);
+ netif_set_hostname(n, "MPY");
+ netif_set_default(n);
+ netif_set_up(n);
+
+ dns_setserver(0, &ipconfig[3]);
+ dhcp_set_struct(n, &self->dhcp_struct);
+ dhcp_start(n);
+
+ netif_set_link_up(n);
+
+ MICROPY_PY_LWIP_EXIT
+}
+
+STATIC void eth_lwip_deinit(eth_t *self) {
+ MICROPY_PY_LWIP_ENTER
+ for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
+ if (netif == &self->netif) {
+ netif_remove(netif);
+ netif->ip_addr.addr = 0;
+ netif->flags = 0;
+ }
+ }
+ MICROPY_PY_LWIP_EXIT
+}
+
+struct netif *eth_netif(eth_t *self) {
+ return &self->netif;
+}
+
+int eth_link_status(eth_t *self) {
+ struct netif *netif = &self->netif;
+ if ((netif->flags & (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP))
+ == (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) {
+ if (netif->ip_addr.addr != 0) {
+ return 3; // link up
+ } else {
+ return 2; // link no-ip;
+ }
+ } else {
+ bool link;
+ PHY_GetLinkStatus(&phyHandle, &link);
+ if (link) {
+ return 1; // link up
+ } else {
+ return 0; // link down
+ }
+ }
+}
+
+int eth_start(eth_t *self) {
+ eth_lwip_deinit(self);
+
+ // Make sure Eth is Not in low power mode.
+ eth_low_power_mode(self, false);
+
+ int ret = eth_mac_init(self);
+ if (ret < 0) {
+ return ret;
+ }
+ eth_lwip_init(self);
+ return 0;
+}
+
+int eth_stop(eth_t *self) {
+ eth_lwip_deinit(self);
+ eth_mac_deinit(self);
+ return 0;
+}
+
+void eth_low_power_mode(eth_t *self, bool enable) {
+ ENET_EnableSleepMode(ENET, enable);
+}
+#endif // defined(MICROPY_HW_ETH_MDC)
diff --git a/ports/mimxrt/eth.h b/ports/mimxrt/eth.h
new file mode 100644
index 000000000..56327d08a
--- /dev/null
+++ b/ports/mimxrt/eth.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2021 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_MIMXRT_ETH_H
+#define MICROPY_INCLUDED_MIMXRT_ETH_H
+
+typedef struct _eth_t eth_t;
+extern eth_t eth_instance;
+
+void eth_init(eth_t *self, int mac_idx);
+void eth_set_trace(eth_t *self, uint32_t value);
+struct netif *eth_netif(eth_t *self);
+int eth_link_status(eth_t *self);
+int eth_start(eth_t *self);
+int eth_stop(eth_t *self);
+void eth_low_power_mode(eth_t *self, bool enable);
+
+#endif // MICROPY_INCLUDED_MIMXRT_ETH_H
diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
new file mode 100644
index 000000000..2aca609a0
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phydp83825.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY PD83825 vendor defined registers. */
+#define PHY_PHYSTS_REG 0x10U // Phy status register
+#define PHY_BISCR_REG 0x16U // RMII Config register.
+#define PHY_RCSR_REG 0x17U // RMII Config register.
+#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control register 2. */
+
+/*! @brief Defines the PHY DP82825 ID number. */
+#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 */
+
+/*! @brief Defines the mask flag of operation mode in control registers */
+#define PHY_PHYSTS_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */
+#define PHY_PHYSTS_DUPLEX_MASK 0x0004U /*!< The PHY full duplex mask. */
+#define PHY_PHYSTS_100M_MASK 0x0002U /*!< The PHY 100M mask. */
+#define PHY_PHYSTS_LINK_MASK 0x0001U /*!< The PHY link up mask. */
+
+#define PYH_RMII_CLOCK_SELECT 0x80 // Select 50MHz clock
+#define PHY_BISCR_REMOTELOOP_MASK 0x1FU // !< The PHY remote loopback mask.
+#define PHY_BISCR_REMOTELOOP_MODE 0x08U // !< The PHY remote loopback mode.
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const phy_operations_t phydp83825_ops = {.phyInit = PHY_DP83825_Init,
+ .phyWrite = PHY_DP83825_Write,
+ .phyRead = PHY_DP83825_Read,
+ .getAutoNegoStatus = PHY_DP83825_GetAutoNegotiationStatus,
+ .getLinkStatus = PHY_DP83825_GetLinkStatus,
+ .getLinkSpeedDuplex = PHY_DP83825_GetLinkSpeedDuplex,
+ .setLinkSpeedDuplex = PHY_DP83825_SetLinkSpeedDuplex,
+ .enableLoopback = PHY_DP83825_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_DP83825_Init(phy_handle_t *handle, const phy_config_t *config) {
+ uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+ status_t result = kStatus_Success;
+ uint32_t regValue = 0;
+
+ /* Init MDIO interface. */
+ MDIO_Init(handle->mdioHandle);
+
+ /* Assign phy address. */
+ handle->phyAddr = config->phyAddr;
+
+ /* Check PHY ID. */
+ do
+ {
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ counter--;
+ } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+ if (counter == 0U) {
+ return kStatus_Fail;
+ }
+
+ /* Reset PHY. */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+ if (result == kStatus_Success) {
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_RCSR_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ result =
+ MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_RCSR_REG, (regValue | PYH_RMII_CLOCK_SELECT));
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ if (config->autoNeg) {
+ /* Set the auto-negotiation then start it. */
+ result =
+ MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+ (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
+ PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
+ if (result == kStatus_Success) {
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ } else {
+ /* This PHY only supports 10/100M speed. */
+ assert(config->speed <= kPHY_Speed100M);
+
+ /* Disable isolate mode */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ regValue &= ~PHY_BCTL_ISOLATE_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+ result = PHY_DP83825_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+ }
+ }
+ return result;
+}
+
+status_t PHY_DP83825_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_DP83825_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+ return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_DP83825_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ *status = false;
+
+ /* Check auto negotiation complete. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+ if (result == kStatus_Success) {
+ if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+ *status = true;
+ }
+ }
+ return result;
+}
+
+status_t PHY_DP83825_GetLinkStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ /* Read the basic status register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+ if (result == kStatus_Success) {
+ if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+ /* Link up. */
+ *status = true;
+ } else {
+ /* Link down. */
+ *status = false;
+ }
+ }
+ return result;
+}
+
+status_t PHY_DP83825_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+ assert(!((speed == NULL) && (duplex == NULL)));
+
+ status_t result;
+ uint32_t regValue;
+ uint32_t flag;
+
+ /* Read the control register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
+ if (result == kStatus_Success) {
+ if (speed != NULL) {
+ flag = regValue & PHY_PHYSTS_100M_MASK;
+ if (flag) {
+ *speed = kPHY_Speed10M;
+ } else {
+ *speed = kPHY_Speed100M;
+ }
+ }
+
+ if (duplex != NULL) {
+ flag = regValue & PHY_PHYSTS_DUPLEX_MASK;
+ if (flag) {
+ *duplex = kPHY_FullDuplex;
+ } else {
+ *duplex = kPHY_HalfDuplex;
+ }
+ }
+ }
+ return result;
+}
+
+status_t PHY_DP83825_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+ /* This PHY only supports 10/100M speed. */
+ assert(speed <= kPHY_Speed100M);
+
+ status_t result;
+ uint32_t regValue;
+
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result == kStatus_Success) {
+ /* Disable the auto-negotiation and set according to user-defined configuration. */
+ regValue &= ~PHY_BCTL_AUTONEG_MASK;
+ if (speed == kPHY_Speed100M) {
+ regValue |= PHY_BCTL_SPEED0_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_SPEED0_MASK;
+ }
+ if (duplex == kPHY_FullDuplex) {
+ regValue |= PHY_BCTL_DUPLEX_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_DUPLEX_MASK;
+ }
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ }
+ return result;
+}
+status_t PHY_DP83825_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+ /* This PHY only supports local/remote loopback and 10/100M speed. */
+ assert(mode <= kPHY_RemoteLoop);
+ assert(speed <= kPHY_Speed100M);
+
+ status_t result = kStatus_Success;
+ uint32_t regValue;
+
+ /* Set the loop mode. */
+ if (enable) {
+ if (mode == kPHY_LocalLoop) {
+ if (speed == kPHY_Speed100M) {
+ regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ } else {
+ regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ }
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ } else {
+ /* Remote loopback only supports 100M full-duplex. */
+ assert(speed == kPHY_Speed100M);
+
+ regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ /* Set the remote loopback bit. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, &regValue);
+ if (result == kStatus_Success) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG,
+ (regValue & ~PHY_BISCR_REMOTELOOP_MASK) | PHY_BISCR_REMOTELOOP_MODE);
+ }
+ }
+ } else {
+ /* Disable the loop mode. */
+ if (mode != kPHY_LocalLoop) {
+ /* First read the current status in control one register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, &regValue);
+ if (result == kStatus_Success) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG,
+ (regValue & ~PHY_BISCR_REMOTELOOP_MASK));
+ }
+ }
+ /* First read the current status in control register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result == kStatus_Success) {
+ regValue &= ~PHY_BCTL_LOOP_MASK;
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ }
+
+ return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
new file mode 100644
index 000000000..9d6b4fdf7
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY DP83825 driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phyksz8081 PHYDP83825
+ The current PHYDP83825 driver version is 2.0.0.
+
+ - 2.0.0
+ - Initial version.
+*/
+
+#ifndef _FSL_DP83825_H_
+#define _FSL_DP83825_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phydp83825_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ * This function initialize PHY.
+ *
+ * @param handle PHY device handle.
+ * @param config Pointer to structure of phy_config_t.
+ * @retval kStatus_Success PHY initialization succeeds
+ * @retval kStatus_Fail PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param data The data written to the PHY register.
+ * @retval kStatus_Success PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param dataPtr The address to store the data read from the PHY register.
+ * @retval kStatus_Success PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle PHY device handle.
+ * @param status The auto-negotiation status of the PHY.
+ * - true the auto-negotiation is over.
+ * - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle PHY device handle.
+ * @param status The link up or down status of the PHY.
+ * - true the link is up.
+ * - false the link is down.
+ * @retval kStatus_Success PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle PHY device handle.
+ * @param speed The address of PHY link speed.
+ * @param duplex The link duplex of PHY.
+ * @retval kStatus_Success PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle PHY device handle.
+ * @param speed Specified PHY link speed.
+ * @param duplex Specified PHY link duplex.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle PHY device handle.
+ * @param mode The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed PHY speed for loopback mode.
+ * @param enable True to enable, false to disable.
+ * @retval kStatus_Success PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_DP83825_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_DP83825_H_ */
diff --git a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c
new file mode 100644
index 000000000..32cabacdb
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phyksz8081.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY KSZ8081 vendor defined registers. */
+#define PHY_CONTROL1_REG 0x1EU /*!< The PHY control one register. */
+#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */
+
+/*! @brief Defines the PHY KSZ8081 ID number. */
+#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1 */
+
+/*! @brief Defines the mask flag of operation mode in control registers */
+#define PHY_CTL2_REMOTELOOP_MASK 0x0004U /*!< The PHY remote loopback mask. */
+#define PHY_CTL2_REFCLK_SELECT_MASK 0x0080U /*!< The PHY RMII reference clock select. */
+#define PHY_CTL1_10HALFDUPLEX_MASK 0x0001U /*!< The PHY 10M half duplex mask. */
+#define PHY_CTL1_100HALFDUPLEX_MASK 0x0002U /*!< The PHY 100M half duplex mask. */
+#define PHY_CTL1_10FULLDUPLEX_MASK 0x0005U /*!< The PHY 10M full duplex mask. */
+#define PHY_CTL1_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */
+#define PHY_CTL1_SPEEDUPLX_MASK 0x0007U /*!< The PHY speed and duplex mask. */
+#define PHY_CTL1_ENERGYDETECT_MASK 0x10U /*!< The PHY signal present on rx differential pair. */
+#define PHY_CTL1_LINKUP_MASK 0x100U /*!< The PHY link up. */
+#define PHY_LINK_READY_MASK (PHY_CTL1_ENERGYDETECT_MASK | PHY_CTL1_LINKUP_MASK)
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const phy_operations_t phyksz8081_ops = {.phyInit = PHY_KSZ8081_Init,
+ .phyWrite = PHY_KSZ8081_Write,
+ .phyRead = PHY_KSZ8081_Read,
+ .getAutoNegoStatus = PHY_KSZ8081_GetAutoNegotiationStatus,
+ .getLinkStatus = PHY_KSZ8081_GetLinkStatus,
+ .getLinkSpeedDuplex = PHY_KSZ8081_GetLinkSpeedDuplex,
+ .setLinkSpeedDuplex = PHY_KSZ8081_SetLinkSpeedDuplex,
+ .enableLoopback = PHY_KSZ8081_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config) {
+ uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+ status_t result = kStatus_Success;
+ uint32_t regValue = 0;
+
+ /* Init MDIO interface. */
+ MDIO_Init(handle->mdioHandle);
+
+ /* Assign phy address. */
+ handle->phyAddr = config->phyAddr;
+
+ /* Check PHY ID. */
+ do
+ {
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ counter--;
+ } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+ if (counter == 0U) {
+ return kStatus_Fail;
+ }
+
+ /* Reset PHY. */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+ if (result == kStatus_Success) {
+ #if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE)
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ result =
+ MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, (regValue | PHY_CTL2_REFCLK_SELECT_MASK));
+ if (result != kStatus_Success) {
+ return result;
+ }
+ #endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */
+
+ if (config->autoNeg) {
+ /* Set the auto-negotiation then start it. */
+ result =
+ MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+ (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
+ PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
+ if (result == kStatus_Success) {
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ } else {
+ /* This PHY only supports 10/100M speed. */
+ assert(config->speed <= kPHY_Speed100M);
+
+ /* Disable isolate mode */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ regValue &= ~PHY_BCTL_ISOLATE_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+ result = PHY_KSZ8081_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+ }
+ }
+ return result;
+}
+
+status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+ return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ *status = false;
+
+ /* Check auto negotiation complete. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+ if (result == kStatus_Success) {
+ if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+ *status = true;
+ }
+ }
+ return result;
+}
+
+status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ /* Read the basic status register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+ if (result == kStatus_Success) {
+ if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+ /* Link up. */
+ *status = true;
+ } else {
+ /* Link down. */
+ *status = false;
+ }
+ }
+ return result;
+}
+
+status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+ assert(!((speed == NULL) && (duplex == NULL)));
+
+ status_t result;
+ uint32_t regValue;
+ uint32_t flag;
+
+ /* Read the control register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL1_REG, &regValue);
+ if (result == kStatus_Success) {
+ if (speed != NULL) {
+ flag = regValue & PHY_CTL1_SPEEDUPLX_MASK;
+ if ((PHY_CTL1_100HALFDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) {
+ *speed = kPHY_Speed100M;
+ } else {
+ *speed = kPHY_Speed10M;
+ }
+ }
+
+ if (duplex != NULL) {
+ flag = regValue & PHY_CTL1_SPEEDUPLX_MASK;
+ if ((PHY_CTL1_10FULLDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) {
+ *duplex = kPHY_FullDuplex;
+ } else {
+ *duplex = kPHY_HalfDuplex;
+ }
+ }
+ }
+ return result;
+}
+
+status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+ /* This PHY only supports 10/100M speed. */
+ assert(speed <= kPHY_Speed100M);
+
+ status_t result;
+ uint32_t regValue;
+
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result == kStatus_Success) {
+ /* Disable the auto-negotiation and set according to user-defined configuration. */
+ regValue &= ~PHY_BCTL_AUTONEG_MASK;
+ if (speed == kPHY_Speed100M) {
+ regValue |= PHY_BCTL_SPEED0_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_SPEED0_MASK;
+ }
+ if (duplex == kPHY_FullDuplex) {
+ regValue |= PHY_BCTL_DUPLEX_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_DUPLEX_MASK;
+ }
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ }
+ return result;
+}
+
+status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+ /* This PHY only supports local/remote loopback and 10/100M speed. */
+ assert(mode <= kPHY_RemoteLoop);
+ assert(speed <= kPHY_Speed100M);
+
+ status_t result;
+ uint32_t regValue;
+
+ /* Set the loop mode. */
+ if (enable) {
+ if (mode == kPHY_LocalLoop) {
+ if (speed == kPHY_Speed100M) {
+ regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ } else {
+ regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ }
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ } else {
+ /* Remote loopback only supports 100M full-duplex. */
+ assert(speed == kPHY_Speed100M);
+
+ regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ /* Set the remote loopback bit. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, &regValue);
+ if (result == kStatus_Success) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG,
+ (regValue | PHY_CTL2_REMOTELOOP_MASK));
+ }
+ }
+ } else {
+ /* Disable the loop mode. */
+ if (mode == kPHY_LocalLoop) {
+ /* First read the current status in control register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result == kStatus_Success) {
+ regValue &= ~PHY_BCTL_LOOP_MASK;
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ } else {
+ /* First read the current status in control one register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, &regValue);
+ if (result == kStatus_Success) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG,
+ (regValue & ~PHY_CTL2_REMOTELOOP_MASK));
+ }
+ }
+ }
+ return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
new file mode 100644
index 000000000..5b93c5698
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY KSZ8081 driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phyksz8081 PHYKSZ8081
+ The current PHYKSZ8081 driver version is 2.0.0.
+
+ - 2.0.0
+ - Initial version.
+*/
+
+#ifndef _FSL_PHYKSZ8081_H_
+#define _FSL_PHYKSZ8081_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phyksz8081_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ * This function initialize PHY.
+ *
+ * @param handle PHY device handle.
+ * @param config Pointer to structure of phy_config_t.
+ * @retval kStatus_Success PHY initialization succeeds
+ * @retval kStatus_Fail PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param data The data written to the PHY register.
+ * @retval kStatus_Success PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param dataPtr The address to store the data read from the PHY register.
+ * @retval kStatus_Success PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle PHY device handle.
+ * @param status The auto-negotiation status of the PHY.
+ * - true the auto-negotiation is over.
+ * - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle PHY device handle.
+ * @param status The link up or down status of the PHY.
+ * - true the link is up.
+ * - false the link is down.
+ * @retval kStatus_Success PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle PHY device handle.
+ * @param speed The address of PHY link speed.
+ * @param duplex The link duplex of PHY.
+ * @retval kStatus_Success PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle PHY device handle.
+ * @param speed Specified PHY link speed.
+ * @param duplex Specified PHY link duplex.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle PHY device handle.
+ * @param mode The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed PHY speed for loopback mode.
+ * @param enable True to enable, false to disable.
+ * @retval kStatus_Success PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PHYKSZ8081_H_ */
diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
new file mode 100644
index 000000000..b7435c2d0
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phylan8720.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY LAN8720 vendor defined registers. */
+#define PHY_PHYSTS_REG 0x1FU // Phy status register
+#define PHY_MCSR_REG 0x11U // Mode Control/Status Register for loopback
+
+/*! @brief Defines the PHY LAN8720 ID number. */
+#define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1 */
+
+/*! @brief Defines the mask flag of operation mode in control registers */
+#define PHY_PHYSTS_MASK 0x001CU /*!< The PHY Status mask. */
+#define PHY_PHYSTS_DUPLEX_MASK 0x0010U /*!< The PHY full duplex mask. */
+#define PHY_PHYSTS_100M_MASK 0x000CU /*!< The PHY 100M mask. */
+#define PHY_PHYSTS_100M_FLAG 0x0008U /*!< The PHY 100M flag. */
+#define PHY_PHYSTS_LINK_MASK 0x0001U /*!< The PHY link up mask. */
+
+#define PHY_MCSR_REMOTELOOP_MASK 0x100U // !< The PHY remote loopback mask.
+#define PHY_MCSR_REMOTELOOP_MODE 0x100U // !< The PHY remote loopback mode.
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const phy_operations_t phylan8720_ops = {.phyInit = PHY_LAN8720_Init,
+ .phyWrite = PHY_LAN8720_Write,
+ .phyRead = PHY_LAN8720_Read,
+ .getAutoNegoStatus = PHY_LAN8720_GetAutoNegotiationStatus,
+ .getLinkStatus = PHY_LAN8720_GetLinkStatus,
+ .getLinkSpeedDuplex = PHY_LAN8720_GetLinkSpeedDuplex,
+ .setLinkSpeedDuplex = PHY_LAN8720_SetLinkSpeedDuplex,
+ .enableLoopback = PHY_LAN8720_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_LAN8720_Init(phy_handle_t *handle, const phy_config_t *config) {
+ uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+ status_t result = kStatus_Success;
+ uint32_t regValue = 0;
+
+ /* Init MDIO interface. */
+ MDIO_Init(handle->mdioHandle);
+
+ /* Assign phy address. */
+ handle->phyAddr = config->phyAddr;
+
+ /* Check PHY ID. */
+ do
+ {
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ counter--;
+ } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+ if (counter == 0U) {
+ return kStatus_Fail;
+ }
+
+ /* Reset PHY. */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+ if (result == kStatus_Success) {
+ if (config->autoNeg) {
+ /* Set the auto-negotiation then start it. */
+ result =
+ MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+ (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
+ PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
+ if (result == kStatus_Success) {
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ } else {
+ /* This PHY only supports 10/100M speed. */
+ assert(config->speed <= kPHY_Speed100M);
+
+ /* Disable isolate mode */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ regValue &= ~PHY_BCTL_ISOLATE_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+ result = PHY_LAN8720_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+ }
+ }
+ return result;
+}
+
+status_t PHY_LAN8720_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_LAN8720_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+ return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_LAN8720_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ *status = false;
+
+ /* Check auto negotiation complete. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+ if (result == kStatus_Success) {
+ if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+ *status = true;
+ }
+ }
+ return result;
+}
+
+status_t PHY_LAN8720_GetLinkStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ /* Read the basic status register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+ if (result == kStatus_Success) {
+ if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+ /* Link up. */
+ *status = true;
+ } else {
+ /* Link down. */
+ *status = false;
+ }
+ }
+ return result;
+}
+
+status_t PHY_LAN8720_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+ assert(!((speed == NULL) && (duplex == NULL)));
+
+ status_t result;
+ uint32_t regValue;
+ uint32_t flag;
+
+ /* Read the control register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
+ if (result == kStatus_Success) {
+ regValue &= PHY_PHYSTS_MASK;
+ if (speed != NULL) {
+ flag = regValue & PHY_PHYSTS_100M_MASK;
+ if (flag == PHY_PHYSTS_100M_FLAG) {
+ *speed = kPHY_Speed100M;
+ } else {
+ *speed = kPHY_Speed10M;
+ }
+ }
+
+ if (duplex != NULL) {
+ flag = regValue & PHY_PHYSTS_DUPLEX_MASK;
+ if (flag) {
+ *duplex = kPHY_FullDuplex;
+ } else {
+ *duplex = kPHY_HalfDuplex;
+ }
+ }
+ }
+ return result;
+}
+
+status_t PHY_LAN8720_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+ /* This PHY only supports 10/100M speed. */
+ assert(speed <= kPHY_Speed100M);
+
+ status_t result;
+ uint32_t regValue;
+
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result == kStatus_Success) {
+ /* Disable the auto-negotiation and set according to user-defined configuration. */
+ regValue &= ~PHY_BCTL_AUTONEG_MASK;
+ if (speed == kPHY_Speed100M) {
+ regValue |= PHY_BCTL_SPEED0_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_SPEED0_MASK;
+ }
+ if (duplex == kPHY_FullDuplex) {
+ regValue |= PHY_BCTL_DUPLEX_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_DUPLEX_MASK;
+ }
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ }
+ return result;
+}
+
+status_t PHY_LAN8720_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+ /* This PHY only supports local/remote loopback and 10/100M speed. */
+ assert(mode <= kPHY_RemoteLoop);
+ assert(speed <= kPHY_Speed100M);
+
+ status_t result = kStatus_Success;
+ uint32_t regValue;
+
+ /* Set the loop mode. */
+ if (enable) {
+ if (mode == kPHY_LocalLoop) {
+ if (speed == kPHY_Speed100M) {
+ regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ } else {
+ regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ }
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ } else {
+ /* Remote loopback only supports 100M full-duplex. */
+ assert(speed == kPHY_Speed100M);
+
+ regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ /* Set the remote loopback bit. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, &regValue);
+ if (result == kStatus_Success) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG,
+ (regValue & ~PHY_MCSR_REMOTELOOP_MASK) | PHY_MCSR_REMOTELOOP_MODE);
+ }
+ }
+ } else {
+ /* Disable the loop mode. */
+ if (mode != kPHY_LocalLoop) {
+ /* First read the current status in control one register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, &regValue);
+ if (result == kStatus_Success) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG,
+ (regValue & ~PHY_MCSR_REMOTELOOP_MASK));
+ }
+ }
+ /* First read the current status in control register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+ if (result == kStatus_Success) {
+ regValue &= ~PHY_BCTL_LOOP_MASK;
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ }
+
+ return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
new file mode 100644
index 000000000..2e8b4e363
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY KSZ8081 driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phylan8720 PHYLAN8720
+ The current PHYLAN8720 driver version is 2.0.0.
+
+ - 2.0.0
+ - Initial version.
+*/
+
+#ifndef _FSL_PHYLAN8720_H_
+#define _FSL_PHYLAN8720_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phylan8720_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ * This function initialize PHY.
+ *
+ * @param handle PHY device handle.
+ * @param config Pointer to structure of phy_config_t.
+ * @retval kStatus_Success PHY initialization succeeds
+ * @retval kStatus_Fail PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param data The data written to the PHY register.
+ * @retval kStatus_Success PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param dataPtr The address to store the data read from the PHY register.
+ * @retval kStatus_Success PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle PHY device handle.
+ * @param status The auto-negotiation status of the PHY.
+ * - true the auto-negotiation is over.
+ * - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle PHY device handle.
+ * @param status The link up or down status of the PHY.
+ * - true the link is up.
+ * - false the link is down.
+ * @retval kStatus_Success PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle PHY device handle.
+ * @param speed The address of PHY link speed.
+ * @param duplex The link duplex of PHY.
+ * @retval kStatus_Success PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle PHY device handle.
+ * @param speed Specified PHY link speed.
+ * @param duplex Specified PHY link duplex.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle PHY device handle.
+ * @param mode The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed PHY speed for loopback mode.
+ * @param enable True to enable, false to disable.
+ * @retval kStatus_Success PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_LAN8720_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PHYLAN8720_H_ */
diff --git a/ports/mimxrt/hal/phy/fsl_mdio.h b/ports/mimxrt/hal/phy/fsl_mdio.h
new file mode 100644
index 000000000..6bfee2a24
--- /dev/null
+++ b/ports/mimxrt/hal/phy/fsl_mdio.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_MDIO_H_
+#define _FSL_MDIO_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the timeout macro. */
+#if defined(MDIO_TIMEOUT_COUNT_NUMBER) && MDIO_TIMEOUT_COUNT_NUMBER
+#define MDIO_TIMEOUT_COUNT MDIO_TIMEOUT_COUNT_NUMBER
+#endif
+
+/*! @brief Defines the PHY status. */
+enum _mdio_status
+{
+ kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 0), /*!< ENET PHY SMI visit timeout. */
+};
+
+typedef struct _mdio_operations mdio_operations_t;
+
+/*! @brief MDIO resource. */
+typedef struct _mdio_resource
+{
+ void *base; /*!< ENET Ip register base. */
+ uint32_t csrClock_Hz; /*!< ENET CSR clock. */
+} mdio_resource_t;
+
+/*! @brief MDIO handle. */
+typedef struct _mdio_handle
+{
+ mdio_resource_t resource;
+ const mdio_operations_t *ops;
+} mdio_handle_t;
+
+/*! @brief Camera receiver operations. */
+struct _mdio_operations
+{
+ void (*mdioInit)(mdio_handle_t *handle); /*!< MDIO interface init. */
+ status_t (*mdioWrite)(mdio_handle_t *handle,
+ uint32_t phyAddr,
+ uint32_t devAddr,
+ uint32_t data); /*!< MDIO write data. */
+ status_t (*mdioRead)(mdio_handle_t *handle,
+ uint32_t phyAddr,
+ uint32_t devAddr,
+ uint32_t *dataPtr); /*!< MDIO read data. */
+ status_t (*mdioWriteExt)(mdio_handle_t *handle,
+ uint32_t phyAddr,
+ uint32_t devAddr,
+ uint32_t data); /*!< MDIO write data. */
+ status_t (*mdioReadExt)(mdio_handle_t *handle,
+ uint32_t phyAddr,
+ uint32_t devAddr,
+ uint32_t *dataPtr); /*!< MDIO read data. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+/*!
+ * @name MDIO Driver
+ * @{
+ */
+
+/*!
+ * @brief MDIO Write function. This function write data over the SMI to
+ * the specified MDIO register. This function is called by all MDIO interfaces.
+ *
+ * @param handle MDIO device handle.
+ * @retval kStatus_Success MDIO write success
+ * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out
+ */
+static inline void MDIO_Init(mdio_handle_t *handle) {
+ handle->ops->mdioInit(handle);
+}
+
+/*!
+ * @brief MDIO Write function. This function write data over the SMI to
+ * the specified MDIO register. This function is called by all MDIO interfaces.
+ *
+ * @param handle MDIO device handle.
+ * @param phyAddr MDIO PHY address handle.
+ * @param devAddr The PHY device register.
+ * @param data The data written to the MDIO register.
+ * @retval kStatus_Success MDIO write success
+ * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out
+ */
+static inline status_t MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) {
+ return handle->ops->mdioWrite(handle, phyAddr, devAddr, data);
+}
+
+/*!
+ * @brief MDIO Read function. This interface read data over the SMI from the
+ * specified MDIO register. This function is called by all MDIO interfaces.
+ *
+ * @param handle MDIO device handle.
+ * @param phyAddr MDIO PHY address handle.
+ * @param devAddr The PHY device register.
+ * @param dataPtr The address to store the data read from the MDIO register.
+ * @retval kStatus_Success MDIO read success
+ * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out
+ */
+static inline status_t MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) {
+ return handle->ops->mdioRead(handle, phyAddr, devAddr, dataPtr);
+}
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/ports/mimxrt/hal/phy/fsl_phy.h b/ports/mimxrt/hal/phy/fsl_phy.h
new file mode 100644
index 000000000..6a022d4ea
--- /dev/null
+++ b/ports/mimxrt/hal/phy/fsl_phy.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_PHY_H_
+#define _FSL_PHY_H_
+
+#include "fsl_mdio.h"
+
+/*! @note The following PHY registers are the IEEE802.3 standard definition, same register and bit field may
+ have different names in various PHYs, but the feature they represent should be same or very similar. */
+
+/*! @brief Defines the IEEE802.3 standard PHY registers. */
+#define PHY_BASICCONTROL_REG 0x00U /*!< The PHY basic control register. */
+#define PHY_BASICSTATUS_REG 0x01U /*!< The PHY basic status register. */
+#define PHY_ID1_REG 0x02U /*!< The PHY ID one register. */
+#define PHY_ID2_REG 0x03U /*!< The PHY ID two register. */
+#define PHY_AUTONEG_ADVERTISE_REG 0x04U /*!< The PHY auto-negotiate advertise register. */
+#define PHY_AUTONEG_LINKPARTNER_REG 0x05U /*!< The PHY auto negotiation link partner ability register. */
+#define PHY_AUTONEG_EXPANSION_REG 0x06U /*!< The PHY auto negotiation expansion register. */
+#define PHY_1000BASET_CONTROL_REG 0x09U /*!< The PHY 1000BASE-T control register. */
+#define PHY_MMD_ACCESS_CONTROL_REG 0x0DU /*!< The PHY MMD access control register. */
+#define PHY_MMD_ACCESS_DATA_REG 0x0EU /*!< The PHY MMD access data register. */
+
+/*! @brief Defines the mask flag in basic control register(Address 0x00). */
+#define PHY_BCTL_SPEED1_MASK 0x0040U /*!< The PHY speed bit mask(MSB).*/
+#define PHY_BCTL_ISOLATE_MASK 0x0400U /*!< The PHY isolate mask.*/
+#define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */
+#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */
+#define PHY_BCTL_AUTONEG_MASK 0x1000U /*!< The PHY auto negotiation bit mask. */
+#define PHY_BCTL_SPEED0_MASK 0x2000U /*!< The PHY speed bit mask(LSB). */
+#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */
+#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */
+
+/*! @brief Defines the mask flag in basic status register(Address 0x01). */
+#define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */
+#define PHY_BSTATUS_AUTONEGABLE_MASK 0x0008U /*!< The PHY auto-negotiation ability mask. */
+#define PHY_BSTATUS_SPEEDUPLX_MASK 0x001CU /*!< The PHY speed and duplex mask. */
+#define PHY_BSTATUS_AUTONEGCOMP_MASK 0x0020U /*!< The PHY auto-negotiation complete mask. */
+
+/*! @brief Defines the mask flag in PHY auto-negotiation advertise register(Address 0x04). */
+#define PHY_100BaseT4_ABILITY_MASK 0x200U /*!< The PHY have the T4 ability. */
+#define PHY_100BASETX_FULLDUPLEX_MASK 0x100U /*!< The PHY has the 100M full duplex ability.*/
+#define PHY_100BASETX_HALFDUPLEX_MASK 0x080U /*!< The PHY has the 100M full duplex ability.*/
+#define PHY_10BASETX_FULLDUPLEX_MASK 0x040U /*!< The PHY has the 10M full duplex ability.*/
+#define PHY_10BASETX_HALFDUPLEX_MASK 0x020U /*!< The PHY has the 10M full duplex ability.*/
+#define PHY_IEEE802_3_SELECTOR_MASK 0x001U /*!< The message type being sent by Auto-Nego.*/
+
+/*! @brief Defines the mask flag in the 1000BASE-T control register(Address 0x09). */
+#define PHY_1000BASET_FULLDUPLEX_MASK 0x200U /*!< The PHY has the 1000M full duplex ability.*/
+#define PHY_1000BASET_HALFDUPLEX_MASK 0x100U /*!< The PHY has the 1000M half duplex ability.*/
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+typedef struct _phy_handle phy_handle_t;
+/*! @brief Defines the PHY link speed. */
+typedef enum _phy_speed
+{
+ kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */
+ kPHY_Speed100M, /*!< ENET PHY 100M speed. */
+ kPHY_Speed1000M /*!< ENET PHY 1000M speed. */
+} phy_speed_t;
+
+/*! @brief Defines the PHY link duplex. */
+typedef enum _phy_duplex
+{
+ kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */
+ kPHY_FullDuplex /*!< ENET PHY full duplex. */
+} phy_duplex_t;
+
+/*! @brief Defines the PHY loopback mode. */
+typedef enum _phy_loop
+{
+ kPHY_LocalLoop = 0U, /*!< ENET PHY local/digital loopback. */
+ kPHY_RemoteLoop, /*!< ENET PHY remote loopback. */
+ kPHY_ExternalLoop, /*!< ENET PHY external loopback. */
+} phy_loop_t;
+
+/*! @brief Defines the PHY MMD data access mode. */
+typedef enum _phy_mmd_access_mode
+{
+ kPHY_MMDAccessNoPostIncrement = (1U << 14), /*!< ENET PHY MMD access data with no address post increment. */
+ kPHY_MMDAccessRdWrPostIncrement =
+ (2U << 14), /*!< ENET PHY MMD access data with Read/Write address post increment. */
+ kPHY_MMDAccessWrPostIncrement = (3U << 14), /*!< ENET PHY MMD access data with Write address post increment. */
+} phy_mmd_access_mode_t;
+
+/*! @brief Defines PHY configuration. */
+typedef struct _phy_config
+{
+ uint32_t phyAddr; /*!< PHY address. */
+ phy_speed_t speed; /*!< PHY speed configuration. */
+ phy_duplex_t duplex; /*!< PHY duplex configuration. */
+ bool autoNeg; /*!< PHY auto-negotiation, true: enable, false: disable. */
+ bool enableEEE; /*!< PHY Energy Efficient Ethernet. */
+} phy_config_t;
+
+/*! @brief PHY device operations. */
+typedef struct _phy_operations
+{
+ status_t (*phyInit)(phy_handle_t *handle, const phy_config_t *config);
+ status_t (*phyWrite)(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+ status_t (*phyRead)(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+ status_t (*getAutoNegoStatus)(phy_handle_t *handle, bool *status);
+ status_t (*getLinkStatus)(phy_handle_t *handle, bool *status);
+ status_t (*getLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+ status_t (*setLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+ status_t (*enableLoopback)(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+} phy_operations_t;
+
+/*! @brief PHY device handle. */
+
+struct _phy_handle
+{
+ uint32_t phyAddr; /*!< PHY address. */
+ mdio_handle_t *mdioHandle; /*!< The MDIO handle used by the phy device, it is specified by device. */
+ const phy_operations_t *ops; /*!< The device related operations. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ * This function initialize PHY.
+ *
+ * @param handle PHY device handle.
+ * @param config Pointer to structure of phy_config_t.
+ * @retval kStatus_Success PHY initialization succeeds
+ * @retval kStatus_Fail PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_Init(phy_handle_t *handle, const phy_config_t *config) {
+ return handle->ops->phyInit(handle, config);
+}
+/*!
+ * @brief PHY Write function. This function write data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param data The data written to the PHY register.
+ * @retval kStatus_Success PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+ return handle->ops->phyWrite(handle, phyReg, data);
+}
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param dataPtr The address to store the data read from the PHY register.
+ * @retval kStatus_Success PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+ return handle->ops->phyRead(handle, phyReg, dataPtr);
+}
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle PHY device handle.
+ * @param status The auto-negotiation status of the PHY.
+ * - true the auto-negotiation is over.
+ * - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+ return handle->ops->getAutoNegoStatus(handle, status);
+}
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle PHY device handle.
+ * @param status The link up or down status of the PHY.
+ * - true the link is up.
+ * - false the link is down.
+ * @retval kStatus_Success PHY get link status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_GetLinkStatus(phy_handle_t *handle, bool *status) {
+ return handle->ops->getLinkStatus(handle, status);
+}
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle PHY device handle.
+ * @param speed The address of PHY link speed.
+ * @param duplex The link duplex of PHY.
+ * @retval kStatus_Success PHY get link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+ return handle->ops->getLinkSpeedDuplex(handle, speed, duplex);
+}
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle PHY device handle.
+ * @param speed Specified PHY link speed.
+ * @param duplex Specified PHY link duplex.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+ return handle->ops->setLinkSpeedDuplex(handle, speed, duplex);
+}
+
+/*!
+ * @brief Enable PHY loopcback mode.
+ *
+ * @param handle PHY device handle.
+ * @param mode The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed PHY speed for loopback mode.
+ * @param enable True to enable, false to disable.
+ * @retval kStatus_Success PHY get link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+static inline status_t PHY_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+ return handle->ops->enableLoopback(handle, mode, speed, enable);
+}
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+#endif
diff --git a/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c
new file mode 100644
index 000000000..8e679cd98
--- /dev/null
+++ b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_enet_mdio.h"
+#include "fsl_enet.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+static void ENET_MDIO_Init(mdio_handle_t *handle);
+static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data);
+static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr);
+
+uint32_t ENET_GetInstance(ENET_Type *base);
+extern clock_ip_name_t s_enetClock[];
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+const mdio_operations_t enet_ops = {.mdioInit = ENET_MDIO_Init,
+ .mdioWrite = ENET_MDIO_Write,
+ .mdioRead = ENET_MDIO_Read,
+ .mdioWriteExt = NULL,
+ .mdioReadExt = NULL};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void ENET_MDIO_Init(mdio_handle_t *handle) {
+ mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
+ ENET_Type *base = (ENET_Type *)resource->base;
+ uint32_t instance = ENET_GetInstance(base);
+
+ #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Set SMI first. */
+ (void)CLOCK_EnableClock(s_enetClock[instance]);
+ #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ ENET_SetSMI(base, resource->csrClock_Hz, false);
+}
+
+static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) {
+ mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
+ ENET_Type *base = (ENET_Type *)resource->base;
+ status_t result = kStatus_Success;
+ #ifdef MDIO_TIMEOUT_COUNT
+ uint32_t counter;
+ #endif
+
+ /* Clear the SMI interrupt event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ /* Starts a SMI write command. */
+ ENET_StartSMIWrite(base, phyAddr, devAddr, kENET_MiiWriteValidFrame, data);
+
+ /* Wait for SMI complete. */
+ #ifdef MDIO_TIMEOUT_COUNT
+ for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--)
+ {
+ if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+ break;
+ }
+ }
+ /* Check for timeout. */
+ if (0U == counter) {
+ result = kStatus_PHY_SMIVisitTimeout;
+ }
+ #else
+ while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+ }
+ #endif
+
+ /* Clear SMI interrupt event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ return result;
+}
+
+static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) {
+ assert(dataPtr);
+
+ mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
+ ENET_Type *base = (ENET_Type *)resource->base;
+ #ifdef MDIO_TIMEOUT_COUNT
+ uint32_t counter;
+ #endif
+
+ /* Clear the SMI interrupt event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ /* Starts a SMI read command operation. */
+ ENET_StartSMIRead(base, phyAddr, devAddr, kENET_MiiReadValidFrame);
+
+ /* Wait for SMI complete. */
+ #ifdef MDIO_TIMEOUT_COUNT
+ for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--)
+ {
+ if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+ break;
+ }
+ }
+ /* Check for timeout. */
+ if (0U == counter) {
+ return kStatus_PHY_SMIVisitTimeout;
+ }
+ #else
+ while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+ }
+ #endif
+
+ /* Get data from SMI register. */
+ *dataPtr = ENET_ReadSMIData(base);
+
+ /* Clear SMI interrupt event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ return kStatus_Success;
+}
diff --git a/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h
new file mode 100644
index 000000000..500985d8f
--- /dev/null
+++ b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ENET_MDIO_H_
+#define _FSL_ENET_MDIO_H_
+
+#include "fsl_enet.h"
+#include "fsl_mdio.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief ENET MDIO operations structure. */
+extern const mdio_operations_t enet_ops;
+
+#endif
diff --git a/ports/mimxrt/lwip_inc/arch/cc.h b/ports/mimxrt/lwip_inc/arch/cc.h
new file mode 100644
index 000000000..c37e62b83
--- /dev/null
+++ b/ports/mimxrt/lwip_inc/arch/cc.h
@@ -0,0 +1,10 @@
+#ifndef MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H
+#define MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H
+
+#include <assert.h>
+#define LWIP_PLATFORM_DIAG(x)
+#define LWIP_PLATFORM_ASSERT(x) { assert(1); }
+
+#define LWIP_NO_CTYPE_H 1
+
+#endif // MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H
diff --git a/ports/mimxrt/lwip_inc/arch/sys_arch.h b/ports/mimxrt/lwip_inc/arch/sys_arch.h
new file mode 100644
index 000000000..8b1a39374
--- /dev/null
+++ b/ports/mimxrt/lwip_inc/arch/sys_arch.h
@@ -0,0 +1 @@
+// empty
diff --git a/ports/mimxrt/lwip_inc/lwipopts.h b/ports/mimxrt/lwip_inc/lwipopts.h
new file mode 100644
index 000000000..42dc9fc5d
--- /dev/null
+++ b/ports/mimxrt/lwip_inc/lwipopts.h
@@ -0,0 +1,59 @@
+#ifndef MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H
+#define MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H
+
+#include <stdint.h>
+
+// This protection is not needed, instead we execute all lwIP code at PendSV priority
+#define SYS_ARCH_DECL_PROTECT(lev) do { } while (0)
+#define SYS_ARCH_PROTECT(lev) do { } while (0)
+#define SYS_ARCH_UNPROTECT(lev) do { } while (0)
+
+#define NO_SYS 1
+#define SYS_LIGHTWEIGHT_PROT 1
+#define MEM_ALIGNMENT 4
+
+#define LWIP_CHKSUM_ALGORITHM 3
+// Chksum generaration by HW fails for ICMP
+// Maybe caused by LWIP inserting ffff instead of 0000
+// The checksum flags are set in eth.c
+#define LWIP_CHECKSUM_CTRL_PER_NETIF 0
+#define LWIP_CHECKSUM_ON_COPY 0
+
+#define LWIP_ARP 1
+#define LWIP_ETHERNET 1
+#define LWIP_RAW 1
+#define LWIP_NETCONN 0
+#define LWIP_SOCKET 0
+#define LWIP_STATS 0
+#define LWIP_NETIF_HOSTNAME 1
+#define LWIP_NETIF_EXT_STATUS_CALLBACK 1
+
+#define LWIP_IPV6 0
+#define LWIP_DHCP 1
+#define LWIP_DHCP_CHECK_LINK_UP 1
+#define DHCP_DOES_ARP_CHECK 0 // to speed DHCP up
+#define LWIP_DNS 1
+#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1
+#define LWIP_MDNS_RESPONDER 1
+#define LWIP_IGMP 1
+
+#define LWIP_NUM_NETIF_CLIENT_DATA LWIP_MDNS_RESPONDER
+#define MEMP_NUM_UDP_PCB (4 + LWIP_MDNS_RESPONDER)
+#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + LWIP_MDNS_RESPONDER)
+
+#define SO_REUSE 1
+#define TCP_LISTEN_BACKLOG 1
+
+extern uint32_t trng_random_u32(void);
+#define LWIP_RAND() trng_random_u32()
+
+// lwip takes 26700 bytes
+#define MEM_SIZE (8000)
+#define TCP_MSS (800)
+#define TCP_WND (8 * TCP_MSS)
+#define TCP_SND_BUF (8 * TCP_MSS)
+#define MEMP_NUM_TCP_SEG (32)
+
+typedef uint32_t sys_prot_t;
+
+#endif // MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index e81974afa..f921f50a0 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -36,8 +36,16 @@
#include "ticks.h"
#include "tusb.h"
#include "led.h"
+#include "pendsv.h"
#include "modmachine.h"
+#if MICROPY_PY_LWIP
+#include "lwip/init.h"
+#include "lwip/apps/mdns.h"
+#endif
+#include "systick.h"
+#include "extmod/modnetwork.h"
+
extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end;
void board_init(void);
@@ -47,10 +55,22 @@ int main(void) {
ticks_init();
tusb_init();
led_init();
+ pendsv_init();
mp_stack_set_top(&_estack);
mp_stack_set_limit(&_estack - &_sstack - 1024);
+ #if MICROPY_PY_LWIP
+ // lwIP doesn't allow to reinitialise itself by subsequent calls to this function
+ // because the system timeout list (next_timeout) is only ever reset by BSS clearing.
+ // So for now we only init the lwIP stack once on power-up.
+ lwip_init();
+ #if LWIP_MDNS_RESPONDER
+ mdns_resp_init();
+ #endif
+ systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper);
+ #endif
+
for (;;) {
gc_init(&_gc_heap_start, &_gc_heap_end);
mp_init();
@@ -58,6 +78,9 @@ int main(void) {
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
+ #if MICROPY_PY_NETWORK
+ mod_network_init();
+ #endif
// Initialise sub-systems.
readline_init0();
@@ -93,6 +116,9 @@ int main(void) {
soft_reset_exit:
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
machine_pin_irq_deinit();
+ #if MICROPY_PY_NETWORK
+ mod_network_deinit();
+ #endif
gc_sweep_all();
mp_deinit();
}
diff --git a/ports/mimxrt/mbedtls/mbedtls_config.h b/ports/mimxrt/mbedtls/mbedtls_config.h
new file mode 100644
index 000000000..1ab748d8e
--- /dev/null
+++ b/ports/mimxrt/mbedtls/mbedtls_config.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018-2019 Damien P. George
+ *
+ * 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_MBEDTLS_CONFIG_H
+#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H
+
+// Set mbedtls configuration
+#define MBEDTLS_PLATFORM_MEMORY
+#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+#define MBEDTLS_DEPRECATED_REMOVED
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+#define MBEDTLS_AES_ROM_TABLES
+#define MBEDTLS_CIPHER_MODE_CBC
+#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+#define MBEDTLS_ECP_DP_BP256R1_ENABLED
+#define MBEDTLS_ECP_DP_BP384R1_ENABLED
+#define MBEDTLS_ECP_DP_BP512R1_ENABLED
+#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
+#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_PKCS1_V15
+#define MBEDTLS_SHA256_SMALLER
+#define MBEDTLS_SSL_PROTO_TLS1
+#define MBEDTLS_SSL_PROTO_TLS1_1
+#define MBEDTLS_SSL_PROTO_TLS1_2
+#define MBEDTLS_SSL_SERVER_NAME_INDICATION
+
+// Use a smaller output buffer to reduce size of SSL context
+#define MBEDTLS_SSL_MAX_CONTENT_LEN (16384)
+#define MBEDTLS_SSL_IN_CONTENT_LEN (MBEDTLS_SSL_MAX_CONTENT_LEN)
+#define MBEDTLS_SSL_OUT_CONTENT_LEN (4096)
+
+// Enable mbedtls modules
+#define MBEDTLS_AES_C
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_CTR_DRBG_C
+// #define MBEDTLS_ECP_C
+#define MBEDTLS_ENTROPY_C
+#define MBEDTLS_ERROR_C
+#define MBEDTLS_MD_C
+#define MBEDTLS_MD5_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_PKCS5_C
+#define MBEDTLS_PK_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_PLATFORM_C
+#define MBEDTLS_RSA_C
+#define MBEDTLS_SHA1_C
+#define MBEDTLS_SHA256_C
+#define MBEDTLS_SHA512_C
+#define MBEDTLS_SSL_CLI_C
+#define MBEDTLS_SSL_SRV_C
+#define MBEDTLS_SSL_TLS_C
+#define MBEDTLS_X509_CRT_PARSE_C
+#define MBEDTLS_X509_USE_C
+
+// Memory allocation hooks
+#include <stdlib.h>
+#include <stdio.h>
+void *m_calloc_mbedtls(size_t nmemb, size_t size);
+void m_free_mbedtls(void *ptr);
+#define MBEDTLS_PLATFORM_STD_CALLOC m_calloc_mbedtls
+#define MBEDTLS_PLATFORM_STD_FREE m_free_mbedtls
+#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf
+
+#include "mbedtls/check_config.h"
+
+#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */
diff --git a/ports/mimxrt/mbedtls/mbedtls_port.c b/ports/mimxrt/mbedtls/mbedtls_port.c
new file mode 100644
index 000000000..eb11f5141
--- /dev/null
+++ b/ports/mimxrt/mbedtls/mbedtls_port.c
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * 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.
+ */
+
+#ifdef MICROPY_SSL_MBEDTLS
+
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "fsl_trng.h"
+#include "mbedtls_config.h"
+
+#define DEBUG (0)
+
+#if DEBUG
+static size_t count_links(uint32_t *nb) {
+ void **p = MP_STATE_PORT(mbedtls_memory);
+ size_t n = 0;
+ *nb = 0;
+ while (p != NULL) {
+ ++n;
+ *nb += gc_nbytes(p);
+ p = (void **)p[1];
+ }
+ return n;
+}
+#endif
+
+void *m_calloc_mbedtls(size_t nmemb, size_t size) {
+ void **ptr = m_malloc0(nmemb * size + 2 * sizeof(uintptr_t));
+ #if DEBUG
+ uint32_t nb;
+ size_t n = count_links(&nb);
+ printf("mbed_alloc(%u, %u) -> (%u;%u) %p\n", nmemb, size, n, (uint)nb, ptr);
+ #endif
+ if (MP_STATE_PORT(mbedtls_memory) != NULL) {
+ MP_STATE_PORT(mbedtls_memory)[0] = ptr;
+ }
+ ptr[0] = NULL;
+ ptr[1] = MP_STATE_PORT(mbedtls_memory);
+ MP_STATE_PORT(mbedtls_memory) = ptr;
+ return &ptr[2];
+}
+
+void m_free_mbedtls(void *ptr_in) {
+ void **ptr = &((void **)ptr_in)[-2];
+ #if DEBUG
+ uint32_t nb;
+ size_t n = count_links(&nb);
+ printf("mbed_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", ptr, ptr[0], ptr[1], gc_nbytes(ptr), n, (uint)nb);
+ #endif
+ if (ptr[1] != NULL) {
+ ((void **)ptr[1])[0] = ptr[0];
+ }
+ if (ptr[0] != NULL) {
+ ((void **)ptr[0])[1] = ptr[1];
+ } else {
+ MP_STATE_PORT(mbedtls_memory) = ptr[1];
+ }
+ m_free(ptr);
+}
+
+int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) {
+
+ // assumes that TRNG_Init was called during startup
+ *olen = len;
+ TRNG_GetRandomData(TRNG, output, len);
+
+ return 0;
+}
+
+#endif
diff --git a/ports/mimxrt/moduos.c b/ports/mimxrt/moduos.c
index ff0f0824c..b59a5f448 100644
--- a/ports/mimxrt/moduos.c
+++ b/ports/mimxrt/moduos.c
@@ -30,6 +30,8 @@
#include "py/objstr.h"
#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/misc.h"
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
#include "extmod/vfs_lfs.h"
@@ -96,6 +98,21 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
+#if MICROPY_PY_OS_DUPTERM
+STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) {
+ (void)obj_in;
+ for (;;) {
+ int c = mp_uos_dupterm_rx_chr();
+ if (c < 0) {
+ break;
+ }
+ ringbuf_put(&stdin_ringbuf, c);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify);
+#endif
+
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
@@ -118,6 +135,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
#if MICROPY_PY_OS_DUPTERM
{ MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) },
#endif
#if MICROPY_VFS
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 0fe6cd129..f1c38b1fa 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -44,7 +44,6 @@ uint32_t trng_random_u32(void);
#define MICROPY_EMIT_INLINE_THUMB (1)
// Compiler configuration
-#define MICROPY_COMP_CONST (0)
// Python internal features
#define MICROPY_READER_VFS (1)
@@ -118,6 +117,7 @@ uint32_t trng_random_u32(void);
#define MICROPY_PY_UBINASCII (1)
#define MICROPY_PY_UBINASCII_CRC32 (1)
#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_OS_DUPTERM (3)
#define MICROPY_PY_URANDOM (1)
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32())
@@ -139,12 +139,38 @@ uint32_t trng_random_u32(void);
#define MICROPY_FATFS_MAX_SS (4096)
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
+// If MICROPY_PY_LWIP is defined, add network support
+#if MICROPY_PY_LWIP
+
+#define MICROPY_PY_NETWORK (1)
+#define MICROPY_PY_USOCKET (1)
+#define MICROPY_PY_UWEBSOCKET (1)
+#define MICROPY_PY_WEBREPL (1)
+#define MICROPY_PY_UHASHLIB_SHA1 (1)
+#define MICROPY_PY_LWIP_SOCK_RAW (1)
+#define MICROPY_HW_ETH_MDC (1)
+
+// Prevent the "LWIP task" from running.
+#define MICROPY_PY_LWIP_ENTER MICROPY_PY_PENDSV_ENTER
+#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER
+#define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT
+
+#endif
+
+// For regular code that wants to prevent "background tasks" from running.
+// These background tasks (LWIP, Bluetooth) run in PENDSV context.
+// TODO: Check for the settings of the STM32 port in irq.h
+#define MICROPY_PY_PENDSV_ENTER uint32_t atomic_state = disable_irq();
+#define MICROPY_PY_PENDSV_REENTER atomic_state = disable_irq();
+#define MICROPY_PY_PENDSV_EXIT enable_irq(atomic_state);
+
// Use VfsLfs2's types for fileio/textio
#define mp_type_fileio mp_type_vfs_lfs2_fileio
#define mp_type_textio mp_type_vfs_lfs2_textio
// Use VFS's functions for import stat and builtin open
#define mp_import_stat mp_vfs_import_stat
+#define mp_builtin_open mp_vfs_open
#define mp_builtin_open_obj mp_vfs_open_obj
// Hooks to add builtins
@@ -170,6 +196,38 @@ extern const struct _mp_obj_module_t mp_module_mimxrt;
extern const struct _mp_obj_module_t mp_module_onewire;
extern const struct _mp_obj_module_t mp_module_uos;
extern const struct _mp_obj_module_t mp_module_utime;
+extern const struct _mp_obj_module_t mp_module_usocket;
+extern const struct _mp_obj_module_t mp_module_network;
+
+#if MICROPY_PY_NETWORK
+#define NETWORK_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) },
+#else
+#define NETWORK_BUILTIN_MODULE
+#endif
+
+#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP
+// usocket implementation provided by lwIP
+#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) },
+#elif MICROPY_PY_USOCKET
+// usocket implementation provided by skeleton wrapper
+#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) },
+#else
+// no usocket module
+#define SOCKET_BUILTIN_MODULE
+#endif
+
+#if MICROPY_SSL_MBEDTLS
+#define MICROPY_PORT_ROOT_POINTER_MBEDTLS void **mbedtls_memory;
+#else
+#define MICROPY_PORT_ROOT_POINTER_MBEDTLS
+#endif
+
+#if defined(MICROPY_HW_ETH_MDC)
+extern const struct _mp_obj_type_t network_lan_type;
+#define MICROPY_HW_NIC_ETH { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) },
+#else
+#define MICROPY_HW_NIC_ETH
+#endif
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \
@@ -177,6 +235,11 @@ extern const struct _mp_obj_module_t mp_module_utime;
{ MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \
{ MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \
{ MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \
+ SOCKET_BUILTIN_MODULE \
+ NETWORK_BUILTIN_MODULE \
+
+#define MICROPY_PORT_NETWORK_INTERFACES \
+ MICROPY_HW_NIC_ETH \
#define MICROPY_HW_PIT_NUM_CHANNELS 3
@@ -184,6 +247,10 @@ extern const struct _mp_obj_module_t mp_module_utime;
const char *readline_hist[8]; \
struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]; \
void *machine_pin_irq_objects[MICROPY_HW_NUM_PIN_IRQS]; \
+ /* list of registered NICs */ \
+ mp_obj_list_t mod_network_nic_list; \
+ /* root pointers for sub-systems */ \
+ MICROPY_PORT_ROOT_POINTER_MBEDTLS \
#define MP_STATE_PORT MP_STATE_VM
diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c
index ff7e988df..66498d7b2 100644
--- a/ports/mimxrt/mphalport.c
+++ b/ports/mimxrt/mphalport.c
@@ -29,14 +29,21 @@
#include "py/stream.h"
#include "py/mphal.h"
#include "shared/timeutils/timeutils.h"
+#include "extmod/misc.h"
#include "ticks.h"
#include "tusb.h"
#include "fsl_snvs_lp.h"
+#include "fsl_ocotp.h"
#include CPU_HEADER_H
+STATIC uint8_t stdin_ringbuf_array[260];
+ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0};
+
#if MICROPY_KBD_EXCEPTION
+int mp_interrupt_char = -1;
+
void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
(void)itf;
(void)wanted_char;
@@ -45,6 +52,7 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
}
void mp_hal_set_interrupt_char(int c) {
+ mp_interrupt_char = c;
tud_cdc_set_wanted_char(c);
}
@@ -52,6 +60,9 @@ void mp_hal_set_interrupt_char(int c) {
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
uintptr_t ret = 0;
+ if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
+ ret |= MP_STREAM_POLL_RD;
+ }
if (tud_cdc_connected() && tud_cdc_available()) {
ret |= MP_STREAM_POLL_RD;
}
@@ -64,6 +75,10 @@ int mp_hal_stdin_rx_chr(void) {
// if (USARTx->USART.INTFLAG.bit.RXC) {
// return USARTx->USART.DATA.bit.DATA;
// }
+ int c = ringbuf_get(&stdin_ringbuf);
+ if (c != -1) {
+ return c;
+ }
if (tud_cdc_connected() && tud_cdc_available()) {
uint8_t buf[1];
uint32_t count = tud_cdc_read(buf, sizeof(buf));
@@ -90,6 +105,7 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
i += n2;
}
}
+ mp_uos_dupterm_tx_strn(str, len);
// TODO
// while (len--) {
// while (!(USARTx->USART.INTFLAG.bit.DRE)) { }
@@ -103,3 +119,29 @@ uint64_t mp_hal_time_ns(void) {
uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second);
return s * 1000000000ULL;
}
+
+/*******************************************************************************/
+// MAC address
+
+// Generate a random locally administered MAC address (LAA)
+void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) {
+ // Take the MAC addr from the OTP's Configuration and Manufacturing Info
+ OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk));
+ buf[0] = 0x02; // Locally Administered MAC
+ *(uint32_t *)&buf[1] = OCOTP->CFG0 ^ (OCOTP->CFG0 >> 8);
+ *(uint16_t *)&buf[4] = (uint16_t)(OCOTP->CFG1 ^ (OCOTP->CFG1 >> 16));
+}
+
+// A board can override this if needed
+MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) {
+ mp_hal_generate_laa_mac(idx, buf);
+}
+
+void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest) {
+ static const char hexchr[16] = "0123456789ABCDEF";
+ uint8_t mac[6];
+ mp_hal_get_mac(idx, mac);
+ for (; chr_len; ++chr_off, --chr_len) {
+ *dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf];
+ }
+}
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index 3f0ae51bb..a98ae5ed7 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -29,10 +29,12 @@
#include <stdint.h>
#include "ticks.h"
+#include "py/ringbuf.h"
#include "pin.h"
#include "fsl_clock.h"
#define MP_HAL_PIN_FMT "%q"
+extern ringbuf_t stdin_ringbuf;
#define mp_hal_pin_obj_t const machine_pin_obj_t *
#define mp_hal_get_pin_obj(o) pin_find(o)
@@ -85,5 +87,15 @@ static inline mp_uint_t mp_hal_get_cpu_freq(void) {
return CLOCK_GetCpuClkFreq();
}
+enum {
+ MP_HAL_MAC_WLAN0 = 0,
+ MP_HAL_MAC_WLAN1,
+ MP_HAL_MAC_BDADDR,
+ MP_HAL_MAC_ETH0,
+};
+
+void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
+void mp_hal_get_mac(int idx, uint8_t buf[6]);
+void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
#endif // MICROPY_INCLUDED_MIMXRT_MPHALPORT_H
diff --git a/ports/mimxrt/mpnetworkport.c b/ports/mimxrt/mpnetworkport.c
new file mode 100644
index 000000000..2e6a49b90
--- /dev/null
+++ b/ports/mimxrt/mpnetworkport.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "shared/netutils/netutils.h"
+#include "systick.h"
+#include "pendsv.h"
+#include "extmod/modnetwork.h"
+
+#if MICROPY_PY_LWIP
+#include "lwip/netif.h"
+#include "lwip/timeouts.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+#include "lwip/apps/mdns.h"
+
+// Poll lwIP every 128ms
+#define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
+
+u32_t sys_now(void) {
+ return mp_hal_ticks_ms();
+}
+
+STATIC void pyb_lwip_poll(void) {
+ // Run the lwIP internal updates
+ sys_check_timeouts();
+}
+
+void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) {
+ if (LWIP_TICK(ticks_ms)) {
+ pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll);
+ }
+}
+
+#endif // MICROPY_PY_LWIP
diff --git a/ports/mimxrt/network_lan.c b/ports/mimxrt/network_lan.c
new file mode 100644
index 000000000..c0d6e4136
--- /dev/null
+++ b/ports/mimxrt/network_lan.c
@@ -0,0 +1,171 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * 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/runtime.h"
+#include "py/mphal.h"
+#include "extmod/modnetwork.h"
+#include "eth.h"
+
+#if defined(MICROPY_HW_ETH_MDC)
+
+#include "lwip/netif.h"
+
+typedef struct _network_lan_obj_t {
+ mp_obj_base_t base;
+ eth_t *eth;
+} network_lan_obj_t;
+
+STATIC const network_lan_obj_t network_lan_eth0 = { { &network_lan_type }, &eth_instance };
+
+STATIC void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ struct netif *netif = eth_netif(self->eth);
+ int status = eth_link_status(self->eth);
+ mp_printf(print, "<ETH %u %u.%u.%u.%u>",
+ status,
+ netif->ip_addr.addr & 0xff,
+ netif->ip_addr.addr >> 8 & 0xff,
+ netif->ip_addr.addr >> 16 & 0xff,
+ netif->ip_addr.addr >> 24
+ );
+}
+
+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) {
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ const network_lan_obj_t *self = &network_lan_eth0;
+ eth_init(self->eth, MP_HAL_MAC_ETH0);
+ // register with network module
+ mod_network_register_nic((mp_obj_t *)self);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t network_lan_active(size_t n_args, const mp_obj_t *args) {
+ network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (n_args == 1) {
+ return mp_obj_new_bool(eth_link_status(self->eth));
+ } else {
+ int ret;
+ if (mp_obj_is_true(args[1])) {
+ ret = eth_start(self->eth);
+ } else {
+ ret = eth_stop(self->eth);
+ }
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_active_obj, 1, 2, network_lan_active);
+
+STATIC mp_obj_t network_lan_isconnected(mp_obj_t self_in) {
+ network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(eth_link_status(self->eth) == 3);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_lan_isconnected_obj, network_lan_isconnected);
+
+STATIC mp_obj_t network_lan_ifconfig(size_t n_args, const mp_obj_t *args) {
+ network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ return mod_network_nic_ifconfig(eth_netif(self->eth), n_args - 1, args + 1);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_ifconfig_obj, 1, 2, network_lan_ifconfig);
+
+STATIC mp_obj_t network_lan_status(size_t n_args, const mp_obj_t *args) {
+ network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ (void)self;
+
+ if (n_args == 1) {
+ // No arguments: return link status
+ return MP_OBJ_NEW_SMALL_INT(eth_link_status(self->eth));
+ }
+
+ mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_status_obj, 1, 2, network_lan_status);
+
+STATIC mp_obj_t network_lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+ network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (kwargs->used == 0) {
+ // Get config value
+ if (n_args != 2) {
+ mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
+ }
+
+ switch (mp_obj_str_get_qstr(args[1])) {
+ case MP_QSTR_mac: {
+ return mp_obj_new_bytes(&eth_netif(self->eth)->hwaddr[0], 6);
+ }
+ default:
+ mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+ }
+ } else {
+ // Set config value(s)
+ if (n_args != 1) {
+ mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args"));
+ }
+
+ for (size_t i = 0; i < kwargs->alloc; ++i) {
+ if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
+ mp_map_elem_t *e = &kwargs->table[i];
+ switch (mp_obj_str_get_qstr(e->key)) {
+ case MP_QSTR_trace: {
+ eth_set_trace(self->eth, mp_obj_get_int(e->value));
+ break;
+ }
+ case MP_QSTR_low_power: {
+ eth_low_power_mode(self->eth, mp_obj_get_int(e->value));
+ break;
+ }
+ default:
+ mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+ }
+ }
+ }
+
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_lan_config_obj, 1, network_lan_config);
+
+STATIC const mp_rom_map_elem_t network_lan_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_lan_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_lan_isconnected_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_config), MP_ROM_PTR(&network_lan_config_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table);
+
+const mp_obj_type_t network_lan_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_LAN,
+ .print = network_lan_print,
+ .make_new = network_lan_make_new,
+ .locals_dict = (mp_obj_dict_t *)&network_lan_locals_dict,
+};
+
+#endif // defined(MICROPY_HW_ETH_MDC)
diff --git a/ports/mimxrt/pendsv.c b/ports/mimxrt/pendsv.c
new file mode 100644
index 000000000..7638b160d
--- /dev/null
+++ b/ports/mimxrt/pendsv.c
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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 <stdlib.h>
+
+#include "py/runtime.h"
+#include "shared/runtime/interrupt_char.h"
+#include "pendsv.h"
+#include "lib/nxp_driver/sdk/CMSIS/Include/core_cm7.h"
+
+#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003)
+#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
+
+#if defined(PENDSV_DISPATCH_NUM_SLOTS)
+uint32_t pendsv_dispatch_active;
+pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
+#endif
+
+void pendsv_init(void) {
+ #if defined(PENDSV_DISPATCH_NUM_SLOTS)
+ pendsv_dispatch_active = false;
+ #endif
+
+ // set PendSV interrupt at lowest priority
+ NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
+}
+
+#if defined(PENDSV_DISPATCH_NUM_SLOTS)
+void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
+ pendsv_dispatch_table[slot] = f;
+ pendsv_dispatch_active = true;
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+}
+
+void pendsv_dispatch_handler(void) {
+ for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
+ if (pendsv_dispatch_table[i] != NULL) {
+ pendsv_dispatch_t f = pendsv_dispatch_table[i];
+ pendsv_dispatch_table[i] = NULL;
+ f();
+ }
+ }
+}
+
+void PendSV_Handler(void) {
+ if (pendsv_dispatch_active) {
+ pendsv_dispatch_handler();
+ }
+}
+#endif
diff --git a/ports/mimxrt/pendsv.h b/ports/mimxrt/pendsv.h
new file mode 100644
index 000000000..64883c903
--- /dev/null
+++ b/ports/mimxrt/pendsv.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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_PENDSV_H
+#define MICROPY_INCLUDED_STM32_PENDSV_H
+
+enum {
+ PENDSV_DISPATCH_SOFT_TIMER, // For later & for having at least one entry
+ #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
+ PENDSV_DISPATCH_LWIP,
+ #endif
+ PENDSV_DISPATCH_MAX
+};
+
+#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX
+
+typedef void (*pendsv_dispatch_t)(void);
+
+void pendsv_init(void);
+void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);
+
+#endif // MICROPY_INCLUDED_STM32_PENDSV_H
diff --git a/ports/mimxrt/pin.c b/ports/mimxrt/pin.c
index 7a437661e..964fb537b 100644
--- a/ports/mimxrt/pin.c
+++ b/ports/mimxrt/pin.c
@@ -116,6 +116,21 @@ const machine_pin_af_obj_t *pin_find_af(const machine_pin_obj_t *pin, uint8_t fn
return NULL;
}
+const machine_pin_af_obj_t *pin_find_af_by_base(const machine_pin_obj_t *pin, void *base_ptr[], size_t base_size) {
+ const machine_pin_af_obj_t *af_obj = NULL;
+
+ for (int i = 0; i < pin->af_list_len; ++i) {
+ af_obj = &pin->af_list[i];
+ for (int j = 0; j < base_size; ++j) {
+ if (af_obj->instance == base_ptr[j]) {
+ return af_obj;
+ }
+ }
+ }
+
+ return NULL;
+}
+
const machine_pin_af_obj_t *pin_find_af_by_index(const machine_pin_obj_t *pin, mp_uint_t af_idx) {
// TODO: Implement pin_find_af_by_index function
return NULL;
diff --git a/ports/mimxrt/systick.c b/ports/mimxrt/systick.c
new file mode 100644
index 000000000..086bf1670
--- /dev/null
+++ b/ports/mimxrt/systick.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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/runtime.h"
+#include "py/mphal.h"
+#include "systick.h"
+
+volatile uint32_t systick_ms = 0;
+
+systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
+
+void SysTick_Handler(void) {
+ // Instead of calling HAL_IncTick we do the increment here of the counter.
+ // This is purely for efficiency, since SysTick is called 1000 times per
+ // second at the highest interrupt priority.
+ uint32_t uw_tick = systick_ms + 1;
+ systick_ms = uw_tick;
+
+ // Dispatch to any registered handlers in a cycle
+ systick_dispatch_t f = systick_dispatch_table[uw_tick & (SYSTICK_DISPATCH_NUM_SLOTS - 1)];
+ if (f != NULL) {
+ f(uw_tick);
+ }
+}
+
+bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
+ return systick_ms - start_tick >= delay_ms;
+}
+
+// waits until at least delay_ms milliseconds have passed from the sampling of
+// startTick. Handles overflow properly. Assumes stc was taken from
+// HAL_GetTick() some time before calling this function.
+void systick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
+ while (!systick_has_passed(start_tick, delay_ms)) {
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+}
diff --git a/ports/mimxrt/systick.h b/ports/mimxrt/systick.h
new file mode 100644
index 000000000..2638905cd
--- /dev/null
+++ b/ports/mimxrt/systick.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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_MIMXRT_SYSTICK_H
+#define MICROPY_INCLUDED_MIMXRT_SYSTICK_H
+
+// Works for x between 0 and 16 inclusive
+#define POW2_CEIL(x) ((((x) - 1) | ((x) - 1) >> 1 | ((x) - 1) >> 2 | ((x) - 1) >> 3) + 1)
+
+enum {
+ SYSTICK_DISPATCH_DMA = 0,
+ #if MICROPY_HW_ENABLE_STORAGE
+ SYSTICK_DISPATCH_STORAGE,
+ #endif
+ #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
+ SYSTICK_DISPATCH_LWIP,
+ #endif
+ SYSTICK_DISPATCH_MAX
+};
+
+#define SYSTICK_DISPATCH_NUM_SLOTS POW2_CEIL(SYSTICK_DISPATCH_MAX)
+
+typedef void (*systick_dispatch_t)(uint32_t);
+
+extern systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
+
+static inline void systick_enable_dispatch(size_t slot, systick_dispatch_t f) {
+ systick_dispatch_table[slot] = f;
+}
+
+static inline void systick_disable_dispatch(size_t slot) {
+ systick_dispatch_table[slot] = NULL;
+}
+
+void systick_wait_at_least(uint32_t stc, uint32_t delay_ms);
+bool systick_has_passed(uint32_t stc, uint32_t delay_ms);
+
+#endif // MICROPY_INCLUDED_MIMXRT_SYSTICK_H