diff options
Diffstat (limited to 'board/gth')
-rw-r--r-- | board/gth/gth.c | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/board/gth/gth.c b/board/gth/gth.c new file mode 100644 index 0000000..94e7a65 --- /dev/null +++ b/board/gth/gth.c @@ -0,0 +1,595 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Adapted from FADS and other board config files to GTH by thomas@corelatus.com + * + * 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 <config.h> +#include <watchdog.h> +#include <mpc8xx.h> +#include "ee_access.h" +#include "ee_dev.h" + +#ifdef CONFIG_BDM +#undef printf +#define printf(a,...) /* nothing */ +#endif + + +int checkboard (void) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + int Id = 0; + int Rev = 0; + u32 Pbdat; + + puts ("Board: "); + + /* Turn on leds and setup for reading rev and id */ + +#define PB_OUTS (PB_BLUE_LED|PB_ID_GND) +#define PB_INS (PB_ID_0|PB_ID_1|PB_ID_2|PB_ID_3|PB_REV_1|PB_REV_0) + + immap->im_cpm.cp_pbpar &= ~(PB_OUTS | PB_INS); + + immap->im_cpm.cp_pbdir &= ~PB_INS; + + immap->im_cpm.cp_pbdir |= PB_OUTS; + immap->im_cpm.cp_pbodr |= PB_OUTS; + immap->im_cpm.cp_pbdat &= ~PB_OUTS; + + /* Hold 100 Mbit in reset until fpga is loaded */ + immap->im_ioport.iop_pcpar &= ~PC_ENET100_RESET; + immap->im_ioport.iop_pcdir |= PC_ENET100_RESET; + immap->im_ioport.iop_pcso &= ~PC_ENET100_RESET; + immap->im_ioport.iop_pcdat &= ~PC_ENET100_RESET; + + /* Turn on front led to show that we are alive */ + immap->im_ioport.iop_papar &= ~PA_FRONT_LED; + immap->im_ioport.iop_padir |= PA_FRONT_LED; + immap->im_ioport.iop_paodr |= PA_FRONT_LED; + immap->im_ioport.iop_padat &= ~PA_FRONT_LED; + + Pbdat = immap->im_cpm.cp_pbdat; + + if (!(Pbdat & PB_ID_0)) + Id += 1; + if (!(Pbdat & PB_ID_1)) + Id += 2; + if (!(Pbdat & PB_ID_2)) + Id += 4; + if (!(Pbdat & PB_ID_3)) + Id += 8; + + if (Pbdat & PB_REV_0) + Rev += 1; + if (Pbdat & PB_REV_1) + Rev += 2; + + /* Turn ID off since we dont need it anymore */ + immap->im_cpm.cp_pbdat |= PB_ID_GND; + + printf ("GTH board, rev %d, id=0x%01x\n", Rev, Id); + return 0; +} + +#define _NOT_USED_ 0xffffffff +const uint sdram_table[] = { + /* Single read, offset 0 */ + 0x0f3dfc04, 0x0eefbc04, 0x01bf7c04, 0x0feafc00, + 0x1fb5fc45, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Burst read, Offset 0x8, 4 reads */ + 0x0f3dfc04, 0x0eefbc04, 0x00bf7c04, 0x00ffec00, + 0x00fffc00, 0x01eafc00, 0x1fb5fc00, 0xfffffc45, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Not used part of burst read is used for MRS, Offset 0x14 */ + 0xefeabc34, 0x1fb57c34, 0xfffffc05, _NOT_USED_, + /* _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, */ + + /* Single write, Offset 0x18 */ + 0x0f3dfc04, 0x0eebbc00, 0x01a27c04, 0x1fb5fc45, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Burst write, Offset 0x20. 4 writes */ + 0x0f3dfc04, 0x0eebbc00, 0x00b77c00, 0x00fffc00, + 0x00fffc00, 0x01eafc04, 0x1fb5fc45, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Not used part of burst write is used for precharge, Offset 0x2C */ + 0x0ff5fc04, 0xfffffc05, _NOT_USED_, _NOT_USED_, + /* _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, */ + + /* Period timer service. Offset 0x30. Refresh. Wait at least 70 ns after refresh command */ + 0x1ffd7c04, 0xfffffc04, 0xfffffc04, 0xfffffc05, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Exception, Offset 0x3C */ + 0xfffffc04, 0xfffffc05, _NOT_USED_, _NOT_USED_ +}; + +const uint fpga_table[] = { + /* Single read, offset 0 */ + 0x0cffec04, 0x00ffec04, 0x00ffec04, 0x00ffec04, + 0x00fffc04, 0x00fffc00, 0x00ffec04, 0xffffec05, + + /* Burst read, Offset 0x8 */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Single write, Offset 0x18 */ + 0x0cffec04, 0x00ffec04, 0x00ffec04, 0x00ffec04, + 0x00fffc04, 0x00fffc00, 0x00ffec04, 0xffffec05, + + /* Burst write, Offset 0x20. */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Period timer service. Offset 0x30. */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + + /* Exception, Offset 0x3C */ + 0xfffffc04, 0xfffffc05, _NOT_USED_, _NOT_USED_ +}; + +int _initsdram (uint base, uint * noMbytes) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + volatile memctl8xx_t *mc = &immap->im_memctl; + volatile u32 *memptr; + + mc->memc_mptpr = MPTPR_PTP_DIV16; /* (16-17) */ + + /* SDRAM in UPMA + + GPL_0 is connected instead of A19 to SDRAM. + According to table 16-17, AMx should be 001, i.e. type 1 + and GPL_0 should hold address A10 when multiplexing */ + + 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) */ + + upmconfig (UPMA, (uint *) sdram_table, + sizeof (sdram_table) / sizeof (uint)); + + /* Perform init of sdram ( Datasheet Page 9 ) + Precharge */ + mc->memc_mcr = 0x8000212C; /* run upm a at 0x2C (16-15) */ + + /* Run 2 refresh cycles */ + mc->memc_mcr = 0x80002130; /* run upm a at 0x30 (16-15) */ + mc->memc_mcr = 0x80002130; /* run upm a at 0x30 (16-15) */ + + /* Set Mode register */ + mc->memc_mar = 0x00000088; /* set mode register (address) to 0x022 (16-17) */ + /* Lower 2 bits are not connected to chip */ + mc->memc_mcr = 0x80002114; /* run upm a at 0x14 (16-15) */ + + /* CS1, base 0x0000000 - 64 Mbyte, use UPM A */ + mc->memc_or1 = 0xfc000000 | OR_CSNT_SAM; + mc->memc_br1 = BR_MS_UPMA | BR_V; /* SDRAM base always 0 */ + + /* Test if we really have 64 MB SDRAM */ + memptr = (u32 *) 0; + *memptr = 0; + + memptr = (u32 *) 0x2000000; /* First u32 in upper 32 MB */ + *memptr = 0x12345678; + + memptr = (u32 *) 0; + if (*memptr == 0x12345678) { + /* Wrapped, only have 32 MB */ + mc->memc_or1 = 0xfe000000 | OR_CSNT_SAM; + *noMbytes = 32; + } else { + /* 64 MB */ + *noMbytes = 64; + } + + /* Setup FPGA in UPMB */ + upmconfig (UPMB, (uint *) fpga_table, + sizeof (fpga_table) / sizeof (uint)); + + /* Enable UPWAITB */ + mc->memc_mbmr = MAMR_GPL_B4DIS; /* (16-13) */ + + /* CS2, base FPGA_2_BASE - 4 MByte, use UPM B 32 Bit */ + mc->memc_or2 = 0xffc00000 | OR_BI; + mc->memc_br2 = FPGA_2_BASE | BR_MS_UPMB | BR_V; + + /* CS3, base FPGA_3_BASE - 4 MByte, use UPM B 16 bit */ + mc->memc_or3 = 0xffc00000 | OR_BI; + mc->memc_br3 = FPGA_3_BASE | BR_MS_UPMB | BR_V | BR_PS_16; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +void _sdramdisable (void) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + + memctl->memc_br1 = 0x00000000; + + /* maybe we should turn off upmb here or something */ +} + +/* ------------------------------------------------------------------------- */ + +int initsdram (uint base, uint * noMbytes) +{ + *noMbytes = 32; + +#ifdef CONFIG_START_IN_RAM + /* SDRAM is already setup. Dont touch it */ + return 0; +#else + + if (!_initsdram (base, noMbytes)) { + + return 0; + } else { + _sdramdisable (); + + return -1; + } +#endif +} + +long int initdram (int board_type) +{ + u32 *i; + u32 j; + u32 k; + + /* GTH only have SDRAM */ + uint sdramsz; + + if (!initsdram (0x00000000, &sdramsz)) { + printf ("(%u MB SDRAM) ", sdramsz); + } else { + /******************************** + *SDRAM ERROR, HALT PROCESSOR + *********************************/ + printf ("SDRAM ERROR\n"); + while (1); + } + +#ifndef CONFIG_START_IN_RAM + +#define U32_S ((sdramsz<<18)-1) + +#if 1 + /* Do a simple memory test */ + for (i = (u32 *) 0, j = 0; (u32) i < U32_S; i += 2, j += 2) { + *i = j + (j << 17); + *(i + 1) = ~(j + (j << 18)); + } + + WATCHDOG_RESET (); + + printf ("."); + + for (i = (u32 *) 0, j = 0; (u32) i < U32_S; i += 2, j += 2) { + k = *i; + if (k != (j + (j << 17))) { + printf ("Mem test error, i=0x%x, 0x%x\n, 0x%x", (u32) i, j, k); + while (1); + } + k = *(i + 1); + if (k != ~(j + (j << 18))) { + printf ("Mem test error(+1), i=0x%x, 0x%x\n, 0x%x", + (u32) i + 1, j, k); + while (1); + } + } +#endif + + WATCHDOG_RESET (); + + /* Clear memory */ + for (i = (u32 *) 0; (u32) i < U32_S; i++) { + *i = 0; + } +#endif /* !start in ram */ + + WATCHDOG_RESET (); + + return (sdramsz << 20); +} + +#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 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); + + if ((System != FAILSAFE_BOOT) & (System != SYSTEM_BOOT)) { + 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; + } + + if (System == FAILSAFE_BOOT) { + printf ("Setting failsafe boot in flash\n"); + } else { + printf ("Setting system boot in flash\n"); + } + 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 void maybe_update_restart_reason (volatile u32 * addr32) +{ + /* Update addr if sw wd restart */ + volatile u16 *flash = (u16 *) (CFG_FLASH_BASE); + volatile u16 *addr_16 = (u16 *) addr32; + u32 rsr; + + /* Dont reset register now */ + rsr = ((volatile immap_t *) CFG_IMMR)->im_clkrst.car_rsr; + + rsr >>= 24; + + if (rsr & 0x10) { + /* Was really a sw wd restart, update reason */ + + printf ("Last restart by software watchdog\n"); + + /* AMD 16 bit */ + WRITE_FLASH16 (&flash[0x555], 0xAAAA); + WRITE_FLASH16 (&flash[0x2AA], 0x5555); + WRITE_FLASH16 (&flash[0x555], 0xA0A0); + + WRITE_FLASH16 (addr_16, 0); + + udelay (1000); + + WATCHDOG_RESET (); + + /* AMD 16 bit */ + WRITE_FLASH16 (&flash[0x555], 0xAAAA); + WRITE_FLASH16 (&flash[0x2AA], 0x5555); + WRITE_FLASH16 (&flash[0x555], 0xA0A0); + + WRITE_FLASH16 (addr_16 + 1, SW_WATCHDOG_REASON); + + } +} + +static void check_restart_reason (void) +{ + /* Update restart reason if sw watchdog was + triggered */ + + int i; + volatile u32 *raddr; + + raddr = (u32 *) (CFG_FLASH_BASE + POWER_OFFSET); + + if (*raddr == 0xFFFFFFFF) { + /* Nothing written */ + maybe_update_restart_reason (raddr); + } else { + /* Search for latest written reason */ + i = 0; + while ((*(raddr + 2) != 0xFFFFFFFF) & (i < 2000)) { + raddr += 2; + i++; + } + if (i >= 2000) { + /* Whoa, dont write any more */ + printf ("*** No free restart reason found ***\n"); + } else { + /* Check if written */ + if (*raddr == 0) { + /* Erased by kernel, no new reason written */ + maybe_update_restart_reason (raddr + 2); + } + } + } +} + +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; + int failsafe = 1; + u8 system; + 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 != 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 = 3 - 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 = 3 - system; + } + } + write_bootdata (addr + 1, system, count); + if (system == SYSTEM_BOOT) { + failsafe = 0; + } + } + } + if (failsafe) { + printf ("Booting failsafe system\n"); + setenv ("bootargs", "panic=1 root=/dev/hda7"); + setenv ("bootcmd", "disk 100000 0:5;bootm 100000"); + } else { + printf ("Using normal system\n"); + setenv ("bootargs", "panic=1 root=/dev/hda4"); + setenv ("bootcmd", "disk 100000 0:2;bootm 100000"); + } +} + +int misc_init_r (void) +{ + u8 Rx[80]; + u8 Tx[5]; + int page; + int read = 0; + volatile immap_t *immap = (immap_t *) CFG_IMMR; + + /* Kill fpga */ + immap->im_ioport.iop_papar &= ~(PA_FL_CONFIG | PA_FL_CE); + immap->im_ioport.iop_padir |= (PA_FL_CONFIG | PA_FL_CE); + immap->im_ioport.iop_paodr &= ~(PA_FL_CONFIG | PA_FL_CE); + + /* Enable fpga, active low */ + immap->im_ioport.iop_padat &= ~PA_FL_CE; + + /* Start configuration */ + immap->im_ioport.iop_padat &= ~PA_FL_CONFIG; + udelay (2); + + immap->im_ioport.iop_padat |= (PA_FL_CONFIG | PA_FL_CE); + + /* Check if we need to boot failsafe system */ + check_boot_tries (); + + /* Check if we need to update restart reason */ + check_restart_reason (); + + if (ee_init_data ()) { + printf ("EEPROM init failed\n"); + return (0); + } + + /* 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_command (Tx, 2, NULL, 0, TRUE)) { + printf ("EE user page %d recall failed\n", page); + return (0); + } + + Tx[0] = READ_SCRATCHPAD; + if (ee_do_command (Tx, 2, Rx + read, 9, TRUE)) { + 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); +} |