mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-26 21:13:48 +00:00
436 lines
10 KiB
C
436 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 <watchdog.h>
|
||
|
|
||
|
#include "ee_access.h"
|
||
|
|
||
|
static int wdi_status = 0;
|
||
|
|
||
|
unsigned long mips_io_port_base = 0;
|
||
|
|
||
|
#define SDRAM_SIZE ((64*1024*1024)-(12*4096))
|
||
|
|
||
|
|
||
|
#define SERIAL_LOG_BUFFER KSEG1ADDR(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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long int 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_32bit_cp0_register(CP0_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);
|
||
|
}
|
||
|
#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 */
|
||
|
CFG_PCMCIA_IO_BASE, /* Hi */
|
||
|
0x3C000017, /* Lo0 */
|
||
|
0x3C200017); /* Lo1 */
|
||
|
|
||
|
write_one_tlb(21, /* index */
|
||
|
0x01ffe000, /* Pagemask, 16 MB pages */
|
||
|
CFG_PCMCIA_ATTR_BASE, /* Hi */
|
||
|
0x3D000017, /* Lo0 */
|
||
|
0x3D200017); /* Lo1 */
|
||
|
|
||
|
write_one_tlb(22, /* index */
|
||
|
0x01ffe000, /* Pagemask, 16 MB pages */
|
||
|
CFG_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 *) (CFG_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 *) (CFG_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", Rx);
|
||
|
}
|
||
|
return (0);
|
||
|
}
|