aboutsummaryrefslogtreecommitdiff
path: root/board/gen860t
diff options
context:
space:
mode:
authorwdenk <wdenk>2002-11-03 00:24:07 +0000
committerwdenk <wdenk>2002-11-03 00:24:07 +0000
commitc609719b8d1b2dca590e0ed499016d041203e403 (patch)
tree7ea1755d80903ff972f312a249eb856061d40e15 /board/gen860t
parent5b1d713721c3ea02549940133f09236783dda1f9 (diff)
Initial revision
Diffstat (limited to 'board/gen860t')
-rw-r--r--board/gen860t/README142
-rw-r--r--board/gen860t/beeper.c213
-rw-r--r--board/gen860t/flash.c644
-rw-r--r--board/gen860t/fpga.c401
-rw-r--r--board/gen860t/gen860t.c299
-rw-r--r--board/gen860t/ioport.c276
-rw-r--r--board/gen860t/u-boot.lds135
7 files changed, 2110 insertions, 0 deletions
diff --git a/board/gen860t/README b/board/gen860t/README
new file mode 100644
index 000000000..761ceed30
--- /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.
+<keith_outwater@mvis.com>
+<outwater@eskimo.com>
+
+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 000000000..46fe66ba6
--- /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 <common.h>
+#include <mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <linux/ctype.h>
+
+/*
+ * 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 000000000..902b1b0af
--- /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 <common.h>
+#include <mpc8xx.h>
+
+#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; i<info->sector_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 000000000..2c4fbf14c
--- /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 <common.h>
+#include <virtex2.h>
+#include <command.h>
+#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 000000000..16a3262c4
--- /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 <virtex2.h>
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include "beeper.h"
+#include "fpga.h"
+#include "ioport.h"
+
+#ifdef CONFIG_STATUS_LED
+#include <status_led.h>
+#endif
+
+#if defined(CFG_CMD_MII) && defined(CONFIG_MII)
+#include <net.h>
+#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("<unknown> ");
+ }
+
+ i = getenv_r("serial#", buf, sizeof(buf));
+ s = (i>0) ? buf : NULL;
+
+ if (s) {
+ printf("S/N %s\n", s);
+ } else {
+ printf("S/N <unknown>\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 000000000..5d6524dbd
--- /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 <common.h>
+#include <mpc8xx.h>
+#include <asm/8xx_immap.h>
+#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 000000000..1b53c723d
--- /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 = .);
+}
+