From c609719b8d1b2dca590e0ed499016d041203e403 Mon Sep 17 00:00:00 2001 From: wdenk Date: Sun, 3 Nov 2002 00:24:07 +0000 Subject: Initial revision --- board/gen860t/README | 142 +++++++++++ board/gen860t/beeper.c | 213 ++++++++++++++++ board/gen860t/flash.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++ board/gen860t/fpga.c | 401 +++++++++++++++++++++++++++++ board/gen860t/gen860t.c | 299 ++++++++++++++++++++++ board/gen860t/ioport.c | 276 ++++++++++++++++++++ board/gen860t/u-boot.lds | 135 ++++++++++ 7 files changed, 2110 insertions(+) create mode 100644 board/gen860t/README create mode 100644 board/gen860t/beeper.c create mode 100644 board/gen860t/flash.c create mode 100644 board/gen860t/fpga.c create mode 100644 board/gen860t/gen860t.c create mode 100644 board/gen860t/ioport.c create mode 100644 board/gen860t/u-boot.lds (limited to 'board/gen860t') diff --git a/board/gen860t/README b/board/gen860t/README new file mode 100644 index 0000000..761ceed --- /dev/null +++ b/board/gen860t/README @@ -0,0 +1,142 @@ + +This directory contains board specific code for a generic MPC860T based +embedded computer, called 'GEN860T'. The design is generic in the sense that +common, readily available components are used and that the architecture of the +system is i(relatively) straightforward: + + One eight bit wide boot (FLASH) memory + 32 bit main memory using SDRAM + DOC 2000+ + Ethernet PHY + Some I2C peripheral devices: Atmel AT24C256 EEPROM, Maxim DS1337 RTC. + Some other miscellaneous peripherals + +NOTE: There are references to a XIlinx FPGA and Mil-Std 1553 databus in this +port. I guess the computer is not as generic as I first said 8) However, +these extras can be safely ignored. + +Given the GEN860T files, it should be pretty easy to reverse engineer the +hardware configuration, if that's useful to you. Hopefully, this code will +be useful to someone as a basis for a port to a new system or as a head start +on a custom design. If you end up using any of this, I would appreciate +hearing from you, especially if you discover bugs or find ways to improve the +quality of this U-Boot port. + +Here are the salient features of the system: +Clock : 33 Mhz oscillator +Processor core frequency : 66 Mhz if in 1:2:1 mode; can also run 1:1 +Bus frequency : 33 Mhz + +Main memory: + Type : SDRAM + Width : 32 bits + Size : 64 megabytes + Chip : Two Micron MT48LC16M16A2TG-7E + CS : MPC860T CS1*/UPMA + UPMA CONNECTIONS: + SDRAM A10 : GPLA0* + SDRAM CAS* : GPLA2* + SDRAM WE* : GPLA3* + SDRAM RAS* : GPLA4* + +Boot memory: + Type : FLASH + Width : 8 bits + Size : 16 megabytes + Chip : One Intel 28F128J3A (StrataFlash) + CS : MPC860T CS0*/GPCM (this is the "boot" chip select) + +EEPROM memory: + Type : Serial I2C EEPROM + Width : 8 bits + Size : 32 kibibytes + Chip : One Atmel AT25C256 + CS : 0x50 (external I2C address pins on device are tied to GND) + +Filesystem memory: + Type : NAND FLASH (Toshiba) + Width : 8 bits (i.e. interface to DOC is 8 bits) + Size : 32 megabytes + Chip : One DiskOnCHip Millenium Plus (DOC 2000+) + CS : MPC860T CS2*/GPCM + +Network support: + MAC : MPC86OT FEC (Fast Ethernet Controller) + PHY : Intel LXT971A + MII Addr: 0x0 (hardwired on the board) + MII IRQ : + +Console: + RS-232 on SMC1 (Maxim MAX3232 LVCMOS-RS232 level shifter) + +Real Time Clock: + Type : Low power, I2C interface + Chip : Maxim DS1337 + CS : Address 0x68 on I2C bus + + The MPC860T's internal RTC has a defect in Mask rev D that increases + the current drain on the KAPWR line to 10 mA. Since this is an + unreasonable amount of current draw for a RTC, and Motorola does not + plan to fix this in future mask revisions, a serial (I2C) RTC that + works has been included instead. NOTE that the DS1337 can be + configured to output a 32768 Hz clock while the main power is on. + This clock output has been routed to the MPC860T's EXTAL pin to allow + the internal RTC to be used. NOTE also that due to yet another + defect in the rev D mask, the RTC does not operate reliably when the + internal RTC divisor is set to use a 32768 Hz reference. So just use + the I2C RTC. + +Miscellaneous: + Xilinx Virtex FPGA on CS3*/GPCM. + Virtex FPGA slave SelectMap interface on cs4*/UPMB. + Mil-Std 1553 databus interface on CS5*/GPCM. + Audio sounder (beeper) with digital volume control connected to SPKROUT. + +Issues: + The DOC 2000+ returns 0x40 as its device ID when probed using the method + desxribed in the DOC datasheet. Unfortunately, the U-Boot DOC driver + does not recognize this device. As of this writing, it seems that MTD + does not support the DOC 2000+ either. + +Status: + Everything appears to work except DOC support. As of this writing, + David Woodhouse has stated on the MTD mailing list that he has no + knowledge of the DOC Millineum Plus and therfore there is no support + in MTD for this device. I wish I had known this sooner :( + +The GEN860T board specific files and configuration is based on the work +of others who have contributed to U-Boot. The copright and license notices +of these authors have been retained wherever their code has been reused. +All new code to support the GEN860T board is: + + (C) Copyright 2001-2002 + Keith Outwater (keith_outwater@mvis.com) + +and the following license applies: + +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, +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 + +Thanks to Wolfgang Denk for a great software package and to everyone +who contributed to its development. + +Keith Outwater +Sr. Staff Engineer +Microvision, Inc. + + + +vim: set ts=4 sw=4 tw=78: + diff --git a/board/gen860t/beeper.c b/board/gen860t/beeper.c new file mode 100644 index 0000000..46fe66b --- /dev/null +++ b/board/gen860t/beeper.c @@ -0,0 +1,213 @@ +/* + * (C) Copyright 2002 + * Keith Outwater, keith_outwater@mvis.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 +#include +#include +#include + +/* + * Basic beeper support for the GEN860T board. The GEN860T includes + * an audio sounder driven by a Phillips TDA8551 amplifier. The + * TDA8551 features a digital volume control which uses a "trinary" + * input (high/high-Z/low) to set volume. The 860's SPKROUT pin + * drives the amplifier input. + */ + + +/* + * Initialize beeper-related hardware. Initialize timer 1 for use with + * the beeper. Use 66 Mhz internal clock with prescale of 33 to get + * 1 uS period per count. + * FIXME: we should really compute the prescale based on the reported + * core clock frequency. + */ +void +init_beeper(void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + immap->im_cpmtimer.cpmt_tgcr &= ~TGCR_RST1 | TGCR_STP1; + immap->im_cpmtimer.cpmt_tmr1 = ((33 << TMR_PS_SHIFT) & TMR_PS_MSK) + | TMR_OM | TMR_FRR | TMR_ICLK_IN_GEN; + immap->im_cpmtimer.cpmt_tcn1 = 0; + immap->im_cpmtimer.cpmt_ter1 = 0xffff; + immap->im_cpmtimer.cpmt_tgcr |= TGCR_RST1; +} + + +/* + * Set beeper frequency. Max allowed frequency is 2.5 KHz. This limit + * is mostly arbitrary, but the beeper isn't really much good beyond this + * frequency. + */ +void +set_beeper_frequency(uint frequency) +{ +#define FREQ_LIMIT 2500 + + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + /* + * Compute timer ticks given desired frequency. The timer is set up + * to count 0.5 uS per tick and it takes two ticks per cycle (Hz). + */ + if (frequency > FREQ_LIMIT) frequency = FREQ_LIMIT; + frequency = 1000000/frequency; + immap->im_cpmtimer.cpmt_trr1 = (ushort)frequency; +} + + +/* + * Turn the beeper on + */ +void +beeper_on(void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + immap->im_cpmtimer.cpmt_tgcr &= ~TGCR_STP1; +} + + +/* + * Turn the beeper off + */ +void +beeper_off(void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + immap->im_cpmtimer.cpmt_tgcr |= TGCR_STP1; +} + + +/* + * Increase or decrease the beeper volume. Volume can be set + * from off to full in 64 steps. To increase volume, the output + * pin is actively driven high, then returned to tristate. + * To decrease volume, output a low on the port pin (no need to + * change pin mode to tristate) then output a high to go back to + * tristate. + */ +void +set_beeper_volume(int steps) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + int i; + + if (steps >= 0) { + for (i = 0; i < (steps >= 64 ? 64 : steps); i++) { + immap->im_cpm.cp_pbodr &= ~(0x80000000 >> 19); + udelay(1); + immap->im_cpm.cp_pbodr |= (0x80000000 >> 19); + udelay(1); + } + } + else { + for (i = 0; i > (steps <= -64 ? -64 : steps); i--) { + immap->im_cpm.cp_pbdat &= ~(0x80000000 >> 19); + udelay(1); + immap->im_cpm.cp_pbdat |= (0x80000000 >> 19); + udelay(1); + } + } +} + + +/* + * Check the environment to see if the beeper needs beeping. + * Controlled by a sequence of the form: + * freq/delta volume/on time/off time;... where: + * freq = frequency in Hz (0 - 2500) + * delta volume = volume steps up or down (-64 <= vol <= 64) + * on time = time in mS + * off time = time in mS + * + * Return 1 on success, 0 on failure + */ +int +do_beeper(char *sequence) +{ +#define DELIMITER ';' + +int args[4]; +int i; +int val; +char *p = sequence; +char *tp; + + /* + * Parse the control sequence. This is a really simple parser + * without any real error checking. You can probably blow it + * up really easily. + */ + if (*p == '\0' || !isdigit(*p)) { + printf("%s:%d: null or invalid string (%s)\n", + __FILE__, __LINE__, p); + return 0; + } + + i = 0; + while (*p != '\0') { + while (*p != DELIMITER) { + if (i > 3) i = 0; + val = (int) simple_strtol(p, &tp, 0); + if (tp == p) { + printf("%s:%d: no digits or bad format\n", + __FILE__,__LINE__); + return 0; + } + else { + args[i] = val; + } + + i++; + if (*tp == DELIMITER) + p = tp; + else + p = ++tp; + } + p++; + + /* + * Well, we got something that has a chance of being correct + */ +#if 0 + for (i = 0; i < 4; i++) { + printf("%s:%d:arg %d = %d\n", __FILE__, __LINE__, i, args[i]); + } + printf("\n"); +#endif + + set_beeper_frequency(args[0]); + set_beeper_volume(args[1]); + beeper_on(); + udelay(1000 * args[2]); + beeper_off(); + udelay(1000 * args[3]); + } + return 1; +} + +/* vim: set ts=4 sw=4 tw=78: */ diff --git a/board/gen860t/flash.c b/board/gen860t/flash.c new file mode 100644 index 0000000..902b1b0 --- /dev/null +++ b/board/gen860t/flash.c @@ -0,0 +1,644 @@ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Keith Outwater, keith_outwater@mvsi.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 +#include + +#if defined(CFG_ENV_IS_IN_FLASH) +# ifndef CFG_ENV_ADDR +# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET) +# endif +# ifndef CFG_ENV_SIZE +# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE +# endif +# ifndef CFG_ENV_SECT_SIZE +# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE +# endif +#endif + +/* + * Use buffered writes to flash by default - they are about 32x faster than + * single byte writes. + */ +#ifndef CFG_GEN860T_FLASH_USE_WRITE_BUFFER +#define CFG_GEN860T_FLASH_USE_WRITE_BUFFER +#endif + +/* + * Max time to wait (in mS) for flash device to allocate a write buffer. + */ +#ifndef CFG_FLASH_ALLOC_BUFFER_TOUT +#define CFG_FLASH_ALLOC_BUFFER_TOUT 100 +#endif + +/* + * These functions support a single Intel StrataFlash device (28F128J3A) + * in byte mode only!. The flash routines are very basic and simple + * since there isn't really any remapping necessary. + */ + +/* + * Intel SCS (Scalable Command Set) command definitions + * (taken from 28F128J3A datasheet) + */ +#define SCS_READ_CMD 0xff +#define SCS_READ_ID_CMD 0x90 +#define SCS_QUERY_CMD 0x98 +#define SCS_READ_STATUS_CMD 0x70 +#define SCS_CLEAR_STATUS_CMD 0x50 +#define SCS_WRITE_BUF_CMD 0xe8 +#define SCS_PROGRAM_CMD 0x40 +#define SCS_BLOCK_ERASE_CMD 0x20 +#define SCS_BLOCK_ERASE_RESUME_CMD 0xd0 +#define SCS_PROGRAM_RESUME_CMD 0xd0 +#define SCS_BLOCK_ERASE_SUSPEND_CMD 0xb0 +#define SCS_SET_BLOCK_LOCK_CMD 0x60 +#define SCS_CLR_BLOCK_LOCK_CMD 0x60 + +/* + * SCS status/extended status register bit definitions + */ +#define SCS_SR7 0x80 +#define SCS_XSR7 0x80 + +/*---------------------------------------------------------------------*/ +#if 0 +#define DEBUG_FLASH +#endif + +#ifdef DEBUG_FLASH +#define PRINTF(fmt,args...) printf(fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif +/*---------------------------------------------------------------------*/ + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size (vu_char *addr, flash_info_t *info); +static int write_data8 (flash_info_t *info, ulong dest, uchar data); +static void flash_get_offsets (ulong base, flash_info_t *info); + +/*----------------------------------------------------------------------- + * Initialize the flash memory. + */ +unsigned long +flash_init (void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + unsigned long size_b0; + int i; + + for (i= 0; i < CFG_MAX_FLASH_BANKS; ++i) { + flash_info[i].flash_id = FLASH_UNKNOWN; + } + + /* + * The gen860t board only has one FLASH memory device, so the + * FLASH Bank configuration is done statically. + */ + PRINTF("\n## Get flash bank 1 size @ 0x%08x\n", FLASH_BASE0_PRELIM); + size_b0 = flash_get_size((vu_char *)FLASH_BASE0_PRELIM, &flash_info[0]); + if (flash_info[0].flash_id == FLASH_UNKNOWN) { + printf ("## Unknown FLASH on Bank 0: " + "ID 0x%lx, Size = 0x%08lx = %ld MB\n", + flash_info[0].flash_id,size_b0, size_b0 << 20); + } + + PRINTF("## Before remap:\n" + " BR0: 0x%08x OR0: 0x%08x\n BR1: 0x%08x OR1: 0x%08x\n", + memctl->memc_br0, memctl->memc_or0, + memctl->memc_br1, memctl->memc_or1); + + /* + * Remap FLASH according to real size + */ + memctl->memc_or0 |= (-size_b0 & 0xFFFF8000); + memctl->memc_br0 |= (CFG_FLASH_BASE & BR_BA_MSK); + + PRINTF("## After remap:\n" + " BR0: 0x%08x OR0: 0x%08x\n", memctl->memc_br0, memctl->memc_or0); + + /* + * Re-do sizing to get full correct info + */ + size_b0 = flash_get_size ((vu_char *)CFG_FLASH_BASE, &flash_info[0]); + flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]); + flash_info[0].size = size_b0; + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + /* + * Monitor protection is ON by default + */ + flash_protect(FLAG_PROTECT_SET, + CFG_MONITOR_BASE, + CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, + &flash_info[0]); +#endif + +#ifdef CFG_ENV_IS_IN_FLASH + /* + * Environment protection ON by default + */ + flash_protect(FLAG_PROTECT_SET, + CFG_ENV_ADDR, + CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, + &flash_info[0]); +#endif + + PRINTF("## Final Flash bank size: 0x%08lx\n",size_b0); + return (size_b0); +} + + +/*----------------------------------------------------------------------- + * Fill in the FLASH offset table + */ +static void +flash_get_offsets (ulong base, flash_info_t *info) +{ + int i; + + if (info->flash_id == FLASH_UNKNOWN) { + return; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_INTEL: + for (i = 0; i < info->sector_count; i++) { + info->start[i] = base; + base += 1024 * 128; + } + return; + + default: + printf ("Don't know sector offsets for FLASH" + " type 0x%lx\n", info->flash_id); + return; + } +} + + +/*----------------------------------------------------------------------- + * Display FLASH device info + */ +void +flash_print_info (flash_info_t *info) +{ + int i; + + if (info->flash_id == FLASH_UNKNOWN) { + printf ("Missing or unknown FLASH type\n"); + return; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_INTEL: + printf ("Intel "); + break; + default: + printf ("Unknown Vendor "); + break; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_28F128J3A: + printf ("28F128J3A (128Mbit = 128K x 128)\n"); + break; + default: + printf ("Unknown Chip Type\n"); + break; + } + + if (info->size >= (1024 * 1024)) { + i = 20; + } else { + i = 10; + } + printf (" Size: %ld %cB in %d Sectors\n", + info->size >> i, + (i == 20) ? 'M' : 'k', + info->sector_count); + + printf (" Sector Start Addresses:"); + for (i=0; isector_count; ++i) { + if ((i % 5) == 0) + printf ("\n "); + printf (" %08lX%s", + info->start[i], + info->protect[i] ? " (RO)" : " " + ); + } + printf ("\n"); + return; +} + + +/*----------------------------------------------------------------------- + * Get size and other information for a FLASH device. + * NOTE: The following code cannot be run from FLASH! + */ +static +ulong flash_get_size (vu_char *addr, flash_info_t *info) +{ +#define NO_FLASH 0 + + vu_char value[2]; + + /* + * Try to read the manufacturer ID + */ + addr[0] = SCS_READ_CMD; + addr[0] = SCS_READ_ID_CMD; + value[0] = addr[0]; + value[1] = addr[2]; + addr[0] = SCS_READ_CMD; + + PRINTF("Manuf. ID @ 0x%08lx: 0x%02x\n", (ulong)addr, value[0]); + switch (value[0]) { + case (INTEL_MANUFACT & 0xff): + info->flash_id = FLASH_MAN_INTEL; + break; + default: + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + return (NO_FLASH); + } + + /* + * Read the device ID + */ + PRINTF("Device ID @ 0x%08lx: 0x%02x\n", (ulong)(&addr[2]), value[1]); + switch (value[1]) { + case (INTEL_ID_28F128J3A & 0xff): + info->flash_id += FLASH_28F128J3A; + info->sector_count = 128; + info->size = 16 * 1024 * 1024; + break; + + default: + info->flash_id = FLASH_UNKNOWN; + return (NO_FLASH); + } + + if (info->sector_count > CFG_MAX_FLASH_SECT) { + printf ("** ERROR: sector count %d > max (%d) **\n", + info->sector_count, CFG_MAX_FLASH_SECT); + info->sector_count = CFG_MAX_FLASH_SECT; + } + return (info->size); +} + + +/*----------------------------------------------------------------------- + * Erase the specified sectors in the specified FLASH device + */ +int +flash_erase(flash_info_t *info, int s_first, int s_last) +{ + int flag, prot, sect; + ulong start, now, last; + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf ("- missing\n"); + } else { + printf ("- no sectors to erase\n"); + } + return 1; + } + + if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) { + printf ("Can erase only Intel flash types - aborted\n"); + return 1; + } + + prot = 0; + for (sect=s_first; sect<=s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + + if (prot) { + printf ("- Warning: %d protected sectors will not be erased!\n", + prot); + } else { + printf ("\n"); + } + + start = get_timer (0); + last = start; + + /* + * Start erase on unprotected sectors + */ + for (sect = s_first; sect<=s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + vu_char *addr = (uchar *)(info->start[sect]); + vu_char status; + + /* + * Disable interrupts which might cause a timeout + */ + flag = disable_interrupts(); + + *addr = SCS_CLEAR_STATUS_CMD; + *addr = SCS_BLOCK_ERASE_CMD; + *addr = SCS_BLOCK_ERASE_RESUME_CMD; + + /* + * Re-enable interrupts if necessary + */ + if (flag) + enable_interrupts(); + + /* + * Wait at least 80us - let's wait 1 ms + */ + udelay (1000); + + while (((status = *addr) & SCS_SR7) != SCS_SR7) { + if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) { + printf ("Timeout\n"); + *addr = SCS_BLOCK_ERASE_SUSPEND_CMD; + *addr = SCS_READ_CMD; + return 1; + } + + /* + * Show that we're waiting + */ + if ((now - last) > 1000) { /* 1 second */ + putc ('.'); + last = now; + } + } + *addr = SCS_READ_CMD; + } + } + printf (" done\n"); + return 0; +} + + +#ifdef CFG_GEN860T_FLASH_USE_WRITE_BUFFER +/* + * Allocate a flash buffer, fill it with data and write it to the flash. + * 0 - OK + * 1 - Timeout on buffer request + * + * NOTE: After the last call to this function, WSM status needs to be checked! + */ +static int +write_flash_buffer8(flash_info_t *info_p, vu_char *src_p, vu_char *dest_p, + uint count) +{ + vu_char *block_addr_p = NULL; + vu_char *start_addr_p = NULL; + ulong blocksize = info_p->size / (ulong)info_p->sector_count; + + int i; + uint time = get_timer(0); + + PRINTF("%s:%d: src: 0x%p dest: 0x%p count: %d\n", + __FUNCTION__, __LINE__, src_p, dest_p, count); + + /* + * What block are we in? We already know that the source address is + * in the flash address range, but we also can't cross a block boundary. + * We assume that the block does not cross a boundary (we'll check before + * calling this function). + */ + for (i = 0; i < info_p->sector_count; ++i) { + if ( ((ulong)dest_p >= info_p->start[i]) && + ((ulong)dest_p < (info_p->start[i] + blocksize)) ) { + PRINTF("%s:%d: Dest addr 0x%p is in block %d @ 0x%.8lx\n", + __FUNCTION__, __LINE__, dest_p, i, info_p->start[i]); + block_addr_p = (vu_char *)info_p->start[i]; + break; + } + } + + /* + * Request a buffer + */ + *block_addr_p = SCS_WRITE_BUF_CMD; + while ((*block_addr_p & SCS_XSR7) != SCS_XSR7) { + if (get_timer(time) > CFG_FLASH_ALLOC_BUFFER_TOUT) { + PRINTF("%s:%d: Buffer allocation timeout @ 0x%p (waited %d mS)\n", + __FUNCTION__, __LINE__, block_addr_p, + CFG_FLASH_ALLOC_BUFFER_TOUT); + return 1; + } + *block_addr_p = SCS_WRITE_BUF_CMD; + } + + /* + * Fill the buffer with data + */ + start_addr_p = dest_p; + *block_addr_p = count - 1; /* flash device wants count - 1 */ + PRINTF("%s:%d: Fill buffer at block addr 0x%p\n", + __FUNCTION__, __LINE__, block_addr_p); + for (i = 0; i < count; i++) { + *start_addr_p++ = *src_p++; + } + + /* + * Flush buffer to flash + */ + *block_addr_p = SCS_PROGRAM_RESUME_CMD; +#if 1 + time = get_timer(0); + while ((*block_addr_p & SCS_SR7) != SCS_SR7) { + if (get_timer(time) > CFG_FLASH_WRITE_TOUT) { + PRINTF("%s:%d: Write timeout @ 0x%p (waited %d mS)\n", + __FUNCTION__, __LINE__, block_addr_p, CFG_FLASH_WRITE_TOUT); + return 1; + } + } + +#endif + return 0; +} +#endif + + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + * 4 - Flash not identified + */ +int +write_buff(flash_info_t *info_p, uchar *src_p, ulong addr, ulong count) +{ + int rc = 0; +#ifdef CFG_GEN860T_FLASH_USE_WRITE_BUFFER +#define FLASH_WRITE_BUF_SIZE 0x00000020 /* 32 bytes */ + int i; + uint bufs; + ulong buf_count; + vu_char *sp; + vu_char *dp; +#else + ulong wp; +#endif + + PRINTF("\n%s:%d: src: 0x%.8lx dest: 0x%.8lx size: %d (0x%.8lx)\n", + __FUNCTION__, __LINE__, (ulong)src_p, addr, (uint)count, count); + + if (info_p->flash_id == FLASH_UNKNOWN) { + return 4; + } + +#ifdef CFG_GEN860T_FLASH_USE_WRITE_BUFFER + sp = src_p; + dp = (uchar *)addr; + + /* + * For maximum performance, we want to align the start address to + * the beginning of a write buffer boundary (i.e. A4-A0 of the + * start address = 0). See how many bytes are required to get to a + * write-buffer-aligned address. If that number is non-zero, do + * non buffered writes of the non-aligned data. By doing non-buffered + * writes, we avoid the problem of crossing a block (sector) boundary + * with buffered writes. + */ + buf_count = FLASH_WRITE_BUF_SIZE - (addr & (FLASH_WRITE_BUF_SIZE - 1)); + if (buf_count == FLASH_WRITE_BUF_SIZE) { /* already on a boundary */ + buf_count = 0; + } + if (buf_count > count) { /* not a full buffers worth of data to write */ + buf_count = count; + } + count -= buf_count; + + PRINTF("%s:%d: Write buffer alignment count = %ld\n", + __FUNCTION__, __LINE__, buf_count); + while (buf_count-- >= 1) { + if ((rc = write_data8(info_p, (ulong)dp++, *sp++)) != 0) { + return (rc); + } + } + + PRINTF("%s:%d: count = %ld\n", __FUNCTION__, __LINE__, count); + if (count == 0) { /* all done */ + PRINTF("%s:%d: Less than 1 buffer (%d) worth of bytes\n", + __FUNCTION__, __LINE__, FLASH_WRITE_BUF_SIZE); + return (rc); + } + + /* + * Now that we are write buffer aligned, write full or partial buffers. + * The fact that we are write buffer aligned automatically avoids + * crossing a block address during a write buffer operation. + */ + bufs = count / FLASH_WRITE_BUF_SIZE; + PRINTF("%s:%d: %d (0x%x) buffers to write\n", __FUNCTION__, __LINE__, + bufs, bufs); + while (bufs >= 1) { + rc = write_flash_buffer8(info_p, sp, dp, FLASH_WRITE_BUF_SIZE); + if (rc != 0) { + PRINTF("%s:%d: ** Error writing buf %d\n", + __FUNCTION__, __LINE__, bufs); + return (rc); + } + bufs--; + sp += FLASH_WRITE_BUF_SIZE; + dp += FLASH_WRITE_BUF_SIZE; + } + + /* + * Do the leftovers + */ + i = count % FLASH_WRITE_BUF_SIZE; + PRINTF("%s:%d: %d (0x%x) leftover bytes\n", __FUNCTION__, __LINE__, i, i); + if (i > 0) { + rc = write_flash_buffer8(info_p, sp, dp, i); + } + + sp = (vu_char*)info_p->start[0]; + *sp = SCS_READ_CMD; + return (rc); + +#else + wp = addr; + while (count-- >= 1) { + if((rc = write_data8(info_p, wp++, *src_p++)) != 0) + return (rc); + } + return 0; +#endif +} + + +/*----------------------------------------------------------------------- + * Write a byte to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int +write_data8 (flash_info_t *info, ulong dest, uchar data) +{ + vu_char *addr = (vu_char *)dest; + vu_char status; + ulong start; + int flag; + + /* Check if Flash is (sufficiently) erased */ + if ((*addr & data) != data) { + return (2); + } + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + *addr = SCS_PROGRAM_CMD; + *addr = data; + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + start = get_timer (0); + + while (((status = *addr) & SCS_SR7) != SCS_SR7) { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + *addr = SCS_READ_CMD; + return (1); + } + } + *addr = SCS_READ_CMD; + return (0); +} + +/* vim: set ts=4 sw=4 tw=78: */ diff --git a/board/gen860t/fpga.c b/board/gen860t/fpga.c new file mode 100644 index 0000000..2c4fbf1 --- /dev/null +++ b/board/gen860t/fpga.c @@ -0,0 +1,401 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * Keith Outwater, keith_outwater@mvis.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 + * + */ + +/* + * Virtex2 FPGA configuration support for the GEN860T computer + */ + +#include +#include +#include +#include "fpga.h" + +#if (CONFIG_FPGA) + +#if 0 +#define GEN860T_FPGA_DEBUG +#endif + +#ifdef GEN860T_FPGA_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* + * Port bit numbers for the Selectmap controls + */ +#define FPGA_INIT_BIT_NUM 22 /* PB22 */ +#define FPGA_RESET_BIT_NUM 11 /* PC11 */ +#define FPGA_DONE_BIT_NUM 16 /* PB16 */ +#define FPGA_PROGRAM_BIT_NUM 7 /* PA7 */ + +/* Note that these are pointers to code that is in Flash. They will be + * relocated at runtime. + */ +Xilinx_Virtex2_Slave_SelectMap_fns fpga_fns = { + fpga_pre_config_fn, + fpga_pgm_fn, + fpga_init_fn, + fpga_err_fn, + fpga_done_fn, + fpga_clk_fn, + fpga_cs_fn, + fpga_wr_fn, + fpga_read_data_fn, + fpga_write_data_fn, + fpga_busy_fn, + fpga_abort_fn, + fpga_post_config_fn +}; + +Xilinx_desc fpga[CONFIG_FPGA_COUNT] = { + { Xilinx_Virtex2, + slave_selectmap, + XILINX_XC2V3000_SIZE, + (void *)&fpga_fns, + 0 + } +}; + +/* + * Display FPGA revision information + */ +void +print_fpga_revision(void) +{ + vu_long *rev_p = (vu_long *)0x60000008; + + printf("FPGA Revision 0x%.8lx" + " (Date %.2lx/%.2lx/%.2lx, Status \"%.1lx\", Version %.3lu)\n", + *rev_p, + ((*rev_p >> 28) & 0xf), + ((*rev_p >> 20) & 0xff), + ((*rev_p >> 12) & 0xff), + ((*rev_p >> 8) & 0xf), + (*rev_p & 0xff)); +} + + +/* + * Perform a simple test of the FPGA to processor interface using the FPGA's + * inverting bus test register. The great thing about doing a read/write + * test on a register that inverts it's contents is that you avoid any + * problems with bus charging. + * Return 0 on failure, 1 on success. + */ +int +test_fpga_ibtr(void) +{ + vu_long *ibtr_p = (vu_long *)0x60000010; + vu_long readback; + vu_long compare; + int i; + int j; + int k; + int pass = 1; + + static const ulong bitpattern[] = { + 0xdeadbeef, /* magic ID pattern for debug */ + 0x00000001, /* single bit */ + 0x00000003, /* two adjacent bits */ + 0x00000007, /* three adjacent bits */ + 0x0000000F, /* four adjacent bits */ + 0x00000005, /* two non-adjacent bits */ + 0x00000015, /* three non-adjacent bits */ + 0x00000055, /* four non-adjacent bits */ + 0xaaaaaaaa, /* alternating 1/0 */ + }; + + for (i = 0; i < 1024; i++) { + for (j = 0; j < 31; j++) { + for (k = 0; k < sizeof(bitpattern)/sizeof(bitpattern[0]); k++) { + *ibtr_p = compare = (bitpattern[k] << j); + readback = *ibtr_p; + if (readback != ~compare) { + printf("%s:%d: FPGA test fail: expected 0x%.8lx" + " actual 0x%.8lx\n", + __FUNCTION__, __LINE__, ~compare, readback); + pass = 0; + break; + } + } + if (!pass) break; + } + if (!pass) break; + } + if (pass) { + printf("FPGA inverting bus test passed\n"); + print_fpga_revision(); + } + else { + printf("** FPGA inverting bus test failed\n"); + } + return pass; +} + + +/* + * Set the active-low FPGA reset signal. + */ +void +fpga_reset(int assert) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + PRINTF("%s:%d: RESET ", __FUNCTION__, __LINE__); + if (assert) { + immap->im_ioport.iop_pcdat &= ~(0x8000 >> FPGA_RESET_BIT_NUM); + PRINTF("asserted\n"); + } + else { + immap->im_ioport.iop_pcdat |= (0x8000 >> FPGA_RESET_BIT_NUM); + PRINTF("deasserted\n"); + } +} + + +/* + * Initialize the SelectMap interface. We assume that the mode and the + * initial state of all of the port pins have already been set! + */ +void +fpga_selectmap_init(void) +{ + PRINTF("%s:%d: Initialize SelectMap interface\n", __FUNCTION__, __LINE__); + fpga_pgm_fn(FALSE, FALSE, 0); /* make sure program pin is inactive */ +} + + +/* + * Initialize the fpga. Return 1 on success, 0 on failure. + */ +int +gen860t_init_fpga(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + int i; + + PRINTF("%s:%d: Initialize FPGA interface (relocation offset = 0x%.8lx)\n", + __FUNCTION__, __LINE__, gd->reloc_off); + fpga_init(gd->reloc_off); + fpga_selectmap_init(); + + for(i=0; i < CONFIG_FPGA_COUNT; i++) { + PRINTF("%s:%d: Adding fpga %d\n", __FUNCTION__, __LINE__, i); + fpga_add(fpga_xilinx, &fpga[i]); + } + return 1; +} + + +/* + * Set the FPGA's active-low SelectMap program line to the specified level + */ +int +fpga_pgm_fn(int assert, int flush, int cookie) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + PRINTF("%s:%d: FPGA PROGRAM ", __FUNCTION__, __LINE__); + + if (assert) { + immap->im_ioport.iop_padat &= ~(0x8000 >> FPGA_PROGRAM_BIT_NUM); + PRINTF("asserted\n"); + } + else { + immap->im_ioport.iop_padat |= (0x8000 >> FPGA_PROGRAM_BIT_NUM); + PRINTF("deasserted\n"); + } + return assert; +} + + +/* + * Test the state of the active-low FPGA INIT line. Return 1 on INIT + * asserted (low). + */ +int +fpga_init_fn(int cookie) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + PRINTF("%s:%d: INIT check... ", __FUNCTION__, __LINE__); + if(immap->im_cpm.cp_pbdat & (0x80000000 >> FPGA_INIT_BIT_NUM)) { + PRINTF("high\n"); + return 0; + } + else { + PRINTF("low\n"); + return 1; + } +} + + +/* + * Test the state of the active-high FPGA DONE pin + */ +int +fpga_done_fn(int cookie) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + PRINTF("%s:%d: DONE check... ", __FUNCTION__, __LINE__); + if (immap->im_cpm.cp_pbdat & (0x80000000 >> FPGA_DONE_BIT_NUM)) { + PRINTF("high\n"); + return FPGA_SUCCESS; + } + else { + PRINTF("low\n"); + return FPGA_FAIL; + } +} + + +/* + * Read FPGA SelectMap data. + */ +int +fpga_read_data_fn(unsigned char *data, int cookie) +{ + vu_char *p = (vu_char *)SELECTMAP_BASE; + + *data = *p; +#if 0 + PRINTF("%s: Read 0x%x into 0x%p\n", __FUNCTION__, (int)data, data); +#endif + return (int)data; +} + + +/* + * Write data to the FPGA SelectMap port + */ +int +fpga_write_data_fn(unsigned char data, int flush, int cookie) +{ + vu_char *p = (vu_char *)SELECTMAP_BASE; + +#if 0 + PRINTF("%s: Write Data 0x%x\n", __FUNCTION__, (int)data); +#endif + *p = data; + return (int)data; +} + + +/* + * Abort and FPGA operation + */ +int +fpga_abort_fn(int cookie) +{ + PRINTF("%s:%d: FPGA program sequence aborted\n", + __FUNCTION__, __LINE__); + return FPGA_FAIL; +} + + +/* + * FPGA pre-configuration function. Just make sure that + * FPGA reset is asserted to keep the FPGA from starting up after + * configuration. + */ +int +fpga_pre_config_fn(int cookie) +{ + PRINTF("%s:%d: FPGA pre-configuration\n", __FUNCTION__, __LINE__); + fpga_reset(TRUE); + return 0; +} + + +/* + * FPGA post configuration function. Blip the FPGA reset line and then see if + * the FPGA appears to be running. + */ +int +fpga_post_config_fn(int cookie) +{ + int rc; + + PRINTF("%s:%d: FPGA post configuration\n", __FUNCTION__, __LINE__); + fpga_reset(TRUE); + udelay(1000); + fpga_reset(FALSE); + udelay (1000); + + /* + * Use the FPGA,s inverting bus test register to do a simple test of the + * processor interface. + */ + rc = test_fpga_ibtr(); + return rc; +} + + +/* + * Clock, chip select and write signal assert functions and error check + * and busy functions. These are only stubs because the GEN860T selectmap + * interface handles sequencing of control signals automatically (it uses + * a memory-mapped interface to the FPGA SelectMap port). The design of + * the interface guarantees that the SelectMap port cannot be overrun so + * no busy check is needed. A configuration error is signalled by INIT + * going low during configuration, so there is no need for a separate error + * function. + */ +int +fpga_clk_fn(int assert_clk, int flush, int cookie) +{ + return assert_clk; +} + +int +fpga_cs_fn(int assert_cs, int flush, int cookie) +{ + return assert_cs; +} + +int +fpga_wr_fn(int assert_write, int flush, int cookie) +{ + return assert_write; +} + +int +fpga_err_fn(int cookie) +{ + return 0; +} + +int +fpga_busy_fn(int cookie) +{ + return 0; +} +#endif + +/* vim: set ts=4 tw=78 sw=4: */ diff --git a/board/gen860t/gen860t.c b/board/gen860t/gen860t.c new file mode 100644 index 0000000..16a3262 --- /dev/null +++ b/board/gen860t/gen860t.c @@ -0,0 +1,299 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Keith Outwater, keith_outwater@mvis.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 +#include +#include +#include +#include "beeper.h" +#include "fpga.h" +#include "ioport.h" + +#ifdef CONFIG_STATUS_LED +#include +#endif + +#if defined(CFG_CMD_MII) && defined(CONFIG_MII) +#include +#endif + +#if 0 +#define GEN860T_DEBUG +#endif + +#ifdef GEN860T_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* + * The following UPM init tables were generated automatically by + * Motorola's MCUINIT program. See the README file for UPM to + * SDRAM pin assignments if you want to type this data into + * MCUINIT in order to reverse engineer the waveforms. + */ + +/* + * UPM initialization tables for MICRON MT48LC16M16A2TG SDRAM devices + * (UPMA) and Virtex FPGA SelectMap interface (UPMB). + * NOTE that unused areas of the table are used to hold NOP, precharge + * and mode register set sequences. + * + */ +#define UPMA_NOP_ADDR 0x5 +#define UPMA_PRECHARGE_ADDR 0x6 +#define UPMA_MRS_ADDR 0x12 + +#define UPM_SINGLE_READ_ADDR 0x00 +#define UPM_BURST_READ_ADDR 0x08 +#define UPM_SINGLE_WRITE_ADDR 0x18 +#define UPM_BURST_WRITE_ADDR 0x20 +#define UPM_REFRESH_ADDR 0x30 + +const uint sdram_upm_table[] = { + /* single read (offset 0x00 in upm ram) */ + 0x0e0fdc04, 0x01adfc04, 0x0fbffc00, 0x1fff5c05, + 0xffffffff, 0x0fffffcd, 0x0fff0fce, 0xefcfffff, + /* burst read (offset 0x08 in upm ram) */ + 0x0f0fdc04, 0x00fdfc04, 0xf0fffc00, 0xf0fffc00, + 0xf1fffc00, 0xfffffc00, 0xfffffc05, 0xffffffff, + 0xffffffff, 0xffffffff, 0x0ffffff4, 0x1f3d5ff4, + 0xfffffff4, 0xfffffff5, 0xffffffff, 0xffffffff, + /* single write (offset 0x18 in upm ram) */ + 0x0f0fdc04, 0x00ad3c00, 0x1fff5c05, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + /* burst write (offset 0x20 in upm ram) */ + 0x0f0fdc00, 0x10fd7c00, 0xf0fffc00, 0xf0fffc00, + 0xf1fffc04, 0xfffffc05, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff7ff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + /* refresh (offset 0x30 in upm ram) */ + 0x1ffddc84, 0xfffffc04, 0xfffffc04, 0xfffffc84, + 0xfffffc05, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + /* exception (offset 0x3C in upm ram) */ + }; + +const uint selectmap_upm_table[] = { + /* single read (offset 0x00 in upm ram) */ + 0x88fffc06, 0x00fff404, 0x00fffc04, 0x33fffc00, + 0xfffffc05, 0xffffffff, 0xffffffff, 0xffffffff, + /* burst read (offset 0x08 in upm ram) */ + 0xfffffc04, 0xfffffc05, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + /* single write (offset 0x18 in upm ram) */ + 0x88fffc04, 0x00fff400, 0x77fffc05, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + /* burst write (offset 0x20 in upm ram) */ + 0xfffffc04, 0xfffffc05, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + /* refresh (offset 0x30 in upm ram) */ + 0xfffffc04, 0xfffffc05, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + /* exception (offset 0x3C in upm ram) */ + 0xfffffc05, 0xffffffff, 0xffffffff, 0xffffffff +}; + +/* + * Check board identity. Always successful (gives information only) + */ +int +checkboard(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + unsigned char *s; + unsigned char buf[64]; + int i; + + i = getenv_r("board_id", buf, sizeof(buf)); + s = (i>0) ? buf : NULL; + + if (s) { + printf("%s ", s); + } else { + printf(" "); + } + + i = getenv_r("serial#", buf, sizeof(buf)); + s = (i>0) ? buf : NULL; + + if (s) { + printf("S/N %s\n", s); + } else { + printf("S/N \n"); + } + + printf("CPU at %s MHz, ",strmhz(buf, gd->cpu_clk)); + printf("local bus at %s MHz\n", strmhz(buf, gd->bus_clk)); + return (0); +} + +/* + * Initialize SDRAM + */ +long int +initdram(int board_type) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immr->im_memctl; + + upmconfig(UPMA, + (uint *)sdram_upm_table, + sizeof(sdram_upm_table) / sizeof(uint) + ); + + /* + * Setup MAMR register + */ + memctl->memc_mptpr = CFG_MPTPR_1BK_8K; + memctl->memc_mamr = CFG_MAMR_8COL & (~(MAMR_PTAE)); /* no refresh yet */ + + /* + * Map CS1* to SDRAM bank + */ + memctl->memc_or1 = CFG_OR1; + memctl->memc_br1 = CFG_BR1; + + /* + * Perform SDRAM initialization sequence: + * 1. Apply at least one NOP command + * 2. 100 uS delay (JEDEC standard says 200 uS) + * 3. Issue 4 precharge commands + * 4. Perform two refresh cycles + * 5. Program mode register + * + * Program SDRAM for standard operation, sequential burst, burst length + * of 4, CAS latency of 2. + */ + memctl->memc_mar = 0x00000000; + memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 | + MCR_MLCF(0) | UPMA_NOP_ADDR; + udelay(200); + memctl->memc_mar = 0x00000000; + memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 | + MCR_MLCF(4) | UPMA_PRECHARGE_ADDR; + + memctl->memc_mar = 0x00000000; + memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 | + MCR_MLCF(2) | UPM_REFRESH_ADDR; + + memctl->memc_mar = 0x00000088; + memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 | + MCR_MLCF(1) | UPMA_MRS_ADDR; + + memctl->memc_mar = 0x00000000; + memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 | + MCR_MLCF(0) | UPMA_NOP_ADDR; + /* + * Enable refresh + */ + memctl->memc_mamr |= MAMR_PTAE; + + return (SDRAM_SIZE); +} + +/* + * Disk On Chip (DOC) Millenium initialization. + * The DOC lives in the CS2* space + */ +#if (CONFIG_COMMANDS & CFG_CMD_DOC) +extern void +doc_probe(ulong physadr); + +void +doc_init(void) +{ + printf("Probing at 0x%.8x: ", DOC_BASE); + doc_probe(DOC_BASE); +} +#endif + +/* + * Miscellaneous intialization + */ +int +misc_init_r (void) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immr->im_memctl; + + /* + * Set up UPMB to handle the Virtex FPGA SelectMap interface + */ + upmconfig(UPMB, (uint *)selectmap_upm_table, + sizeof(selectmap_upm_table) / sizeof(uint)); + + memctl->memc_mbmr = 0x0; + + config_mpc8xx_ioports(immr); + +#if (CONFIG_COMMANDS & CFG_CMD_MII) + mii_init(); +#endif + +#if (CONFIG_FPGA) + gen860t_init_fpga(); +#endif + return 0; +} + +/* + * Final init hook before entering command loop. + */ +int +last_stage_init(void) +{ + unsigned char buf[256]; + int i; + + /* + * Set LEDs here since status LED init code has already run + */ + status_led_set(STATUS_LED_BIT1, STATUS_LED_ON); + status_led_set(STATUS_LED_BIT3, STATUS_LED_ON); + + /* + * Turn the beeper volume all the way down in case this is a warm + * boot. + */ + set_beeper_volume(-64); + init_beeper(); + + /* + * Read the environment to see what to do with the beeper + */ + i = getenv_r("beeper", buf, sizeof(buf)); + if (i > 0) { + do_beeper(buf); + } + return 0; +} +/* vim: set ts=4 sw=4 tw=78 : */ diff --git a/board/gen860t/ioport.c b/board/gen860t/ioport.c new file mode 100644 index 0000000..5d6524d --- /dev/null +++ b/board/gen860t/ioport.c @@ -0,0 +1,276 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 +#include +#include +#include "ioport.h" + +#if 0 +#define IOPORT_DEBUG +#endif + +#ifdef IOPORT_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* + * The ioport configuration table. + */ +const mpc8xx_iop_conf_t iop_conf_tab[NUM_PORTS][PORT_BITS] = { + /* + * Port A configuration + * Pin Signal Type Active Initial state + * PA7 fpgaProgramLowOut Out Low High + */ + { /* conf ppar psor pdir podr pdat pint function */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* No pin */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* No pin */ + /* PA15 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA14 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA13 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA12 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA11 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA10 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA9 */ { 1, 0, 0, 1, 0, 0, 0 }, /* grn bicolor LED 1*/ + /* PA8 */ { 1, 0, 0, 1, 0, 0, 0 }, /* red bicolor LED 1*/ + /* PA7 */ { 1, 0, 0, 1, 0, 1, 0 }, /* fpgaProgramLow */ + /* PA6 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA5 */ { 1, 0, 0, 1, 0, 0, 0 }, /* grn bicolor LED 0*/ + /* PA4 */ { 1, 0, 0, 1, 0, 0, 0 }, /* red bicolor LED 0*/ + /* PA3 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA2 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA1 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PA0 */ { 0, 0, 0, 0, 0, 0, 0 } /* */ + }, + + /* + * Pin Signal Type Active Initial state + * PB14 docBusyLowIn In Low X + * PB15 gpio1Sig Out High Low + * PB16 fpgaDoneBi In High X + * PB17 swBitOkLowOut Out Low Low + * PB19 speakerVolSig Out/Hi-Z High/Low High (Hi-Z) + * PB22 fpgaInitLowBi In Low X + * PB23 batteryOkSig In High X + */ + { /* conf ppar psor pdir podr pdat pint function */ + /* PB31 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB30 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB29 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB28 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB27 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB26 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB25 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB24 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB23 */ { 1, 0, 0, 0, 0, 0, 0 }, /* batteryOk */ + /* PB22 */ { 1, 0, 0, 0, 0, 0, 0 }, /* fpgaInitLowBi */ + /* PB21 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB20 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB19 */ { 1, 0, 0, 1, 1, 1, 0 }, /* speakerVol */ + /* PB18 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PB17 */ { 1, 0, 0, 1, 0, 0, 0 }, /* swBitOkLow */ + /* PB16 */ { 1, 0, 0, 0, 0, 0, 0 }, /* fpgaDone */ + /* PB15 */ { 1, 0, 0, 1, 0, 0, 0 }, /* gpio1 */ + /* PB14 */ { 1, 0, 0, 0, 0, 0, 0 } /* docBusyLow */ + }, + + /* + * Pin Signal Type Active Initial state + * PC4 i2cBus1EnSig Out High High + * PC5 i2cBus2EnSig Out High High + * PC6 gpio0Sig Out High Low + * PC8 i2cBus3EnSig Out High High + * PC10 i2cBus4EnSig Out High High + * PC11 fpgaResetLowOut Out Low High + * PC12 systemBitOkIn In High X + * PC15 selfDreqLow In Low X + */ + { /* conf ppar psor pdir podr pdat pint function */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PC15 */ { 1, 0, 0, 0, 0, 0, 0 }, /* selfDreqLowIn */ + /* PC14 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PC13 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PC12 */ { 1, 0, 0, 0, 0, 0, 0 }, /* systemBitOkIn */ + /* PC11 */ { 1, 0, 0, 1, 0, 1, 0 }, /* fpgaResetLowOut */ + /* PC10 */ { 1, 0, 0, 1, 0, 1, 0 }, /* i2cBus4EnSig */ + /* PC9 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PC8 */ { 1, 0, 0, 1, 0, 1, 0 }, /* i2cBus3EnSig */ + /* PC7 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PC6 */ { 1, 0, 0, 1, 0, 1, 0 }, /* gpio0 */ + /* PC5 */ { 1, 0, 0, 1, 0, 1, 0 }, /* i2cBus2EnSig */ + /* PC4 */ { 1, 0, 0, 1, 0, 1, 0 }, /* i2cBus1EnSig */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 } /* */ + }, + + /* Port D configuration */ + { /* conf ppar psor pdir podr pdat pint function */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD15 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD14 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD13 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD12 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD11 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD10 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD9 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD8 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD7 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD6 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD5 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD4 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* PD3 */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 }, /* */ + /* N/A */ { 0, 0, 0, 0, 0, 0, 0 } /* */ + } +}; + +/* + * Configure the MPC8XX I/O ports per the ioport configuration table + * (taken from ./cpu/mpc8260/cpu_init.c) + */ +void +config_mpc8xx_ioports(volatile immap_t *immr) +{ + int portnum; + + for (portnum = 0; portnum < NUM_PORTS; portnum++) { + uint pmsk = 0, ppar = 0, psor = 0, pdir = 0; + uint podr = 0, pdat = 0, pint = 0; + uint msk = 1; + mpc8xx_iop_conf_t *iopc = (mpc8xx_iop_conf_t *)&iop_conf_tab[portnum][0]; + mpc8xx_iop_conf_t *eiopc = iopc + PORT_BITS; + + /* + * For all ports except port B, ignore the two don't care entries + * in the configuration tables. + */ + if (portnum != 1) { + iopc = (mpc8xx_iop_conf_t *)&iop_conf_tab[portnum][2]; + } + + /* + * NOTE: index 0 refers to pin 17, index 17 refers to pin 0 + */ + while (iopc < eiopc) { + if (iopc->conf) { + pmsk |= msk; + if (iopc->ppar) ppar |= msk; + if (iopc->psor) psor |= msk; + if (iopc->pdir) pdir |= msk; + if (iopc->podr) podr |= msk; + if (iopc->pdat) pdat |= msk; + if (iopc->pint) pint |= msk; + } + msk <<= 1; + iopc++; + } + + PRINTF("%s:%d:\n portnum=%d ", __FUNCTION__, __LINE__, portnum); +#ifdef IOPORT_DEBUG + switch(portnum) { + case 0: printf("(A)\n"); break; + case 1: printf("(B)\n"); break; + case 2: printf("(C)\n"); break; + case 3: printf("(D)\n"); break; + default: printf("(?)\n"); break; + } +#endif + PRINTF(" ppar=0x%.8x pdir=0x%.8x podr=0x%.8x\n" + " pdat=0x%.8x psor=0x%.8x pint=0x%.8x pmsk=0x%.8x\n", + ppar, pdir, podr, pdat, psor, pint, pmsk); + + /* + * Have to handle the ioports on a port-by-port basis since there + * are three different flavors. + */ + if (pmsk != 0) { + uint tpmsk = ~pmsk; + + if (0 == portnum) { /* port A */ + immr->im_ioport.iop_papar &= tpmsk; + immr->im_ioport.iop_padat = + (immr->im_ioport.iop_padat & tpmsk) | pdat; + immr->im_ioport.iop_padir = + (immr->im_ioport.iop_padir & tpmsk) | pdir; + immr->im_ioport.iop_paodr = + (immr->im_ioport.iop_paodr & tpmsk) | podr; + immr->im_ioport.iop_papar |= ppar; + } + else if (1 == portnum) { /* port B */ + immr->im_cpm.cp_pbpar &= tpmsk; + immr->im_cpm.cp_pbdat = (immr->im_cpm.cp_pbdat & tpmsk) | pdat; + immr->im_cpm.cp_pbdir = (immr->im_cpm.cp_pbdir & tpmsk) | pdir; + immr->im_cpm.cp_pbodr = (immr->im_cpm.cp_pbodr & tpmsk) | podr; + immr->im_cpm.cp_pbpar |= ppar; + } + else if (2 == portnum) { /* port C */ + immr->im_ioport.iop_pcpar &= tpmsk; + immr->im_ioport.iop_pcdat = + (immr->im_ioport.iop_pcdat & tpmsk) | pdat; + immr->im_ioport.iop_pcdir = + (immr->im_ioport.iop_pcdir & tpmsk) | pdir; + immr->im_ioport.iop_pcint = + (immr->im_ioport.iop_pcint & tpmsk) | pint; + immr->im_ioport.iop_pcso = + (immr->im_ioport.iop_pcso & tpmsk) | psor; + immr->im_ioport.iop_pcpar |= ppar; + } + else if (3 == portnum) { /* port D */ + immr->im_ioport.iop_pdpar &= tpmsk; + immr->im_ioport.iop_pddat = + (immr->im_ioport.iop_pddat & tpmsk) | pdat; + immr->im_ioport.iop_pddir = + (immr->im_ioport.iop_pddir & tpmsk) | pdir; + immr->im_ioport.iop_pdpar |= ppar; + } + } + } + + PRINTF("%s:%d: Port A:\n papar=0x%.4x padir=0x%.4x" + " paodr=0x%.4x\n padat=0x%.4x\n", __FUNCTION__, __LINE__, + immr->im_ioport.iop_papar, immr->im_ioport.iop_padir, + immr->im_ioport.iop_paodr, immr->im_ioport.iop_padat); + PRINTF("%s:%d: Port B:\n pbpar=0x%.8x pbdir=0x%.8x" + " pbodr=0x%.8x\n pbdat=0x%.8x\n", __FUNCTION__, __LINE__, + immr->im_cpm.cp_pbpar, immr->im_cpm.cp_pbdir, + immr->im_cpm.cp_pbodr, immr->im_cpm.cp_pbdat); + PRINTF("%s:%d: Port C:\n pcpar=0x%.4x pcdir=0x%.4x" + " pcdat=0x%.4x\n pcso=0x%.4x pcint=0x%.4x\n ", + __FUNCTION__, __LINE__, immr->im_ioport.iop_pcpar, + immr->im_ioport.iop_pcdir, immr->im_ioport.iop_pcdat, + immr->im_ioport.iop_pcso, immr->im_ioport.iop_pcint); + PRINTF("%s:%d: Port D:\n pdpar=0x%.4x pddir=0x%.4x" + " pddat=0x%.4x\n", __FUNCTION__, __LINE__, + immr->im_ioport.iop_pdpar, immr->im_ioport.iop_pddir, + immr->im_ioport.iop_pddat); +} + +/* vim: set ts=4 sw=4 tw=78: */ diff --git a/board/gen860t/u-boot.lds b/board/gen860t/u-boot.lds new file mode 100644 index 0000000..1b53c72 --- /dev/null +++ b/board/gen860t/u-boot.lds @@ -0,0 +1,135 @@ +/* + * Linker command file for the GEN860T board. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +SECTIONS +{ + /* + * Read-only sections, merged into text segment: + */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/mpc8xx/start.o (.text) + common/dlmalloc.o (.text) + lib_ppc/ppcstring.o (.text) + lib_generic/vsprintf.o (.text) + lib_generic/crc32.o (.text) + lib_generic/zlib.o (.text) + +/* . = env_offset; + common/environment.o(.text) */ + + *(.text) + *(.fixup) + *(.got1) + } + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* + * Read-write section, merged into data segment: + */ + . = (. + 0x00FF) & 0xFFFFFF00; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; + __fixup_entries = (. - _FIXUP_TABLE_)>>2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + + _end = . ; + PROVIDE (end = .); +} + -- cgit v1.1