udoo: Add ethernet support (FEC + Micrel KSZ9031).
authorGiuseppe Pagano <giuseppe.pagano@seco.com>
Fri, 15 Nov 2013 16:42:51 +0000 (17:42 +0100)
committerStefano Babic <sbabic@denx.de>
Thu, 28 Nov 2013 07:28:54 +0000 (08:28 +0100)
Add Ethernet and networking support on uDoo board (FEC +phy Micrel KSZ9031).
Ethernet speed is currently limited to 10/100Mbps.

Signed-off-by: Giuseppe Pagano <giuseppe.pagano@seco.com>
Tested-by: Fabio Estevam <fabio.estevam@freescale.com>
CC: Stefano Babic <sbabic@denx.de>
CC: Fabio Estevam <fabio.estevam@freescale.com>
board/udoo/udoo.c
include/configs/udoo.h
include/micrel.h

index ab7b655..3257aaf 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/iomux.h>
+#include <malloc.h>
 #include <asm/arch/mx6-pins.h>
 #include <asm/errno.h>
 #include <asm/gpio.h>
@@ -18,6 +19,9 @@
 #include <asm/arch/crm_regs.h>
 #include <asm/io.h>
 #include <asm/arch/sys_proto.h>
+#include <micrel.h>
+#include <miiphy.h>
+#include <netdev.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -25,6 +29,9 @@ DECLARE_GLOBAL_DATA_PTR;
        PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm |                 \
        PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
 
+#define ENET_PAD_CTRL  (PAD_CTL_PUS_100K_UP |                   \
+       PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS)
+
 #define USDHC_PAD_CTRL (PAD_CTL_PUS_47K_UP |                   \
        PAD_CTL_SPEED_LOW | PAD_CTL_DSE_80ohm |                 \
        PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
@@ -58,6 +65,99 @@ static iomux_v3_cfg_t const wdog_pads[] = {
        MX6_PAD_EIM_D19__GPIO3_IO19,
 };
 
+int mx6_rgmii_rework(struct phy_device *phydev)
+{
+       /*
+        * Bug: Apparently uDoo does not works with Gigabit switches...
+        * Limiting speed to 10/100Mbps, and setting master mode, seems to
+        * be the only way to have a successfull PHY auto negotiation.
+        * How to fix: Understand why Linux kernel do not have this issue.
+        */
+       phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, 0x1c00);
+
+       /* control data pad skew - devaddr = 0x02, register = 0x04 */
+       ksz9031_phy_extended_write(phydev, 0x02,
+                                  MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW,
+                                  MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0000);
+       /* rx data pad skew - devaddr = 0x02, register = 0x05 */
+       ksz9031_phy_extended_write(phydev, 0x02,
+                                  MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW,
+                                  MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0000);
+       /* tx data pad skew - devaddr = 0x02, register = 0x05 */
+       ksz9031_phy_extended_write(phydev, 0x02,
+                                  MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW,
+                                  MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0000);
+       /* gtx and rx clock pad skew - devaddr = 0x02, register = 0x08 */
+       ksz9031_phy_extended_write(phydev, 0x02,
+                                  MII_KSZ9031_EXT_RGMII_CLOCK_SKEW,
+                                  MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x03FF);
+       return 0;
+}
+
+static iomux_v3_cfg_t const enet_pads1[] = {
+       MX6_PAD_ENET_MDIO__ENET_MDIO            | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_ENET_MDC__ENET_MDC              | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_TXC__RGMII_TXC    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_TD0__RGMII_TD0    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_TD1__RGMII_TD1    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_TD2__RGMII_TD2    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_TD3__RGMII_TD3    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_TX_CTL__RGMII_TX_CTL      | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_ENET_REF_CLK__ENET_TX_CLK       | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_RXC__RGMII_RXC    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       /* RGMII reset */
+       MX6_PAD_EIM_D23__GPIO3_IO23             | MUX_PAD_CTRL(NO_PAD_CTRL),
+       /* Ethernet power supply */
+       MX6_PAD_EIM_EB3__GPIO2_IO31             | MUX_PAD_CTRL(NO_PAD_CTRL),
+       /* pin 32 - 1 - (MODE0) all */
+       MX6_PAD_RGMII_RD0__GPIO6_IO25           | MUX_PAD_CTRL(NO_PAD_CTRL),
+       /* pin 31 - 1 - (MODE1) all */
+       MX6_PAD_RGMII_RD1__GPIO6_IO27           | MUX_PAD_CTRL(NO_PAD_CTRL),
+       /* pin 28 - 1 - (MODE2) all */
+       MX6_PAD_RGMII_RD2__GPIO6_IO28           | MUX_PAD_CTRL(NO_PAD_CTRL),
+       /* pin 27 - 1 - (MODE3) all */
+       MX6_PAD_RGMII_RD3__GPIO6_IO29           | MUX_PAD_CTRL(NO_PAD_CTRL),
+       /* pin 33 - 1 - (CLK125_EN) 125Mhz clockout enabled */
+       MX6_PAD_RGMII_RX_CTL__GPIO6_IO24        | MUX_PAD_CTRL(NO_PAD_CTRL),
+};
+
+static iomux_v3_cfg_t const enet_pads2[] = {
+       MX6_PAD_RGMII_RD0__RGMII_RD0    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_RD1__RGMII_RD1    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_RD2__RGMII_RD2    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_RD3__RGMII_RD3    | MUX_PAD_CTRL(ENET_PAD_CTRL),
+       MX6_PAD_RGMII_RX_CTL__RGMII_RX_CTL      | MUX_PAD_CTRL(ENET_PAD_CTRL),
+};
+
+static void setup_iomux_enet(void)
+{
+       imx_iomux_v3_setup_multiple_pads(enet_pads1, ARRAY_SIZE(enet_pads1));
+       udelay(20);
+       gpio_direction_output(IMX_GPIO_NR(2, 31), 1); /* Power supply on */
+
+       gpio_direction_output(IMX_GPIO_NR(3, 23), 0); /* assert PHY rst */
+
+       gpio_direction_output(IMX_GPIO_NR(6, 24), 1);
+       gpio_direction_output(IMX_GPIO_NR(6, 25), 1);
+       gpio_direction_output(IMX_GPIO_NR(6, 27), 1);
+       gpio_direction_output(IMX_GPIO_NR(6, 28), 1);
+       gpio_direction_output(IMX_GPIO_NR(6, 29), 1);
+       udelay(1000);
+
+       gpio_set_value(IMX_GPIO_NR(3, 23), 1); /* deassert PHY rst */
+
+       /* Need 100ms delay to exit from reset. */
+       udelay(1000 * 100);
+
+       gpio_free(IMX_GPIO_NR(6, 24));
+       gpio_free(IMX_GPIO_NR(6, 25));
+       gpio_free(IMX_GPIO_NR(6, 27));
+       gpio_free(IMX_GPIO_NR(6, 28));
+       gpio_free(IMX_GPIO_NR(6, 29));
+
+       imx_iomux_v3_setup_multiple_pads(enet_pads2, ARRAY_SIZE(enet_pads2));
+}
+
 static void setup_iomux_uart(void)
 {
        imx_iomux_v3_setup_multiple_pads(uart2_pads, ARRAY_SIZE(uart2_pads));
@@ -77,6 +177,37 @@ int board_mmc_getcd(struct mmc *mmc)
        return 1; /* Always present */
 }
 
+int board_eth_init(bd_t *bis)
+{
+       uint32_t base = IMX_FEC_BASE;
+       struct mii_dev *bus = NULL;
+       struct phy_device *phydev = NULL;
+       int ret;
+
+       setup_iomux_enet();
+
+#ifdef CONFIG_FEC_MXC
+       bus = fec_get_miibus(base, -1);
+       if (!bus)
+               return 0;
+       /* scan phy 4,5,6,7 */
+       phydev = phy_find_by_mask(bus, (0xf << 4), PHY_INTERFACE_MODE_RGMII);
+
+       if (!phydev) {
+               free(bus);
+               return 0;
+       }
+       printf("using phy at %d\n", phydev->addr);
+       ret  = fec_probe(bis, -1, base, bus, phydev);
+       if (ret) {
+               printf("FEC MXC: %s:failed\n", __func__);
+               free(phydev);
+               free(bus);
+       }
+#endif
+       return 0;
+}
+
 int board_mmc_init(bd_t *bis)
 {
        imx_iomux_v3_setup_multiple_pads(usdhc3_pads, ARRAY_SIZE(usdhc3_pads));
@@ -94,6 +225,15 @@ int board_early_init_f(void)
        return 0;
 }
 
+int board_phy_config(struct phy_device *phydev)
+{
+       mx6_rgmii_rework(phydev);
+       if (phydev->drv->config)
+               phydev->drv->config(phydev);
+
+       return 0;
+}
+
 int board_init(void)
 {
        /* address of boot parameters */
index 78df071..b9a493c 100644 (file)
 #define CONFIG_MXC_UART
 #define CONFIG_MXC_UART_BASE           UART2_BASE
 
+/* Network support */
+
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_NET
+#define CONFIG_FEC_MXC
+#define CONFIG_MII
+#define IMX_FEC_BASE                    ENET_BASE_ADDR
+#define CONFIG_FEC_XCV_TYPE             RGMII
+#define CONFIG_ETHPRIME                 "FEC"
+#define CONFIG_FEC_MXC_PHYADDR          6
+#define CONFIG_PHYLIB
+#define CONFIG_PHY_MICREL
+#define CONFIG_PHY_MICREL_KSZ9031
+
 /* allow to overwrite serial and ethaddr */
 #define CONFIG_ENV_OVERWRITE
 #define CONFIG_CONS_INDEX              1
index e1c62d8..1d72b50 100644 (file)
 #define MII_KSZ9031_MOD_DATA_POST_INC_RW       0x8000
 #define MII_KSZ9031_MOD_DATA_POST_INC_W                0xC000
 
+#define MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW    0x4
+#define MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW     0x5
+#define MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW     0x6
+#define MII_KSZ9031_EXT_RGMII_CLOCK_SKEW       0x8
+
 struct phy_device;
 int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val);
 int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum);