//========================================================================== // // devs_eth_arm_tx51.inl // // Board ethernet I/O definitions. // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. // at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //=========================================================================== #include // CYGNUM_HAL_INTERRUPT_ETHR #include #include #ifdef CYGPKG_REDBOOT #include #ifdef CYGSEM_REDBOOT_FLASH_CONFIG #include #include #endif #endif #ifdef __WANT_DEVS #ifdef CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0 #ifdef CYGPKG_DEVS_ETH_PHY static char mxc_fec_name[] = "mxc_fec"; #define MX51_GPIO_ADDR(bank) (GPIO1_BASE_ADDR + (((bank) - 1) << 14)) #define FEC_POWER_GPIO 1, 3 #define FEC_RESET_GPIO 2, 14 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE // // Verify that the given ESA is valid for this platform // static char oui[3] = CYGDAT_DEVS_ETH_ARM_TX51KARO_OUI; bool cyg_plf_redboot_esa_validate(unsigned char *val) { return (val[0] == oui[0]) && (val[1] == oui[1]) && (val[2] == oui[2]); } #endif extern int tx51_mac_addr_program(unsigned char mac_addr[ETHER_ADDR_LEN]); static inline void tx51_write_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset, CYG_WORD32 val) { if (net_debug) { diag_printf("Changing reg %08x from %08x to %08x\n", base_addr + offset, readl(base_addr + offset), val); } HAL_WRITE_UINT32(base_addr + offset, val); } static inline CYG_WORD32 tx51_read_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset) { CYG_WORD32 val; HAL_READ_UINT32(base_addr + offset, val); if (net_debug) diag_printf("Read %08x from reg %08x\n", val, base_addr + offset); return val; } static inline void tx51_set_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset, CYG_WORD32 set_mask, CYG_WORD32 clr_mask) { CYG_WORD32 val; HAL_READ_UINT32(base_addr + offset, val); if (net_debug) diag_printf("Changing reg %08x from %08x to %08x\n", base_addr + offset, val, (val & ~clr_mask) | set_mask); val = (val & ~clr_mask) | set_mask; HAL_WRITE_UINT32(base_addr + offset, val); } static struct tx51_gpio_setup { cyg_uint32 iomux_addr; cyg_uint8 on_func; cyg_uint8 off_func; cyg_uint8 grp; cyg_uint8 shift; } tx51_fec_gpio_data[] = { /* iomux reg offset, func, gpgrp, */ /* gpiofn, gpshift, */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS3, 0x12, 0x13, 3, 19, }, /* MDC */ { IOMUXC_SW_MUX_CTL_PAD_EIM_EB2, 0x13, 0x11, 2, 22, }, /* MDIO */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_RB3, 0x11, 0x13, 3, 11, }, /* RXC */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_D11, 0x12, 0x13, 3, 29, }, /* RDV */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_D9, 0x12, 0x13, 3, 31, }, /* RXD0 */ { IOMUXC_SW_MUX_CTL_PAD_EIM_EB3, 0x13, 0x11, 2, 23, }, /* RXD1 */ { IOMUXC_SW_MUX_CTL_PAD_EIM_CS2, 0x13, 0x11, 2, 27, }, /* RXD2 */ { IOMUXC_SW_MUX_CTL_PAD_EIM_CS3, 0x13, 0x11, 2, 28, }, /* RXD3 */ { IOMUXC_SW_MUX_CTL_PAD_EIM_CS4, 0x13, 0x11, 2, 29, }, /* RX_ER */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_RDY_INT, 0x11, 0x13, 3, 24, }, /* TXC */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS7, 0x11, 0x13, 3, 23, }, /* TXE */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_D8, 0x12, 0x13, 4, 0, }, /* TXD0 */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS4, 0x12, 0x13, 3, 20, }, /* TXD1 */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS5, 0x12, 0x13, 3, 21, }, /* TXD2 */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS6, 0x12, 0x13, 3, 22, }, /* TXD3 */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_RB2, 0x11, 0x13, 3, 10, }, /* COL */ { IOMUXC_SW_MUX_CTL_PAD_EIM_CS5, 0x13, 0x11, 2, 30, }, /* CRS */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS2, 0x13, 0x13, 3, 18, }, /* TX_ER */ }; static struct tx51_gpio_setup tx51_fec_pwr_pins[] = { { IOMUXC_SW_MUX_CTL_PAD_EIM_A20, 0x11, 0x11, 2, 14, }, /* PHY reset */ { IOMUXC_SW_MUX_CTL_PAD_GPIO1_3, 0x10, 0x10, 1, 3, }, /* PHY power enable */ }; static struct tx51_gpio_setup tx51_fec_strap_pins[] = { { IOMUXC_SW_MUX_CTL_PAD_GPIO1_3, 0x10, 0x10, 1, 3, }, /* PHY Power enable */ { IOMUXC_SW_MUX_CTL_PAD_NANDF_D9, 0x12, 0x13, 3, 31, }, /* Mode[0] */ { IOMUXC_SW_MUX_CTL_PAD_EIM_EB3, 0x13, 0x11, 2, 23, }, /* Mode[1] */ { IOMUXC_SW_MUX_CTL_PAD_EIM_CS2, 0x13, 0x11, 2, 27, }, /* Mode[2] */ { IOMUXC_SW_MUX_CTL_PAD_EIM_CS3, 0x13, 0x11, 2, 28, }, /* nINTSEL */ }; static inline void tx51_phy_power_off(void) { int i; if (net_debug) diag_printf("Switching PHY POWER off\n"); #if 1 for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) { struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i]; if (net_debug) diag_printf("%s: GPIO%d_%d[%d] is %d\n", __FUNCTION__, gs->grp, gs->shift, i, gpio_tst_bit(gs->grp, gs->shift)); } #endif /* deassert all pins attached to the PHY */ for (i = 0; i < NUM_ELEMS(tx51_fec_pwr_pins); i++) { struct tx51_gpio_setup *gs = &tx51_fec_pwr_pins[i]; tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_DR, 0, 1 << gs->shift); tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_GDIR, 1 << gs->shift, 0); } for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) { struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i]; #if 0 tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_GDIR, 0, 1 << gs->shift); #else tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_DR, 0, 1 << gs->shift); tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_GDIR, 1 << gs->shift, 0); #endif tx51_write_reg(0, gs->iomux_addr, gs->off_func); } for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) { struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i]; if (gpio_tst_bit(gs->grp, gs->shift)) { diag_printf("%s: GPIO%d_%d[%d] is not low\n", __FUNCTION__, gs->grp, gs->shift, i); } } if (net_debug) diag_printf("PHY POWER off done\n"); } static bool mxc_fec_init(struct cyg_netdevtab_entry *tab); static bool tx51_fec_init(struct cyg_netdevtab_entry *tab) { #if 1 cyg_bool esa_set; int ok; /* Check, whether MAC address is enabled */ ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, "fec_esa", &esa_set, CONFIG_BOOL); #if 0 ok |= 0; //esa_set |= ok; net_debug |= 1; #endif if (!(ok && esa_set)) { diag_printf("FEC disabled; set fec_esa=true to enable networking\n"); return false; } #endif return mxc_fec_init(tab); } static void tx51_fec_phy_init(void) { int i; int phy_reset_delay = 100; int dbg = net_debug; #if 0 net_debug |= 1; #endif /* * make sure the ETH PHY strap pins are pulled to the right voltage * before deasserting the PHY reset GPIO */ /* assert FEC PHY Reset (GPIO2_14) and switch PHY power on (GPIO1_3) */ #if 0 tx51_phy_power_off(); #endif if (!gpio_tst_bit(1, 3)) { if (0 || net_debug) diag_printf("Switching PHY POWER on\n"); gpio_clr_bit(2, 14); gpio_set_bit(1, 3); /* wait for 22ms for LAN8700 to power up */ phy_reset_delay = 22000; #if 1 if (!gpio_tst_bit(1, 3)) { diag_printf("**Failed to switch PHY power on: GPIO1_PSR[%08lx]=%08x\n", MX51_GPIO_ADDR(1) + GPIO_PSR, tx51_read_reg(MX51_GPIO_ADDR(1), GPIO_PSR)); } #endif #if 1 if (gpio_tst_bit(2, 14)) { diag_printf("**Failed to assert PHY reset: GPIO2_PSR[%08lx]=%08x\n", MX51_GPIO_ADDR(2) + GPIO_PSR, tx51_read_reg(MX51_GPIO_ADDR(2), GPIO_PSR)); } #endif } else { if (0 || net_debug) diag_printf("Asserting PHY RESET\n"); gpio_clr_bit(2, 14); #if 1 if (gpio_tst_bit(2, 14)) { diag_printf("**Failed to assert PHY reset: GPIO2_PSR[%08lx]=%08x\n", MX51_GPIO_ADDR(2) + GPIO_PSR, tx51_read_reg(MX51_GPIO_ADDR(2), GPIO_PSR)); } #endif } for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) { struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i]; int j; int strap = 0; for (j = 0; j < NUM_ELEMS(tx51_fec_strap_pins); j++) { struct tx51_gpio_setup *sp = &tx51_fec_strap_pins[j]; if (gs->grp == sp->grp && gs->shift == sp->shift) { strap = 1; break; } } if (strap) { gpio_set_bit(gs->grp, gs->shift); if (net_debug) diag_printf("Setting GPIO%d_%d[%d] high\n", gs->grp, gs->shift, i); } else { gpio_clr_bit(gs->grp, gs->shift); if (net_debug) diag_printf("Setting GPIO%d_%d[%d] low\n", gs->grp, gs->shift, i); } tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_GDIR, 1 << gs->shift, 0); tx51_write_reg(0, gs->iomux_addr, gs->off_func); } #if 1 /* configure FEC strap pins to their required values */ for (i = 0; i < NUM_ELEMS(tx51_fec_strap_pins); i++) { struct tx51_gpio_setup *gs = &tx51_fec_strap_pins[i]; if (net_debug) diag_printf("Asserting GPIO%d_%d\n", gs->grp, gs->shift); tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_GDIR, 1 << gs->shift, 0); tx51_set_reg(MX51_GPIO_ADDR(gs->grp), GPIO_DR, 1 << gs->shift, 0); tx51_write_reg(0, gs->iomux_addr, gs->off_func); gpio_set_bit(gs->grp, gs->shift); if (!gpio_tst_bit(gs->grp, gs->shift)) { diag_printf("**Failed to assert GPIO%d_%d: GPIO%d_PSR[%08lx]=%08x\n", gs->grp, gs->shift, gs->grp, MX51_GPIO_ADDR(gs->grp) + GPIO_PSR, tx51_read_reg(MX51_GPIO_ADDR(gs->grp), GPIO_PSR)); } } #endif for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) { struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i]; int j; int strap = 0; for (j = 0; j < NUM_ELEMS(tx51_fec_strap_pins); j++) { struct tx51_gpio_setup *sp = &tx51_fec_strap_pins[j]; if (gs->grp == sp->grp && gs->shift == sp->shift) { strap = 1; break; } } if (strap) { if (!gpio_tst_bit(gs->grp, gs->shift)) { diag_printf("GPIO%d_%d[%d] is low instead of high\n", gs->grp, gs->shift, i); } } else { if (gpio_tst_bit(gs->grp, gs->shift)) { diag_printf("GPIO%d_%d[%d] is high instead of low\n", gs->grp, gs->shift, i); } } } /* wait for 100us according to LAN8700 spec. before ... */ HAL_DELAY_US(phy_reset_delay); /* ... deasserting FEC PHY reset */ if (0 || net_debug) diag_printf("Releasing PHY RESET\n"); gpio_set_bit(2, 14); if (!gpio_tst_bit(2, 14)) { diag_printf("**Failed to release PHY reset\n"); } /* configure all FEC pins to their required functions */ for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) { struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i]; tx51_write_reg(0, gs->iomux_addr, gs->on_func); HAL_DELAY_US(10000); } net_debug = dbg; } ETH_PHY_REG_LEVEL_ACCESS_FUNS(eth0_phy, tx51_fec_phy_init, mxc_fec_phy_reset, mxc_fec_phy_write, mxc_fec_phy_read); cyg_bool _tx51_provide_fec_esa(unsigned char *addr) { cyg_bool enabled; int ok; ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, "fec_esa", &enabled, CONFIG_BOOL); if (ok && enabled) { #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE cyg_uint8 addr2[ETHER_ADDR_LEN]; addr[0] = readl(SOC_FEC_MAC_BASE + 0x14); addr[1] = readl(SOC_FEC_MAC_BASE + 0x10); addr[2] = readl(SOC_FEC_MAC_BASE + 0xC); addr[3] = readl(SOC_FEC_MAC_BASE + 0x8); addr[4] = readl(SOC_FEC_MAC_BASE + 0x4); addr[5] = readl(SOC_FEC_MAC_BASE + 0x0); if (cyg_plf_redboot_esa_validate(addr)) { diag_printf("Ethernet FEC MAC address from fuse bank: "); diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, "fec_esa_data", addr2, CONFIG_ESA); if (memcmp(addr, addr2, sizeof(addr)) != 0) { CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_SET, "fec_esa_data", addr, CONFIG_ESA); } #ifdef SOC_MAC_ADDR_LOCK_FUSE if ((readl(IIM_BASE_ADDR + 0x800 + SOC_MAC_ADDR_FUSE_BANK * 0x400 + SOC_MAC_ADDR_LOCK_FUSE * 4) & SOC_MAC_ADDR_LOCK_BIT) == 0) { tx51_mac_addr_program(addr); } #endif // SOC_MAC_ADDR_LOCK_FUSE return true; } #endif // CYGSEM_REDBOOT_PLF_ESA_VALIDATE CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, "fec_esa_data", addr, CONFIG_ESA); diag_printf("Ethernet FEC MAC address from fconfig: "); diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE if (cyg_plf_redboot_esa_validate(addr)) { tx51_mac_addr_program(addr); return true; } diag_printf("** Error: Invalid MAC address: "); diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); writel(addr[0], SOC_FEC_MAC_BASE + 0x14); writel(addr[1], SOC_FEC_MAC_BASE + 0x10); writel(addr[2], SOC_FEC_MAC_BASE + 0xC); writel(addr[3], SOC_FEC_MAC_BASE + 0x8); writel(addr[4], SOC_FEC_MAC_BASE + 0x4); writel(addr[5], SOC_FEC_MAC_BASE + 0x0); #ifdef SOC_MAC_ADDR_LOCK_FUSE if ((readl(IIM_BASE_ADDR + 0x800 + SOC_MAC_ADDR_FUSE_BANK * 0x400 + SOC_MAC_ADDR_LOCK_FUSE * 4) & SOC_MAC_ADDR_LOCK_BIT) == 0) { diag_printf("Use 'fconfig fec_esa_data' to set the MAC address\n"); return false; } else { diag_printf("Using MAC address from fconfig\n"); } #else diag_printf("Using MAC address from fconfig\n"); #endif // SOC_MAC_ADDR_LOCK_FUSE #endif // CYGSEM_REDBOOT_PLF_ESA_VALIDATE return true; } return false; } static mxc_fec_priv_t mxc_fec_private = { .phy = ð0_phy, // PHY access routines .provide_esa = _tx51_provide_fec_esa, }; ETH_DRV_SC(mxc_fec_sc, &mxc_fec_private, // Driver specific data mxc_fec_name, mxc_fec_start, mxc_fec_stop, mxc_fec_control, mxc_fec_can_send, mxc_fec_send, mxc_fec_recv, mxc_fec_deliver, // "pseudoDSR" called from fast net thread mxc_fec_poll, // poll function, encapsulates ISR and DSR mxc_fec_int_vector); NETDEVTAB_ENTRY(mxc_fec_netdev, mxc_fec_name, tx51_fec_init, &mxc_fec_sc); #endif #if defined(CYGPKG_REDBOOT) && defined(CYGSEM_REDBOOT_FLASH_CONFIG) RedBoot_config_option("Set FEC network hardware address [MAC]", fec_esa, ALWAYS_ENABLED, true, CONFIG_BOOL, false ); RedBoot_config_option("FEC network hardware address [MAC]", fec_esa_data, "fec_esa", true, CONFIG_ESA, 0 ); #endif // CYGPKG_REDBOOT && CYGSEM_REDBOOT_FLASH_CONFIG #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // Note that this section *is* active in an application, outside RedBoot, // where the above section is not included. #endif // CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT #endif // CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0 #endif // __WANT_DEVS