Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions connectivity/drivers/emac/CompositeEMAC.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ Unlike the MAC driver and the DMA, the PHY driver does not need to be subclassed

```json5
"MY_TARGET": {
"nsapi.emac-phy-model": "LAN8742",
"nsapi.emac-phy-model": "LAN87XX",
"nsapi.emac-phy-mdio-address": 0
}
```

This will work out of the box, as long as `LAN8742` names a PHY driver defined in PhyDrivers.cpp. Individual PHY models will generally need their own drivers, since often PHYs have errata that need to be worked around or need other configuration that isn't defined in the standard. However, GenericEthPhy allows implementing the absolute minimum amount of logic per-phy as possible!
This will work out of the box, as long as `LAN87XX` names a PHY driver defined in PhyDrivers.cpp. Individual PHY models will generally need their own drivers, since often PHYs have errata that need to be worked around or need other configuration that isn't defined in the standard. However, GenericEthPhy allows implementing the absolute minimum amount of logic per-phy as possible!

Since user boards may want to use a different ethernet PHY, the driver can be customized in an application by overriding the `mbed::get_eth_phy_driver` weak function to return a different driver class. This might look something like

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

void EthInitPinmappings(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIOs clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

void EthInitPinmappings(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIOs clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

void EthInitPinmappings(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIOs clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

void EthInitPinmappings(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIOs clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
Expand Down
5 changes: 3 additions & 2 deletions connectivity/drivers/emac/include/GenericEthPhy.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ class GenericEthPhy : public mbed::CompositeEMAC::PHYDriver {
/// 24-bit OUI of the organization that produced the ethernet PHY.
uint32_t OUI;

/// 5-bit model number of the phy. This plus the OUI is used to verify that the
/// Range of 5-bit model number of the phy. This plus the OUI is used to verify that the
/// chip in hardware matches what's expected.
uint8_t model;
uint8_t model_min;
uint8_t model_max;

/// MDIO address of the phy chip.
/// NOTE: 0 is *supposed* to be reserved as the general call address but lots of phy chips use
Expand Down
9 changes: 5 additions & 4 deletions connectivity/drivers/emac/sources/GenericEthPhy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ CompositeEMAC::ErrCode GenericEthPhy::init() {
// ID1 should be the upper 18 MSBits of the OUI, with the two MSBits chopped off.
const uint16_t expectedID1 = config.OUI >> 6;
// Bits 10-15 of ID2 are the 6 LSBits of the OUI. Bits 4-9 are the model number. Bits 0-3 are the revision and may be anything.
const uint16_t expectedID2 = (config.OUI << 10) | (config.model << 4);
const uint16_t expectedID2Min = (config.OUI << 10) | (config.model_min << 4);
const uint16_t expectedID2Max = (config.OUI << 10) | (config.model_max << 4);
const uint16_t expectedID2Mask = 0xFFF0;

// Read IDs
Expand All @@ -58,16 +59,16 @@ CompositeEMAC::ErrCode GenericEthPhy::init() {
FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::PHYIDR1, actualID1));
FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::PHYIDR2, actualID2));

if(actualID1 == expectedID1 && (actualID2 & expectedID2Mask) == expectedID2) {
if(actualID1 == expectedID1 && (actualID2 & expectedID2Mask) >= expectedID2Min && (actualID2 & expectedID2Mask) <= expectedID2Max) {
// OK
tr_info("Detected ethernet PHY at MDIO addr %" PRIu8 " with OUI 0x%" PRIx32 ", model 0x%" PRIx8 ", and revision number %" PRIu8, config.address, config.OUI, config.model, actualID2 % 0xF);
tr_info("Detected ethernet PHY at MDIO addr %" PRIu8 " with OUI 0x%" PRIx32 ", model 0x%" PRIx8 ", and revision number %" PRIu8, config.address, config.OUI, (actualID2 >> 4) & 0x3F, actualID2 % 0xF);
}
else if(actualID1 == std::numeric_limits<uint16_t>::max() && actualID2 == std::numeric_limits<uint16_t>::max()) {
tr_error("Got all 0xFFs when reading Ethernet PHY. Since MDIO is an open drain bus, this means the phy is not connected or not responding.");
return CompositeEMAC::ErrCode::PHY_NOT_RESPONDING;
}
else {
tr_error("Ethernet phy model number verification mismatch. Expected PHYIDR1 = %" PRIu16 ", PHYIDR2 = %" PRIu16 ", got PHYIDR1 = %" PRIu16 ", PHYIDR2 = %" PRIu16 " [note: bottom 4 bits of PHYIDR2 ignored]", expectedID1, expectedID2, actualID1, actualID2);
tr_error("Ethernet phy model number verification mismatch. Expected PHYIDR1 = %" PRIu16 ", PHYIDR2 = %" PRIu16 "-%" PRIu16 ", got PHYIDR1 = %" PRIu16 ", PHYIDR2 = %" PRIu16 " [note: bottom 4 bits of PHYIDR2 ignored]", expectedID1, expectedID2Min, expectedID2Max, actualID1, actualID2);
return CompositeEMAC::ErrCode::PHY_NOT_RESPONDING;
}

Expand Down
37 changes: 33 additions & 4 deletions connectivity/drivers/emac/sources/PhyDrivers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ namespace mbed {

using namespace std::chrono_literals;

namespace LAN8742 {
namespace LAN87XX {

/// Driver for the Microchip LAN8742 PHY
/// Driver for the Microchip LAN8742 & LAN8720 PHY
/// Datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/DS_LAN8742_00001989A.pdf
/// https://ww1.microchip.com/downloads/en/devicedoc/8720a.pdf
/// @{

inline constexpr GenericEthPhy::Config DefaultConfig = {
.OUI = 0x1F0,
.model = 0x13,
.model_min = 0x0F, // LAN8720
.model_max = 0x13, // LAN8742
.address = 0, // Address set via PHYAD[0] strap.
};

Expand All @@ -52,7 +54,8 @@ namespace IP101G {

inline constexpr GenericEthPhy::Config DefaultConfig = {
.OUI = 0x90C3,
.model = 0x5,
.model_min = 0x5,
.model_max = 0x5,
.address = 1, // Address set via strapping pins, 1 is used on Nuvoton boards
};

Expand All @@ -68,6 +71,32 @@ namespace IP101G {

}

namespace DP8384X {

/// Driver for the DP8384X PHY
/// Datasheet: https://www.ti.com/lit/ds/symlink/dp83848c.pdf
/// https://www.ti.com/lit/ds/symlink/dp83849i.pdf
/// @{

inline constexpr GenericEthPhy::Config DefaultConfig = {
.OUI = 0x80017,
.model_min = 0x09, // DP83848VV, DP83849I
.model_max = 0x0A, // DP83848C/I/VYB/YB
.address = 1, // Address set via PHYAD[0] strap.
};

class Driver : public GenericEthPhy {
public:
explicit Driver(GenericEthPhy::Config const & config = DefaultConfig):
GenericEthPhy(config)
{}
};


/// @}

}

/**
* @brief Obtains the PHY driver for Ethernet port 0.
*
Expand Down
2 changes: 1 addition & 1 deletion connectivity/netsocket/mbed_lib.json5
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
},
"MCU_STM32": {
// First-party STM32 boards generally use a LAN8742 PHY at MDIO address 0
"nsapi.emac-phy-model": "LAN8742",
"nsapi.emac-phy-model": "LAN87XX",
"nsapi.emac-phy-mdio-address": 0
},
"MCU_M480": {
Expand Down