mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 18:35:42 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			438 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (C) Copyright 2005
 | |
|  * Thomas.Lange@corelatus.se
 | |
|  *
 | |
|  * See file CREDITS for list of people who contributed to this
 | |
|  * project.
 | |
|  *
 | |
|  * This program 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 of
 | |
|  * the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program 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 this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | |
|  * MA 02111-1307 USA
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <command.h>
 | |
| #include <asm/au1x00.h>
 | |
| #include <asm/addrspace.h>
 | |
| #include <asm/mipsregs.h>
 | |
| #include <asm/io.h>
 | |
| #include <watchdog.h>
 | |
| 
 | |
| #include "ee_access.h"
 | |
| 
 | |
| static int wdi_status = 0;
 | |
| 
 | |
| #define SDRAM_SIZE ((64*1024*1024)-(12*4096))
 | |
| 
 | |
| 
 | |
| #define SERIAL_LOG_BUFFER CKSEG1ADDR(SDRAM_SIZE + (8*4096))
 | |
| 
 | |
| void inline log_serial_char(char c){
 | |
| 	char *serial_log_buffer = (char*)SERIAL_LOG_BUFFER;
 | |
| 	int serial_log_offset;
 | |
| 	u32 *serial_log_offsetp = (u32*)SERIAL_LOG_BUFFER;
 | |
| 
 | |
| 	serial_log_offset = *serial_log_offsetp;
 | |
| 
 | |
| 	*(serial_log_buffer + serial_log_offset) = c;
 | |
| 
 | |
| 	serial_log_offset++;
 | |
| 
 | |
| 	if(serial_log_offset >= 4096){
 | |
| 		serial_log_offset = 4;
 | |
| 	}
 | |
| 	*serial_log_offsetp = serial_log_offset;
 | |
| }
 | |
| 
 | |
| void init_log_serial(void){
 | |
| 	char *serial_log_buffer = (char*)SERIAL_LOG_BUFFER;
 | |
| 	u32 *serial_log_offsetp = (u32*)SERIAL_LOG_BUFFER;
 | |
| 
 | |
| 	/* Copy buffer from last run */
 | |
| 	memcpy(serial_log_buffer + 4096,
 | |
| 	       serial_log_buffer,
 | |
| 	       4096);
 | |
| 
 | |
| 	memset(serial_log_buffer, 0, 4096);
 | |
| 
 | |
| 	*serial_log_offsetp = 4;
 | |
| }
 | |
| 
 | |
| 
 | |
| void hw_watchdog_reset(void){
 | |
| 	volatile u32 *sys_outputset = (volatile u32*)SYS_OUTPUTSET;
 | |
| 	volatile u32 *sys_outputclear = (volatile u32*)SYS_OUTPUTCLR;
 | |
| 	if(wdi_status){
 | |
| 		*sys_outputset = GPIO_CPU_LED|GPIO_WDI;
 | |
| 		wdi_status = 0;
 | |
| 	}
 | |
| 	else{
 | |
| 		*sys_outputclear = GPIO_CPU_LED|GPIO_WDI;
 | |
| 		wdi_status = 1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| phys_size_t initdram(int board_type)
 | |
| {
 | |
| 	/* Sdram is setup by assembler code */
 | |
| 	/* If memory could be changed, we should return the true value here */
 | |
| 
 | |
| 	WATCHDOG_RESET();
 | |
| 
 | |
| 	return (SDRAM_SIZE);
 | |
| }
 | |
| 
 | |
| /* In cpu/mips/cpu.c */
 | |
| void write_one_tlb( int index, u32 pagemask, u32 hi, u32 low0, u32 low1 );
 | |
| 
 | |
| void set_ledcard(u32 value){
 | |
| 	/* Clock 24 bits to led card */
 | |
| 	int i;
 | |
| 	volatile u32 *sys_outputset = (volatile u32*)SYS_OUTPUTSET;
 | |
| 	volatile u32 *sys_outputclr = (volatile u32*)SYS_OUTPUTCLR;
 | |
| 
 | |
| 	/* Start with known values */
 | |
| 	*sys_outputclr = GPIO_LEDCLK|GPIO_LEDD;
 | |
| 
 | |
| 	for(i=0;i<24;i++){
 | |
| 		if(value&0x00800000){
 | |
| 			*sys_outputset = GPIO_LEDD;
 | |
| 		}
 | |
| 		else{
 | |
| 			*sys_outputclr = GPIO_LEDD;
 | |
| 		}
 | |
| 		udelay(1);
 | |
| 		*sys_outputset = GPIO_LEDCLK;
 | |
| 		udelay(1);
 | |
| 		*sys_outputclr = GPIO_LEDCLK;
 | |
| 		udelay(1);
 | |
| 
 | |
| 		value<<=1;
 | |
| 	}
 | |
| 	/* Data is enable output */
 | |
| 	*sys_outputset = GPIO_LEDD;
 | |
| }
 | |
| 
 | |
| int checkboard (void)
 | |
| {
 | |
| 	volatile u32 *sys_counter = (volatile u32*)SYS_COUNTER_CNTRL;
 | |
| 	volatile u32 *sys_outputset = (volatile u32*)SYS_OUTPUTSET;
 | |
| 	volatile u32 *sys_outputclr = (volatile u32*)SYS_OUTPUTCLR;
 | |
| 	u32 proc_id;
 | |
| 
 | |
| 	WATCHDOG_RESET();
 | |
| 
 | |
| 	*sys_counter = 0x100; /* Enable 32 kHz oscillator for RTC/TOY */
 | |
| 
 | |
| 	proc_id = read_c0_prid();
 | |
| 
 | |
| 	switch (proc_id >> 24) {
 | |
| 	case 0:
 | |
| 		puts ("Board: GTH2\n");
 | |
| 		printf ("CPU: Au1000 500 MHz, id: 0x%02x, rev: 0x%02x\n",
 | |
| 			(proc_id >> 8) & 0xFF, proc_id & 0xFF);
 | |
| 		break;
 | |
| 	default:
 | |
| 		printf ("Unsupported cpu %d, proc_id=0x%x\n", proc_id >> 24, proc_id);
 | |
| 	}
 | |
| 
 | |
| 	set_io_port_base(0);
 | |
| 
 | |
| #ifdef CONFIG_IDE_PCMCIA
 | |
| 	/* PCMCIA is on a 36 bit physical address.
 | |
| 	   We need to map it into a 32 bit addresses */
 | |
| 	write_one_tlb(20,                 /* index */
 | |
| 		      0x01ffe000,         /* Pagemask, 16 MB pages */
 | |
| 		      CONFIG_SYS_PCMCIA_IO_BASE, /* Hi */
 | |
| 		      0x3C000017,         /* Lo0 */
 | |
| 		      0x3C200017);        /* Lo1 */
 | |
| 
 | |
| 	write_one_tlb(21,                   /* index */
 | |
| 		      0x01ffe000,           /* Pagemask, 16 MB pages */
 | |
| 		      CONFIG_SYS_PCMCIA_ATTR_BASE, /* Hi */
 | |
| 		      0x3D000017,           /* Lo0 */
 | |
| 		      0x3D200017);          /* Lo1 */
 | |
| 
 | |
| 	write_one_tlb(22,                   /* index */
 | |
| 		      0x01ffe000,           /* Pagemask, 16 MB pages */
 | |
| 		      CONFIG_SYS_PCMCIA_MEM_ADDR,  /* Hi */
 | |
| 		      0x3E000017,           /* Lo0 */
 | |
| 		      0x3E200017);          /* Lo1 */
 | |
| 
 | |
| #endif	/* CONFIG_IDE_PCMCIA */
 | |
| 
 | |
| 	/* Wait for GPIO ports to become stable */
 | |
| 	udelay(5000); /* FIXME */
 | |
| 
 | |
| 	/* Release reset of ethernet PHY chips */
 | |
| 	/* Always do this, because linux does not know about it */
 | |
| 	*sys_outputset = GPIO_ERESET;
 | |
| 
 | |
| 	/* Kill FPGA:s */
 | |
| 	*sys_outputclr = GPIO_CACONFIG|GPIO_DPACONFIG;
 | |
| 	udelay(2);
 | |
| 	*sys_outputset = GPIO_CACONFIG|GPIO_DPACONFIG;
 | |
| 
 | |
| 	/* Turn front led yellow */
 | |
| 	set_ledcard(0x00100000);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #define POWER_OFFSET    0xF0000
 | |
| #define SW_WATCHDOG_REASON 13
 | |
| 
 | |
| #define BOOTDATA_OFFSET 0xF8000
 | |
| #define MAX_ATTEMPTS 5
 | |
| 
 | |
| #define FAILSAFE_BOOT 1
 | |
| #define SYSTEM_BOOT   2
 | |
| #define SYSTEM2_BOOT  3
 | |
| 
 | |
| #define WRITE_FLASH16(a, d)      \
 | |
| do                              \
 | |
| {                               \
 | |
|   *((volatile u16 *) (a)) = (d);\
 | |
|  } while(0)
 | |
| 
 | |
| static void write_bootdata (volatile u16 * addr, u8 System, u8 Count)
 | |
| {
 | |
| 	u16 data;
 | |
| 	volatile u16 *flash = (u16 *) (CONFIG_SYS_FLASH_BASE);
 | |
| 
 | |
| 	switch(System){
 | |
| 	case FAILSAFE_BOOT:
 | |
| 		printf ("Setting failsafe boot in flash\n");
 | |
| 		break;
 | |
| 	case SYSTEM_BOOT:
 | |
| 		printf ("Setting system boot in flash\n");
 | |
| 		break;
 | |
| 	case SYSTEM2_BOOT:
 | |
| 		printf ("Setting system2 boot in flash\n");
 | |
| 		break;
 | |
| 	default:
 | |
| 		printf ("Invalid system data %u, setting failsafe\n", System);
 | |
| 		System = FAILSAFE_BOOT;
 | |
| 	}
 | |
| 
 | |
| 	if ((Count < 1) | (Count > MAX_ATTEMPTS)) {
 | |
| 		printf ("Invalid boot count %u, setting 1\n", Count);
 | |
| 		Count = 1;
 | |
| 	}
 | |
| 
 | |
| 	printf ("Boot attempt %d\n", Count);
 | |
| 
 | |
| 	data = (System << 8) | Count;
 | |
| 	/* AMD 16 bit */
 | |
| 	WRITE_FLASH16 (&flash[0x555], 0xAAAA);
 | |
| 	WRITE_FLASH16 (&flash[0x2AA], 0x5555);
 | |
| 	WRITE_FLASH16 (&flash[0x555], 0xA0A0);
 | |
| 
 | |
| 	WRITE_FLASH16 (addr, data);
 | |
| }
 | |
| 
 | |
| static int random_system(void){
 | |
| 	/* EEPROM read failed. Just try to choose one
 | |
| 	   system release and hope it works */
 | |
| 
 | |
| 	/* FIXME */
 | |
| 	return(SYSTEM_BOOT);
 | |
| }
 | |
| 
 | |
| static int switch_system(int old_system){
 | |
| 	u8 Rx[10];
 | |
| 	u8 Tx[5];
 | |
| 	int valid_release;
 | |
| 
 | |
| 	if(old_system==FAILSAFE_BOOT){
 | |
| 		/* Find out which system release to use */
 | |
| 
 | |
| 		/* Copy from nvram to scratchpad */
 | |
| 		Tx[0] = RECALL_MEMORY;
 | |
| 		Tx[1] = 7; /* Page */
 | |
| 		if (ee_do_cpu_command (Tx, 2, NULL, 0, 1)) {
 | |
| 			printf ("EE user page 7 recall failed\n");
 | |
| 			return (random_system());
 | |
| 		}
 | |
| 
 | |
| 		Tx[0] = READ_SCRATCHPAD;
 | |
| 		if (ee_do_cpu_command (Tx, 2, Rx, 9, 1)) {
 | |
| 			printf ("EE user page 7 read failed\n");
 | |
| 			return (random_system());
 | |
| 		}
 | |
| 		/* Crc in 9:th byte */
 | |
| 		if (!ee_crc_ok (Rx, 8, *(Rx + 8))) {
 | |
| 			printf ("EE read failed, page 7. CRC error\n");
 | |
| 			return (random_system());
 | |
| 		}
 | |
| 
 | |
| 		valid_release = Rx[7];
 | |
| 		if((valid_release==0xFF)|
 | |
| 		   ((valid_release&1) == 0)){
 | |
| 			return(SYSTEM_BOOT);
 | |
| 		}
 | |
| 		else{
 | |
| 			return(SYSTEM2_BOOT);
 | |
| 		}
 | |
| 	}
 | |
| 	else{
 | |
| 		return(FAILSAFE_BOOT);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void check_boot_tries (void)
 | |
| {
 | |
| 	/* Count the number of boot attemps
 | |
| 	   switch system if too many */
 | |
| 
 | |
| 	int i;
 | |
| 	volatile u16 *addr;
 | |
| 	volatile u16 data;
 | |
| 	u8 system = FAILSAFE_BOOT;
 | |
| 	u8 count;
 | |
| 
 | |
| 	addr = (u16 *) (CONFIG_SYS_FLASH_BASE + BOOTDATA_OFFSET);
 | |
| 
 | |
| 	if (*addr == 0xFFFF) {
 | |
| 		printf ("*** No bootdata exists. ***\n");
 | |
| 		write_bootdata (addr, FAILSAFE_BOOT, 1);
 | |
| 	} else {
 | |
| 		/* Search for latest written bootdata */
 | |
| 		i = 0;
 | |
| 		while ((*(addr + 1) != 0xFFFF) & (i < 8000)) {
 | |
| 			addr++;
 | |
| 			i++;
 | |
| 		}
 | |
| 		if (i >= 8000) {
 | |
| 			/* Whoa, dont write any more */
 | |
| 			printf ("*** No bootdata found. Not updating flash***\n");
 | |
| 		} else {
 | |
| 			/* See how many times we have tried to boot real system */
 | |
| 			data = *addr;
 | |
| 			system = data >> 8;
 | |
| 			count = data & 0xFF;
 | |
| 			if ((system != SYSTEM_BOOT) &
 | |
| 			    (system != SYSTEM2_BOOT) &
 | |
| 			    (system != FAILSAFE_BOOT)) {
 | |
| 				printf ("*** Wrong system %d\n", system);
 | |
| 				system = FAILSAFE_BOOT;
 | |
| 				count = 1;
 | |
| 			} else {
 | |
| 				switch (count) {
 | |
| 				case 0:
 | |
| 				case 1:
 | |
| 				case 2:
 | |
| 				case 3:
 | |
| 				case 4:
 | |
| 					/* Try same system again if needed */
 | |
| 					count++;
 | |
| 					break;
 | |
| 
 | |
| 				case 5:
 | |
| 					/* Switch system and reset tries */
 | |
| 					count = 1;
 | |
| 					system = switch_system(system);
 | |
| 					printf ("***Too many boot attempts, switching system***\n");
 | |
| 					break;
 | |
| 				default:
 | |
| 					/* Switch system, start over and hope it works */
 | |
| 					printf ("***Unexpected data on addr 0x%x, %u***\n",
 | |
| 						(u32) addr, data);
 | |
| 					count = 1;
 | |
| 					system = switch_system(system);
 | |
| 				}
 | |
| 			}
 | |
| 			write_bootdata (addr + 1, system, count);
 | |
| 		}
 | |
| 	}
 | |
| 	switch(system){
 | |
| 	case FAILSAFE_BOOT:
 | |
| 		printf ("Booting failsafe system\n");
 | |
| 		setenv ("bootargs", "panic=1 root=/dev/hda7");
 | |
| 		setenv ("bootcmd", "ide reset;disk 0x81000000 0:5;run addmisc;bootm");
 | |
| 		break;
 | |
| 
 | |
| 	case SYSTEM_BOOT:
 | |
| 		printf ("Using normal system\n");
 | |
| 		setenv ("bootargs", "panic=1 root=/dev/hda4");
 | |
| 		setenv ("bootcmd", "ide reset;disk 0x81000000 0:2;run addmisc;bootm");
 | |
| 		break;
 | |
| 
 | |
| 	case SYSTEM2_BOOT:
 | |
| 		printf ("Using normal system2\n");
 | |
| 		setenv ("bootargs", "panic=1 root=/dev/hda9");
 | |
| 		setenv ("bootcmd", "ide reset;disk 0x81000000 0:8;run addmisc;bootm");
 | |
| 		break;
 | |
| 	default:
 | |
| 		printf ("Invalid system %d\n", system);
 | |
| 		printf ("Hanging\n");
 | |
| 		while(1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int misc_init_r(void){
 | |
| 	u8 Rx[80];
 | |
| 	u8 Tx[5];
 | |
| 	int page;
 | |
| 	int read = 0;
 | |
| 
 | |
| 	WATCHDOG_RESET();
 | |
| 
 | |
| 	if (ee_init_cpu_data ()) {
 | |
| 		printf ("EEPROM init failed\n");
 | |
| 		return (0);
 | |
| 	}
 | |
| 
 | |
| 	/* Check which release to boot */
 | |
| 	check_boot_tries ();
 | |
| 
 | |
| 	/* Read the pages where ethernet address is stored */
 | |
| 
 | |
| 	for (page = EE_USER_PAGE_0; page <= EE_USER_PAGE_0 + 2; page++) {
 | |
| 		/* Copy from nvram to scratchpad */
 | |
| 		Tx[0] = RECALL_MEMORY;
 | |
| 		Tx[1] = page;
 | |
| 		if (ee_do_cpu_command (Tx, 2, NULL, 0, 1)) {
 | |
| 			printf ("EE user page %d recall failed\n", page);
 | |
| 			return (0);
 | |
| 		}
 | |
| 
 | |
| 		Tx[0] = READ_SCRATCHPAD;
 | |
| 		if (ee_do_cpu_command (Tx, 2, Rx + read, 9, 1)) {
 | |
| 			printf ("EE user page %d read failed\n", page);
 | |
| 			return (0);
 | |
| 		}
 | |
| 		/* Crc in 9:th byte */
 | |
| 		if (!ee_crc_ok (Rx + read, 8, *(Rx + read + 8))) {
 | |
| 			printf ("EE read failed, page %d. CRC error\n", page);
 | |
| 			return (0);
 | |
| 		}
 | |
| 		read += 8;
 | |
| 	}
 | |
| 
 | |
| 	/* Add eos after eth addr */
 | |
| 	Rx[17] = 0;
 | |
| 
 | |
| 	printf ("Ethernet addr read from eeprom: %s\n\n", Rx);
 | |
| 
 | |
| 	if ((Rx[2] != ':') |
 | |
| 	    (Rx[5] != ':') |
 | |
| 	    (Rx[8] != ':') | (Rx[11] != ':') | (Rx[14] != ':')) {
 | |
| 		printf ("*** ethernet addr invalid, using default ***\n");
 | |
| 	} else {
 | |
| 		setenv ("ethaddr", (char *)Rx);
 | |
| 	}
 | |
| 	return (0);
 | |
| }
 |