Embedded systems from ground up: PHYnal Fantasy
by Anne Macedo
On my last post about embedded systems and the Orange Pi One Plus, I mentioned that I was having trouble with ethernet. This is all documented on [1] and [2] but I wanted to document this in my blog as well.
Basically, ethernet doesnāt seem to work out of the box on the Orange Pi One Plus and on the upstream u-boot and I want to understand why.
One thing I found out from the device dts:
reg_gmac_3v3: gmac-3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc-gmac-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
startup-delay-us = <100000>;
enable-active-high;
gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
vin-supply = <®_aldo2>;
};
This is the definition of the voltage regulator for PHY. I still donāt really understand what PHY is, but it is important for making ethernet work. This line:
gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
is something that made me try a lot of things before reading the datasheet (always read the datasheet!). I saw this GPIO and thought āhey, let me short pin 3 and 6 and it will workā. After some tries, it did, but I couldnāt replicate, so I believe I just glitched the board.
The datasheets and all the stuff related to this board is on a Google Drive [3]. Looking at the Allwinner H6 datasheet, I saw that the GPIO3_6
(or PD6) was not accessible through the header, but it was accessible through u-boot.
I gave it a try, after a few reboots and with this config:
u-boot config:
CONFIG_SPL_SPI_SUNXI=y
CONFIG_SUN8I_EMAC=y
tfa config:
SUNXI_SETUP_REGULATORS=1
I was able to get eth0 (and for some reason it only shows up after a lot of restarts). And then, on the shell:
gpio set pd6
After that, the LED on ethernet started blinking! However, the dhcp command failedā¦ it worked once, I donāt know how, but it fails consistently now.
The Orange Pi One Plus has an interesting schematic that shows exactly this pinout. Itās very hard to read and understand, but Iāll make sense out of it soon:
The EMAC section of the Allwinner H6 datasheet seems to match this pinout
From the Realtek RTL8211E datasheet, I could figure out that MII is 100mbps while RGMII is gigabit. Interesting!
Okay, so, when we enable the PD6 pin, what are we enabling on RGMII? To try to make sense, I made this spreadsheet:
Quite surprising why they use PD6 for voltage regulation. Strange, actually. I donāt understand why.
LOL, the quick way to enable eth0 is to do a mii dump
and let u-boot crash and restart.
Iām quite tired now, Iāll leave this link in Chinese here [4] (ps.: I should definitely continue studying Chinese!) which has some information about the LicheeZero u-boot ethernet. I believe they both have the same processor, so maybe its config should have some clue. I need to rest now.
Pinmux
After playing a lot with SPL and figuring out that SPL memory is too small, I decided to go back to playing with GPIO. One thing I found on u-boot is
=> pinmux status PD6
PD6 : gpio input
I noticed that PD6 wasnāt on the pinout for ext_rgmii_pins
in arch/arm/dts/sun50i-h6.dtsi and PD6 was showing on pinmux as disabled! After I added it, there was a function linked to it, but Ethernet still didnāt workā¦
If I set PD6 to output and then back to input, the LEDs dieā¦ but it clearly says on the datasheet that this pin is input. Is it undocumented (since itās not even referenced on RGMII but on GMII instead)?
PD6 is only defined on the reg_gmac_3v3
blockā¦ why doesnāt it enable stuff?
After carefully checking the Allwinner H6 datasheet and the Realtek, I noticed that, on the Realtek Datasheet, RXER is Output while on Allwinner itās Input! That explains why I need to enable it to output to make the port go alive?
I also noticed that itās only RXER for RMII, but for RGMII itās null! So that makes sense. Since itās not used, itās being used for some kind of voltage regulation.
Iāve noticed that PD7 and others also make the LED turn on, but dhcp doesnāt work and I see sun8i_emac_eth_start: Timeout
.
Enabling PD7 and PD8 makes dhcp start! But I get no IP :(.
After almost losing hope, I found this: CONFIG_MACPWR
. [5] IT TURNED ETHERNET ON!!!!! I still get weird PHY errors, and I keep getting:
Net: Could not get PHY for ethernet@5020000: addr 1
No ethernet found.
Changed the phy-mode on arch/arm/dts/sun50i-h6-orangepi-one-plus.dts
to rgmii
instead of rgmii-id
. Still getting the error. It seems that CONFIG_MACPWR
turned the PHY error pretty consistent :(
I also see these errors on dhcp:
=> dhcp
mdio_register: non unique device name 'ethernet@5020000'
Could not get PHY for ethernet@5020000: addr 1
I wonder if Iām hitting this regression? [6]
Back to DM
Iāve read in a couple of patches that we should focus on DM for loading stuff, so Iām trying to make the regulator-fixed work. The regulator-fixed was the part of the dts file that had the PD6 GPIO definition. I wonder if that regulator will in fact enable GPIO, but things are looking so strange.
After I added regulator-boot-on;
to arch/arm/dts/sun50i-h6-orangepi-one-plus.dts and crash-rebooted the device with mii dump
, the Ethernet LED turned on :) at least one, the orange one didnāt turn onā¦
I found out that thereās a command that I can enable on u-boot using CONFIG_CMD_REGULATOR
. Nice!
I tried to enable the regulator:
=> regulator enable
First, set the regulator device!
=> regulator dev vcc-gmac-3v3
dev: vcc-gmac-3v3 @ gmac-3v3
=> regulator enable
=> dhcp
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
Yay! Itās not getting an IP tho, but this may be for reasons.
itās PHYnally over!
Iāve made it! Patch is sent!
The first thing I did was to focus on why ethernet initialization was so flaky (I would see the āCould not get PHY for ethernet@xxxxxā from time to time after reset. And also, I read that some TX and RX values that impacted dhcp from running were fixed by the Realtek PHY driver, but I could never use it and driver initialization would always fallback to Generic PHYā¦ strange!
The code that printed this error was under drivers/net/phy/phy.c
and I read it and added some print-debugs here and there.
The fun stuff is here:
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
struct udevice *dev,
phy_interface_t interface)
{
struct phy_device *phydev = NULL;
uint mask = (addr >= 0) ? (1 << addr) : 0xffffffff;
#ifdef CONFIG_PHY_FIXED
phydev = phy_connect_fixed(bus, dev);
#endif
#ifdef CONFIG_PHY_NCSI
if (!phydev && interface == PHY_INTERFACE_MODE_NCSI)
phydev = phy_device_create(bus, 0, PHY_NCSI_ID, false);
#endif
#ifdef CONFIG_PHY_ETHERNET_ID
if (!phydev)
phydev = phy_connect_phy_id(bus, dev, addr);
#endif
#ifdef CONFIG_PHY_XILINX_GMII2RGMII
if (!phydev)
phydev = phy_connect_gmii2rgmii(bus, dev);
#endif
if (!phydev)
phydev = phy_find_by_mask(bus, mask);
if (phydev)
phy_connect_dev(phydev, dev, interface);
else
printf("Could not get PHY for %s: addr %d\n", bus->name, addr);
return phydev;
}
I set this config CONFIG_PHY_ETHERNET_ID
and I thought that it was going to work, but nahā¦ but looking at the phy_connect_phy_id
, it looks on the dts for which phy it should use. Thatās very cool, but itās not working for me. It should!
After some print-debugs, I figured out where things returned and it was in this function under drivers/core/ofnode.c
.
int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
{
const char *list, *end;
int len;
list = ofnode_get_property(node, "compatible", &len);
if (!list)
return -ENOENT;
end = list + len;
while (list < end) {
len = strlen(list);
if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
char *s = strstr(list, "ethernet-phy-id");
/*
* check if the string is something like
* ethernet-phy-idVVVV.DDDD
*/
if (s && s[19] == '.') {
s += strlen("ethernet-phy-id");
*vendor = simple_strtol(s, NULL, 16);
s += 5;
*device = simple_strtol(s, NULL, 16);
return 0;
}
}
list += (len + 1);
}
return -ENOENT;
}
From what I understood, it lists all the compatible properties and try to match which driver is compatible with each compatible blog. Pay close attention to the format:
ethernet-phy-idVVVV.DDDD
What we had on the Orange Pi One Plus dts was this:
ethernet-phy-ieee802.3-c22
After searching for the VID.PID for the Realtek driver, I added this to the dtsās PHY compatible line: ethernet-phy-id001c.c915
.
Also added these configs:
# EMAC driver, needed for doing MAC stuff on sunxi
CONFIG_SUN8I_EMAC=y
# Load realtek phy driver
CONFIG_PHY_REALTEK=y
# Explained above
CONFIG_PHY_ETHERNET_ID=y
# This one is tricky: remember PD6? There are two ways to enable it: use this config
# or use a regulator.
# I still haven't figured out how to probe the regulator on u-boot, so I'm using this one.
CONFIG_MACPWR="PD6"
After sending the image to the SD-Card and turning the board onā¦ I see eth0 being loadedā¦ and mdio reports REALTEK PHY DRIVER! AND DHCP WORKS!!!
Iām so happy. Folks from meta-sunxi merged my patch and it was already sent to u-boot (currently waiting for approval).
Next steps: figure out stuff about the regulator, or why it isnāt being probed.
This was a nice journey. On another post, Iāll explain about tbot or how I did TDD on the u-boot layer.
References
[1] Ethernet not working on Orange Pi One Plus_
[2] [bug report] sunxi: H6: no ethernet on Orange Pi One Plus
[3] Orange Pi One Plus datasheets
[5] [RFC,02/17] sunxi: remove CONFIG_MACPWR
[6] [PATCH 0/2] sunxi: Fix Ethernet on mostly A20 boards
[7] [PATCH] sunxi: H6: Enable Ethernet on Orange Pi One Plus
tags: hardware - embedded - yocto - networking