gth.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * (C) Copyright 2000
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * Adapted from FADS and other board config files to GTH by thomas@corelatus.com
  6. *
  7. * See file CREDITS for list of people who contributed to this
  8. * project.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2 of
  13. * the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23. * MA 02111-1307 USA
  24. */
  25. #include <common.h>
  26. #include <config.h>
  27. #include <watchdog.h>
  28. #include <mpc8xx.h>
  29. #include "ee_access.h"
  30. #include "ee_dev.h"
  31. #ifdef CONFIG_BDM
  32. #undef printf
  33. #define printf(a,...) /* nothing */
  34. #endif
  35. int checkboard (void)
  36. {
  37. volatile immap_t *immap = (immap_t *) CFG_IMMR;
  38. int Id = 0;
  39. int Rev = 0;
  40. u32 Pbdat;
  41. puts ("Board: ");
  42. /* Turn on leds and setup for reading rev and id */
  43. #define PB_OUTS (PB_BLUE_LED|PB_ID_GND)
  44. #define PB_INS (PB_ID_0|PB_ID_1|PB_ID_2|PB_ID_3|PB_REV_1|PB_REV_0)
  45. immap->im_cpm.cp_pbpar &= ~(PB_OUTS | PB_INS);
  46. immap->im_cpm.cp_pbdir &= ~PB_INS;
  47. immap->im_cpm.cp_pbdir |= PB_OUTS;
  48. immap->im_cpm.cp_pbodr |= PB_OUTS;
  49. immap->im_cpm.cp_pbdat &= ~PB_OUTS;
  50. /* Hold 100 Mbit in reset until fpga is loaded */
  51. immap->im_ioport.iop_pcpar &= ~PC_ENET100_RESET;
  52. immap->im_ioport.iop_pcdir |= PC_ENET100_RESET;
  53. immap->im_ioport.iop_pcso &= ~PC_ENET100_RESET;
  54. immap->im_ioport.iop_pcdat &= ~PC_ENET100_RESET;
  55. /* Turn on front led to show that we are alive */
  56. immap->im_ioport.iop_papar &= ~PA_FRONT_LED;
  57. immap->im_ioport.iop_padir |= PA_FRONT_LED;
  58. immap->im_ioport.iop_paodr |= PA_FRONT_LED;
  59. immap->im_ioport.iop_padat &= ~PA_FRONT_LED;
  60. Pbdat = immap->im_cpm.cp_pbdat;
  61. if (!(Pbdat & PB_ID_0))
  62. Id += 1;
  63. if (!(Pbdat & PB_ID_1))
  64. Id += 2;
  65. if (!(Pbdat & PB_ID_2))
  66. Id += 4;
  67. if (!(Pbdat & PB_ID_3))
  68. Id += 8;
  69. if (Pbdat & PB_REV_0)
  70. Rev += 1;
  71. if (Pbdat & PB_REV_1)
  72. Rev += 2;
  73. /* Turn ID off since we dont need it anymore */
  74. immap->im_cpm.cp_pbdat |= PB_ID_GND;
  75. printf ("GTH board, rev %d, id=0x%01x\n", Rev, Id);
  76. return 0;
  77. }
  78. #define _NOT_USED_ 0xffffffff
  79. const uint sdram_table[] = {
  80. /* Single read, offset 0 */
  81. 0x0f3dfc04, 0x0eefbc04, 0x01bf7c04, 0x0feafc00,
  82. 0x1fb5fc45, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  83. /* Burst read, Offset 0x8, 4 reads */
  84. 0x0f3dfc04, 0x0eefbc04, 0x00bf7c04, 0x00ffec00,
  85. 0x00fffc00, 0x01eafc00, 0x1fb5fc00, 0xfffffc45,
  86. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  87. /* Not used part of burst read is used for MRS, Offset 0x14 */
  88. 0xefeabc34, 0x1fb57c34, 0xfffffc05, _NOT_USED_,
  89. /* _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, */
  90. /* Single write, Offset 0x18 */
  91. 0x0f3dfc04, 0x0eebbc00, 0x01a27c04, 0x1fb5fc45,
  92. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  93. /* Burst write, Offset 0x20. 4 writes */
  94. 0x0f3dfc04, 0x0eebbc00, 0x00b77c00, 0x00fffc00,
  95. 0x00fffc00, 0x01eafc04, 0x1fb5fc45, _NOT_USED_,
  96. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  97. /* Not used part of burst write is used for precharge, Offset 0x2C */
  98. 0x0ff5fc04, 0xfffffc05, _NOT_USED_, _NOT_USED_,
  99. /* _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, */
  100. /* Period timer service. Offset 0x30. Refresh. Wait at least 70 ns after refresh command */
  101. 0x1ffd7c04, 0xfffffc04, 0xfffffc04, 0xfffffc05,
  102. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  103. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  104. /* Exception, Offset 0x3C */
  105. 0xfffffc04, 0xfffffc05, _NOT_USED_, _NOT_USED_
  106. };
  107. const uint fpga_table[] = {
  108. /* Single read, offset 0 */
  109. 0x0cffec04, 0x00ffec04, 0x00ffec04, 0x00ffec04,
  110. 0x00fffc04, 0x00fffc00, 0x00ffec04, 0xffffec05,
  111. /* Burst read, Offset 0x8 */
  112. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  113. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  114. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  115. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  116. /* Single write, Offset 0x18 */
  117. 0x0cffec04, 0x00ffec04, 0x00ffec04, 0x00ffec04,
  118. 0x00fffc04, 0x00fffc00, 0x00ffec04, 0xffffec05,
  119. /* Burst write, Offset 0x20. */
  120. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  121. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  122. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  123. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  124. /* Period timer service. Offset 0x30. */
  125. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  126. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  127. _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
  128. /* Exception, Offset 0x3C */
  129. 0xfffffc04, 0xfffffc05, _NOT_USED_, _NOT_USED_
  130. };
  131. int _initsdram (uint base, uint * noMbytes)
  132. {
  133. volatile immap_t *immap = (immap_t *) CFG_IMMR;
  134. volatile memctl8xx_t *mc = &immap->im_memctl;
  135. volatile u32 *memptr;
  136. mc->memc_mptpr = MPTPR_PTP_DIV16; /* (16-17) */
  137. /* SDRAM in UPMA
  138. GPL_0 is connected instead of A19 to SDRAM.
  139. According to table 16-17, AMx should be 001, i.e. type 1
  140. and GPL_0 should hold address A10 when multiplexing */
  141. mc->memc_mamr = (0x2E << MAMR_PTA_SHIFT) | MAMR_PTAE | MAMR_AMA_TYPE_1 | MAMR_G0CLA_A10 | MAMR_RLFA_1X | MAMR_WLFA_1X | MAMR_TLFA_1X; /* (16-13) */
  142. upmconfig (UPMA, (uint *) sdram_table,
  143. sizeof (sdram_table) / sizeof (uint));
  144. /* Perform init of sdram ( Datasheet Page 9 )
  145. Precharge */
  146. mc->memc_mcr = 0x8000212C; /* run upm a at 0x2C (16-15) */
  147. /* Run 2 refresh cycles */
  148. mc->memc_mcr = 0x80002130; /* run upm a at 0x30 (16-15) */
  149. mc->memc_mcr = 0x80002130; /* run upm a at 0x30 (16-15) */
  150. /* Set Mode register */
  151. mc->memc_mar = 0x00000088; /* set mode register (address) to 0x022 (16-17) */
  152. /* Lower 2 bits are not connected to chip */
  153. mc->memc_mcr = 0x80002114; /* run upm a at 0x14 (16-15) */
  154. /* CS1, base 0x0000000 - 64 Mbyte, use UPM A */
  155. mc->memc_or1 = 0xfc000000 | OR_CSNT_SAM;
  156. mc->memc_br1 = BR_MS_UPMA | BR_V; /* SDRAM base always 0 */
  157. /* Test if we really have 64 MB SDRAM */
  158. memptr = (u32 *) 0;
  159. *memptr = 0;
  160. memptr = (u32 *) 0x2000000; /* First u32 in upper 32 MB */
  161. *memptr = 0x12345678;
  162. memptr = (u32 *) 0;
  163. if (*memptr == 0x12345678) {
  164. /* Wrapped, only have 32 MB */
  165. mc->memc_or1 = 0xfe000000 | OR_CSNT_SAM;
  166. *noMbytes = 32;
  167. } else {
  168. /* 64 MB */
  169. *noMbytes = 64;
  170. }
  171. /* Setup FPGA in UPMB */
  172. upmconfig (UPMB, (uint *) fpga_table,
  173. sizeof (fpga_table) / sizeof (uint));
  174. /* Enable UPWAITB */
  175. mc->memc_mbmr = MBMR_GPL_B4DIS; /* (16-13) */
  176. /* CS2, base FPGA_2_BASE - 4 MByte, use UPM B 32 Bit */
  177. mc->memc_or2 = 0xffc00000 | OR_BI;
  178. mc->memc_br2 = FPGA_2_BASE | BR_MS_UPMB | BR_V;
  179. /* CS3, base FPGA_3_BASE - 4 MByte, use UPM B 16 bit */
  180. mc->memc_or3 = 0xffc00000 | OR_BI;
  181. mc->memc_br3 = FPGA_3_BASE | BR_MS_UPMB | BR_V | BR_PS_16;
  182. return 0;
  183. }
  184. /* ------------------------------------------------------------------------- */
  185. void _sdramdisable (void)
  186. {
  187. volatile immap_t *immap = (immap_t *) CFG_IMMR;
  188. volatile memctl8xx_t *memctl = &immap->im_memctl;
  189. memctl->memc_br1 = 0x00000000;
  190. /* maybe we should turn off upmb here or something */
  191. }
  192. /* ------------------------------------------------------------------------- */
  193. int initsdram (uint base, uint * noMbytes)
  194. {
  195. *noMbytes = 32;
  196. #ifdef CONFIG_START_IN_RAM
  197. /* SDRAM is already setup. Dont touch it */
  198. return 0;
  199. #else
  200. if (!_initsdram (base, noMbytes)) {
  201. return 0;
  202. } else {
  203. _sdramdisable ();
  204. return -1;
  205. }
  206. #endif
  207. }
  208. long int initdram (int board_type)
  209. {
  210. u32 *i;
  211. u32 j;
  212. u32 k;
  213. /* GTH only have SDRAM */
  214. uint sdramsz;
  215. if (!initsdram (0x00000000, &sdramsz)) {
  216. printf ("(%u MB SDRAM) ", sdramsz);
  217. } else {
  218. /********************************
  219. *SDRAM ERROR, HALT PROCESSOR
  220. *********************************/
  221. printf ("SDRAM ERROR\n");
  222. while (1);
  223. }
  224. #ifndef CONFIG_START_IN_RAM
  225. #define U32_S ((sdramsz<<18)-1)
  226. #if 1
  227. /* Do a simple memory test */
  228. for (i = (u32 *) 0, j = 0; (u32) i < U32_S; i += 2, j += 2) {
  229. *i = j + (j << 17);
  230. *(i + 1) = ~(j + (j << 18));
  231. }
  232. WATCHDOG_RESET ();
  233. printf (".");
  234. for (i = (u32 *) 0, j = 0; (u32) i < U32_S; i += 2, j += 2) {
  235. k = *i;
  236. if (k != (j + (j << 17))) {
  237. printf ("Mem test error, i=0x%x, 0x%x\n, 0x%x", (u32) i, j, k);
  238. while (1);
  239. }
  240. k = *(i + 1);
  241. if (k != ~(j + (j << 18))) {
  242. printf ("Mem test error(+1), i=0x%x, 0x%x\n, 0x%x",
  243. (u32) i + 1, j, k);
  244. while (1);
  245. }
  246. }
  247. #endif
  248. WATCHDOG_RESET ();
  249. /* Clear memory */
  250. for (i = (u32 *) 0; (u32) i < U32_S; i++) {
  251. *i = 0;
  252. }
  253. #endif /* !start in ram */
  254. WATCHDOG_RESET ();
  255. return (sdramsz << 20);
  256. }
  257. #define POWER_OFFSET 0xF0000
  258. #define SW_WATCHDOG_REASON 13
  259. #define BOOTDATA_OFFSET 0xF8000
  260. #define MAX_ATTEMPTS 5
  261. #define FAILSAFE_BOOT 1
  262. #define SYSTEM_BOOT 2
  263. #define WRITE_FLASH16(a, d) \
  264. do \
  265. { \
  266. *((volatile u16 *) (a)) = (d);\
  267. } while(0)
  268. static void write_bootdata (volatile u16 * addr, u8 System, u8 Count)
  269. {
  270. u16 data;
  271. volatile u16 *flash = (u16 *) (CFG_FLASH_BASE);
  272. if ((System != FAILSAFE_BOOT) & (System != SYSTEM_BOOT)) {
  273. printf ("Invalid system data %u, setting failsafe\n", System);
  274. System = FAILSAFE_BOOT;
  275. }
  276. if ((Count < 1) | (Count > MAX_ATTEMPTS)) {
  277. printf ("Invalid boot count %u, setting 1\n", Count);
  278. Count = 1;
  279. }
  280. if (System == FAILSAFE_BOOT) {
  281. printf ("Setting failsafe boot in flash\n");
  282. } else {
  283. printf ("Setting system boot in flash\n");
  284. }
  285. printf ("Boot attempt %d\n", Count);
  286. data = (System << 8) | Count;
  287. /* AMD 16 bit */
  288. WRITE_FLASH16 (&flash[0x555], 0xAAAA);
  289. WRITE_FLASH16 (&flash[0x2AA], 0x5555);
  290. WRITE_FLASH16 (&flash[0x555], 0xA0A0);
  291. WRITE_FLASH16 (addr, data);
  292. }
  293. static void maybe_update_restart_reason (volatile u32 * addr32)
  294. {
  295. /* Update addr if sw wd restart */
  296. volatile u16 *flash = (u16 *) (CFG_FLASH_BASE);
  297. volatile u16 *addr_16 = (u16 *) addr32;
  298. u32 rsr;
  299. /* Dont reset register now */
  300. rsr = ((volatile immap_t *) CFG_IMMR)->im_clkrst.car_rsr;
  301. rsr >>= 24;
  302. if (rsr & 0x10) {
  303. /* Was really a sw wd restart, update reason */
  304. printf ("Last restart by software watchdog\n");
  305. /* AMD 16 bit */
  306. WRITE_FLASH16 (&flash[0x555], 0xAAAA);
  307. WRITE_FLASH16 (&flash[0x2AA], 0x5555);
  308. WRITE_FLASH16 (&flash[0x555], 0xA0A0);
  309. WRITE_FLASH16 (addr_16, 0);
  310. udelay (1000);
  311. WATCHDOG_RESET ();
  312. /* AMD 16 bit */
  313. WRITE_FLASH16 (&flash[0x555], 0xAAAA);
  314. WRITE_FLASH16 (&flash[0x2AA], 0x5555);
  315. WRITE_FLASH16 (&flash[0x555], 0xA0A0);
  316. WRITE_FLASH16 (addr_16 + 1, SW_WATCHDOG_REASON);
  317. }
  318. }
  319. static void check_restart_reason (void)
  320. {
  321. /* Update restart reason if sw watchdog was
  322. triggered */
  323. int i;
  324. volatile u32 *raddr;
  325. raddr = (u32 *) (CFG_FLASH_BASE + POWER_OFFSET);
  326. if (*raddr == 0xFFFFFFFF) {
  327. /* Nothing written */
  328. maybe_update_restart_reason (raddr);
  329. } else {
  330. /* Search for latest written reason */
  331. i = 0;
  332. while ((*(raddr + 2) != 0xFFFFFFFF) & (i < 2000)) {
  333. raddr += 2;
  334. i++;
  335. }
  336. if (i >= 2000) {
  337. /* Whoa, dont write any more */
  338. printf ("*** No free restart reason found ***\n");
  339. } else {
  340. /* Check if written */
  341. if (*raddr == 0) {
  342. /* Erased by kernel, no new reason written */
  343. maybe_update_restart_reason (raddr + 2);
  344. }
  345. }
  346. }
  347. }
  348. static void check_boot_tries (void)
  349. {
  350. /* Count the number of boot attemps
  351. switch system if too many */
  352. int i;
  353. volatile u16 *addr;
  354. volatile u16 data;
  355. int failsafe = 1;
  356. u8 system;
  357. u8 count;
  358. addr = (u16 *) (CFG_FLASH_BASE + BOOTDATA_OFFSET);
  359. if (*addr == 0xFFFF) {
  360. printf ("*** No bootdata exists. ***\n");
  361. write_bootdata (addr, FAILSAFE_BOOT, 1);
  362. } else {
  363. /* Search for latest written bootdata */
  364. i = 0;
  365. while ((*(addr + 1) != 0xFFFF) & (i < 8000)) {
  366. addr++;
  367. i++;
  368. }
  369. if (i >= 8000) {
  370. /* Whoa, dont write any more */
  371. printf ("*** No bootdata found. Not updating flash***\n");
  372. } else {
  373. /* See how many times we have tried to boot real system */
  374. data = *addr;
  375. system = data >> 8;
  376. count = data & 0xFF;
  377. if ((system != SYSTEM_BOOT) & (system != FAILSAFE_BOOT)) {
  378. printf ("*** Wrong system %d\n", system);
  379. system = FAILSAFE_BOOT;
  380. count = 1;
  381. } else {
  382. switch (count) {
  383. case 0:
  384. case 1:
  385. case 2:
  386. case 3:
  387. case 4:
  388. /* Try same system again if needed */
  389. count++;
  390. break;
  391. case 5:
  392. /* Switch system and reset tries */
  393. count = 1;
  394. system = 3 - system;
  395. printf ("***Too many boot attempts, switching system***\n");
  396. break;
  397. default:
  398. /* Switch system, start over and hope it works */
  399. printf ("***Unexpected data on addr 0x%x, %u***\n",
  400. (u32) addr, data);
  401. count = 1;
  402. system = 3 - system;
  403. }
  404. }
  405. write_bootdata (addr + 1, system, count);
  406. if (system == SYSTEM_BOOT) {
  407. failsafe = 0;
  408. }
  409. }
  410. }
  411. if (failsafe) {
  412. printf ("Booting failsafe system\n");
  413. setenv ("bootargs", "panic=1 root=/dev/hda7");
  414. setenv ("bootcmd", "disk 100000 0:5;bootm 100000");
  415. } else {
  416. printf ("Using normal system\n");
  417. setenv ("bootargs", "panic=1 root=/dev/hda4");
  418. setenv ("bootcmd", "disk 100000 0:2;bootm 100000");
  419. }
  420. }
  421. int misc_init_r (void)
  422. {
  423. u8 Rx[80];
  424. u8 Tx[5];
  425. int page;
  426. int read = 0;
  427. volatile immap_t *immap = (immap_t *) CFG_IMMR;
  428. /* Kill fpga */
  429. immap->im_ioport.iop_papar &= ~(PA_FL_CONFIG | PA_FL_CE);
  430. immap->im_ioport.iop_padir |= (PA_FL_CONFIG | PA_FL_CE);
  431. immap->im_ioport.iop_paodr &= ~(PA_FL_CONFIG | PA_FL_CE);
  432. /* Enable fpga, active low */
  433. immap->im_ioport.iop_padat &= ~PA_FL_CE;
  434. /* Start configuration */
  435. immap->im_ioport.iop_padat &= ~PA_FL_CONFIG;
  436. udelay (2);
  437. immap->im_ioport.iop_padat |= (PA_FL_CONFIG | PA_FL_CE);
  438. /* Check if we need to boot failsafe system */
  439. check_boot_tries ();
  440. /* Check if we need to update restart reason */
  441. check_restart_reason ();
  442. if (ee_init_data ()) {
  443. printf ("EEPROM init failed\n");
  444. return (0);
  445. }
  446. /* Read the pages where ethernet address is stored */
  447. for (page = EE_USER_PAGE_0; page <= EE_USER_PAGE_0 + 2; page++) {
  448. /* Copy from nvram to scratchpad */
  449. Tx[0] = RECALL_MEMORY;
  450. Tx[1] = page;
  451. if (ee_do_command (Tx, 2, NULL, 0, TRUE)) {
  452. printf ("EE user page %d recall failed\n", page);
  453. return (0);
  454. }
  455. Tx[0] = READ_SCRATCHPAD;
  456. if (ee_do_command (Tx, 2, Rx + read, 9, TRUE)) {
  457. printf ("EE user page %d read failed\n", page);
  458. return (0);
  459. }
  460. /* Crc in 9:th byte */
  461. if (!ee_crc_ok (Rx + read, 8, *(Rx + read + 8))) {
  462. printf ("EE read failed, page %d. CRC error\n", page);
  463. return (0);
  464. }
  465. read += 8;
  466. }
  467. /* Add eos after eth addr */
  468. Rx[17] = 0;
  469. printf ("Ethernet addr read from eeprom: %s\n\n", Rx);
  470. if ((Rx[2] != ':') |
  471. (Rx[5] != ':') |
  472. (Rx[8] != ':') | (Rx[11] != ':') | (Rx[14] != ':')) {
  473. printf ("*** ethernet addr invalid, using default ***\n");
  474. } else {
  475. setenv ("ethaddr", (char *)Rx);
  476. }
  477. return (0);
  478. }