|  | /* | 
|  | * (C) Copyright 2006 | 
|  | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 
|  | * | 
|  | * SPDX-License-Identifier:	GPL-2.0+ | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <mpc5xxx.h> | 
|  |  | 
|  | /* For the V38B board the pin is GPIO_PSC_6 */ | 
|  | #define GPIO_PIN	GPIO_PSC6_0 | 
|  |  | 
|  | #define NO_ERROR	0 | 
|  | #define ERR_NO_NUMBER	1 | 
|  | #define ERR_BAD_NUMBER	2 | 
|  |  | 
|  | static int is_high(void); | 
|  | static int check_device(void); | 
|  | static void io_out(int value); | 
|  | static void io_input(void); | 
|  | static void io_output(void); | 
|  | static void init_gpio(void); | 
|  | static void read_byte(unsigned char *data); | 
|  | static void write_byte(unsigned char command); | 
|  |  | 
|  | void read_2501_memory(unsigned char *psernum, unsigned char *perr); | 
|  | void board_get_enetaddr(uchar *enetaddr); | 
|  |  | 
|  |  | 
|  | static int is_high() | 
|  | { | 
|  | return (*((vu_long *) MPC5XXX_WU_GPIO_DATA_I) & GPIO_PIN); | 
|  | } | 
|  |  | 
|  | static void io_out(int value) | 
|  | { | 
|  | if (value) | 
|  | *((vu_long *) MPC5XXX_WU_GPIO_DATA_O) |= GPIO_PIN; | 
|  | else | 
|  | *((vu_long *) MPC5XXX_WU_GPIO_DATA_O) &= ~GPIO_PIN; | 
|  | } | 
|  |  | 
|  | static void io_input() | 
|  | { | 
|  | *((vu_long *) MPC5XXX_WU_GPIO_DIR) &= ~GPIO_PIN; | 
|  | udelay(3);	/* allow input to settle */ | 
|  | } | 
|  |  | 
|  | static void io_output() | 
|  | { | 
|  | *((vu_long *) MPC5XXX_WU_GPIO_DIR) |= GPIO_PIN; | 
|  | } | 
|  |  | 
|  | static void init_gpio() | 
|  | { | 
|  | *((vu_long *) MPC5XXX_WU_GPIO_ENABLE) |= GPIO_PIN;	/* Enable appropriate pin */ | 
|  | } | 
|  |  | 
|  | void read_2501_memory(unsigned char *psernum, unsigned char *perr) | 
|  | { | 
|  | #define NBYTES 28 | 
|  | unsigned char crcval, i; | 
|  | unsigned char buf[NBYTES]; | 
|  |  | 
|  | *perr = 0; | 
|  | crcval = 0; | 
|  |  | 
|  | for (i = 0; i < NBYTES; i++) | 
|  | buf[i] = 0; | 
|  |  | 
|  | if (!check_device()) | 
|  | *perr = ERR_NO_NUMBER; | 
|  | else { | 
|  | *perr = NO_ERROR; | 
|  | write_byte(0xCC);		/* skip ROM (0xCC) */ | 
|  | write_byte(0xF0);		/* Read memory command 0xF0 */ | 
|  | write_byte(0x00);		/* Address TA1=0, TA2=0 */ | 
|  | write_byte(0x00); | 
|  | read_byte(&crcval);		/* Read CRC of address and command */ | 
|  |  | 
|  | for (i = 0; i < NBYTES; i++) | 
|  | read_byte(&buf[i]); | 
|  | } | 
|  | if (strncmp((const char *) &buf[11], "MAREL IEEE 802.3", 16)) { | 
|  | *perr = ERR_BAD_NUMBER; | 
|  | psernum[0] = 0x00; | 
|  | psernum[1] = 0xE0; | 
|  | psernum[2] = 0xEE; | 
|  | psernum[3] = 0xFF; | 
|  | psernum[4] = 0xFF; | 
|  | psernum[5] = 0xFF; | 
|  | } else { | 
|  | psernum[0] = 0x00; | 
|  | psernum[1] = 0xE0; | 
|  | psernum[2] = 0xEE; | 
|  | psernum[3] = buf[7]; | 
|  | psernum[4] = buf[6]; | 
|  | psernum[5] = buf[5]; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int check_device() | 
|  | { | 
|  | int found; | 
|  |  | 
|  | io_output(); | 
|  | io_out(0); | 
|  | udelay(500);  /* must be at least 480 us low pulse */ | 
|  |  | 
|  | io_input(); | 
|  | udelay(60); | 
|  |  | 
|  | found = (is_high() == 0) ? 1 : 0; | 
|  | udelay(500);  /* must be at least 480 us low pulse */ | 
|  |  | 
|  | return found; | 
|  | } | 
|  |  | 
|  | static void write_byte(unsigned char command) | 
|  | { | 
|  | char i; | 
|  |  | 
|  | for (i = 0; i < 8; i++) { | 
|  | /* 1 us to 15 us low pulse starts bit slot */ | 
|  | /* Start with high pulse for 3 us */ | 
|  | io_input(); | 
|  | udelay(3); | 
|  |  | 
|  | io_out(0); | 
|  | io_output(); | 
|  | udelay(3); | 
|  |  | 
|  | if (command & 0x01) { | 
|  | /* 60 us high for 1-bit */ | 
|  | io_input(); | 
|  | udelay(60); | 
|  | } else | 
|  | /* 60 us low for 0-bit */ | 
|  | udelay(60); | 
|  | /*  Leave pin as input */ | 
|  | io_input(); | 
|  |  | 
|  | command = command >> 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void read_byte(unsigned char *data) | 
|  | { | 
|  | unsigned char i, rdat = 0; | 
|  |  | 
|  | for (i = 0; i < 8; i++) { | 
|  | /* read one bit from one-wire device */ | 
|  |  | 
|  | /* 1 - 15 us low starts bit slot */ | 
|  | io_out(0); | 
|  | io_output(); | 
|  | udelay(0); | 
|  |  | 
|  | /* allow line to be pulled high */ | 
|  | io_input(); | 
|  |  | 
|  | /* delay 10 us */ | 
|  | udelay(10); | 
|  |  | 
|  | /* now sample input status */ | 
|  | if (is_high()) | 
|  | rdat = (rdat >> 1) | 0x80; | 
|  | else | 
|  | rdat = rdat >> 1; | 
|  |  | 
|  | udelay(60);	/* at least 60 us */ | 
|  | } | 
|  | /* copy the return value */ | 
|  | *data = rdat; | 
|  | } | 
|  |  | 
|  | void board_get_enetaddr(uchar *enetaddr) | 
|  | { | 
|  | unsigned char sn[6], err = NO_ERROR; | 
|  |  | 
|  | init_gpio(); | 
|  |  | 
|  | read_2501_memory(sn, &err); | 
|  |  | 
|  | if (err == NO_ERROR) { | 
|  | sprintf((char *)enetaddr, "%02x:%02x:%02x:%02x:%02x:%02x", | 
|  | sn[0], sn[1], sn[2], sn[3], sn[4], sn[5]); | 
|  | printf("MAC address: %s\n", enetaddr); | 
|  | setenv("ethaddr", (char *)enetaddr); | 
|  | } else { | 
|  | sprintf((char *)enetaddr, "00:01:02:03:04:05"); | 
|  | printf("Error reading MAC address.\n"); | 
|  | printf("Setting default to %s\n", enetaddr); | 
|  | setenv("ethaddr", (char *)enetaddr); | 
|  | } | 
|  | } |