I wish to use a LAN8720 (RMII) with the iMX6SX.
The IMX6SXHDG does not cover the Ethernet Interface at all.
The SX Reference Manual covers it very badly:
http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6SXRM.pdf?fasp=1
1) My main problem is how to generate the RMII clock for the LAN8720.
The IMX6DQ6SDLHDG outlines how it is done for S/D/L processors (see below), by using GPIO_16.
Does this apply to iMX6SX devices too ?
2) The following screenshots show my connections between LAN8720 and iMX6SX.
Do they seem correct ?
Hi Martin,
getting back to the SX + LAN8720 circuit after a _long_ absence......
Did your second PCB version work ?
I ask because our 1st one has a fatal clock problem, and I am about to spin a 2nd revision in the hope that correcting the clock error will allow it to work.
I'd be obliged if you could review my circuit above and compare it to yours or if you could share the relevant parts of your schematic. I'd hate to build a second set of board that still didn't work!
BTW: For those in Freescale/NXP, the IMX6SXHDG has recently been revised - but it _still_ doesn't mention the RMII interface !
1. change the device tree to set the pin ctrl correctly . Especially loop back the clock.
#define MX6SX_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x0090 0x03D8 0x0760 0x11 0x1
2. change the device tree to set the fec correctly. using rmii
3. Using 50M for RMII
arch/arm/mach-imx/clk-imx6sx.c
imx_clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 50000000);
4. Add phy fix up for LAN8720 as ar8031 does
193 #define PHY_ID_AR8031 0x004dd074
194 static void __init imx6sx_enet_phy_init(void)
195 {
196 if (IS_BUILTIN(CONFIG_PHYLIB))
197 phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
198 ar8031_phy_fixup);
199 }
200
Hi Sun,
can you please note that the reference clock is connected to ENET2_RX_CLK, do you think looks ok?
Currently I'm going to patch our custom board under uboot-imx with this pinmux.
/* mx6sx_pins.h */
MX6SX_PAD_ENET2_RX_CLK__ENET2_RX_CLK = IOMUX_PAD(0x03E4, 0x009C, 0 | IOMUX_CONFIG_SION, 0x0000, 0, NO_PAD_CTRL)
/* board pinmux */
#define GPIO_FEC1_PHY_RESET IMX_GPIO_NR(2, 7)
static iomux_v3_cfg_t const fec1_pads[] = {
MX6SX_PAD_ENET1_MDC__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_MDIO__ENET1_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_CRS__GPIO2_IO_7 | MUX_PAD_CTRL(NO_PAD_CTRL),
MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_RX_CLK__ENET2_RX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_TX_CLK__GPIO2_IO_9 | MUX_PAD_CTRL(ENET_PAD_CTRL),
};
Thanks in advance,
Roberto Fichera.
Which BSP you are using?
i.MXSX is L3.10.53_1.1.0 and later.
I'm using yocto fido fully updated. u-boot is imx version.
If you use the freescale release. Now the pin is handled by device tree.
Could not have the following array to configure the iomux.
Please use the freescale BSP.
static iomux_v3_cfg_t const fec1_pads[] = {
MX6SX_PAD_ENET1_MDC__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_MDIO__ENET1_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_CRS__GPIO2_IO_7 | MUX_PAD_CTRL(NO_PAD_CTRL),
MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_RX_CLK__ENET2_RX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_TX_CLK__GPIO2_IO_9 | MUX_PAD_CTRL(ENET_PAD_CTRL),
};
Sorry but I guess you are referring to the linux kernel and not regarding u-boot. I'm currently using the last u-boot-imx version you will find in L3.14.28_1.0.0_ga release. Here the my git log:
* 88123ea - (HEAD, tag: rel_imx_3.14.28_1.0.0_ga) MLK-10215 Add elan init in i.MX6SL-EVK board (5 months ago) <Haibo Chen>
* 1d4e7b2 - MLK-10134 imx: mx6dqarm2: Add MX6DQ PoP validation board support (6 months ago) <Ye.Li>
* cd67d51 - MA-6048 Correct word in uboot log for android recovery mode (7 months ago) <guoyin.chen>
* 9045626 - MLK-10035-2: supports NAND chips with oob size up to 744 byte (7 months ago) <Allen Xu>
[...]
The changes you are talking above seems related to the linux kernel not u-boot as I've requested. By the way my current pinmux settings is:
static iomux_v3_cfg_t const fec1_pads[] = {
MX6SX_PAD_ENET1_MDC__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_MDIO__ENET1_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_CRS__GPIO2_IO_7 | MUX_PAD_CTRL(NO_PAD_CTRL),
MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_RX_CLK__ENET1_RX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_RX_CLK__ENET2_RX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_PAD_CTRL),
};
we are actually fixing the RX_CLK vs TX_CLK issue by a patch but we want to enable both ENET1/2
ref clocks in order to feed the clock to LAN8720 pin, so I've this fec initialization code:
static int setup_fec(int fec_id)
{
struct iomuxc_gpr_base_regs *const iomuxc_gpr_regs = (struct iomuxc_gpr_base_regs *) IOMUXC_GPR_BASE_ADDR;
int ret;
/* Use 50MHz anatop REF_CLK1/2 for both ENET1/2, clear gpr1[13:14], gpr1[17:18]*/
clrsetbits_le32(&iomuxc_gpr_regs->gpr[1], IOMUX_GPR1_FEC1_MASK, 0);
clrsetbits_le32(&iomuxc_gpr_regs->gpr[1], IOMUX_GPR1_FEC2_MASK, 0);
ret = enable_fec_anatop_clock(0, ENET_50MHz);
ret |= enable_fec_anatop_clock(1, ENET_50MHz);
if (ret)
return ret;
return 0;
}
But we don't see anything on the ENET2_TX_CLK pin right now. Any idea how to get both clocks up and running?
Cheers,
Roberto Fichera.
In the referece design, the hardware is shared MDIO/MDC.
Could you please check you hardware and also read the phy id to confirm which phy you are controlling?
Currently I'm not able to read the phy id. The RX/TX_CLK is not present, hence the MDIO is transmitting all "1"s.
for the RMII, the clock should be provided by the transmit side.
And please make sure, the pad configure as SION to loop back.
The RX side clock should provide by the phy.
My code actually is the following:
arch/arm/include/include/asm/arch-mx6/mx6sx_pins.h has the following changes:
MX6SX_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 = IOMUX_PAD(0x03D8, 0x0090, 1 | IOMUX_CONFIG_SION, 0x0760, 1, 0),
MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 = IOMUX_PAD(0x03E8, 0x00A0, 1 | IOMUX_CONFIG_SION, 0x076C, 1, 0),
board specific code looks:
#define ENET_PAD_CTRL (PAD_CTL_PUS_100K_UP | PAD_CTL_PUE | \
PAD_CTL_SPEED_HIGH | \
PAD_CTL_DSE_48ohm | PAD_CTL_SRE_FAST)
#define ENET_CLK_PAD_CTRL (PAD_CTL_SPEED_MED | \
PAD_CTL_DSE_120ohm | PAD_CTL_SRE_FAST)
#define ENET_RX_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
PAD_CTL_SPEED_HIGH | PAD_CTL_SRE_FAST)
#define GPIO_FEC1_PHY_RESET IMX_GPIO_NR(2, 7)
static iomux_v3_cfg_t const fec1_pads[] = {
MX6SX_PAD_ENET1_MDC__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_MDIO__ENET1_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_RX_CLK__ENET1_REF_CLK_25M | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_PAD_CTRL),
/* ENET PHY Reset */
MX6SX_PAD_ENET2_CRS__GPIO2_IO_7 | MUX_PAD_CTRL(NO_PAD_CTRL),
};
....
static int voneus_enable_fec_anatop_clock(enum enet_freq freq)
{
extern struct mxc_ccm_reg *imx_ccm;
u32 reg = 0;
s32 timeout = 100000;
if (freq < ENET_25MHz || freq > ENET_125MHz)
return -EINVAL;
reg = readl(&imx_ccm->analog_pll_enet);
reg &= ~(BM_ANADIG_PLL_ENET_DIV_SELECT|BM_ANADIG_PLL_ENET2_DIV_SELECT);
reg |= BF_ANADIG_PLL_ENET_DIV_SELECT(freq) | BF_ANADIG_PLL_ENET2_DIV_SELECT(freq);
if ((reg & BM_ANADIG_PLL_ENET_POWERDOWN) ||
(!(reg & BM_ANADIG_PLL_ENET_LOCK))) {
reg &= ~BM_ANADIG_PLL_ENET_POWERDOWN;
writel(reg, &imx_ccm->analog_pll_enet);
while (timeout--) {
if (readl(&imx_ccm->analog_pll_enet) & BM_ANADIG_PLL_ENET_LOCK)
break;
}
if (timeout < 0) {
printf("FEC MXC: %s:timeout\n", __func__);
return -ETIMEDOUT;
}
}
/* Enable FEC clock */
reg |= BM_ANADIG_PLL_ENET_ENABLE|BM_ANADIG_PLL_ENET2_ENABLE;
reg &= ~BM_ANADIG_PLL_ENET_BYPASS;
#ifdef CONFIG_FEC_MXC_25M_REF_CLK
reg |= BM_ANADIG_PLL_ENET_REF_25M_ENABLE;
#endif
writel(reg, &imx_ccm->analog_pll_enet);
return 0;
}
static int probe_lan8720(bd_t *bd, int dev_id, int phy_id, uint32_t addr)
{
uint32_t base_mii;
struct mii_dev *bus = NULL;
#ifdef CONFIG_PHYLIB
struct phy_device *phydev = NULL;
#endif
int ret;
base_mii = addr;
printf("eth_init: fec_probe(bd, %i, %i) @ %08x\n", dev_id, phy_id, addr);
bus = fec_get_miibus(base_mii, dev_id);
if (!bus)
return -ENOMEM;
#ifdef CONFIG_PHYLIB
phydev = phy_find_by_mask(bus, 1 << phy_id, PHY_INTERFACE_MODE_RMII);
if (!phydev) {
free(bus);
return -ENOMEM;
}
ret = fec_probe(bd, dev_id, addr, bus, phydev);
#else
ret = fec_probe(bd, dev_id, addr, bus, phy_id);
#endif
if (ret) {
#ifdef CONFIG_PHYLIB
free(phydev);
#endif
free(bus);
}
return ret;
}
int board_eth_init(bd_t *bis)
{
struct iomuxc_gpr_base_regs *const iomuxc_gpr_regs = (struct iomuxc_gpr_base_regs *) IOMUXC_GPR_BASE_ADDR;
int ret;
int reg;
imx_iomux_v3_setup_multiple_pads(fec1_pads, ARRAY_SIZE(fec1_pads));
gpio_direction_output(GPIO_FEC1_PHY_RESET, 0);
reg = readl(&iomuxc_gpr_regs->gpr[1]);
/* reset ENET1/2_TX_CLK_DIR gpr1[14:13] to set reference clock driven by ref_enetpll0/1
* Clock is output to pins via IOMUX ENET_REF_CLK1/2
*/
reg &= ~(IOMUX_GPR1_FEC1_CLOCK_MUX2_SEL_MASK|IOMUX_GPR1_FEC2_CLOCK_MUX2_SEL_MASK);
/* set ENET1/2_TX_CLK_DIR gpr1[18:17] to enable output driver when ENET1/2_TX_CLK when in ALT1 */
reg |= IOMUX_GPR1_FEC1_CLOCK_MUX1_SEL_MASK|IOMUX_GPR1_FEC2_CLOCK_MUX1_SEL_MASK;
writel(reg, &iomuxc_gpr_regs->gpr[1]);
ret = voneus_enable_fec_anatop_clock(ENET_50MHz);
enable_enet_clock();
mdelay(30);
gpio_set_value(GPIO_FEC1_PHY_RESET, 1);
mdelay(100);
ret = probe_lan8720(bis, CONFIG_FEC_ENET_DEV, CONFIG_FEC_MXC_PHYADDR, IMX_FEC_BASE);
if (ret)
printf("FEC MXC: %s:failed (%0x)\n", __func__, ret);
return ret;
}
int board_phy_config(struct phy_device *phydev)
{
if (phydev->drv->config)
phydev->drv->config(phydev);
return 0;
}
I want to reply myself because finally I've got it working and now the PHY is finally recognized correctly!
U-Boot 2014.04-imx_v2014.04_3.14.28_1.0.0_ga+g88123ea (Aug 05 2015 - 16:44:08)
CPU: Freescale i.MX6SX rev1.2 at 792 MHz
CPU: Temperature 35 C, calibration data: 0x5c553569
Reset cause: POR
Board: Domus iMX6SX (ID:e301dab51823b1d4)
I2C: ready
DRAM: 512 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Found PFUZE200! deviceid 0x1, revid 0x21
mmc0 is current device
FEC0 connected to SMSC LAN8710/LAN8720
FEC0
Warning: failed to set MAC address
Normal Boot
Hit any key to stop autoboot: 0
=>
Hi Roberto,
I've exactly the same config as you apparently.
Did you make it works finally ? (with 50MHz generation and internal loopack)
Can you explain me U-Boot and linux configurations ?
I actually can generate 50MHz on Ref_clk and so the MDIO is OK but the RMII (ping/data) seems KO.
I think it's only a loopback issue but I'm quite lost between GPR1, MUX, ANALOG_PLL, ENET registers .....
Can you help me please (again ;-) ) ?
Ok, it seems that it was only missing MUX_MODE_SION in Muxing :
#define MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_PAD_CTRL) | MUX_MODE_SION,
Now I'm able to send packet ... but RX doesn't work because the ENET_RX_EN signal is not wired on my board :-/
I copied my design from an iMX6Solo and it seems that RX_EN signal is now muxed on RX_CTL pad instead of CRS pad.
I need to wait the second board version .... :-(
Hi Martin,
Once patched the PCB but keeping the clocks from the second MAC I was able to progress a bit. uboot was patched accordingly with such particular clock wiring. The interface was able to acquire a DHCP address but pinging never worked. Due to that I haven't invested much time to check it, I have preferred to complete my tests with the rest of the peripherals and wait a new PCB version with the right wiring.