From cb13624f6feab411c98421323d29e0ad7587f7b3 Mon Sep 17 00:00:00 2001 From: Vladimir Umek Date: Mon, 13 Jan 2025 15:42:32 +0100 Subject: [PATCH] Add Ethernet MAC and PHY driver --- .../cmsis/layers/sensor_sdk/Board.clayer.yml | 9 +- .../sensor_sdk/CMSIS/Driver/EMAC_MCXN947.c | 765 ++++++++++++++++++ .../sensor_sdk/CMSIS/Driver/EMAC_MCXN947.h | 57 ++ .../sensor_sdk/CMSIS/Driver/PHY_LAN8741A.c | 301 +++++++ .../sensor_sdk/CMSIS/Driver/PHY_LAN8741A.h | 109 +++ .../cmsis/layers/sensor_sdk/FRDM-MCXN947.h | 8 +- .../MCUXpressoConfig/FRDM-MCXN947.mex | 126 +++ .../MCUXpressoConfig/board/pin_mux.c | 248 ++++++ .../MCUXpressoConfig/board/pin_mux.h | 6 + 9 files changed, 1625 insertions(+), 4 deletions(-) create mode 100644 boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.c create mode 100644 boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.h create mode 100644 boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.c create mode 100644 boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.h diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/Board.clayer.yml b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/Board.clayer.yml index d33b795..3c48931 100644 --- a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/Board.clayer.yml +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/Board.clayer.yml @@ -15,7 +15,7 @@ layer: connections: - connect: FRDM-MCXN947 Board provides: -# - CMSIS_ETH + - CMSIS_ETH - CMSIS_VIO - ARDUINO_UNO_I2C - ARDUINO_UNO_SPI @@ -68,6 +68,8 @@ layer: components: - component: CMSIS:CORE + - component: CMSIS Driver:Ethernet MAC:Custom + - component: CMSIS Driver:Ethernet PHY:Custom - component: CMSIS Driver:I2C:lpi2c_cmsis - component: CMSIS Driver:SPI:lpspi_cmsis - component: CMSIS Driver:USART:lpuart_cmsis @@ -98,6 +100,7 @@ layer: - LPFLEXCOMM_INIT_NOT_USED_IN_DRIVER: 1 - component: Device:SDK Drivers:lpuart_adapter - component: Device:SDK Drivers:lpuart_edma + - component: Device:SDK Drivers:mcx_enet - component: Device:SDK Drivers:mcx_spc - component: Device:SDK Drivers:port - component: Device:SDK Drivers:reset @@ -119,6 +122,10 @@ layer: - file: ./main.h - file: ./FRDM-MCXN947.h - file: ./retarget_stdio.c + - file: ./CMSIS/Driver/EMAC_MCXN947.c + - file: ./CMSIS/Driver/EMAC_MCXN947.h + - file: ./CMSIS/Driver/PHY_LAN8741A.c + - file: ./CMSIS/Driver/PHY_LAN8741A.h # - group: Driver # files: diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.c b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.c new file mode 100644 index 0000000..4a9e72b --- /dev/null +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.c @@ -0,0 +1,765 @@ +/* -------------------------------------------------------------------------- + * Copyright (c) 2019-2024 Arm Limited (or its affiliates). + * All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * $Date: 5. December 2024 + * $Revision: V1.0 + * + * Driver: Driver_ETH_MAC0 + * Configured: pin/clock configuration via MCUXpresso Config Tools + * Project: CMSIS Ethernet Media Access (MAC) Driver for NXP MCXN947 + * -------------------------------------------------------------------------- + * Use the following configuration settings in the middleware component + * to connect to this driver. + * + * Configuration Setting Value + * --------------------- ----- + * Connect to hardware via Driver_ETH_MAC# = 0 + * -------------------------------------------------------------------------- */ + +/* History: + * Version 1.0 + * Initial release + */ + +#include "EMAC_MCXN947.h" +#include "fsl_enet.h" + +/* Receive/transmit checksum offload enabled by default */ +#ifndef EMAC_CHECKSUM_OFFLOAD + #define EMAC_CHECKSUM_OFFLOAD 1 +#endif + +#define ARM_ETH_MAC_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0) /* driver version */ + +/* EMAC Memory Buffer configuration */ +#define EMAC_BUF_SIZE 1536U /* ETH Receive/Transmit buffer size */ +#define EMAC_RX_BUF_CNT 4U /* 0x1800 for Rx (4*1536=6K) */ +#define EMAC_TX_BUF_CNT 4U /* 0x1800 for Tx (4*1536=6K) */ + +/* Driver Version */ +static const ARM_DRIVER_VERSION DriverVersion = { + ARM_ETH_MAC_API_VERSION, + ARM_ETH_MAC_DRV_VERSION +}; + +/* Driver Capabilities */ +static const ARM_ETH_MAC_CAPABILITIES DriverCapabilities = { + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_rx_ip4 */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_rx_ip6 */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_rx_udp */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_rx_tcp */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_rx_icmp */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_tx_ip4 */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_tx_ip6 */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_tx_udp */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_tx_tcp */ + (EMAC_CHECKSUM_OFFLOAD) ? 1U : 0U, /* checksum_offload_tx_icmp */ + (ENET_RMII) ? ARM_ETH_INTERFACE_RMII : + ARM_ETH_INTERFACE_MII, /* media_interface */ + 0U, /* mac_address */ + 1U, /* event_rx_frame */ + 1U, /* event_tx_frame */ + 1U, /* event_wakeup */ + 0U, /* precision_timer */ + 0U /* reserved */ +}; + +/* Frame buffers */ +static uint32_t Rx_Buf[EMAC_RX_BUF_CNT][EMAC_BUF_SIZE>>2]; +static uint32_t Tx_Buf[EMAC_TX_BUF_CNT][EMAC_BUF_SIZE>>2]; + +/* Frame buffer descriptors */ +static enet_rx_bd_struct_t Rx_Desc[EMAC_RX_BUF_CNT]; +static enet_tx_bd_struct_t Tx_Desc[EMAC_TX_BUF_CNT]; + +/* EMAC control structure */ +static EMAC_INFO emac = { 0 }; + +/** + \fn ARM_DRIVER_VERSION GetVersion (void) + \brief Get driver version. + \return \ref ARM_DRIVER_VERSION +*/ +static ARM_DRIVER_VERSION GetVersion (void) { + return DriverVersion; +} + +/** + \fn ARM_ETH_MAC_CAPABILITIES GetCapabilities (void) + \brief Get driver capabilities. + \return \ref ARM_ETH_MAC_CAPABILITIES +*/ +static ARM_ETH_MAC_CAPABILITIES GetCapabilities (void) { + return DriverCapabilities; +} + +/** + \fn int32_t Initialize (ARM_ETH_MAC_SignalEvent_t cb_event) + \brief Initialize Ethernet MAC Device. + \param[in] cb_event Pointer to \ref ARM_ETH_MAC_SignalEvent + \return \ref execution_status +*/ +static int32_t Initialize (ARM_ETH_MAC_SignalEvent_t cb_event) { + + if (emac.flags & EMAC_FLAG_INIT) { + return ARM_DRIVER_OK; + } + + /* Clear control structure */ + memset (&emac, 0, sizeof (EMAC_INFO)); + + /* Register driver callback function */ + emac.cb_event = cb_event; + + emac.flags = EMAC_FLAG_INIT; + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t Uninitialize (void) + \brief De-initialize Ethernet MAC Device. + \return \ref execution_status +*/ +static int32_t Uninitialize (void) { + + emac.flags = 0U; + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t PowerControl (ARM_POWER_STATE state) + \brief Control Ethernet MAC Device Power. + \param[in] state Power state + \return \ref execution_status +*/ +static int32_t PowerControl (ARM_POWER_STATE state) { + uint32_t rx_buffer[EMAC_RX_BUF_CNT]; + enet_buffer_config_t buf_cfg; + enet_config_t cfg; + int32_t i, retv; + + switch (state) { + case ARM_POWER_OFF: + if (!(emac.flags & EMAC_FLAG_POWER)) { + break; + } + + /* Disable ENET module */ + ENET_Deinit (ENET); + + /* Disable ENET interrupts in NVIC */ + NVIC_DisableIRQ (ETHERNET_IRQn); + + emac.flags = EMAC_FLAG_INIT; + break; + + case ARM_POWER_LOW: + return ARM_DRIVER_ERROR_UNSUPPORTED; + + case ARM_POWER_FULL: + if (!(emac.flags & EMAC_FLAG_INIT)) { + return ARM_DRIVER_ERROR; + } + if (emac.flags & EMAC_FLAG_POWER) { + break; + } + + /* Use external reference clock */ + CLOCK_AttachClk (kNONE_to_ENETRMII); + CLOCK_EnableClock (kCLOCK_Enet); + + /* Setup ENET configuration */ + ENET_GetDefaultConfig (&cfg); +#if (EMAC_CHECKSUM_OFFLOAD) + cfg.specialControl = kENET_RxChecksumOffloadEnable | kENET_StoreAndForward; +#endif + cfg.miiMode = (ENET_RMII) ? kENET_RmiiMode : kENET_MiiMode; + cfg.interrupt = kENET_DmaTx | kENET_DmaRx; + + /* Initialize ENET */ + ENET_Init (ENET, &cfg, NULL, 50000000U); + + /* Setup ENET-DMA descriptors */ + buf_cfg.rxRingLen = EMAC_RX_BUF_CNT; + buf_cfg.txRingLen = EMAC_TX_BUF_CNT; + buf_cfg.txDescStartAddrAlign = &Tx_Desc[0]; + buf_cfg.txDescTailAddrAlign = &Tx_Desc[0]; + buf_cfg.txDirtyStartAddr = NULL; + buf_cfg.rxDescStartAddrAlign = &Rx_Desc[0]; + buf_cfg.rxDescTailAddrAlign = &Rx_Desc[EMAC_RX_BUF_CNT]; + buf_cfg.rxBufferStartAddr = &rx_buffer[0]; + buf_cfg.rxBuffSizeAlign = EMAC_BUF_SIZE; + + /* Get Rx buffer addresses */ + for (i = 0; i < EMAC_RX_BUF_CNT; i++) { + rx_buffer[i] = (uint32_t)&Rx_Buf[i]; + } + + /* Initialize ENET-DMA descriptors */ + retv = ENET_DescriptorInit (ENET, &cfg, &buf_cfg); + + /* Initialize MDIO management interface */ + ENET_SetSMI (ENET, CLOCK_GetCoreSysClkFreq()); + + /* Enable ENET peripheral interrupts in NVIC */ + NVIC_EnableIRQ (ETHERNET_IRQn); + + emac.flags |= EMAC_FLAG_POWER; + + if (retv != kStatus_Success) { + return ARM_DRIVER_ERROR; + } + break; + + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t GetMacAddress (ARM_ETH_MAC_ADDR *ptr_addr) + \brief Get Ethernet MAC Address. + \param[in] ptr_addr Pointer to address + \return \ref execution_status +*/ +static int32_t GetMacAddress (ARM_ETH_MAC_ADDR *ptr_addr) { + uint32_t val; + + if (ptr_addr == NULL) { + return ARM_DRIVER_ERROR_PARAMETER; + } + + // ENET_GetMacAddr (ENET, (uint8_t *)ptr_addr); + + val = ENET->MAC_ADDRESS0_HIGH; + ptr_addr->b[5] = (uint8_t)(val >> 8); + ptr_addr->b[4] = (uint8_t)(val); + val = ENET->MAC_ADDRESS0_LOW; + ptr_addr->b[3] = (uint8_t)(val >> 24); + ptr_addr->b[2] = (uint8_t)(val >> 16); + ptr_addr->b[1] = (uint8_t)(val >> 8); + ptr_addr->b[0] = (uint8_t)(val); + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t SetMacAddress (const ARM_ETH_MAC_ADDR *ptr_addr) + \brief Set Ethernet MAC Address. + \param[in] ptr_addr Pointer to address + \return \ref execution_status +*/ +static int32_t SetMacAddress (const ARM_ETH_MAC_ADDR *ptr_addr) { + + if (ptr_addr == NULL) { + return ARM_DRIVER_ERROR_PARAMETER; + } + + if (!(emac.flags & EMAC_FLAG_POWER)) { + return ARM_DRIVER_ERROR; + } + + ENET_SetMacAddr (ENET, (uint8_t *)ptr_addr); + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t SetAddressFilter (const ARM_ETH_MAC_ADDR *ptr_addr, + uint32_t num_addr) + \brief Configure Address Filter. + \param[in] ptr_addr Pointer to addresses + \param[in] num_addr Number of addresses to configure + \return \ref execution_status +*/ +static int32_t SetAddressFilter (const ARM_ETH_MAC_ADDR *ptr_addr, uint32_t num_addr) { + (void)ptr_addr; + (void)num_addr; + + /* Not supported by ENET module */ + return ARM_DRIVER_ERROR_UNSUPPORTED; +} + +/** + \fn int32_t SendFrame (const uint8_t *frame, uint32_t len, uint32_t flags) + \brief Send Ethernet frame. + \param[in] frame Pointer to frame buffer with data to send + \param[in] len Frame buffer length in bytes + \param[in] flags Frame transmit flags (see ARM_ETH_MAC_TX_FRAME_...) + \return \ref execution_status +*/ +static int32_t SendFrame (const uint8_t *frame, uint32_t len, uint32_t flags) { + + if ((frame == NULL) || (len == 0U)) { + return ARM_DRIVER_ERROR_PARAMETER; + } + + if (!(emac.flags & EMAC_FLAG_POWER)) { + return ARM_DRIVER_ERROR; + } + + if (emac.tx_len == 0U) { + /* Start of a new transmit frame */ + if (ENET_IsTxDescriptorDmaOwn (&Tx_Desc[emac.tx_index])) { + /* Transmitter is busy, wait */ + return ARM_DRIVER_ERROR_BUSY; + } + } + + /* Copy data fragments to EMAC-DMA buffer */ + memcpy ((uint8_t *)&Tx_Buf[emac.tx_index] + emac.tx_len, frame, len); + emac.tx_len += len; + + if (flags & ARM_ETH_MAC_TX_FRAME_FRAGMENT) { + /* More data to come */ + return ARM_DRIVER_OK; + } + + /* Frame is now ready, pass it on to DMA */ + ENET_SetupTxDescriptor (&Tx_Desc[emac.tx_index], Tx_Buf[emac.tx_index], emac.tx_len, NULL, 0, + emac.tx_len, true, false, kENET_FirstLastFlag, 0); +#if (EMAC_CHECKSUM_OFFLOAD) + Tx_Desc[emac.tx_index].tdes3 |= ENET_TXDESCRIP_RD_CIC(kENET_TxOffloadAll); +#endif + /* Update the transmit tail address */ + ENET_UpdateTxDescriptorTail (ENET, 0, (uint32_t)&Tx_Desc[++emac.tx_index]); + + if (emac.tx_index >= EMAC_TX_BUF_CNT) { + emac.tx_index = 0U; + } + emac.tx_len = 0U; + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t ReadFrame (uint8_t *frame, uint32_t len) + \brief Read data of received Ethernet frame. + \param[in] frame Pointer to frame buffer for data to read into + \param[in] len Frame buffer length in bytes + \return number of data bytes read or execution status + - value >= 0: number of data bytes read + - value < 0: error occurred, value is execution status as defined with \ref execution_status +*/ +static int32_t ReadFrame (uint8_t *frame, uint32_t len) { + + if ((frame == NULL) && (len != 0U)) { + /* Invalid parameters */ + return ARM_DRIVER_ERROR_PARAMETER; + } + + if (!(emac.flags & EMAC_FLAG_POWER)) { + return ARM_DRIVER_ERROR; + } + + memcpy (frame, Rx_Buf[emac.rx_index], len); + + /* Return this block back to ENET-DMA */ + ENET_UpdateRxDescriptor (&Rx_Desc[emac.rx_index], Rx_Buf[emac.rx_index], NULL, true, false); + + /* Resume DMA if receive suspended */ + if (ENET_GetDmaInterruptStatus (ENET, 0) & kENET_DmaRxBuffUnavail) { + ENET_UpdateRxDescriptorTail (ENET, 0, (uint32_t)&Rx_Desc[EMAC_RX_BUF_CNT]); + } + + if (++emac.rx_index >= EMAC_RX_BUF_CNT) { + emac.rx_index = 0U; + } + + return (int32_t)len; +} + +/** + \fn uint32_t GetRxFrameSize (void) + \brief Get size of received Ethernet frame. + \return number of bytes in received frame +*/ +static uint32_t GetRxFrameSize (void) { + uint32_t stat; + + if (!(emac.flags & EMAC_FLAG_POWER)) { + return ARM_DRIVER_ERROR; + } + + stat = ENET_GetRxDescriptor (&Rx_Desc[emac.rx_index]); + if (stat & ENET_RXDESCRIP_RD_OWN_MASK) { + /* Owned by DMA */ + return 0U; + } + + if (!(stat & ENET_RXDESCRIP_WR_FD_MASK) || + !(stat & ENET_RXDESCRIP_WR_LD_MASK) || + (stat & ENET_RXDESCRIP_WR_ERRSUM_MASK)) { + /* Error, this block is invalid */ + return 0xFFFFFFFFU; + } + + return (stat & ENET_RXDESCRIP_WR_PACKETLEN_MASK) - ENET_FCS_LEN; +} + +/** + \fn int32_t GetRxFrameTime (ARM_ETH_MAC_TIME *time) + \brief Get time of received Ethernet frame. + \param[in] time Pointer to time structure for data to read into + \return \ref execution_status +*/ +static int32_t GetRxFrameTime (ARM_ETH_MAC_TIME *time) { + (void)time; + + /* Not implemented */ + return ARM_DRIVER_ERROR_UNSUPPORTED; +} + +/** + \fn int32_t GetTxFrameTime (ARM_ETH_MAC_TIME *time) + \brief Get time of transmitted Ethernet frame. + \param[in] time Pointer to time structure for data to read into + \return \ref execution_status +*/ +static int32_t GetTxFrameTime (ARM_ETH_MAC_TIME *time) { + (void)time; + + /* Not implemented */ + return ARM_DRIVER_ERROR_UNSUPPORTED; +} + +/** + \fn int32_t Control (uint32_t control, uint32_t arg) + \brief Control Ethernet Interface. + \param[in] control operation + \param[in] arg argument of operation (optional) + \return \ref execution_status +*/ +static int32_t Control (uint32_t control, uint32_t arg) { + enet_vlan_ctrl_t vlan_ctrl = { 0 }; + uint32_t mac_filter, mac_config; + + if (!(emac.flags & EMAC_FLAG_POWER)) { + return ARM_DRIVER_ERROR; + } + + switch (control) { + case ARM_ETH_MAC_CONFIGURE: + mac_config = ENET->MAC_CONFIGURATION; + /* Configure 100MBit/10MBit mode */ + switch (arg & ARM_ETH_MAC_SPEED_Msk) { + case ARM_ETH_MAC_SPEED_10M: + mac_config &= ~ENET_MAC_CONFIGURATION_FES_MASK; + break; + case ARM_ETH_SPEED_100M: + mac_config |= ENET_MAC_CONFIGURATION_FES_MASK; + break; + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + /* Configure Half/Full duplex mode */ + switch (arg & ARM_ETH_MAC_DUPLEX_Msk) { + case ARM_ETH_MAC_DUPLEX_HALF: + mac_config &= ~ENET_MAC_CONFIGURATION_DM_MASK; + break; + case ARM_ETH_MAC_DUPLEX_FULL: + mac_config |= ENET_MAC_CONFIGURATION_DM_MASK; + break; + } + + /* Configure loopback mode */ + if (arg & ARM_ETH_MAC_LOOPBACK) { + mac_config |= ENET_MAC_CONFIGURATION_LM_MASK; + } + else { + mac_config &= ~ENET_MAC_CONFIGURATION_LM_MASK; + } + ENET->MAC_CONFIGURATION = mac_config; + +#if (EMAC_CHECKSUM_OFFLOAD) + /* Enable rx checksum verification */ + if (arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_RX) { + ENET->MTL_QUEUE[0].MTL_RXQX_OP_MODE |= ENET_MTL_QUEUE_MTL_RXQX_OP_MODE_RSF_MASK; + ENET->MAC_CONFIGURATION |= ENET_MAC_CONFIGURATION_IPC_MASK; + } + else { + ENET->MTL_QUEUE[0].MTL_RXQX_OP_MODE &= ~ENET_MTL_QUEUE_MTL_RXQX_OP_MODE_RSF_MASK; + ENET->MAC_CONFIGURATION &= ~ENET_MAC_CONFIGURATION_IPC_MASK; + } + + /* Enable tx checksum generation */ + if (arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_TX) { + ENET->MTL_QUEUE[0].MTL_TXQX_OP_MODE |= ENET_MTL_QUEUE_MTL_TXQX_OP_MODE_TSF_MASK; + } + else { + ENET->MTL_QUEUE[0].MTL_TXQX_OP_MODE &= ~ENET_MTL_QUEUE_MTL_TXQX_OP_MODE_TSF_MASK; + } +#else + if ((arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_RX) || + (arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_TX)) { + /* Checksum offload is disabled in the driver */ + return ARM_DRIVER_ERROR; + } +#endif + + /* Keep VLAN tag filter setting */ + mac_filter = ENET->MAC_PACKET_FILTER & ENET_MAC_PACKET_FILTER_VTFE_MASK; + + /* Enable broadcast frame receive */ + if (!(arg & ARM_ETH_MAC_ADDRESS_BROADCAST)) { + mac_filter |= ENET_MAC_PACKET_FILTER_DBF_MASK; + } + + /* Enable all multicast frame receive */ + if (arg & ARM_ETH_MAC_ADDRESS_MULTICAST) { + mac_filter |= ENET_MAC_PACKET_FILTER_PM_MASK; + } + + /* Enable promiscuous mode (no filtering) */ + if (arg & ARM_ETH_MAC_ADDRESS_ALL) { + mac_filter |= ENET_MAC_PACKET_FILTER_PR_MASK; + } + + ENET->MAC_PACKET_FILTER = mac_filter; + break; + + case ARM_ETH_MAC_CONTROL_TX: + /* Enable/disable MAC transmitter */ + if (arg != 0U) { + ENET->DMA_CH[0].DMA_CHX_TX_CTRL |= ENET_DMA_CH_DMA_CHX_TX_CTRL_ST_MASK; + ENET->MAC_CONFIGURATION |= ENET_MAC_CONFIGURATION_TE_MASK; + } + else { + ENET->MAC_CONFIGURATION &= ~ENET_MAC_CONFIGURATION_TE_MASK; + ENET->DMA_CH[0].DMA_CHX_TX_CTRL &= ~ENET_DMA_CH_DMA_CHX_TX_CTRL_ST_MASK; + } + break; + + case ARM_ETH_MAC_CONTROL_RX: + /* Enable/disable MAC receiver */ + if (arg != 0U) { + ENET->DMA_CH[0].DMA_CHX_RX_CTRL |= ENET_DMA_CH_DMA_CHX_RX_CTRL_SR_MASK; + ENET->MAC_CONFIGURATION |= ENET_MAC_CONFIGURATION_RE_MASK; + } + else { + ENET->MAC_CONFIGURATION &= ~ENET_MAC_CONFIGURATION_RE_MASK; + ENET->DMA_CH[0].DMA_CHX_RX_CTRL &= ~ENET_DMA_CH_DMA_CHX_RX_CTRL_SR_MASK; + } + break; + + case ARM_ETH_MAC_FLUSH: + /* Flush Tx and Rx buffers */ + if (arg & ARM_ETH_MAC_FLUSH_RX) { + uint32_t dma_rx_ctrl = ENET->DMA_CH[0].DMA_CHX_RX_CTRL; + ENET->DMA_CH[0].DMA_CHX_RX_CTRL &= ~ENET_DMA_CH_DMA_CHX_RX_CTRL_SR_MASK; + ENET->DMA_CH[0].DMA_CHX_RX_CTRL |= ENET_DMA_CH_DMA_CHX_RX_CTRL_RPF_MASK; + ENET->DMA_CH[0].DMA_CHX_RX_CTRL = dma_rx_ctrl; + } + if (arg & ARM_ETH_MAC_FLUSH_TX) { + + } + break; + + case ARM_ETH_MAC_SLEEP: + /* Enable/disable Sleep mode */ + if (arg != 0U) { + /* Enable Power Management interrupts */ + ENET_EnableInterrupts(ENET, kENET_MacPmt); + NVIC_EnableIRQ (ETHERNET_PMT_IRQn); + /* Enter Power-down, Magic packet enable */ + ENET_EnterPowerDown (ENET, NULL); + } + else { + /* Disable Power Management interrupts */ + ENET_DisableInterrupts(ENET, kENET_MacPmt); + NVIC_DisableIRQ (ETHERNET_PMT_IRQn); + ENET->MAC_PMT_CONTROL_STATUS = 0x00000000U; + } + break; + + case ARM_ETH_MAC_VLAN_FILTER: + /* Configure VLAN filter */ + vlan_ctrl.rxVlanTag.vid = arg & 0xFFFF; + if (arg & ARM_ETH_MAC_VLAN_FILTER_ID_ONLY) { + vlan_ctrl.vidComparison = true; + } + if (arg != 0U) { + vlan_ctrl.disableVlanTypeCheck = true; + vlan_ctrl.outerTagInRxStatus = true; + } + ENET_SetVlanCtrl(ENET, &vlan_ctrl); + if (arg != 0U) { + ENET->MAC_PACKET_FILTER |= ENET_MAC_PACKET_FILTER_VTFE_MASK; + } + else { + ENET->MAC_PACKET_FILTER &= ~ENET_MAC_PACKET_FILTER_VTFE_MASK; + } + break; + + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t ControlTimer (uint32_t control, ARM_ETH_MAC_TIME *time) + \brief Control Precision Timer. + \param[in] control operation + \param[in] time Pointer to time structure + \return \ref execution_status +*/ +static int32_t ControlTimer (uint32_t control, ARM_ETH_MAC_TIME *time) { + (void)control; + (void)time; + + /* Not implemented */ + return ARM_DRIVER_ERROR_UNSUPPORTED; +} + +/** + \fn int32_t PHY_Read (uint8_t phy_addr, uint8_t reg_addr, uint16_t *data) + \brief Read Ethernet PHY Register through Management Interface. + \param[in] phy_addr 5-bit device address + \param[in] reg_addr 5-bit register address + \param[out] data Pointer where the result is written to + \return \ref execution_status +*/ +static int32_t PHY_Read (uint8_t phy_addr, uint8_t reg_addr, uint16_t *data) { + uint32_t loop; + + if (data == NULL) { + return ARM_DRIVER_ERROR_PARAMETER; + } + if (!(emac.flags & EMAC_FLAG_POWER)) { + return ARM_DRIVER_ERROR; + } + + ENET_StartSMIRead (ENET, phy_addr, reg_addr); + + /* Wait until operation completed */ + loop = SystemCoreClock >> 12; + while (ENET_IsSMIBusy (ENET)) { + loop--; + if (loop == 0) { + /* Loop counter timeout */ + return ARM_DRIVER_ERROR_TIMEOUT; + } + } + *data = (uint16_t)ENET_ReadSMIData (ENET); + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t PHY_Write (uint8_t phy_addr, uint8_t reg_addr, uint16_t data) + \brief Write Ethernet PHY Register through Management Interface. + \param[in] phy_addr 5-bit device address + \param[in] reg_addr 5-bit register address + \param[in] data 16-bit data to write + \return \ref execution_status +*/ +static int32_t PHY_Write (uint8_t phy_addr, uint8_t reg_addr, uint16_t data) { + uint32_t loop; + + if (!(emac.flags & EMAC_FLAG_POWER)) { + return ARM_DRIVER_ERROR; + } + + ENET_StartSMIWrite (ENET, phy_addr, reg_addr, data); + + /* Wait until operation completed */ + loop = SystemCoreClock >> 12; + while (ENET_IsSMIBusy (ENET)) { + loop--; + if (loop == 0) { + /* Loop counter timeout */ + return ARM_DRIVER_ERROR_TIMEOUT; + } + } + return ARM_DRIVER_OK; +} + +/** + \fn void ETHERNET_IRQHandler (void) + \brief Ethernet Interrupt handler. +*/ +void ETHERNET_IRQHandler (void) { + uint32_t stat, event = 0U; + + stat = ENET_GetDmaInterruptStatus(ENET, 0) & ~kENET_DmaRxBuffUnavail; + if (stat & kENET_DmaTx) { + /* Transmit interrupt */ + event |= ARM_ETH_MAC_EVENT_TX_FRAME; + } + if (stat & kENET_DmaRx) { + /* Receive interrupt */ + event |= ARM_ETH_MAC_EVENT_RX_FRAME; + } + /* Callback event notification */ + if (event && emac.cb_event) { + emac.cb_event (event); + } + /* Clear the interrupt */ + ENET_ClearDmaInterruptStatus(ENET, 0, stat); + SDK_ISR_EXIT_BARRIER; +} + +/** + \fn void ETHERNET_PMT_IRQHandler (void) + \brief Ethernet power management Interrupt handler. +*/ +void ETHERNET_PMT_IRQHandler (void) { + uint32_t stat, event = 0U; + + stat = ENET->MAC_PMT_CONTROL_STATUS; + if (stat & ENET_MAC_PMT_CONTROL_STATUS_MGKPRCVD_MASK) { + /* Magic packet received */ + event |= ARM_ETH_MAC_EVENT_WAKEUP; + } + /* Callback event notification */ + if (event && emac.cb_event) { + emac.cb_event (event); + } + /* Clear the interrupt */ + ENET_ClearMacInterruptStatus(ENET, kENET_MacPmt); + SDK_ISR_EXIT_BARRIER; +} + +/* MAC Driver Control Block */ +ARM_DRIVER_ETH_MAC Driver_ETH_MAC0 = { + GetVersion, + GetCapabilities, + Initialize, + Uninitialize, + PowerControl, + GetMacAddress, + SetMacAddress, + SetAddressFilter, + SendFrame, + ReadFrame, + GetRxFrameSize, + GetRxFrameTime, + GetTxFrameTime, + ControlTimer, + Control, + PHY_Read, + PHY_Write +}; diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.h b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.h new file mode 100644 index 0000000..ae74b09 --- /dev/null +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/EMAC_MCXN947.h @@ -0,0 +1,57 @@ +/* -------------------------------------------------------------------------- + * Copyright (c) 2018-2024 Arm Limited (or its affiliates). + * All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * $Date: 5. December 2024 + * $Revision: V1.0 + * + * Project: Ethernet Media Access (MAC) Definitions for NXP MCXN947 + * -------------------------------------------------------------------------- */ + +#ifndef EMAC_MCXN947_H__ +#define EMAC_MCXN947_H__ + +#include + +#include "Driver_ETH_MAC.h" + +#include "fsl_enet.h" // NXP::Device:SDK Drivers:enet +#include "pin_mux.h" // NXP::Board Support:SDK Project Template:project_template + +/* Configure Reduced-Media-Independent interface mode */ +#ifndef ENET_RMII +#define ENET_RMII 1 +#endif + +/* EMAC Driver state flags */ +#define EMAC_FLAG_INIT (1U << 0) // Driver initialized +#define EMAC_FLAG_POWER (1U << 1) // Driver power on + +/* EMAC Driver Control Information */ +typedef struct _EMAC_INFO { + ARM_ETH_MAC_SignalEvent_t cb_event; // Event callback + uint8_t flags; // Control and state flags + uint8_t rx_index; // Receive descriptor index + uint8_t tx_index; // Transmit descriptor index + uint32_t tx_len; // Length of assembled frame fragments +} EMAC_INFO; + +/* Global functions and variables exported by the driver */ +extern ARM_DRIVER_ETH_MAC Driver_ETH_MAC0; + +#endif /* EMAC_MCXN947_H__ */ diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.c b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.c new file mode 100644 index 0000000..ff88821 --- /dev/null +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2013-2025 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ----------------------------------------------------------------------- + * + * $Date: 8. January 2025 + * $Revision: V1.0 + * + * Driver: Driver_ETH_PHYn (default: Driver_ETH_PHY0) + * Project: Ethernet Physical Layer Transceiver (PHY) + * Driver for LAN8741A + * ----------------------------------------------------------------------- + * Use the following configuration settings in the middleware component + * to connect to this driver. + * + * Configuration Setting Value + * --------------------- ----- + * Connect to hardware via Driver_ETH_PHY# = n (default: 0) + * -------------------------------------------------------------------- */ + +/* History: + * Version 1.0 + * Initial release + */ + +#include "PHY_LAN8741A.h" + +#define ARM_ETH_PHY_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0) /* driver version */ + + +#ifndef ETH_PHY_NUM +#define ETH_PHY_NUM 0 /* Default driver number */ +#endif + +#ifndef ETH_PHY_ADDR +#define ETH_PHY_ADDR 0x00 /* Default device address */ +#endif + + +/* Driver Version */ +static const ARM_DRIVER_VERSION DriverVersion = { + ARM_ETH_PHY_API_VERSION, + ARM_ETH_PHY_DRV_VERSION +}; + +/* Ethernet PHY control structure */ +static PHY_CTRL PHY = { NULL, NULL, 0, 0, 0 }; + + +/** + \fn ARM_DRIVER_VERSION GetVersion (void) + \brief Get driver version. + \return \ref ARM_DRIVER_VERSION +*/ +static ARM_DRIVER_VERSION GetVersion (void) { + return DriverVersion; +} + + +/** + \fn int32_t Initialize (ARM_ETH_PHY_Read_t fn_read, + ARM_ETH_PHY_Write_t fn_write) + \brief Initialize Ethernet PHY Device. + \param[in] fn_read Pointer to \ref ARM_ETH_MAC_PHY_Read + \param[in] fn_write Pointer to \ref ARM_ETH_MAC_PHY_Write + \return \ref execution_status +*/ +static int32_t Initialize (ARM_ETH_PHY_Read_t fn_read, ARM_ETH_PHY_Write_t fn_write) { + + if ((fn_read == NULL) || (fn_write == NULL)) { return ARM_DRIVER_ERROR_PARAMETER; } + + if ((PHY.flags & PHY_INIT) == 0U) { + /* Register PHY read/write functions. */ + PHY.reg_rd = fn_read; + PHY.reg_wr = fn_write; + + PHY.bcr = 0U; + PHY.flags = PHY_INIT; + } + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t Uninitialize (void) + \brief De-initialize Ethernet PHY Device. + \return \ref execution_status +*/ +static int32_t Uninitialize (void) { + + PHY.reg_rd = NULL; + PHY.reg_wr = NULL; + PHY.bcr = 0U; + PHY.flags = 0U; + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t PowerControl (ARM_POWER_STATE state) + \brief Control Ethernet PHY Device Power. + \param[in] state Power state + \return \ref execution_status +*/ +static int32_t PowerControl (ARM_POWER_STATE state) { + uint16_t val; + + switch ((int32_t)state) { + case ARM_POWER_OFF: + if ((PHY.flags & PHY_INIT) == 0U) { + /* Initialize must provide register access function pointers */ + return ARM_DRIVER_ERROR; + } + + PHY.flags &= ~PHY_POWER; + PHY.bcr = BCR_POWER_DOWN; + + return (PHY.reg_wr(ETH_PHY_ADDR, REG_BCR, PHY.bcr)); + + case ARM_POWER_FULL: + if ((PHY.flags & PHY_INIT) == 0U) { + return ARM_DRIVER_ERROR; + } + if (PHY.flags & PHY_POWER) { + return ARM_DRIVER_OK; + } + + /* Check Device Identification. */ + PHY.reg_rd(ETH_PHY_ADDR, REG_PHYIDR1, &val); + + if (val != PHY_ID1) { + /* Invalid PHY ID */ + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + PHY.reg_rd(ETH_PHY_ADDR, REG_PHYIDR2, &val); + + if ((val & 0xFFF0) != PHY_ID2) { + /* Invalid PHY ID */ + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + PHY.bcr = 0U; + + if (PHY.reg_wr(ETH_PHY_ADDR, REG_BCR, PHY.bcr) != ARM_DRIVER_OK) { + return ARM_DRIVER_ERROR; + } + + PHY.flags |= PHY_POWER; + + return ARM_DRIVER_OK; + + case ARM_POWER_LOW: + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } +} + +/** + \fn int32_t SetInterface (uint32_t interface) + \brief Set Ethernet Media Interface. + \param[in] interface Media Interface type + \return \ref execution_status +*/ +static int32_t SetInterface (uint32_t interface) { + uint16_t val; + + if ((PHY.flags & PHY_POWER) == 0U) { return ARM_DRIVER_ERROR; } + + /* Read MII mode status (read only bit) */ + PHY.reg_rd(ETH_PHY_ADDR, REG_SPEC_MODE, &val); + + switch (interface) { + case ARM_ETH_INTERFACE_RMII: + if ((val & SMR_MIIMODE) == 0) { + return ARM_DRIVER_ERROR; + } + break; + case ARM_ETH_INTERFACE_MII: + if ((val & SMR_MIIMODE) != 0) { + return ARM_DRIVER_ERROR; + } + break; + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + return(0); +} + +/** + \fn int32_t SetMode (uint32_t mode) + \brief Set Ethernet PHY Device Operation mode. + \param[in] mode Operation Mode + \return \ref execution_status +*/ +static int32_t SetMode (uint32_t mode) { + uint16_t val; + + if ((PHY.flags & PHY_POWER) == 0U) { return ARM_DRIVER_ERROR; } + + val = PHY.bcr & BCR_POWER_DOWN; + + switch (mode & ARM_ETH_PHY_SPEED_Msk) { + case ARM_ETH_PHY_SPEED_10M: + break; + case ARM_ETH_PHY_SPEED_100M: + val |= BCR_SPEED_SEL; + break; + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + switch (mode & ARM_ETH_PHY_DUPLEX_Msk) { + case ARM_ETH_PHY_DUPLEX_HALF: + break; + case ARM_ETH_PHY_DUPLEX_FULL: + val |= BCR_DUPLEX; + break; + } + + if (mode & ARM_ETH_PHY_AUTO_NEGOTIATE) { + val |= BCR_ANEG_EN; + } + + if (mode & ARM_ETH_PHY_LOOPBACK) { + val |= BCR_LOOPBACK; + } + + if (mode & ARM_ETH_PHY_ISOLATE) { + val |= BCR_ISOLATE; + } + + PHY.bcr = val; + + return (PHY.reg_wr(ETH_PHY_ADDR, REG_BCR, PHY.bcr)); +} + +/** + \fn ARM_ETH_LINK_STATE GetLinkState (void) + \brief Get Ethernet PHY Device Link state. + \return current link status \ref ARM_ETH_LINK_STATE +*/ +static ARM_ETH_LINK_STATE GetLinkState (void) { + ARM_ETH_LINK_STATE state; + uint16_t val = 0U; + + if (PHY.flags & PHY_POWER) { + PHY.reg_rd(ETH_PHY_ADDR, REG_BSR, &val); + } + state = (val & BSR_LINK_STAT) ? ARM_ETH_LINK_UP : ARM_ETH_LINK_DOWN; + + return (state); +} + +/** + \fn ARM_ETH_LINK_INFO GetLinkInfo (void) + \brief Get Ethernet PHY Device Link information. + \return current link parameters \ref ARM_ETH_LINK_INFO +*/ +static ARM_ETH_LINK_INFO GetLinkInfo (void) { + ARM_ETH_LINK_INFO info; + uint16_t val = 0U; + + if (PHY.flags & PHY_POWER) { + PHY.reg_rd(ETH_PHY_ADDR, REG_PSCS, &val); + } + + info.speed = (val & PSCS_SPEED) ? ARM_ETH_SPEED_10M : ARM_ETH_SPEED_100M; + info.duplex = (val & PSCS_DUPLEX) ? ARM_ETH_DUPLEX_FULL : ARM_ETH_DUPLEX_HALF; + + return (info); +} + + +/* PHY Driver Control Block */ +extern +ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(ETH_PHY_NUM); +ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(ETH_PHY_NUM) = { + GetVersion, + Initialize, + Uninitialize, + PowerControl, + SetInterface, + SetMode, + GetLinkState, + GetLinkInfo +}; diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.h b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.h new file mode 100644 index 0000000..9c8b288 --- /dev/null +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/CMSIS/Driver/PHY_LAN8741A.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013-2025 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ----------------------------------------------------------------------- + * + * $Date: 8. January 2025 + * $Revision: V1.0 + * + * Project: Ethernet Physical Layer Transceiver (PHY) + * Definitions for LAN8741A + * -------------------------------------------------------------------- */ + +#ifndef __PHY_LAN8741A_H +#define __PHY_LAN8741A_H + +#include "Driver_ETH_PHY.h" + +/* Basic Registers */ +#define REG_BCR 0 /* Basic Control Register */ +#define REG_BSR 1 /* Basic Status Register */ + +/* Extended Registers */ +#define REG_PHYIDR1 2 /* PHY Identifier 1 */ +#define REG_PHYIDR2 3 /* PHY Identifier 2 */ +#define REG_ANAR 4 /* Auto-Negotiation Advertisement */ +#define REG_ANLPAR 5 /* Auto-Neg. Link Partner Ability */ +#define REG_ANER 6 /* Auto-Neg. Expansion Register */ +#define REG_ANEG_NP_TX 7 /* Auto-Neg. Next Page Tx */ +#define REG_ANEG_NP_RX 8 /* Auto-Neg. Next Page Rx */ +#define REG_MMD_ACCES_CTRL 13 /* MMD Access Control */ +#define REG_MMD_ACCES_AD 14 /* MMD Access Address/Data */ + +/* Vendor-specific Registers */ +#define RET_EDPD_CR 16 /* Energy Detect Power Down Conf.Reg.*/ +#define REG_MCSR 17 /* Mode Control/Status Register */ +#define REG_SPEC_MODE 18 /* Special Modes Register */ +#define REG_SEC 26 /* System Error Counter Register */ +#define REG_SC_SI 27 /* Specifal Control/Status Indication*/ +#define REG_ISF 29 /* Interrupt Source Flag Register */ +#define REG_IM 30 /* Interrupt Mask Register */ +#define REG_PSCS 31 /* PHY Special Ctrl/Status Register */ + +/* Basic Control Register */ +#define BCR_RESET 0x8000 /* Software Reset */ +#define BCR_LOOPBACK 0x4000 /* Loopback mode */ +#define BCR_SPEED_SEL 0x2000 /* Speed Select (1=100Mb/s) */ +#define BCR_ANEG_EN 0x1000 /* Auto Negotiation Enable */ +#define BCR_POWER_DOWN 0x0800 /* Power Down (1=power down mode) */ +#define BCR_ISOLATE 0x0400 /* Isolate Media interface */ +#define BCR_REST_ANEG 0x0200 /* Restart Auto Negotiation */ +#define BCR_DUPLEX 0x0100 /* Duplex Mode (1=Full duplex) */ +#define BCR_COL_TEST 0x0080 /* Enable Collision Test */ + +/* Basic Status Register */ +#define BSR_100B_T4 0x8000 /* 100BASE-T4 Capable */ +#define BSR_100B_TX_FD 0x4000 /* 100BASE-TX Full Duplex Capable */ +#define BSR_100B_TX_HD 0x2000 /* 100BASE-TX Half Duplex Capable */ +#define BSR_10B_T_FD 0x1000 /* 10BASE-T Full Duplex Capable */ +#define BSR_10B_T_HD 0x0800 /* 10BASE-T Half Duplex Capable */ +#define BSR_100B_T2_FD 0x0400 /* 1000BASE-T2 Full Duplex Capable */ +#define BSR_100B_T2_HD 0x0200 /* 1000BASE-T2 Half Duplex Capable */ +#define BSR_EXTENDED_STAT 0x0100 /* Extended Status in register 15 */ +#define BSR_ANEG_COMPL 0x0020 /* Auto Negotiation Complete */ +#define BSR_REM_FAULT 0x0010 /* Remote Fault */ +#define BSR_ANEG_ABIL 0x0008 /* Auto Negotiation Ability */ +#define BSR_LINK_STAT 0x0004 /* Link Status (1=link us up) */ +#define BSR_JABBER_DET 0x0002 /* Jabber Detect */ +#define BSR_EXT_CAPAB 0x0001 /* Extended Capabilities */ + +/* PHY Identifier Registers */ +#define PHY_ID1 0x0007 /* LAN8741A Device Identifier MSB */ +#define PHY_ID2 0xC120 /* LAN8741A Device Identifier LSB */ + +/* PHY Special Modes Register */ +#define SMR_MIIMODE 0x4000 /* MII mode 0=MII, 1=RMII */ + +/* PHY Special Control/Status Register */ +#define PSCS_AUTODONE 0x1000 /* Auto-negotiation is done */ +#define PSCS_DUPLEX 0x0010 /* Duplex Status (1=Full duplex) */ +#define PSCS_SPEED 0x0004 /* Speed10 Status (1=10MBit/s) */ + +/* PHY Driver State Flags */ +#define PHY_INIT 0x01U /* Driver initialized */ +#define PHY_POWER 0x02U /* Driver power is on */ + +/* PHY Driver Control Structure */ +typedef struct phy_ctrl { + ARM_ETH_PHY_Read_t reg_rd; /* PHY register read function */ + ARM_ETH_PHY_Write_t reg_wr; /* PHY register write function */ + uint16_t bcr; /* BCR register value */ + uint8_t flags; /* Control flags */ + uint8_t rsvd; /* Reserved */ +} PHY_CTRL; + +#endif /* __PHY_LAN8741A_H */ diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/FRDM-MCXN947.h b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/FRDM-MCXN947.h index a2f3868..6c32c1f 100644 --- a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/FRDM-MCXN947.h +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/FRDM-MCXN947.h @@ -19,7 +19,8 @@ #ifndef FRDM_MCXN947_H_ #define FRDM_MCXN947_H_ -//TODO: #include "Driver_ETH_MAC.h" +#include "Driver_ETH_MAC.h" +#include "Driver_ETH_PHY.h" #include "Driver_I2C.h" #include "Driver_SPI.h" #include "Driver_USART.h" @@ -58,10 +59,11 @@ //TODO: #define MIKROBUS_UART 0 // CMSIS Driver instances of Board peripherals -//TODO: #define CMSIS_DRIVER_ETH 0 +#define CMSIS_DRIVER_ETH 0 // CMSIS Drivers -//TODO: extern ARM_DRIVER_ETH_MAC ARM_Driver_ETH_MAC_(CMSIS_DRIVER_ETH); /* Ethernet */ +extern ARM_DRIVER_ETH_MAC ARM_Driver_ETH_MAC_(CMSIS_DRIVER_ETH); /* Ethernet MAC */ +extern ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(CMSIS_DRIVER_ETH); /* Ethernet PHY */ extern ARM_DRIVER_I2C ARM_Driver_I2C_(ARDUINO_UNO_I2C); /* Arduino I2C */ extern ARM_DRIVER_SPI ARM_Driver_SPI_(ARDUINO_UNO_SPI); /* Arduino SPI */ extern ARM_DRIVER_USART ARM_Driver_USART_(ARDUINO_UNO_UART); /* Arduino UART */ diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/FRDM-MCXN947.mex b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/FRDM-MCXN947.mex index a3ab039..49d30e2 100644 --- a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/FRDM-MCXN947.mex +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/FRDM-MCXN947.mex @@ -333,6 +333,132 @@ + + Configures pin routing and optionally pin electrical features. + + true + cm33_core0 + true + + + + + true + + + + + true + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.c b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.c index 34fcf13..1b6cc4b 100644 --- a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.c +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.c @@ -34,6 +34,7 @@ void BOARD_InitBootPins(void) BOARD_InitARDUINO_UART(); BOARD_InitARDUINO_I2C(); BOARD_InitARDUINO_SPI(); + BOARD_InitENETPins(); } /* clang-format off */ @@ -531,6 +532,253 @@ void BOARD_InitARDUINO_SPI(void) /* Input Buffer Enable: Enables. */ | PORT_PCR_IBE(PCR_IBE_ibe1)); } + +/* clang-format off */ +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitENETPins: +- options: {callFromInitBoot: 'true', coreID: cm33_core0, enableClock: 'true'} +- pin_list: + - {pin_num: B2, peripheral: ENET0, signal: 'enet_tdata, 0', pin_signal: PIO1_6/TRIG_IN2/FC3_P6/FC5_P2/CT_INP6/SCT0_IN0/FLEXIO0_D14/EZH_PIO2/ENET0_TXD0/SAI1_RX_BCLK/CAN1_TXD/TSI0_CH6/ADC0_A22, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: A2, peripheral: ENET0, signal: 'enet_tdata, 1', pin_signal: PIO1_7/WUU0_IN9/TRIG_OUT2/FC5_P3/CT_INP7/SCT0_IN1/FLEXIO0_D15/EZH_PIO3/PLU_CLK/ENET0_TXD1/SAI1_RX_FS/CAN1_RXD/TSI0_CH7/ADC0_A23, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: K5, peripheral: ENET0, signal: enet_mdc, pin_signal: PIO1_20/TRIG_IN2/FC5_P4/FC4_P0/CT3_MAT2/SCT0_OUT8/FLEXIO0_D28/EZH_PIO16/PLU_OUT6/ENET0_MDC/CAN1_TXD/ADC1_A20/CMP1_IN3, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: L5, peripheral: ENET0, signal: enet_mdio, pin_signal: PIO1_21/TRIG_OUT2/FC5_P5/FC4_P1/CT3_MAT3/SCT0_OUT9/FLEXIO0_D29/EZH_PIO17/PLU_OUT7/ENET0_MDIO/SAI1_MCLK/CAN1_RXD/ADC1_A21/CMP2_IN3, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: B3, peripheral: ENET0, signal: enet_tx_en, pin_signal: PIO1_5/FREQME_CLK_IN1/FC3_P5/FC5_P1/CT1_MAT3/SCT0_OUT1/FLEXIO0_D13/EZH_PIO1/ENET0_TXEN/SAI0_RXD1/TSI0_CH5/ADC0_A21/CMP0_IN3, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: D1, peripheral: ENET0, signal: enet_rx_dv, pin_signal: PIO1_13/TRIG_IN3/FC4_P5/FC3_P1/CT2_MAT3/SCT0_OUT5/FLEXIO0_D21/EZH_PIO9/PLU_OUT3/ENET0_RXDV/CAN1_TXD/TSI0_CH22/ADC1_A13, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: D4, peripheral: ENET0, signal: 'enet_rdata, 0', pin_signal: PIO1_14/FC4_P6/FC3_P2/CT_INP10/SCT0_IN4/FLEXIO0_D22/EZH_PIO10/PLU_IN2/ENET0_RXD0/TSI0_CH23/ADC1_A14, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: E4, peripheral: ENET0, signal: 'enet_rdata, 1', pin_signal: PIO1_15/WUU0_IN13/FC3_P3/CT_INP11/SCT0_IN5/FLEXIO0_D23/EZH_PIO11/PLU_IN3/ENET0_RXD1/I3C1_PUR/TSI0_CH24/ADC1_A15, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: A4, peripheral: ENET0, signal: enet_tx_clk, pin_signal: PIO1_4/WUU0_IN8/FREQME_CLK_IN0/FC3_P4/FC5_P0/CT1_MAT2/SCT0_OUT0/FLEXIO0_D12/EZH_PIO0/ENET0_TX_CLK/SAI0_TXD1/TSI0_CH4/ADC0_A20/CMP0_IN2, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ +/* clang-format on */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitENETPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitENETPins(void) +{ + /* Enables the clock for PORT1: Enables clock */ + CLOCK_EnableClock(kCLOCK_Port1); + + const port_pin_config_t port1_13_pinD1_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_RXDV */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_13 (pin D1) is configured as ENET0_RXDV */ + PORT_SetPinConfig(PORT1, 13U, &port1_13_pinD1_config); + + const port_pin_config_t port1_14_pinD4_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_RXD0 */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_14 (pin D4) is configured as ENET0_RXD0 */ + PORT_SetPinConfig(PORT1, 14U, &port1_14_pinD4_config); + + const port_pin_config_t port1_15_pinE4_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_RXD1 */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_15 (pin E4) is configured as ENET0_RXD1 */ + PORT_SetPinConfig(PORT1, 15U, &port1_15_pinE4_config); + + const port_pin_config_t port1_20_pinK5_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_MDC */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_20 (pin K5) is configured as ENET0_MDC */ + PORT_SetPinConfig(PORT1, 20U, &port1_20_pinK5_config); + + const port_pin_config_t port1_21_pinL5_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_MDIO */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_21 (pin L5) is configured as ENET0_MDIO */ + PORT_SetPinConfig(PORT1, 21U, &port1_21_pinL5_config); + + const port_pin_config_t port1_4_pinA4_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TX_CLK */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_4 (pin A4) is configured as ENET0_TX_CLK */ + PORT_SetPinConfig(PORT1, 4U, &port1_4_pinA4_config); + + const port_pin_config_t port1_5_pinB3_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TXEN */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_5 (pin B3) is configured as ENET0_TXEN */ + PORT_SetPinConfig(PORT1, 5U, &port1_5_pinB3_config); + + const port_pin_config_t port1_6_pinB2_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TXD0 */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_6 (pin B2) is configured as ENET0_TXD0 */ + PORT_SetPinConfig(PORT1, 6U, &port1_6_pinB2_config); + + const port_pin_config_t port1_7_pinA2_config = {/* Internal pull-up/down resistor is disabled */ + .pullSelect = kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + .pullValueSelect = kPORT_LowPullResistor, + /* Fast slew rate is configured */ + .slewRate = kPORT_FastSlewRate, + /* Passive input filter is disabled */ + .passiveFilterEnable = kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + .openDrainEnable = kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + .driveStrength = kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TXD1 */ + .mux = kPORT_MuxAlt9, + /* Digital input enabled */ + .inputBuffer = kPORT_InputBufferEnable, + /* Digital input is not inverted */ + .invertInput = kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + .lockRegister = kPORT_UnlockRegister}; + /* PORT1_7 (pin A2) is configured as ENET0_TXD1 */ + PORT_SetPinConfig(PORT1, 7U, &port1_7_pinA2_config); +} /*********************************************************************************************************************** * EOF **********************************************************************************************************************/ diff --git a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.h b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.h index b8d4aca..ea50766 100644 --- a/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.h +++ b/boards/frdmmcxn947/cmsis/layers/sensor_sdk/MCUXpressoConfig/board/pin_mux.h @@ -179,6 +179,12 @@ void BOARD_InitARDUINO_I2C(void); */ void BOARD_InitARDUINO_SPI(void); +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitENETPins(void); + #if defined(__cplusplus) } #endif