IMX6 Ethernet. Development process to add second ethernet PHY IC support. part 2.

IMX6 Ethernet development process continuation. So after getting working single PHY IC on new revision of OpenWrt driven SoM we continue development process to get working two PHY IC on same PCB.

First of all we soldered second testbench that provides access to core functionality (JTAG, both ethernet interfaces and UART console) of SoM module:

IMX6 Ethernet testbench

One of the testbench loaded with SoM having both PHY IC soldered. Another testbench loaded with single PHY IC soldered SoM module.

At least we have working link under U-boot so we can update firmware of device via TFTP.

As you remember we got working single PHY IC and was reading registers value using u-boot’s mii command. A similar command was sorely lacking under Linux. So we started with searching any utilitiy giving same functionality under Linux and found it here.

Step 3. Adding phytool package.

Clone project and create phytool package folder:

$ git clone https://github.com/wireless-road/imx6ull-openwrt.git
$ cd imx6ull-openwrt
$ mkdir package/phytool
$ cd package/phytool
Create Makefile:
$ touch Makefile
with following content :

include $(TOPDIR)/rules.mk

PKG_NAME:=phytool
PKG_VERSION:=1.0
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/phytool-$(PKG_VERSION)

include $(INCLUDE_DIR)/package.mk

define Package/phytool
SECTION:=examples
CATEGORY:=Examples
TITLE:=PHY registers accessing via MDIO
endef

define Package/phytool/description
PHY registers accessing via MDIO
endef

define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
cp ./src/* $(PKG_BUILD_DIR)/
$(Build/Patch)
endef

define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) CC=»$(TARGET_CC)» CFLAGS=»$(TARGET_CFLAGS)» LDFLAGS=»$(TARGET_LDFLAGS)»
endef

define Package/phytool/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/phytool $(1)/usr/bin
endef

$(eval $(call BuildPackage,phytool))

clone source code of phytool:
$ mkdir src
$ git clone https://github.com/wkz/phytool.git  src
compile package:
$ make package/phytool/compile
make[1] package/phytool/compile
make[2] -C package/libs/toolchain compile
make[2] -C package/phytool compile
and grad executable from build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/phytool-1.0/ folder from SoM module:
$ scp user@host_id_address:/path_to_project/lorawan-imx6ull/build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/phytool-1.0/phytool /tmp

as expected proper PHY registers value on SoM with single PHY IC:

root@OpenWrt:/# phytool eth0/0/0
ieee-phy: reg:BMCR(0x00) val:0x3100
flags:                     -reset -loopback +aneg-enable -power-down -isolate -aneg-restart -collision-test
speed:                 100-full
root@OpenWrt:/# phytool eth0/0/1
ieee-phy: reg:BMSR(0x01) val:0x7849
capabilities:         -100-b4 +100-f +100-h +10-f +10-h -100-t2-f -100-t2-h
flags:                     -ext-status -aneg-complete -remote-fault +aneg-capable -link -jabber +ext-register
root@OpenWrt:/# phytool eth0/0/2
ieee-phy: reg:0x02 val:0x0022
root@OpenWrt:/# phytool eth0/0/3
ieee-phy: reg:0x03 val:0x1561
meaning of each register values can be found in first chapter.

Step 4. DTS modification.

Already implemented DTS supports only one PHY IC. On of them — flexcan_wifi.dts will be used as starting point.
fec1 = &fec1;

fec1 node presents Fast Ethernet Controller

&fec1 {
pinctrl-names = «default»;
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = «rmii»;
phy-handle = <&ethphy0>;
status = «okay»;
mdio {
#address-cells = <1>;
#size-cells = <0>;

ethphy0: ethernet-phy@0 {
compatible = «ethernet-phy-ieee802.3-c22»;
reg = <0>;
};

};
};

mdio presents mdio serial interface used for communication between MAC controller (MCU) and PHY IC for configuration purposes. Currently single IC exist on that bus presented by ethphy0 node with address 0. Address of KSZ8081 must be implemended on circuit design stage. Table 2-2 at page 9 of datasheet explains how it can be done.

Before adding second fec node existing one must be modified according to changes made in new PCB revision — specifically RESET pin GPIO connected to MCU:

phy-reset-gpios = <&gpio3 18 GPIO_ACTIVE_LOW>;
phy-reset-duration = <10>;
phy-reset-post-delay = <50>;

phy-reset-duration and phy-reset-post-delay used to configure reset delay duration and duration of delay after reset in milliseconds. That values should be bigger that minimum applicable delays for specific IC described in datasheet for that IC.

phy-reset-gpios used to set specific GPIO of MCU connected to RST pin of PHY IC. LCD_DATA_13 in our case. GPIO_ACTIVE_LOW configures active signal level (LOW) to perform reset of PHY IC. E.g. reset pin should be driven LOW to perform a reset and remains HIGH in normal operation mode. LOW and HIGH are signal’s voltage levels — 0v and 3.3V.

LCD_DATA_13 pin of MCU must be configured as simple GPIO to drive reset pin of IC so gpio3 18 is number of that pin. All MCU gpios distributed to few GPIO controllers. Each of them controls up to 32 gpio. Exact gpio number of each MCU’s pad can be determined by following iomux map:

just find pad you interested in.

After that we need to add another on fec node describing second PHY IC:

&fec2 {
pinctrl-names = «default»;
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = «rmii»;
phy-handle = <&ethphy1>;
phy-reset-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
phy-reset-duration = <10>;
phy-reset-post-delay = <50>;
status = «okay»;
};

It looks much simplier rather than fec1 node. No need to describe mdio bus as it is already described in fec1 (same MDIO bus shared between two PHY IC). LCD_DATA0 (gpio3 5) pad of MCU connected to reset pin of PHY IC. phy-handle pointed to ethphy1 node not existing in DTS yet so it should be added:

ethphy1: ethernet-phy@3 {
compatible = «ethernet-phy-ieee802.3-c22»;
reg = <3>;
clocks = <&clks IMX6UL_CLK_ENET2_REF>;
clock-names = «rmii-ref»;
};

right after already existing ethphy0 node. Here reg = <3> determines PHY IC address on MDIO bus (Configurable PHY addresses are: 0h, 3h, 4h or 7h as explained in datasheet).

pinctrl-0 points to pinctrl_enet2 need to be implemented too:

pinctrl_enet2: enet2grp {
fsl,pins = <
MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN                 0x1b0b0
MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER                  0x1b0b0
MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00     0x1b0b0
MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01     0x1b0b0
MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN                 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00     0x1b0b0
MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01     0x1b0b0
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2         0x4001b031
>;
};

pinctrl_enet2 should be placed right after pinctrl_enet1 node.

And the last one change — pinctrl_enet1 need to be modified by adding by adding two more pins describing MDIO bus used for communication with PHY ICs:

MX6UL_PAD_GPIO1_IO07__ENET1_MDC         0x1b0b0
MX6UL_PAD_GPIO1_IO06__ENET1_MDIO       0x1b0b0

It might be confusing — where all this magic numbers and pad definitions taken from. As linux not well documented — the only way to understand it — research in existing source code base. I a case of DTS just search for already existing dts samples:

$ find ./ -name «*imx6ull*.dts»
./build_dir/host/u-boot-2018.03/arch/arm/dts/imx6ull-14×14-evk.dts
./build_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-7.5.0_musl_eabi/linux-4.14.199/arch/arm/boot/dts/imx6ull-14×14-evk.dts
./build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/u-boot-wirelessroad_ecspi3/u-boot-2017.07/arch/arm/dts/imx6ull-14×14-evk.dts
./build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/u-boot-2018.03/arch/arm/dts/imx6ull-14×14-evk.dts
./build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/linux-imx6ull_cortexa7/linux-4.14.199/arch/arm/boot/dts/imx6ull-14×14-evk.dts

or commits modifying dts.

If you not sure about proper pad definition you might search for it in source code:

$ grep -rnw «.*LCD_DATA00.*» ./
In next post we will test modified DTS.
To be continued.