karo: tx51: justify and adjust the delay required before releasing the ETN PHY strap...
[karo-tx-redboot.git] / packages / devs / eth / arm / tx51karo / v1_0 / include / devs_eth_arm_tx51.inl
1 //==========================================================================
2 //
3 //      devs_eth_arm_tx51.inl
4 //
5 //      Board ethernet I/O definitions.
6 //
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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 //===========================================================================
41
42 #include <cyg/hal/hal_intr.h>                   // CYGNUM_HAL_INTERRUPT_ETHR
43 #include <cyg/hal/hal_if.h>
44 #include <cyg/hal/mx51_iomux.h>
45
46 #ifdef CYGPKG_REDBOOT
47 #include <pkgconf/redboot.h>
48 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
49 #include <redboot.h>
50 #include <flash_config.h>
51 #endif
52 #endif
53
54
55 #ifdef __WANT_DEVS
56
57 #ifdef CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0
58
59 #ifdef CYGPKG_DEVS_ETH_PHY
60
61 static bool mxc_fec_init(struct cyg_netdevtab_entry *tab);
62
63 static char  mxc_fec_name[] = "mxc_fec";
64
65 #define MX51_GPIO_ADDR(bank)                    (GPIO1_BASE_ADDR + (((bank) - 1) << 14))
66 #define FEC_POWER_GPIO                                  1, 3
67 #define FEC_RESET_GPIO                                  2, 14
68
69 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
70 //
71 // Verify that the given ESA is valid for this platform
72 //
73 static char oui[3] = CYGDAT_DEVS_ETH_ARM_TX51KARO_OUI;
74
75 bool cyg_plf_redboot_esa_validate(unsigned char *val)
76 {
77         return (val[0] == oui[0]) && (val[1] == oui[1]) && (val[2] == oui[2]);
78 }
79 #endif
80
81 extern int tx51_mac_addr_program(unsigned char mac_addr[ETHER_ADDR_LEN]);
82
83 static inline void tx51_write_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset, CYG_WORD32 val)
84 {
85         if (net_debug) {
86                 diag_printf("Changing reg %08x from %08x to %08x\n",
87                                         base_addr + offset, readl(base_addr + offset), val);
88         }
89         HAL_WRITE_UINT32(base_addr + offset, val);
90 }
91
92 static inline CYG_WORD32 tx51_read_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset)
93 {
94         CYG_WORD32 val;
95
96         HAL_READ_UINT32(base_addr + offset, val);
97         if (net_debug) diag_printf("Read %08x from reg %08x\n", val, base_addr + offset);
98         return val;
99 }
100
101 static inline void tx51_set_reg(CYG_ADDRWORD base_addr, CYG_WORD32 offset,
102                                                                 CYG_WORD32 set_mask, CYG_WORD32 clr_mask)
103 {
104         CYG_WORD32 val;
105
106         HAL_READ_UINT32(base_addr + offset, val);
107         if (net_debug) diag_printf("Changing reg %08x from %08x to %08x\n",
108                                                            base_addr + offset, val,
109                                                            (val & ~clr_mask) | set_mask);
110         val = (val & ~clr_mask) | set_mask;
111         HAL_WRITE_UINT32(base_addr + offset, val);
112 }
113
114 static struct tx51_gpio_setup {
115         cyg_uint32 iomux_addr;
116         unsigned on_func:5,
117                 off_func:5,
118                 grp:3,
119                 shift:5,
120                 dir:1, /* 0: input; 1: output */
121                 level:1;
122 } tx51_fec_gpio_data[] = {
123         /* iomux reg offset,                    func,       gpgrp, in/out */
124         /*                                                                    gpiofn,  gpshft,level */
125         { IOMUXC_SW_MUX_CTL_PAD_EIM_A20,                0x11, 0x11, 2, 14, 1, 0, }, /* PHY reset */
126         { IOMUXC_SW_MUX_CTL_PAD_GPIO1_3,                0x10, 0x10, 1,  3, 1, 1, }, /* PHY power enable */
127         { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS3,              0x02, 0x13, 3, 19, 1, 0, }, /* MDC */
128         { IOMUXC_SW_MUX_CTL_PAD_EIM_EB2,                0x03, 0x11, 2, 22, 1, 0, }, /* MDIO */
129         { IOMUXC_SW_MUX_CTL_PAD_NANDF_RB3,              0x01, 0x13, 3, 11, 0, }, /* RX_CLK */
130         { IOMUXC_SW_MUX_CTL_PAD_NANDF_D11,              0x02, 0x13, 3, 29, 0, }, /* RX_DV */
131         { IOMUXC_SW_MUX_CTL_PAD_NANDF_D9,               0x02, 0x13, 3, 31, 1, 1, }, /* RXD0/Mode0 */
132         { IOMUXC_SW_MUX_CTL_PAD_EIM_EB3,                0x03, 0x11, 2, 23, 1, 1, }, /* RXD1/Mode1 */
133         { IOMUXC_SW_MUX_CTL_PAD_EIM_CS2,                0x03, 0x11, 2, 27, 1, 1, }, /* RXD2/Mode2 */
134         { IOMUXC_SW_MUX_CTL_PAD_EIM_CS3,                0x03, 0x11, 2, 28, 1, 1, }, /* RXD3/nINTSEL */
135         { IOMUXC_SW_MUX_CTL_PAD_EIM_CS4,                0x03, 0x11, 2, 29, 0, }, /* RX_ER/RXD4 */
136         { IOMUXC_SW_MUX_CTL_PAD_NANDF_RDY_INT,  0x01, 0x13, 3, 24, 0, }, /* TX_CLK */
137         { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS7,              0x01, 0x13, 3, 23, 1, 0, }, /* TX_EN */
138         { IOMUXC_SW_MUX_CTL_PAD_NANDF_D8,               0x02, 0x13, 4,  0, 1, 0, }, /* TXD0 */
139         { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS4,              0x02, 0x13, 3, 20, 1, 0, }, /* TXD1 */
140         { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS5,              0x02, 0x13, 3, 21, 1, 0, }, /* TXD2 */
141         { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS6,              0x02, 0x13, 3, 22, 1, 0, }, /* TXD3 */
142         { IOMUXC_SW_MUX_CTL_PAD_NANDF_RB2,              0x01, 0x13, 3, 10, 1, 0, }, /* COL/RMII/CRSDV */
143         { IOMUXC_SW_MUX_CTL_PAD_EIM_CS5,                0x03, 0x11, 2, 30, 1, 0, }, /* CRS */
144         { IOMUXC_SW_MUX_CTL_PAD_NANDF_CS2,              0x03, 0x13, 3, 18, 0, }, /* nINT/TX_ER/TXD4 */
145 };
146
147 static inline void tx51_phy_gpio_init(void)
148 {
149         int i;
150
151         if (net_debug) diag_printf("PHY GPIO init\n");
152
153         /* setup all pins attached to the PHY to required level */
154         for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) {
155                 struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i];
156
157                 tx51_set_reg(MX51_GPIO_ADDR(gs->grp),
158                                          GPIO_DR, gs->level << gs->shift, !gs->level << gs->shift);
159                 tx51_set_reg(MX51_GPIO_ADDR(gs->grp),
160                                          GPIO_GDIR, 1 << gs->shift, 0);
161                 tx51_write_reg(gs->iomux_addr, 0, gs->off_func);
162         }
163         for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) {
164                 struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i];
165
166                 if (gs->dir) {
167                         if (gs->level ^ gpio_tst_bit(gs->grp, gs->shift)) {
168                                 diag_printf("%s: GPIO%d_%d[%d] is not %s\n", __FUNCTION__,
169                                                         gs->grp, gs->shift, i, gs->level ? "HIGH" : "LOW");
170                         }
171                 }
172         }
173         if (net_debug) diag_printf("PHY GPIO init done\n");
174 }
175
176 static bool tx51_fec_init(struct cyg_netdevtab_entry *tab)
177 {
178         cyg_bool esa_set;
179         int ok;
180
181         /* Check, whether MAC address is enabled */
182         ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
183                                                                          "fec_esa", &esa_set, CONFIG_BOOL);
184         if (!(ok && esa_set)) {
185                 diag_printf("FEC disabled; set fec_esa=true to enable networking\n");
186                 return false;
187         }
188         return mxc_fec_init(tab);
189 }
190
191 static void tx51_fec_phy_init(void)
192 {
193         int i;
194         int phy_reset_delay = 100;
195
196         /*
197          * make sure the ETH PHY strap pins are pulled to the right voltage
198          * before deasserting the PHY reset GPIO
199          */
200         tx51_phy_gpio_init();
201
202         /* LAN8700 requires 21ms to power up */
203         phy_reset_delay = 22000;
204         if (!gpio_tst_bit(1, 3)) {
205                 diag_printf("**Failed to switch PHY power on: GPIO1_PSR[%08lx]=%08x\n",
206                                         MX51_GPIO_ADDR(1) + GPIO_PSR,
207                                         tx51_read_reg(MX51_GPIO_ADDR(1), GPIO_PSR));
208         }
209         if (gpio_tst_bit(2, 14)) {
210                 diag_printf("**Failed to assert PHY reset: GPIO2_PSR[%08lx]=%08x\n",
211                                         MX51_GPIO_ADDR(2) + GPIO_PSR,
212                                         tx51_read_reg(MX51_GPIO_ADDR(2), GPIO_PSR));
213         }
214
215         /* wait the specified time according to LAN8700 spec. before ... */
216         HAL_DELAY_US(phy_reset_delay);
217         /* ... deasserting FEC PHY reset */
218         if (net_debug) diag_printf("Releasing PHY RESET\n");
219         gpio_set_bit(2, 14);
220         if (!gpio_tst_bit(2, 14)) {
221                 diag_printf("**Failed to release PHY reset\n");
222         }
223         /*
224          * Due to an RC-filter in the PHY RESET line, a minimum
225          * delay of 535us is required to let the RESET line rise
226          * above the logic high threshold of the PHY input pin.
227          */
228         HAL_DELAY_US(550);
229
230         /* configure all FEC pins to their required functions */
231         for (i = 0; i < NUM_ELEMS(tx51_fec_gpio_data); i++) {
232                 struct tx51_gpio_setup *gs = &tx51_fec_gpio_data[i];
233
234                 tx51_write_reg(gs->iomux_addr, 0, gs->on_func);
235         }
236 }
237
238 ETH_PHY_REG_LEVEL_ACCESS_FUNS(eth0_phy,
239                                                           tx51_fec_phy_init,
240                                                           mxc_fec_phy_reset,
241                                                           mxc_fec_phy_write,
242                                                           mxc_fec_phy_read);
243
244 cyg_bool _tx51_provide_fec_esa(unsigned char *addr)
245 {
246         cyg_bool enabled;
247         int ok;
248
249         ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
250                                          "fec_esa", &enabled, CONFIG_BOOL);
251         if (ok && enabled) {
252 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
253                 cyg_uint8 addr2[ETHER_ADDR_LEN];
254
255                 addr[0] = readl(SOC_FEC_MAC_BASE + 0x14);
256                 addr[1] = readl(SOC_FEC_MAC_BASE + 0x10);
257                 addr[2] = readl(SOC_FEC_MAC_BASE + 0xC);
258                 addr[3] = readl(SOC_FEC_MAC_BASE + 0x8);
259                 addr[4] = readl(SOC_FEC_MAC_BASE + 0x4);
260                 addr[5] = readl(SOC_FEC_MAC_BASE + 0x0);
261
262                 if (cyg_plf_redboot_esa_validate(addr)) {
263                         diag_printf("Ethernet FEC MAC address from fuse bank: ");
264                         diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
265                                                 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
266                         CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
267                                                                                 "fec_esa_data", addr2, CONFIG_ESA);
268                         if (memcmp(addr, addr2, sizeof(addr)) != 0) {
269                                 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_SET,
270                                                                                         "fec_esa_data", addr, CONFIG_ESA);
271                         }
272 #ifdef SOC_MAC_ADDR_LOCK_FUSE
273                         if ((readl(IIM_BASE_ADDR + 0x800 + SOC_MAC_ADDR_FUSE_BANK * 0x400 +
274                                            SOC_MAC_ADDR_LOCK_FUSE * 4) &
275                                  SOC_MAC_ADDR_LOCK_BIT) == 0) {
276                                 tx51_mac_addr_program(addr);
277                         }
278 #endif // SOC_MAC_ADDR_LOCK_FUSE
279                         return true;
280                 }
281 #endif // CYGSEM_REDBOOT_PLF_ESA_VALIDATE
282
283                 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
284                                                                         "fec_esa_data", addr, CONFIG_ESA);
285
286                 diag_printf("Ethernet FEC MAC address from fconfig: ");
287                 diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
288                                         addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
289
290 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
291                 if (cyg_plf_redboot_esa_validate(addr)) {
292                         tx51_mac_addr_program(addr);
293                         return true;
294                 }
295
296                 diag_printf("** Error: Invalid MAC address: ");
297                 diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
298                                         addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
299
300                 writel(addr[0], SOC_FEC_MAC_BASE + 0x14);
301                 writel(addr[1], SOC_FEC_MAC_BASE + 0x10);
302                 writel(addr[2], SOC_FEC_MAC_BASE + 0xC);
303                 writel(addr[3], SOC_FEC_MAC_BASE + 0x8);
304                 writel(addr[4], SOC_FEC_MAC_BASE + 0x4);
305                 writel(addr[5], SOC_FEC_MAC_BASE + 0x0);
306
307 #ifdef SOC_MAC_ADDR_LOCK_FUSE
308                 if ((readl(IIM_BASE_ADDR + 0x800 + SOC_MAC_ADDR_FUSE_BANK * 0x400 +
309                                    SOC_MAC_ADDR_LOCK_FUSE * 4) &
310                          SOC_MAC_ADDR_LOCK_BIT) == 0) {
311                         diag_printf("Use 'fconfig fec_esa_data' to set the MAC address\n");
312                         return false;
313                 } else {
314                         diag_printf("Using MAC address from fconfig\n");
315                 }
316 #else
317                 diag_printf("Using MAC address from fconfig\n");
318 #endif // SOC_MAC_ADDR_LOCK_FUSE
319 #endif // CYGSEM_REDBOOT_PLF_ESA_VALIDATE
320                 return true;
321         }
322         return false;
323 }
324
325 static mxc_fec_priv_t mxc_fec_private = {
326         .phy = &eth0_phy,                                                         // PHY access routines
327         .provide_esa = _tx51_provide_fec_esa,
328 };
329
330 ETH_DRV_SC(mxc_fec_sc,
331                    &mxc_fec_private, // Driver specific data
332                    mxc_fec_name,
333                    mxc_fec_start,
334                    mxc_fec_stop,
335                    mxc_fec_control,
336                    mxc_fec_can_send,
337                    mxc_fec_send,
338                    mxc_fec_recv,
339                    mxc_fec_deliver,             // "pseudoDSR" called from fast net thread
340                    mxc_fec_poll,                // poll function, encapsulates ISR and DSR
341                    mxc_fec_int_vector);
342
343 NETDEVTAB_ENTRY(mxc_fec_netdev,
344                                 mxc_fec_name,
345                                 tx51_fec_init,
346                                 &mxc_fec_sc);
347 #endif
348
349 #if defined(CYGPKG_REDBOOT) && defined(CYGSEM_REDBOOT_FLASH_CONFIG)
350 RedBoot_config_option("Set FEC network hardware address [MAC]",
351                                           fec_esa,
352                                           ALWAYS_ENABLED, true,
353                                           CONFIG_BOOL, true
354                                           );
355 RedBoot_config_option("FEC network hardware address [MAC]",
356                                           fec_esa_data,
357                                           "fec_esa", true,
358                                           CONFIG_ESA, 0
359                                           );
360 #endif // CYGPKG_REDBOOT && CYGSEM_REDBOOT_FLASH_CONFIG
361
362 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
363 // Note that this section *is* active in an application, outside RedBoot,
364 // where the above section is not included.
365
366 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
367 #endif // CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0
368
369 #endif // __WANT_DEVS