Skip to content

Commit

Permalink
Teensy 4.1 port with Ethernet support (#144)
Browse files Browse the repository at this point in the history
* Start porting to Teensy 4.1, also fix some compiler warnings in FSL HAL

* Add hardware init for Teensy, refactor phy drivers, rework IMX EMAC autonegotiate code

* Revert some testing changes

* Fix incorrect phy address used outside of low_level_init_successful()

* Ethernet operational!

* Turn off DEBUG_IMX_EMAC

* Style fixes

* Style again

* Bugfix: mbed_lib.json files in project source dir were not getting picked up

* Bugfix: CLion debug configurations not generated properly due to variables going out of scope

* Support Teensy OTP MAC address
  • Loading branch information
multiplemonomials authored Mar 9, 2023
1 parent bf5be9f commit af6d50a
Show file tree
Hide file tree
Showing 31 changed files with 993 additions and 244 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ if(NOT MBED_IS_NATIVE_BUILD)
# Load upload method if one is set up
include(UploadMethodManager)

# Load debug config generator for IDEs
include(mbed_ide_debug_cfg_generator)
endif()

if(MBED_IS_NATIVE_BUILD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
# SPDX-License-Identifier: Apache-2.0

if("MIMXRT1050_EVK" IN_LIST MBED_TARGET_LABELS OR "MIMXRT1060_EVK" IN_LIST MBED_TARGET_LABELS)
add_subdirectory(TARGET_MIMXRT10x0_EVK)
add_subdirectory(TARGET_MIMXRT105x_EVK)
endif()
if("TEENSY_41" IN_LIST MBED_TARGET_LABELS)
add_subdirectory(TARGET_TEENSY_41)
endif()

target_include_directories(mbed-emac
Expand All @@ -13,4 +16,5 @@ target_include_directories(mbed-emac
target_sources(mbed-emac
PRIVATE
imx_emac.cpp
fsl_phy_common.c
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
target_sources(mbed-emac
PRIVATE
hardware_init.c
fsl_phy_ksz8081rnb.c
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*/

#include "fsl_phy.h"
#include "ksz8081rnb_regs.h"

/*******************************************************************************
* Definitions
******************************************************************************/
Expand Down Expand Up @@ -82,123 +84,17 @@ status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
}
#endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */
}
return result;
}

status_t PHY_AutoNegotiation(ENET_Type *base, uint32_t phyAddr)
{
status_t result = kStatus_Success;
uint32_t bssReg;
uint32_t counter = PHY_TIMEOUT_COUNT;
uint32_t timeDelay;
uint32_t ctlReg = 0;

/* Set the negotiation. */
result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
// Enable autonegotiation, allow negotiating for all ethernet types
PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
(PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U));
if (result == kStatus_Success)
{
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG,
(PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
if (result == kStatus_Success)
{
/* Check auto negotiation complete. */
while (counter--)
{
result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg);
if (result == kStatus_Success)
{
PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
if (((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) && (ctlReg & PHY_LINK_READY_MASK))
{
/* Wait a moment for Phy status stable. */
for (timeDelay = 0; timeDelay < PHY_TIMEOUT_COUNT; timeDelay++)
{
__ASM("nop");
}
break;
}
}

if (!counter)
{
return kStatus_PHY_AutoNegotiateFail;
}
}
}
}
PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK));

return result;
}

status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
{
uint32_t counter;

/* Clear the SMI interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);

/* Starts a SMI write command. */
ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data);

/* Wait for SMI complete. */
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
{
if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
{
break;
}
}

/* Check for timeout. */
if (!counter)
{
return kStatus_PHY_SMIVisitTimeout;
}

/* Clear MII interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);

return kStatus_Success;
}

status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
{
assert(dataPtr);

uint32_t counter;

/* Clear the MII interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);

/* Starts a SMI read command operation. */
ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame);

/* Wait for MII complete. */
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
{
if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
{
break;
}
}

/* Check for timeout. */
if (!counter)
{
return kStatus_PHY_SMIVisitTimeout;
}

/* Get data from MII register. */
*dataPtr = ENET_ReadSMIData(base);

/* Clear MII interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);

return kStatus_Success;
}

status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, phy_speed_t speed, bool enable)
{
status_t result;
Expand Down Expand Up @@ -255,31 +151,6 @@ status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode,
return result;
}

status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status)
{
assert(status);

status_t result = kStatus_Success;
uint32_t data;

/* Read the basic status register. */
result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &data);
if (result == kStatus_Success)
{
if (!(PHY_BSTATUS_LINKSTATUS_MASK & data))
{
/* link down. */
*status = false;
}
else
{
/* link up. */
*status = true;
}
}
return result;
}

status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex)
{
assert(duplex);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _KSZ8081RNB_REGS_H_
#define _KSZ8081RNB_REGS_H_

/*! @brief Defines the KSZ8081-specific PHY registers. */
#define PHY_CONTROL1_REG 0x1EU /*!< The PHY control one register. */
#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */

#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1*/

/*!@brief Defines the mask flag of operation mode in control two register*/
#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)

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2020 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

target_sources(mbed-emac
PRIVATE
hardware_init.cpp
fsl_phy_dp83825.c
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _DP83825_REGS_H_
#define _DP83825_REGS_H_

/*! @brief Defines the DP83825-specific PHY registers. */
#define PHY_PHYSTS_REG 0x10 ///< Phy Status Reg
#define PHY_BISCR_REG 0x16 ///< Built-In Self Test Control Register
#define PHY_RCSR_REG 0x17 ///< Receive Clock Select Register
#define PHY_LEDCR_REG 0x18 ///< LED Control Register

#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1*/

/*!@brief Defines the mask flag of operation mode in control two register*/
#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)

// Bits for PHYSTS register
#define PHY_PHYSTS_DUPLEX_Msk (1 << 2)
#define PHY_PHYSTS_SPEED_Msk (1 << 1)

// Bits for BISCR register
#define PHY_BISCR_LOOPBACK_Msk (0b11111)
#define PHY_BISCR_LOOPBACK_Pos 0
#define PHY_BISCR_LOOPBACK_DIGITAL_LOOPBACK_10M_Val 0x1
#define PHY_BISCR_LOOPBACK_DIGITAL_LOOPBACK_100M_Val 0x4
#define PHY_BISCR_LOOPBACK_ANALOG_LOOPBACK_Val 0x8

// Bits for RCSR register
#define PHY_RCSR_RX_ELASTICITY_Pos 0
#define PHY_RCSR_RX_ELASTICITY_Msk 0b11
#define PHY_RCSR_RMII_CLK_SEL_Msk (1 << 7)

// Bits for LEDCR register
#define PHY_LEDCR_POLARITY_Msk (1 << 7)
#define PHY_LEDCR_BLINK_RATE_Msk (0b11 << 9)
#define PHY_LEDCR_BLINK_RATE_Pos 9


#endif
Loading

0 comments on commit af6d50a

Please sign in to comment.