--- /dev/null
+//==========================================================================
+//
+// devs_eth_arm_tx25.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 <cyg/hal/hal_intr.h> // CYGNUM_HAL_INTERRUPT_ETHR
+#include <cyg/hal/hal_if.h>
+
+#ifdef CYGPKG_REDBOOT
+#include <pkgconf/redboot.h>
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <redboot.h>
+#include <flash_config.h>
+#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 OCR_SHIFT(bit) (((bit) * 2) % 32)
+#define OCR_MASK(bit) (3 << (OCR_SHIFT(bit)))
+#define OCR_VAL(bit,val) (((val) << (OCR_SHIFT(bit))) & (OCR_MASK(bit)))
+#define GPR_SHIFT(bit) (bit)
+#define GPR_MASK(bit) (1 << (GPR_SHIFT(bit)))
+#define GPR_VAL(bit,val) (((val) << (GPR_SHIFT(bit))) & (GPR_MASK(bit)))
+
+#ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
+//
+// Verify that the given ESA is valid for this platform
+//
+static char oui[3] = CYGDAT_DEVS_ETH_ARM_TX25KARO_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 tx25_mac_addr_program(unsigned char mac_addr[ETHER_ADDR_LEN]);
+
+static inline CYG_ADDRESS MX25_GPIO_ADDR(int bank)
+{
+ switch (bank) {
+ case 1:
+ return GPIO1_BASE_ADDR;
+ case 2:
+ return GPIO2_BASE_ADDR;
+ case 3:
+ return GPIO3_BASE_ADDR;
+ case 4:
+ return GPIO4_BASE_ADDR;
+ }
+ return ~0;
+}
+
+/*
+TX27 -> TX25 GPIO cross reference
+ TX27 GP Fkt GPIO Pad IOMUXC SW_PAD SW_PAD strap
+ GPIO ALT ALT OFFSET CTRL MUX option
+FEC_MDC PD9 5 0 GPIO3_5 FEC_MDC 0x1c8 0x3c0
+FEC_MDIO PD8 5 0 GPIO3_6 FEC_MDIO 0x1cc 0x3c4
+FEC_RX_CLK PD14 - - NC REGOFF: 0
+FEC_RX_DV PD13 - - NC
+FEC_RXD0 PD12 5 0 GPIO3_10 FEC_RDATA0 0x1dc 0x3d4 MODE0: 1
+FEC_RXD1 PD5 5 0 GPIO3_11 FEC_RDATA1 0x1e0 0x3d8 MODE1: 1
+FEC_RXD2 PD6 - - NC PULLUP MODE2: 1
+FEC_RXD3 PD7 - - NC INTSEL: 0
+FEC_RX_ER PD4 5 5 GPIO4_10 D10 0x09c 0x294
+FEC_TX_CLK PD11 5 0 GPIO3_13 FEC_TX_CLK 0x1e8 0x3e0
+FEC_TX_EN PF23 5 0 GPIO3_9 FEC_TX_EN 0x1d8 0x3d0
+FEC_TXD0 PD0 5 0 GPIO3_7 FEC_TDATA0 0x1d0 0x3c8
+FEC_TXD1 PD1 5 0 GPIO3_8 FEC_TDATA1 0x1d4 0x3cc
+FEC_TXD2 PD2 - - NC
+FEC_TXD3 PD3 - - NC
+FEC_COL PD15 5 0 GPIO3_12 FEC_RX_DV 0x1e4 0x3dc RMII: 1
+FEC_CRS PD10 - - NC PHYAD4: 0
+FEC_TX_ER PD16 5 5 GPIO4_8 D12 0x094 0x28c
+ GPIO2_5 A19 0x024 0x240 0x518 FEC_RX_ER
+FEC_RESET~ PB30 5 5 GPIO4_7 D13 0x090 0x288
+FEC_ENABLE PB27 5 5 GPIO4_9 D11 0x098 0x290
+*/
+
+static inline void tx25_write_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset, CYG_WORD32 val)
+{
+ if (net_debug) diag_printf("Writing %08x to reg %08x\n", val, base_addr + offset);
+ HAL_WRITE_UINT32(base_addr + offset, val);
+}
+
+static inline CYG_WORD32 tx25_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 tx25_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 tx25_gpio_setup {
+ cyg_uint16 iomux_addr;
+ cyg_uint8 on_func;
+ cyg_uint8 off_func;
+ cyg_uint8 grp;
+ cyg_uint8 shift;
+} tx25_fec_gpio_data[] = {
+ /* iomux, func, gpfn, gpgrp, gpshift */
+ { 0x1c8, 0, 0x15, 3, 5, },
+ { 0x1cc, 0, 0x15, 3, 6, },
+ { 0x1dc, 0, 0x15, 3, 10, },
+ { 0x1e0, 0, 0x15, 3, 11, },
+ { 0x09c, 0x85, 5, 4, 10, },
+ { 0x1e8, 0, 0x15, 3, 13, },
+ { 0x1d8, 0, 0x15, 3, 9, },
+ { 0x1d0, 0, 0x15, 3, 7, },
+ { 0x1d4, 0, 0x15, 3, 8, },
+ { 0x1e4, 0x80, 0x15, 3, 12, },
+ { 0x024, 0x05, 0x05, 2, 5, }, /* RX_ER signal; make sure it's a GPIO _without_ SION! */
+ { 0x094, 0x85, 5, 4, 8, },
+ { 0x090, 5, 5, 4, 7, },
+ { 0x098, 5, 5, 4, 9, },
+};
+
+static struct tx25_gpio_setup tx25_fec_strap_pins[] = {
+ { 0x1dc, 0, 0x15, 3, 10, },
+ { 0x1e0, 0, 0x15, 3, 11, },
+ { 0x1e4, 0, 0x15, 3, 12, },
+};
+
+static inline void tx25_phy_power_off(void)
+{
+ int i;
+
+ if (net_debug) diag_printf("Switching PHY POWER off\n");
+
+#if 1
+ for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
+ struct tx25_gpio_setup *gs = &tx25_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(tx25_fec_gpio_data); i++) {
+ struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
+
+ tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
+ gs->off_func);
+ if (gs->on_func & 0x80) {
+ /* configure as input */
+ tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
+ GPIO_GDIR, 0, 1 << gs->shift);
+ } else {
+ /* configure as output */
+ tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
+ GPIO_DR, 0, 1 << gs->shift);
+ tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
+ GPIO_GDIR, 1 << gs->shift, 0);
+ }
+ tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
+ gs->off_func);
+ }
+ for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
+ struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
+
+ if (!(gs->on_func & 0x80) && gpio_tst_bit(gs->grp, gs->shift)) {
+ if (net_debug) 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 tx25_fec_init(struct cyg_netdevtab_entry *tab)
+{
+ 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 (!(ok && esa_set)) {
+ diag_printf("FEC disabled; set fec_esa=true to enable networking\n");
+ tx25_phy_power_off();
+ return false;
+ }
+ /* call init function in devs/eth/fec/current/if_fec.c */
+ return mxc_fec_init(tab);
+}
+
+static void tx25_fec_phy_init(void)
+{
+ int i;
+ int phy_reset_delay = 100;
+
+ /*
+ * make sure the ETH PHY strap pins are pulled to the right voltage
+ * before deasserting the PHY reset GPIO
+ * REGOFF: PD14
+ * RMII: PD15
+ * nINTSEL: PD7
+ * MODE0: PD12
+ * MODE1: PD5
+ * MODE2: PD6
+ * PHYAD0: -
+ * PHYAD1: GND
+ * PHYAD2: GND
+ * PHYAD3: -
+ * PHYAD4: PD10
+ */
+ // assert FEC PHY Reset (PB30) and switch PHY power on
+ /* PB22, PB27, PB30 => GPIO out */
+#if 0
+ tx25_phy_power_off();
+#endif
+#if 0
+ tx25_write_reg(IOMUXC_BASE_ADDR, IOMUXC_GPIO1_7, 0x11);
+ tx25_write_reg(IOMUXC_BASE_ADDR, IOMUXC_NANDF_CS1, 0x14);
+#endif
+#if 0
+ while (1) {
+#if 0
+ gpio_set_bit(4, 9);
+#else
+ tx25_set_reg(MX25_GPIO_ADDR(4), GPIO_DR, 1 << 9, 0);
+#endif
+ tx25_read_reg(MX25_GPIO_ADDR(4), GPIO_DR);
+ HAL_DELAY_US(1000000);
+#if 0
+ gpio_clr_bit(4, 9);
+#else
+ tx25_set_reg(MX25_GPIO_ADDR(4), GPIO_DR, 0, 1 << 9);
+#endif
+ tx25_read_reg(MX25_GPIO_ADDR(4), GPIO_DR);
+ HAL_DELAY_US(1000000);
+ }
+#endif
+ /* Switch PHY power on and assert PHY reset */
+ if (net_debug) diag_printf("Switching PHY POWER on\n");
+ gpio_clr_bit(4, 7);
+ gpio_set_bit(4, 9);
+
+ /* wait for 22ms for LAN8700 to power up */
+ phy_reset_delay = 22000;
+
+ /* configure FEC strap pins to their required values */
+ for (i = 0; i < NUM_ELEMS(tx25_fec_strap_pins); i++) {
+ struct tx25_gpio_setup *gs = &tx25_fec_strap_pins[i];
+
+ if (net_debug) diag_printf("Asserting GPIO%d_%d\n", gs->grp,
+ gs->shift);
+#if 0
+ tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
+ GPIO_GDIR, 1 << gs->shift, 0);
+ tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
+ GPIO_DR, 1 << gs->shift, 0);
+ tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
+ gs->off_func);
+#else
+ gpio_set_bit(gs->grp, gs->shift);
+#endif
+ }
+#if 0
+ for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
+ struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
+ int j;
+ int strap = 0;
+
+ for (j = 0; j < NUM_ELEMS(tx25_fec_strap_pins); j++) {
+ struct tx25_gpio_setup *sp = &tx25_fec_strap_pins[j];
+
+ if (gs->grp == sp->grp && gs->shift == sp->shift) {
+ strap = 1;
+ break;
+ }
+ }
+ if (strap || gs->on_func & 0x80) {
+ if (!gpio_tst_bit(gs->grp, gs->shift)) {
+ if (net_debug) 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)) {
+ if (net_debug) diag_printf("GPIO%d_%d[%d] is high instead of low\n",
+ gs->grp, gs->shift, i);
+ }
+ }
+ }
+#endif
+ /* wait for 100us according to LAN8700 spec. before ... */
+ HAL_DELAY_US(phy_reset_delay);
+
+ /* ... deasserting FEC PHY reset */
+ if (net_debug) diag_printf("Releasing PHY RESET\n");
+ tx25_set_reg(MX25_GPIO_ADDR(4), GPIO_DR, 1 << 7, 0);
+#if 0
+ for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
+ struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
+ int j;
+ int strap = 0;
+
+ for (j = 0; j < NUM_ELEMS(tx25_fec_strap_pins); j++) {
+ struct tx25_gpio_setup *sp = &tx25_fec_strap_pins[j];
+
+ if (gs->grp == sp->grp && gs->shift == sp->shift) {
+ strap = 1;
+ break;
+ }
+ }
+ if (strap || gs->on_func & 0x80) {
+ if (!gpio_tst_bit(gs->grp, gs->shift)) {
+ if (net_debug) 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)) {
+ if (net_debug) diag_printf("GPIO%d_%d[%d] is high instead of low\n",
+ gs->grp, gs->shift, i);
+ }
+ }
+ }
+#endif
+ /* configure all FEC pins to their required functions */
+ for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
+ struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
+
+ tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
+ gs->on_func & ~0x80);
+ }
+}
+
+ETH_PHY_REG_LEVEL_ACCESS_FUNS(eth0_phy,
+ tx25_fec_phy_init,
+ mxc_fec_phy_reset,
+ mxc_fec_phy_write,
+ mxc_fec_phy_read);
+
+#define SOC_MAC_ADDR_LOCK_BIT 2
+
+cyg_bool _tx25_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_MAC_ADDR_BASE + 0x0);
+ addr[1] = readl(SOC_MAC_ADDR_BASE + 0x4);
+ addr[2] = readl(SOC_MAC_ADDR_BASE + 0x8);
+ addr[3] = readl(SOC_MAC_ADDR_BASE + 0xC);
+ addr[4] = readl(SOC_MAC_ADDR_BASE + 0x10);
+ addr[5] = readl(SOC_MAC_ADDR_BASE + 0x14);
+
+ 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_BIT
+ if ((readl(SOC_MAC_ADDR_BASE - 0x68) & SOC_MAC_ADDR_LOCK_BIT) == 0) {
+ tx25_mac_addr_program(addr);
+ }
+#endif // SOC_MAC_ADDR_LOCK_BIT
+ 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)) {
+ tx25_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]);
+
+#ifdef SOC_MAC_ADDR_LOCK_BIT
+ if ((readl(SOC_MAC_ADDR_BASE - 0x68) & 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_BIT
+#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 = _tx25_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,
+ tx25_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