1 //==========================================================================
3 // devs_eth_arm_tx25.inl
5 // Board ethernet I/O definitions.
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //===========================================================================
42 #include <cyg/hal/hal_intr.h> // CYGNUM_HAL_INTERRUPT_ETHR
43 #include <cyg/hal/hal_if.h>
46 #include <pkgconf/redboot.h>
47 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
49 #include <flash_config.h>
56 #ifdef CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0
58 #ifdef CYGPKG_DEVS_ETH_PHY
60 static char mxc_fec_name[] = "mxc_fec";
62 #define OCR_SHIFT(bit) (((bit) * 2) % 32)
63 #define OCR_MASK(bit) (3 << (OCR_SHIFT(bit)))
64 #define OCR_VAL(bit,val) (((val) << (OCR_SHIFT(bit))) & (OCR_MASK(bit)))
65 #define GPR_SHIFT(bit) (bit)
66 #define GPR_MASK(bit) (1 << (GPR_SHIFT(bit)))
67 #define GPR_VAL(bit,val) (((val) << (GPR_SHIFT(bit))) & (GPR_MASK(bit)))
69 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
71 // Verify that the given ESA is valid for this platform
73 static char oui[3] = CYGDAT_DEVS_ETH_ARM_TX25KARO_OUI;
76 cyg_plf_redboot_esa_validate(unsigned char *val)
78 return (val[0] == oui[0]) && (val[1] == oui[1]) && (val[2] == oui[2]);
82 extern int tx25_mac_addr_program(unsigned char mac_addr[ETHER_ADDR_LEN]);
84 static inline CYG_ADDRESS MX25_GPIO_ADDR(int bank)
88 return GPIO1_BASE_ADDR;
90 return GPIO2_BASE_ADDR;
92 return GPIO3_BASE_ADDR;
94 return GPIO4_BASE_ADDR;
100 TX27 -> TX25 GPIO cross reference
101 TX27 GP Fkt GPIO Pad IOMUXC SW_PAD SW_PAD strap
102 GPIO ALT ALT OFFSET CTRL MUX option
103 FEC_MDC PD9 5 0 GPIO3_5 FEC_MDC 0x1c8 0x3c0
104 FEC_MDIO PD8 5 0 GPIO3_6 FEC_MDIO 0x1cc 0x3c4
105 FEC_RX_CLK PD14 - - NC REGOFF: 0
106 FEC_RX_DV PD13 - - NC
107 FEC_RXD0 PD12 5 0 GPIO3_10 FEC_RDATA0 0x1dc 0x3d4 MODE0: 1
108 FEC_RXD1 PD5 5 0 GPIO3_11 FEC_RDATA1 0x1e0 0x3d8 MODE1: 1
109 FEC_RXD2 PD6 - - NC PULLUP MODE2: 1
110 FEC_RXD3 PD7 - - NC INTSEL: 0
111 FEC_RX_ER PD4 5 5 GPIO4_10 D10 0x09c 0x294
112 FEC_TX_CLK PD11 5 0 GPIO3_13 FEC_TX_CLK 0x1e8 0x3e0
113 FEC_TX_EN PF23 5 0 GPIO3_9 FEC_TX_EN 0x1d8 0x3d0
114 FEC_TXD0 PD0 5 0 GPIO3_7 FEC_TDATA0 0x1d0 0x3c8
115 FEC_TXD1 PD1 5 0 GPIO3_8 FEC_TDATA1 0x1d4 0x3cc
118 FEC_COL PD15 5 0 GPIO3_12 FEC_RX_DV 0x1e4 0x3dc RMII: 1
119 FEC_CRS PD10 - - NC PHYAD4: 0
120 FEC_TX_ER PD16 5 5 GPIO4_8 D12 0x094 0x28c
121 GPIO2_5 A19 0x024 0x240 0x518 FEC_RX_ER
122 FEC_RESET~ PB30 5 5 GPIO4_7 D13 0x090 0x288
123 FEC_ENABLE PB27 5 5 GPIO4_9 D11 0x098 0x290
126 static inline void tx25_write_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset, CYG_WORD32 val)
128 if (net_debug) diag_printf("Writing %08x to reg %08x\n", val, base_addr + offset);
129 HAL_WRITE_UINT32(base_addr + offset, val);
132 static inline CYG_WORD32 tx25_read_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset)
135 HAL_READ_UINT32(base_addr + offset, val);
136 if (net_debug) diag_printf("Read %08x from reg %08x\n", val, base_addr + offset);
140 static inline void tx25_set_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset,
141 CYG_WORD32 set_mask, CYG_WORD32 clr_mask)
144 HAL_READ_UINT32(base_addr + offset, val);
145 if (net_debug) diag_printf("Changing reg %08x from %08x to %08x\n",
146 base_addr + offset, val,
147 (val & ~clr_mask) | set_mask);
148 val = (val & ~clr_mask) | set_mask;
149 HAL_WRITE_UINT32(base_addr + offset, val);
152 static struct tx25_gpio_setup {
153 cyg_uint16 iomux_addr;
158 } tx25_fec_gpio_data[] = {
159 /* iomux, func, gpfn, gpgrp, gpshift */
160 { 0x1c8, 0, 0x15, 3, 5, },
161 { 0x1cc, 0, 0x15, 3, 6, },
162 { 0x1dc, 0, 0x15, 3, 10, },
163 { 0x1e0, 0, 0x15, 3, 11, },
164 { 0x09c, 0x85, 5, 4, 10, },
165 { 0x1e8, 0, 0x15, 3, 13, },
166 { 0x1d8, 0, 0x15, 3, 9, },
167 { 0x1d0, 0, 0x15, 3, 7, },
168 { 0x1d4, 0, 0x15, 3, 8, },
169 { 0x1e4, 0x80, 0x15, 3, 12, },
170 { 0x024, 0x05, 0x05, 2, 5, }, /* RX_ER signal; make sure it's a GPIO _without_ SION! */
171 { 0x094, 0x85, 5, 4, 8, },
172 { 0x090, 5, 5, 4, 7, },
173 { 0x098, 5, 5, 4, 9, },
176 static struct tx25_gpio_setup tx25_fec_strap_pins[] = {
177 { 0x1dc, 0, 0x15, 3, 10, },
178 { 0x1e0, 0, 0x15, 3, 11, },
179 { 0x1e4, 0, 0x15, 3, 12, },
182 static inline void tx25_phy_power_off(void)
186 if (net_debug) diag_printf("Switching PHY POWER off\n");
189 for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
190 struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
192 if (net_debug) diag_printf("%s: GPIO%d_%d[%d] is %d\n", __FUNCTION__,
193 gs->grp, gs->shift, i,
194 gpio_tst_bit(gs->grp, gs->shift));
197 /* deassert all pins attached to the PHY */
198 for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
199 struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
201 tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
203 if (gs->on_func & 0x80) {
204 /* configure as input */
205 tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
206 GPIO_GDIR, 0, 1 << gs->shift);
208 /* configure as output */
209 tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
210 GPIO_DR, 0, 1 << gs->shift);
211 tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
212 GPIO_GDIR, 1 << gs->shift, 0);
214 tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
217 for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
218 struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
220 if (!(gs->on_func & 0x80) && gpio_tst_bit(gs->grp, gs->shift)) {
221 if (net_debug) diag_printf("%s: GPIO%d_%d[%d] is not low\n", __FUNCTION__,
222 gs->grp, gs->shift, i);
225 if (net_debug) diag_printf("PHY POWER off done\n");
228 static bool tx25_fec_init(struct cyg_netdevtab_entry *tab)
233 /* Check, whether MAC address is enabled */
234 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
235 "fec_esa", &esa_set, CONFIG_BOOL);
236 if (!(ok && esa_set)) {
237 diag_printf("FEC disabled; set fec_esa=true to enable networking\n");
238 tx25_phy_power_off();
241 /* call init function in devs/eth/fec/current/if_fec.c */
242 return mxc_fec_init(tab);
245 static void tx25_fec_phy_init(void)
248 int phy_reset_delay = 100;
251 * make sure the ETH PHY strap pins are pulled to the right voltage
252 * before deasserting the PHY reset GPIO
265 // assert FEC PHY Reset (PB30) and switch PHY power on
266 /* PB22, PB27, PB30 => GPIO out */
268 tx25_phy_power_off();
271 tx25_write_reg(IOMUXC_BASE_ADDR, IOMUXC_GPIO1_7, 0x11);
272 tx25_write_reg(IOMUXC_BASE_ADDR, IOMUXC_NANDF_CS1, 0x14);
279 tx25_set_reg(MX25_GPIO_ADDR(4), GPIO_DR, 1 << 9, 0);
281 tx25_read_reg(MX25_GPIO_ADDR(4), GPIO_DR);
282 HAL_DELAY_US(1000000);
286 tx25_set_reg(MX25_GPIO_ADDR(4), GPIO_DR, 0, 1 << 9);
288 tx25_read_reg(MX25_GPIO_ADDR(4), GPIO_DR);
289 HAL_DELAY_US(1000000);
292 /* Switch PHY power on and assert PHY reset */
293 if (net_debug) diag_printf("Switching PHY POWER on\n");
297 /* wait for 22ms for LAN8700 to power up */
298 phy_reset_delay = 22000;
300 /* configure FEC strap pins to their required values */
301 for (i = 0; i < NUM_ELEMS(tx25_fec_strap_pins); i++) {
302 struct tx25_gpio_setup *gs = &tx25_fec_strap_pins[i];
304 if (net_debug) diag_printf("Asserting GPIO%d_%d\n", gs->grp,
307 tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
308 GPIO_GDIR, 1 << gs->shift, 0);
309 tx25_set_reg(MX25_GPIO_ADDR(gs->grp),
310 GPIO_DR, 1 << gs->shift, 0);
311 tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
314 gpio_set_bit(gs->grp, gs->shift);
318 for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
319 struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
323 for (j = 0; j < NUM_ELEMS(tx25_fec_strap_pins); j++) {
324 struct tx25_gpio_setup *sp = &tx25_fec_strap_pins[j];
326 if (gs->grp == sp->grp && gs->shift == sp->shift) {
331 if (strap || gs->on_func & 0x80) {
332 if (!gpio_tst_bit(gs->grp, gs->shift)) {
333 if (net_debug) diag_printf("GPIO%d_%d[%d] is low instead of high\n",
334 gs->grp, gs->shift, i);
337 if (gpio_tst_bit(gs->grp, gs->shift)) {
338 if (net_debug) diag_printf("GPIO%d_%d[%d] is high instead of low\n",
339 gs->grp, gs->shift, i);
344 /* wait for 100us according to LAN8700 spec. before ... */
345 HAL_DELAY_US(phy_reset_delay);
347 /* ... deasserting FEC PHY reset */
348 if (net_debug) diag_printf("Releasing PHY RESET\n");
349 tx25_set_reg(MX25_GPIO_ADDR(4), GPIO_DR, 1 << 7, 0);
351 for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
352 struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
356 for (j = 0; j < NUM_ELEMS(tx25_fec_strap_pins); j++) {
357 struct tx25_gpio_setup *sp = &tx25_fec_strap_pins[j];
359 if (gs->grp == sp->grp && gs->shift == sp->shift) {
364 if (strap || gs->on_func & 0x80) {
365 if (!gpio_tst_bit(gs->grp, gs->shift)) {
366 if (net_debug) diag_printf("GPIO%d_%d[%d] is low instead of high\n",
367 gs->grp, gs->shift, i);
370 if (gpio_tst_bit(gs->grp, gs->shift)) {
371 if (net_debug) diag_printf("GPIO%d_%d[%d] is high instead of low\n",
372 gs->grp, gs->shift, i);
377 /* configure all FEC pins to their required functions */
378 for (i = 0; i < NUM_ELEMS(tx25_fec_gpio_data); i++) {
379 struct tx25_gpio_setup *gs = &tx25_fec_gpio_data[i];
381 tx25_write_reg(IOMUXC_BASE_ADDR, gs->iomux_addr,
382 gs->on_func & ~0x80);
386 ETH_PHY_REG_LEVEL_ACCESS_FUNS(eth0_phy,
392 #define SOC_MAC_ADDR_LOCK_BIT 2
394 cyg_bool _tx25_provide_fec_esa(unsigned char *addr)
399 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
400 "fec_esa", &enabled, CONFIG_BOOL);
402 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
403 cyg_uint8 addr2[ETHER_ADDR_LEN];
405 addr[0] = readl(SOC_MAC_ADDR_BASE + 0x0);
406 addr[1] = readl(SOC_MAC_ADDR_BASE + 0x4);
407 addr[2] = readl(SOC_MAC_ADDR_BASE + 0x8);
408 addr[3] = readl(SOC_MAC_ADDR_BASE + 0xC);
409 addr[4] = readl(SOC_MAC_ADDR_BASE + 0x10);
410 addr[5] = readl(SOC_MAC_ADDR_BASE + 0x14);
412 if (cyg_plf_redboot_esa_validate(addr)) {
413 diag_printf("Ethernet FEC MAC address from fuse bank: ");
414 diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
415 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
416 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
417 "fec_esa_data", addr2, CONFIG_ESA);
418 if (memcmp(addr, addr2, sizeof(addr)) != 0) {
419 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_SET,
420 "fec_esa_data", addr, CONFIG_ESA);
422 #ifdef SOC_MAC_ADDR_LOCK_BIT
423 if ((readl(SOC_MAC_ADDR_BASE - 0x68) & SOC_MAC_ADDR_LOCK_BIT) == 0) {
424 tx25_mac_addr_program(addr);
426 #endif // SOC_MAC_ADDR_LOCK_BIT
429 #endif // CYGSEM_REDBOOT_PLF_ESA_VALIDATE
431 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
432 "fec_esa_data", addr, CONFIG_ESA);
434 diag_printf("Ethernet FEC MAC address from fconfig: ");
435 diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
436 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
438 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
439 if (cyg_plf_redboot_esa_validate(addr)) {
440 tx25_mac_addr_program(addr);
444 diag_printf("** Error: Invalid MAC address: ");
445 diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
446 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
448 #ifdef SOC_MAC_ADDR_LOCK_BIT
449 if ((readl(SOC_MAC_ADDR_BASE - 0x68) & SOC_MAC_ADDR_LOCK_BIT) == 0) {
450 diag_printf("Use 'fconfig fec_esa_data' to set the MAC address\n");
453 diag_printf("Using MAC address from fconfig\n");
456 diag_printf("Using MAC address from fconfig\n");
457 #endif // SOC_MAC_ADDR_LOCK_BIT
458 #endif // CYGSEM_REDBOOT_PLF_ESA_VALIDATE
464 static mxc_fec_priv_t mxc_fec_private = {
465 .phy = ð0_phy, // PHY access routines
466 .provide_esa = _tx25_provide_fec_esa,
469 ETH_DRV_SC(mxc_fec_sc,
470 &mxc_fec_private, // Driver specific data
478 mxc_fec_deliver, // "pseudoDSR" called from fast net thread
479 mxc_fec_poll, // poll function, encapsulates ISR and DSR
482 NETDEVTAB_ENTRY(mxc_fec_netdev,
488 #if defined(CYGPKG_REDBOOT) && defined(CYGSEM_REDBOOT_FLASH_CONFIG)
489 RedBoot_config_option("Set FEC network hardware address [MAC]",
491 ALWAYS_ENABLED, true,
494 RedBoot_config_option("FEC network hardware address [MAC]",
499 #endif // CYGPKG_REDBOOT && CYGSEM_REDBOOT_FLASH_CONFIG
501 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
502 // Note that this section *is* active in an application, outside RedBoot,
503 // where the above section is not included.
505 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
506 #endif // CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0
508 #endif // __WANT_DEVS