]> www.infradead.org Git - users/rw/ppcboot.git/commitdiff
Disk On Chip support added
authorwdenk <wdenk>
Tue, 15 Jan 2002 18:58:11 +0000 (18:58 +0000)
committerwdenk <wdenk>
Tue, 15 Jan 2002 18:58:11 +0000 (18:58 +0000)
GESPAC PCIPPC2 preliminary support added

45 files changed:
CHANGELOG
MAKEALL
Makefile
board/pcippc2/Makefile [new file with mode: 0644]
board/pcippc2/config.mk [new file with mode: 0644]
board/pcippc2/cpc710.h [new file with mode: 0644]
board/pcippc2/cpc710_init_ram.c [new file with mode: 0644]
board/pcippc2/cpc710_pci.c [new file with mode: 0644]
board/pcippc2/cpc710_pci.h [new file with mode: 0644]
board/pcippc2/eepro100.c [new file with mode: 0644]
board/pcippc2/flash.c [new file with mode: 0644]
board/pcippc2/fpga_serial.c [new file with mode: 0644]
board/pcippc2/fpga_serial.h [new file with mode: 0644]
board/pcippc2/hardware.h [new file with mode: 0644]
board/pcippc2/i2c.c [new file with mode: 0644]
board/pcippc2/i2c.h [new file with mode: 0644]
board/pcippc2/ns16550.h [new file with mode: 0644]
board/pcippc2/pci.c [new file with mode: 0644]
board/pcippc2/pci.h [new file with mode: 0644]
board/pcippc2/pcippc2.c [new file with mode: 0644]
board/pcippc2/pcippc2.h [new file with mode: 0644]
board/pcippc2/pcippc2_fpga.c [new file with mode: 0644]
board/pcippc2/pcippc2_fpga.h [new file with mode: 0644]
board/pcippc2/ppcboot.lds [new file with mode: 0644]
board/pcippc2/sconsole.c [new file with mode: 0644]
board/pcippc2/sconsole.h [new file with mode: 0644]
common/Makefile
common/board.c
common/cmd_doc.c [new file with mode: 0644]
common/command.c
common/docecc.c [new file with mode: 0644]
cpu/74xx_7xx/Makefile
cpu/74xx_7xx/cpu.c
cpu/74xx_7xx/io.S [new file with mode: 0644]
cpu/74xx_7xx/start.S
include/cmd_confdefs.h
include/cmd_doc.h [new file with mode: 0644]
include/config_LANTEC.h
include/config_MPC8260ADS.h
include/config_PCIPPC2.h [new file with mode: 0644]
include/config_hymod.h
include/linux/mtd/doc2000.h [new file with mode: 0644]
include/linux/mtd/nand.h [new file with mode: 0644]
include/linux/mtd/nand_ids.h [new file with mode: 0644]
include/ppcboot.h

index d74875a9ae340318cd2a4415d1cb219ffdc319dd..d4493cafc6e2fba3c688991986454f6563a6ddc0 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,10 @@
 Modifications for 1.1.4:
 ======================================================================
 
+* Support for M-Systems Disk-On-Chip
+
+* Support for GESPAC PCIPPC2 board
+
 * increased IDE_TIME_OUT as needed on some boards
 
 * Renamed board/ivms8 directory into board/ivm to fit better with new
diff --git a/MAKEALL b/MAKEALL
index 1554adbb8790ebe2e66649ae9910012141ee1675..d09bcf2165e4327b1a600d66135afeb0848a45a7 100755 (executable)
--- a/MAKEALL
+++ b/MAKEALL
@@ -64,7 +64,7 @@ LIST_8260="   \
 #########################################################################
 
 LIST_74xx="    \
-       EVB64260        \
+       EVB64260        PCIPPC2         \
 "
 
 #########################################################################
@@ -97,12 +97,13 @@ build_target() {
 for arg in $@
 do
        case "$arg" in
-       8xx|824x|8260|4xx|74xx) for target in `eval echo '$LIST_'${arg}`
-                               do
-                                       build_target ${target}
-                               done
-                               ;;
-       *)                      build_target ${arg}
-                               ;;
+       8xx|824x|8260|4xx|7xx|74xx)
+                       for target in `eval echo '$LIST_'${arg}`
+                       do
+                               build_target ${target}
+                       done
+                       ;;
+       *)              build_target ${arg}
+                       ;;
        esac
 done
index feb153d4be154781c33c4202a9b8a89ded9b66d6..aaf1de2650f1ad13c023e19ad645039d2cec1dd0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 #
-# (C) Copyright 2000, 2001
+# (C) Copyright 2000, 2001, 2002
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 #
 # See file CREDITS for list of people who contributed to this
@@ -679,6 +679,14 @@ EVB64260_config: unconfig
        echo "CPU   = 74xx_7xx" >>config.mk ;   \
        echo "#include <config_$(@:_config=).h>" >config.h
 
+PCIPPC2_config: unconfig
+       @echo "Configuring for $(@:_config=) Board..." ; \
+       cd include ;                            \
+       echo "ARCH  = ppc"      > config.mk ;   \
+       echo "BOARD = pcippc2"  >>config.mk ;   \
+       echo "CPU   = 74xx_7xx" >>config.mk ;   \
+       echo "#include <config_$(@:_config=).h>" >config.h
+
 #########################################################################
 ## MPC7xx Systems
 #########################################################################  
diff --git a/board/pcippc2/Makefile b/board/pcippc2/Makefile
new file mode 100644 (file)
index 0000000..74caceb
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# (C) Copyright 2002
+# 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 $(TOPDIR)/config.mk
+
+LIB    = lib$(BOARD).a
+
+COBJS  = $(BOARD).o cpc710_pci.o flash.o sconsole.o eepro100.o pci.o \
+         fpga_serial.o pcippc2_fpga.o cpc710_init_ram.o i2c.o
+AOBJS  =
+
+OBJS   = $(COBJS) $(AOBJS)
+
+$(LIB):        .depend $(OBJS)
+       $(AR) crv $@ $^
+
+#########################################################################
+
+.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c)
+       $(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/board/pcippc2/config.mk b/board/pcippc2/config.mk
new file mode 100644 (file)
index 0000000..92d37c9
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# (C) Copyright 2002
+# 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
+#
+
+#
+# PCIPPC-2 boards
+#
+
+TEXT_BASE = 0xfff00000
+
+PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)
diff --git a/board/pcippc2/cpc710.h b/board/pcippc2/cpc710.h
new file mode 100644 (file)
index 0000000..92ff5eb
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _CPC710_H_
+#define _CPC710_H_
+
+/* System control area */
+#define HW_PHYS_SCA            0xff000000
+
+#define HW_SCA_CPC0            0x000000
+#define HW_SCA_SDRAM0          0x000000
+#define HW_SCA_DMA0            0x1C0000
+
+#define HW_PHYS_CPC0           (HW_PHYS_SCA + HW_SCA_CPC0)
+#define HW_PHYS_SDRAM0         (HW_PHYS_SCA + HW_SCA_SDRAM0)
+
+#define HW_CPC0_PCICNFR                0x000c
+#define HW_CPC0_RSTR           0x0010
+#define HW_CPC0_SPOR           0x00e8
+#define HW_CPC0_UCTL           0x1000
+#define HW_CPC0_SIOC0          0x1020
+#define HW_CPC0_ABCNTL         0x1030
+#define HW_CPC0_SESR           0x1060
+#define HW_CPC0_SEAR           0x1070
+#define HW_CPC0_PGCHP          0x1100
+#define HW_CPC0_RGBAN0         0x1110
+#define HW_CPC0_RGBAN1         0x1120
+
+#define HW_CPC0_GPDIR          0x1130
+#define HW_CPC0_GPIN           0x1140
+#define HW_CPC0_GPOUT          0x1150
+
+#define HW_CPC0_ATAS           0x1160
+
+#define HW_CPC0_PCIBAR         0x200018
+#define HW_CPC0_PCIENB         0x201000
+
+#define HW_SDRAM0_MCCR         0x1200
+#define HW_SDRAM0_MESR         0x1220
+#define HW_SDRAM0_MEAR         0x1230
+
+#define HW_SDRAM0_MCER0                0x1300
+#define HW_SDRAM0_MCER1                0x1310
+#define HW_SDRAM0_MCER2                0x1320
+#define HW_SDRAM0_MCER3                0x1330
+#define HW_SDRAM0_MCER4                0x1340
+#define HW_SDRAM0_MCER5                0x1350
+#define HW_SDRAM0_MCER6                0x1360
+#define HW_SDRAM0_MCER7                0x1370
+
+#define HW_BRIDGE_PCIDG                0xf6120
+#define HW_BRIDGE_INTACK       0xf7700
+#define HW_BRIDGE_PIBAR                0xf7800
+#define HW_BRIDGE_PMBAR                0xf7810
+#define HW_BRIDGE_CRR          0xf7ef0
+#define HW_BRIDGE_PR           0xf7f20
+#define HW_BRIDGE_ACR          0xf7f30
+#define HW_BRIDGE_MSIZE                0xf7f40
+#define HW_BRIDGE_IOSIZE       0xf7f60
+#define HW_BRIDGE_SMBAR                0xf7f80
+#define HW_BRIDGE_SIBAR                0xf7fc0
+#define HW_BRIDGE_CFGADDR      0xf8000
+#define HW_BRIDGE_CFGDATA      0xf8010
+#define HW_BRIDGE_PSSIZE       0xf8100
+#define HW_BRIDGE_BARPS                0xf8120
+#define HW_BRIDGE_PSBAR                0xf8140
+
+#endif
diff --git a/board/pcippc2/cpc710_init_ram.c b/board/pcippc2/cpc710_init_ram.c
new file mode 100644 (file)
index 0000000..d1a0f6b
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <asm/io.h>
+
+#include "pcippc2.h"
+#include "i2c.h"
+
+typedef struct cpc710_mem_org_s
+{
+  u8           rows;
+  u8           cols;
+  u8           banks2;
+  u8           org;
+} cpc710_mem_org_t;
+
+static int             cpc710_compute_mcer     (u32 *          mcer,
+                                                unsigned long *
+                                                               size,
+                                                unsigned int   sdram);
+static int             cpc710_eeprom_checksum  (unsigned int   sdram);
+static u8              cpc710_eeprom_read      (unsigned int   sdram,
+                                                unsigned int   offset);
+
+static u32             cpc710_mcer_mem [] =
+{
+  0x000003f3,  /* 18 lines,    4 Mb */
+  0x000003e3,  /* 19 lines,    8 Mb */
+  0x000003c3,  /* 20 lines,   16 Mb */
+  0x00000383,  /* 21 lines,   32 Mb */
+  0x00000303,  /* 22 lines,   64 Mb */
+  0x00000203,  /* 23 lines,  128 Mb */
+  0x00000003,  /* 24 lines,  256 Mb */
+  0x00000002,  /* 25 lines,  512 Mb */
+  0x00000001   /* 26 lines, 1024 Mb */
+};
+static cpc710_mem_org_t        cpc710_mem_org [] =
+{
+  { 0x0c, 0x09, 0x02, 0x00 },  /* 0000: 12/ 9/2 */
+  { 0x0d, 0x09, 0x02, 0x00 },  /* 0000: 13/ 9/2 */
+  { 0x0d, 0x0a, 0x02, 0x00 },  /* 0000: 13/10/2 */
+  { 0x0d, 0x0b, 0x02, 0x00 },  /* 0000: 13/11/2 */
+  { 0x0d, 0x0c, 0x02, 0x00 },  /* 0000: 13/12/2 */
+  { 0x0e, 0x0c, 0x02, 0x00 },  /* 0000: 14/12/2 */
+  { 0x0b, 0x08, 0x02, 0x01 },  /* 0001: 11/ 8/2 */
+  { 0x0b, 0x09, 0x01, 0x02 },  /* 0010: 11/ 9/1 */
+  { 0x0b, 0x0a, 0x01, 0x03 },  /* 0011: 11/10/1 */
+  { 0x0c, 0x08, 0x02, 0x04 },  /* 0100: 12/ 8/2 */
+  { 0x0c, 0x0a, 0x02, 0x05 },  /* 0101: 12/10/2 */
+  { 0x0d, 0x08, 0x01, 0x06 },  /* 0110: 13/ 8/1 */
+  { 0x0d, 0x08, 0x02, 0x07 },  /* 0111: 13/ 8/2 */
+  { 0x0d, 0x09, 0x01, 0x08 },  /* 1000: 13/ 9/1 */
+  { 0x0d, 0x0a, 0x01, 0x09 },  /* 1001: 13/10/1 */
+  { 0x0b, 0x08, 0x01, 0x0a },  /* 1010: 11/ 8/1 */
+  { 0x0c, 0x08, 0x01, 0x0b },  /* 1011: 12/ 8/1 */
+  { 0x0c, 0x09, 0x01, 0x0c },  /* 1100: 12/ 9/1 */
+  { 0x0e, 0x09, 0x02, 0x0d },  /* 1101: 14/ 9/2 */
+  { 0x0e, 0x0a, 0x02, 0x0e },  /* 1110: 14/10/2 */
+  { 0x0e, 0x0b, 0x02, 0x0f }   /* 1111: 14/11/2 */
+};
+
+unsigned long cpc710_ram_init (void)
+{
+  unsigned long        memsize = 0;
+  unsigned long                bank_size;
+  u32                  mcer;
+
+#ifndef CFG_RAMBOOT
+    /* Clear memory banks
+     */
+  out32(REG(SDRAM0, MCER0), 0);
+  out32(REG(SDRAM0, MCER1), 0);
+  out32(REG(SDRAM0, MCER2), 0);
+  out32(REG(SDRAM0, MCER3), 0);
+  out32(REG(SDRAM0, MCER4), 0);
+  out32(REG(SDRAM0, MCER5), 0);
+  out32(REG(SDRAM0, MCER6), 0);
+  out32(REG(SDRAM0, MCER7), 0);
+  iobarrier_rw();
+  
+    /* Disable memory
+     */
+  out32(REG(SDRAM0,MCCR), 0x13b06000);
+  iobarrier_rw();
+#endif
+     
+    /* Only the first memory bank is initialised now
+     */
+  if (! cpc710_compute_mcer(& mcer, & bank_size, 0))
+  {
+    puts("Unsupported SDRAM type !\n");
+    hang();
+  }
+  memsize += bank_size;
+#ifndef CFG_RAMBOOT
+    /* Enable bank, zero start
+     */
+  out32(REG(SDRAM0, MCER0), mcer | 0x80000000);
+  iobarrier_rw();
+#endif
+
+#ifndef CFG_RAMBOOT
+    /* Enable memory
+     */
+  out32(REG(SDRAM0, MCCR), in32(REG(SDRAM0, MCCR)) | 0x80000000);
+
+    /* Wait until initialisation finished
+     */
+  while (! (in32 (REG(SDRAM0, MCCR)) & 0x20000000))
+  {
+    iobarrier_rw();
+  }
+
+    /* Clear Memory Error Status and Address registers
+     */
+  out32(REG(SDRAM0, MESR), 0);
+  out32(REG(SDRAM0, MEAR), 0);
+  iobarrier_rw();
+       
+    /* ECC is not configured now
+     */
+#endif
+
+    /* Memory size counter
+     */
+  out32(REG(CPC0, RGBAN1), memsize);
+  
+  return memsize;
+}
+
+static int cpc710_compute_mcer (
+  u32 *                        mcer,
+  unsigned long        *       size,
+  unsigned int         sdram)
+{
+  u8                   rows;
+  u8                   cols;
+  u8                   banks2;
+  unsigned int         lines;
+  u32                  mc = 0;
+  unsigned int         i;
+  cpc710_mem_org_t *   org = 0;
+
+  if (! cpc710_eeprom_checksum(sdram))
+  {
+    puts("Invalid EEPROM checksum !\n");
+    hang();
+  }
+
+  rows   = cpc710_eeprom_read(sdram, 3);
+  cols   = cpc710_eeprom_read(sdram, 4);
+    /* Can be 2 or 4 banks; divide by 2
+     */
+  banks2 = cpc710_eeprom_read(sdram, 17) / 2;
+
+  lines = rows + cols + banks2;
+  
+  if (lines < 18 || lines > 26)
+  {
+      /* Unsupported configuration
+       */
+    return 0;
+  }
+
+  mc |= cpc710_mcer_mem [lines - 18] << 6;
+  
+  for (i = 0; i < sizeof(cpc710_mem_org) / sizeof(cpc710_mem_org_t); i++)
+  {
+    cpc710_mem_org_t * corg = cpc710_mem_org + i;
+
+    if (corg->rows == rows && corg->cols == cols && corg->banks2 == banks2)
+    {
+      org = corg;
+      
+      break;
+    }
+  }
+
+  if (! org)
+  {
+      /* Unsupported configuration
+       */
+    return 0;
+  }
+  
+  mc |= (u32) org->org << 2;
+  
+    /* Supported configuration
+     */
+  *mcer = mc;
+  *size = 1l << (lines + 4);
+
+  return 1;
+}
+
+static int cpc710_eeprom_checksum (
+  unsigned int         sdram)
+{
+  u8                   sum = 0;
+  unsigned int         i;
+  
+  for (i = 0; i < 63; i++)
+  {
+    sum += cpc710_eeprom_read(sdram, i);
+  }
+  
+  return sum == cpc710_eeprom_read(sdram, 63);
+}
+
+static u8 cpc710_eeprom_read (
+  unsigned int         sdram,
+  unsigned int         offset)
+{
+  u8                   dev = (sdram << 1) | 0xa0;
+  u8                   data;
+  
+  if (! i2c_write_byte(dev, (u8) offset))
+  {
+    puts("I2C error !\n");
+    hang();
+  }
+  
+  if (! i2c_read_byte(& data, dev))
+  {
+    puts("I2C error !\n");
+    hang();
+  }
+  
+  return data;
+}
diff --git a/board/pcippc2/cpc710_pci.c b/board/pcippc2/cpc710_pci.c
new file mode 100644 (file)
index 0000000..64b5c32
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <asm/io.h>
+
+#include "pci.h"
+
+#include "hardware.h"
+#include "pcippc2.h"
+
+static u32     cpc710_mapped_ram;
+
+static inline u32 bdf_to_dev (
+  u32                  bdf)
+{
+  return (bdf >> 11) & 0x1f;
+}
+
+static inline u32 bdf_to_bus (
+  u32                  bdf)
+{
+  return (bdf >> 16) & 0xff;
+}
+
+static inline u32 bdf_to_func (
+  u32                  bdf)
+{
+  return (bdf >> 8) & 0x07;
+}
+
+static inline u32 make_bdf (
+  u32                  bus,
+  u32                  dev,
+  u32                  func)
+{
+  return (bus << 16) | (dev << 11) | (func << 8);
+}
+
+  /* Enable PCI retry timeouts
+   */
+void cpc710_pci_enable_timeout (void)
+{
+  out32(BRIDGE(LOCAL, CFGADDR), 0x50000080);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, CFGDATA), 0x32000000);
+  iobarrier_rw();
+
+  out32(BRIDGE(CPCI, CFGADDR), 0x50000180);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CFGDATA), 0x32000000);
+  iobarrier_rw();
+}
+
+void cpc710_pci_init (void)
+{
+  u32                  sdram_size = pcippc2_sdram_size();
+
+  cpc710_mapped_ram = sdram_size < PCI_MEMORY_MAXSIZE ?
+                      sdram_size : PCI_MEMORY_MAXSIZE;
+
+    /* Select the local PCI
+     */
+  out32(REG(CPC0, PCICNFR), 0x80000002);
+  iobarrier_rw();
+
+  out32(REG(CPC0, PCIBAR), BRIDGE_LOCAL_PHYS);
+  iobarrier_rw();
+
+    /* Enable PCI bridge address decoding
+     */
+  out32(REG(CPC0, PCIENB), 0x80000000);
+  iobarrier_rw();
+
+    /* Select the CPCI bridge
+     */
+  out32(REG(CPC0, PCICNFR), 0x80000003);
+  iobarrier_rw();
+
+  out32(REG(CPC0, PCIBAR), BRIDGE_CPCI_PHYS);
+  iobarrier_rw();
+
+    /* Enable PCI bridge address decoding
+     */
+  out32(REG(CPC0, PCIENB), 0x80000000);
+  iobarrier_rw();
+
+    /* Disable configuration accesses
+     */
+  out32(REG(CPC0, PCICNFR), 0x80000000);
+  iobarrier_rw();
+
+    /* Initialise the local PCI
+     */
+  out32(BRIDGE(LOCAL, CRR), 0x7c000000);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, PCIDG), 0x40000000);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, PIBAR), BRIDGE_LOCAL_IO_BUS);
+  out32(BRIDGE(LOCAL, SIBAR), BRIDGE_LOCAL_IO_PHYS);
+  out32(BRIDGE(LOCAL, IOSIZE), -BRIDGE_LOCAL_IO_SIZE);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, PMBAR), BRIDGE_LOCAL_MEM_BUS);
+  out32(BRIDGE(LOCAL, SMBAR), BRIDGE_LOCAL_MEM_PHYS);
+  out32(BRIDGE(LOCAL, MSIZE), -BRIDGE_LOCAL_MEM_SIZE);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, PR), 0x80ffe000);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, ACR), 0xfe000000);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, PSBAR), PCI_MEMORY_BUS >> 24);
+  out32(BRIDGE(LOCAL, BARPS), PCI_MEMORY_PHYS >> 24);
+  out32(BRIDGE(LOCAL, PSSIZE), 256 - (cpc710_mapped_ram >> 24));
+  iobarrier_rw();
+
+    /* Initialise the CPCI bridge
+     */
+  out32(BRIDGE(CPCI, CRR), 0x7c000000);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, PCIDG), 0xC0000000);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, PIBAR), BRIDGE_CPCI_IO_BUS);
+  out32(BRIDGE(CPCI, SIBAR), BRIDGE_CPCI_IO_PHYS);
+  out32(BRIDGE(CPCI, IOSIZE), -BRIDGE_CPCI_IO_SIZE);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, PMBAR), BRIDGE_CPCI_MEM_BUS);
+  out32(BRIDGE(CPCI, SMBAR), BRIDGE_CPCI_MEM_PHYS);
+  out32(BRIDGE(CPCI, MSIZE), -BRIDGE_CPCI_MEM_SIZE);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, PR), 0x80ffe000);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, ACR), 0xdf000000);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, PSBAR), PCI_MEMORY_BUS >> 24);
+  out32(BRIDGE(CPCI, BARPS), PCI_MEMORY_PHYS >> 24);
+  out32(BRIDGE(CPCI, PSSIZE), 256 - (cpc710_mapped_ram >> 24));
+  iobarrier_rw();
+
+    /* Local PCI
+     */
+
+  out32(BRIDGE(LOCAL, CFGADDR), 0x04000080);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, CFGDATA), 0x56010000);
+  iobarrier_rw();
+
+  out32(BRIDGE(LOCAL, CFGADDR), 0x0c000080);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, CFGDATA), PCI_LATENCY_TIMER << 16);
+  iobarrier_rw();
+  
+    /* Set bus and subbus numbers
+     */
+  out32(BRIDGE(LOCAL, CFGADDR), 0x40000080);
+  iobarrier_rw();
+  out32(BRIDGE(LOCAL, CFGDATA), 0x00000000);
+  iobarrier_rw();
+
+  out32(BRIDGE(LOCAL, CFGADDR), 0x50000080);
+  iobarrier_rw();
+    /* PCI retry timeouts will be enabled later
+     */
+  out32(BRIDGE(LOCAL, CFGDATA), 0x00000000);
+  iobarrier_rw();
+
+    /* CPCI
+     */
+
+    /* Set bus and subbus numbers
+     */
+  out32(BRIDGE(CPCI, CFGADDR), 0x40000080);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CFGDATA), 0x01010000);
+  iobarrier_rw();
+
+  out32(BRIDGE(CPCI, CFGADDR), 0x04000180);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CFGDATA), 0x56010000);
+  iobarrier_rw();
+
+  out32(BRIDGE(CPCI, CFGADDR), 0x0c000180);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CFGDATA), PCI_LATENCY_TIMER << 16);
+  iobarrier_rw();
+
+    /* Write to the PSBAR */
+  out32(BRIDGE(CPCI, CFGADDR), 0x10000180);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CFGDATA), cpu_to_le32(PCI_MEMORY_BUS));
+  iobarrier_rw();
+
+    /* Set bus and subbus numbers
+     */
+  out32(BRIDGE(CPCI, CFGADDR), 0x40000180);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CFGDATA), 0x01ff0000);
+  iobarrier_rw();
+
+  out32(BRIDGE(CPCI, CFGADDR), 0x50000180);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CFGDATA), 0x32000000);
+    /* PCI retry timeouts will be enabled later
+     */
+  out32(BRIDGE(CPCI, CFGDATA), 0x00000000);
+  iobarrier_rw();
+    /* Remove reset on the PCI buses
+     */
+  out32(BRIDGE(LOCAL, CRR), 0xfc000000);
+  iobarrier_rw();
+  out32(BRIDGE(CPCI, CRR), 0xfc000000);
+  iobarrier_rw();
+}
+
+unsigned int PCI_Read_CFG_Reg (
+  int                  busdevfunc,
+  int                  reg,
+  int                  width)
+{
+  u32                  bus = bdf_to_bus(busdevfunc);
+  u32                  dev = bdf_to_dev(busdevfunc);
+  u32                  bridge_addr = bus == 0 ? BRIDGE_LOCAL_PHYS : BRIDGE_CPCI_PHYS;
+  u32                  ret;
+
+    /* Drop out-of-range device numbers
+     */
+  if (bus < 2 && (dev == 0 || dev > 21))
+  {
+    return (1 << (8 * width)) - 1;
+  }
+  
+  out32r(bridge_addr + HW_BRIDGE_CFGADDR, busdevfunc | (reg & 0xfc) | 0x80000000);
+  iobarrier_rw();
+
+  switch (width)
+  {
+    case 1:
+      ret = in8(bridge_addr + HW_BRIDGE_CFGDATA + (reg & 0x3));
+      break;
+    case 2:
+      ret = in16r(bridge_addr + HW_BRIDGE_CFGDATA + (reg & 0x2));
+      break;
+    case 4:
+      ret = in32r(bridge_addr + HW_BRIDGE_CFGDATA);
+      break;
+    default:
+      puts("Invalid PCI access !\n");
+      hang();
+        /* To avoid warning
+        */
+      ret = 0xffffffff;
+  }
+
+  iobarrier_rw();
+  
+  return ret;
+}
+
+int PCI_Write_CFG_Reg (
+  int                  busdevfunc,
+  int                  reg,
+  unsigned int         value,
+  int                  width)
+{
+  u32                  bus = bdf_to_bus(busdevfunc);
+  u32                  dev = bdf_to_dev(busdevfunc);
+  u32                  bridge_addr = bus == 0 ? BRIDGE_LOCAL_PHYS : BRIDGE_CPCI_PHYS;
+
+    /* Drop out-of-range device numbers
+     */
+  if (bus < 2 && (dev == 0 || dev > 21))
+  {
+    return 0;
+  }
+  
+  out32r(bridge_addr + HW_BRIDGE_CFGADDR, busdevfunc | (reg & 0xfc) | 0x80000000);
+  iobarrier_rw();
+
+  switch (width)
+  {
+    case 1:
+      out8(bridge_addr + HW_BRIDGE_CFGDATA + (reg & 0x3), value);
+      break;
+    case 2:
+      out16r(bridge_addr + HW_BRIDGE_CFGDATA + (reg & 0x2), value);
+      break;
+    case 4:
+      out32r(bridge_addr + HW_BRIDGE_CFGDATA, value);
+      break;
+    default:
+      puts("Invalid PCI access !\n");
+      hang();
+  }
+
+  iobarrier_rw();
+
+  return 0;
+}
+
+u32 pci_phys_to_io (
+  u32                  p)
+{
+  if (p >= BRIDGE_LOCAL_IO_PHYS &&
+      p < BRIDGE_LOCAL_IO_PHYS + BRIDGE_LOCAL_IO_SIZE)
+  {
+    return p - BRIDGE_LOCAL_IO_PHYS + BRIDGE_LOCAL_IO_BUS;
+  }
+
+  if (p >= BRIDGE_CPCI_IO_PHYS &&
+      p < BRIDGE_CPCI_IO_PHYS + BRIDGE_CPCI_IO_SIZE)
+  {
+    return p - BRIDGE_CPCI_IO_PHYS + BRIDGE_CPCI_IO_BUS;
+  }
+
+  puts("Address not in the PCI I/O space !\n");
+  hang();
+
+  return 0;
+}
+
+u32 pci_io_to_phys (
+  u32                  i)
+{
+  if (i >= BRIDGE_LOCAL_IO_BUS &&
+      i < BRIDGE_LOCAL_IO_BUS + BRIDGE_LOCAL_IO_SIZE)
+  {
+    return i - BRIDGE_LOCAL_IO_BUS + BRIDGE_LOCAL_IO_PHYS;
+  }
+
+  if (i >= BRIDGE_CPCI_IO_BUS &&
+      i < BRIDGE_CPCI_IO_BUS + BRIDGE_CPCI_IO_SIZE)
+  {
+    return i - BRIDGE_CPCI_IO_BUS + BRIDGE_CPCI_IO_PHYS;
+  }
+
+  puts("Address not in the PCI I/O space !\n");
+  hang();
+
+  return 0;
+}
+
+u32 pci_phys_to_mem (
+  u32                  p)
+{
+  if (p >= BRIDGE_LOCAL_MEM_PHYS &&
+      p < BRIDGE_LOCAL_MEM_PHYS + BRIDGE_LOCAL_MEM_SIZE)
+  {
+    return p - BRIDGE_LOCAL_MEM_PHYS + BRIDGE_LOCAL_MEM_BUS;
+  }
+
+  if (p >= BRIDGE_CPCI_MEM_PHYS &&
+      p < BRIDGE_CPCI_MEM_PHYS + BRIDGE_CPCI_MEM_SIZE)
+  {
+    return p - BRIDGE_CPCI_MEM_PHYS + BRIDGE_CPCI_MEM_BUS;
+  }
+
+  puts("Address not in the PCI memory space !\n");
+  hang();
+
+  return 0;
+}
+
+u32 pci_mem_to_phys (
+  u32                  m)
+{
+  if (m >= BRIDGE_LOCAL_MEM_BUS &&
+      m < BRIDGE_LOCAL_MEM_BUS + BRIDGE_LOCAL_MEM_SIZE)
+  {
+    return m - BRIDGE_LOCAL_MEM_BUS + BRIDGE_LOCAL_MEM_PHYS;
+  }
+
+  if (m >= BRIDGE_CPCI_MEM_BUS &&
+      m < BRIDGE_CPCI_MEM_BUS + BRIDGE_CPCI_MEM_SIZE)
+  {
+    return m - BRIDGE_CPCI_MEM_BUS + BRIDGE_CPCI_MEM_PHYS;
+  }
+
+  puts("Address not in the PCI memory space !\n");
+  hang();
+
+  return 0;
+}
+
+u32 pci_ram_to_mem (
+  u32                  r)
+{
+  if (r >= PCI_MEMORY_PHYS &&
+      r < PCI_MEMORY_PHYS + cpc710_mapped_ram)
+  {
+    return r - PCI_MEMORY_PHYS + PCI_MEMORY_BUS;
+  }
+
+  puts("Address not in the RAM space !\n");
+  hang();
+
+  return 0;
+}
+
+u32 pci_mem_to_ram (
+  u32                  p)
+{
+  if (p >= PCI_MEMORY_BUS &&
+      p < PCI_MEMORY_BUS + cpc710_mapped_ram)
+  {
+    return p - PCI_MEMORY_BUS + PCI_MEMORY_PHYS;
+  }
+
+  puts("Address not in the PCI RAM memory space !\n");
+  hang();
+
+  return 0;
+}
diff --git a/board/pcippc2/cpc710_pci.h b/board/pcippc2/cpc710_pci.h
new file mode 100644 (file)
index 0000000..601652f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _CPC710_PCI_H_
+#define _CPC710_PCI_H_
+
+#define PCI_MEMORY_PHYS                0x00000000
+#define PCI_MEMORY_BUS         0x80000000
+#define PCI_MEMORY_MAXSIZE      0x20000000
+
+#define BRIDGE_CPCI_PHYS       0xff500000
+#define BRIDGE_CPCI_MEM_SIZE   0x08000000
+#define BRIDGE_CPCI_MEM_PHYS    0xf0000000
+#define BRIDGE_CPCI_MEM_BUS     0x00000000
+#define BRIDGE_CPCI_IO_SIZE    0x02000000
+#define BRIDGE_CPCI_IO_PHYS     0xfc000000
+#define BRIDGE_CPCI_IO_BUS      0x00000000
+
+#define BRIDGE_LOCAL_PHYS      0xff400000
+#define BRIDGE_LOCAL_MEM_SIZE  0x04000000
+#define BRIDGE_LOCAL_MEM_PHYS   0xf8000000
+#define BRIDGE_LOCAL_MEM_BUS    0x40000000
+#define BRIDGE_LOCAL_IO_SIZE   0x01000000
+#define BRIDGE_LOCAL_IO_PHYS    0xfe000000
+#define BRIDGE_LOCAL_IO_BUS     0x04000000
+
+#define BRIDGE(r, x)           (BRIDGE_##r##_PHYS + HW_BRIDGE_##x)
+
+#define PCI_LOWEST_IOADDR      BRIDGE_LOCAL_IO_BUS
+#define PCI_LOWEST_MEMADDR     BRIDGE_LOCAL_MEM_BUS
+
+#define PCI_LATENCY_TIMER      0xff
+
+#endif
diff --git a/board/pcippc2/eepro100.c b/board/pcippc2/eepro100.c
new file mode 100644 (file)
index 0000000..94a9a28
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * (C) Copyright 2002
+ * 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 <ppcboot.h>
+#include <net.h>
+#include <asm/io.h>
+
+#include "pci.h"
+
+/* Intel Ethernet */
+#define PCI_VENDOR_ID_INTEL            0x8086
+#define PCI_DEVICE_ID_INTEL_82559ER    0x1209
+#define PCI_DEVICE_ID_INTEL_82557      0x1229
+
+       /* Ethernet chip registers.
+        */
+#define SCBStatus              0          /* Rx/Command Unit Status *Word* */
+#define SCBIntAckByte          1          /* Rx/Command Unit STAT/ACK byte */
+#define SCBCmd                 2          /* Rx/Command Unit Command *Word* */
+#define SCBIntrCtlByte         3          /* Rx/Command Unit Intr.Control Byte */
+#define SCBPointer             4          /* General purpose pointer. */
+#define SCBPort                8          /* Misc. commands and operands. */
+#define SCBflash               12         /* Flash memory control. */
+#define SCBeeprom              14         /* EEPROM memory control. */
+#define SCBCtrlMDI             16         /* MDI interface control. */
+#define SCBEarlyRx             20         /* Early receive byte count. */
+#define SCBGenControl          28         /* 82559 General Control Register */
+#define SCBGenStatus           29         /* 82559 General Status register */
+
+       /* 82559 SCB status word defnitions
+        */
+#define SCB_STATUS_CX          0x8000     /* CU finished command (transmit) */
+#define SCB_STATUS_FR          0x4000     /* frame received */
+#define SCB_STATUS_CNA         0x2000     /* CU left active state */
+#define SCB_STATUS_RNR         0x1000     /* receiver left ready state */
+#define SCB_STATUS_MDI         0x0800     /* MDI read/write cycle done */
+#define SCB_STATUS_SWI         0x0400     /* software generated interrupt */
+#define SCB_STATUS_FCP         0x0100     /* flow control pause interrupt */
+
+#define SCB_INTACK_MASK        0xFD00     /* all the above */
+
+#define SCB_INTACK_TX          (SCB_STATUS_CX | SCB_STATUS_CNA)
+#define SCB_INTACK_RX          (SCB_STATUS_FR | SCB_STATUS_RNR)
+
+       /* System control block commands
+        */
+/* CU Commands */
+#define CU_NOP                 0x0000
+#define        CU_START                0x0010
+#define        CU_RESUME               0x0020
+#define        CU_STATSADDR            0x0040     /* Load Dump Statistics ctrs addr */
+#define        CU_SHOWSTATS            0x0050     /* Dump statistics counters. */
+#define        CU_ADDR_LOAD            0x0060     /* Base address to add to CU commands */
+#define        CU_DUMPSTATS            0x0070     /* Dump then reset stats counters. */
+
+/* RUC Commands */
+#define RUC_NOP                0x0000
+#define        RUC_START               0x0001
+#define        RUC_RESUME              0x0002
+#define RUC_ABORT              0x0004
+#define        RUC_ADDR_LOAD           0x0006     /* (seems not to clear on acceptance) */
+#define RUC_RESUMENR           0x0007
+
+#define CU_CMD_MASK            0x00f0
+#define RU_CMD_MASK            0x0007
+
+#define SCB_M                  0x0100     /* 0 = enable interrupt, 1 = disable */
+#define SCB_SWI                0x0200     /* 1 - cause device to interrupt */
+
+#define CU_STATUS_MASK         0x00C0
+#define RU_STATUS_MASK         0x003C
+
+#define RU_STATUS_IDLE         (0<<2)
+#define RU_STATUS_SUS          (1<<2)
+#define RU_STATUS_NORES        (2<<2)
+#define RU_STATUS_READY        (4<<2)
+#define RU_STATUS_NO_RBDS_SUS   ((1<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_NORES ((2<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_READY ((4<<2)|(8<<2))
+
+       /* 82559 Port interface commands.
+        */
+#define I82559_RESET           0x00000000 /* Software reset */
+#define I82559_SELFTEST                0x00000001 /* 82559 Selftest command */
+#define I82559_SELECTIVE_RESET 0x00000002
+#define I82559_DUMP            0x00000003
+#define I82559_DUMP_WAKEUP     0x00000007
+
+       /* 82559 Eeprom interface.
+        */
+#define EE_SHIFT_CLK           0x01       /* EEPROM shift clock. */
+#define EE_CS                  0x02       /* EEPROM chip select. */
+#define EE_DATA_WRITE          0x04       /* EEPROM chip data in. */
+#define EE_WRITE_0             0x01
+#define EE_WRITE_1             0x05
+#define EE_DATA_READ           0x08       /* EEPROM chip data out. */
+#define EE_ENB                 (0x4800 | EE_CS)
+
+       /* The EEPROM commands include the alway-set leading bit. 
+        */
+#define EE_WRITE_CMD           (5 << addr_len)
+#define EE_READ_CMD            (6 << addr_len)
+#define EE_ERASE_CMD           (7 << addr_len)
+
+       /* Receive frame descriptors.
+        */
+struct RxFD {
+       volatile u16 status;
+       volatile u16 control;
+       volatile u32 link;                  /* struct RxFD * */
+       volatile u32 rx_buf_addr;           /* void * */
+       volatile u32 count;
+
+       volatile u8 data[PKTSIZE_ALIGN];
+};
+
+#define RFD_STATUS_C           0x8000      /* completion of received frame */
+#define RFD_STATUS_OK          0x2000      /* frame received with no errors */
+
+#define RFD_CONTROL_EL         0x8000      /* 1=last RFD in RFA */
+#define RFD_CONTROL_S          0x4000      /* 1=suspend RU after receiving frame */
+#define RFD_CONTROL_H          0x0010      /* 1=RFD is a header RFD */
+#define RFD_CONTROL_SF         0x0008      /* 0=simplified, 1=flexible mode */
+
+#define RFD_COUNT_MASK         0x3fff
+#define RFD_COUNT_F            0x4000
+#define RFD_COUNT_EOF          0x8000
+
+#define RFD_RX_CRC             0x0800      /* crc error */
+#define RFD_RX_ALIGNMENT       0x0400      /* alignment error */
+#define RFD_RX_RESOURCE        0x0200      /* out of space, no resources */
+#define RFD_RX_DMA_OVER        0x0100      /* DMA overrun */
+#define RFD_RX_SHORT           0x0080      /* short frame error */
+#define RFD_RX_LENGTH          0x0020
+#define RFD_RX_ERROR           0x0010      /* receive error */
+#define RFD_RX_NO_ADR_MATCH    0x0004      /* no address match */
+#define RFD_RX_IA_MATCH        0x0002      /* individual address does not match */
+#define RFD_RX_TCO             0x0001      /* TCO indication */
+
+       /* Transmit frame descriptors
+        */
+struct TxFD {                              /* Transmit frame descriptor set. */
+       volatile u16 status;
+       volatile u16 command;
+       volatile u32 link;                  /* void * */
+       volatile u32 tx_desc_addr;          /* Always points to the tx_buf_addr element. */
+       volatile s32 count;
+
+       volatile u32 tx_buf_addr0;          /* void *, frame to be transmitted.  */
+       volatile s32 tx_buf_size0;          /* Length of Tx frame. */
+       volatile u32 tx_buf_addr1;          /* void *, frame to be transmitted.  */
+       volatile s32 tx_buf_size1;          /* Length of Tx frame. */
+};
+
+#define TxCB_CMD_TRANSMIT      0x0004      /* transmit command */
+#define TxCB_CMD_SF            0x0008      /* 0=simplified, 1=flexible mode */
+#define TxCB_CMD_NC            0x0010      /* 0=CRC insert by controller */
+#define TxCB_CMD_I             0x2000      /* generate interrupt on completion */
+#define TxCB_CMD_S             0x4000      /* suspend on completion */
+#define TxCB_CMD_EL            0x8000      /* last command block in CBL */
+
+#define TxCB_COUNT_MASK        0x3fff
+#define TxCB_COUNT_EOF         0x8000
+
+       /* The Speedo3 Rx and Tx frame/buffer descriptors. 
+        */
+struct descriptor {                        /* A generic descriptor. */
+       volatile u16 status;
+       volatile u16 command;
+       volatile u32 link;                  /* struct descriptor *  */
+
+       unsigned char params[0];
+};
+
+#define CFG_CMD_EL             0x8000
+#define CFG_CMD_SUSPEND        0x4000
+#define CFG_CMD_INT            0x2000
+#define CFG_CMD_IAS            0x0001       /* individual address setup */
+#define CFG_CMD_CONFIGURE      0x0002       /* configure */
+
+#define CFG_STATUS_C           0x8000
+#define CFG_STATUS_OK          0x2000
+
+       /* Misc.
+        */
+#define NUM_RX_DESC            PKTBUFSRX
+#define NUM_TX_DESC            1            /* Number of TX descriptors   */
+
+#define TOUT_LOOP              1000000
+
+#define ETH_ALEN               6
+
+static struct RxFD rx_ring[NUM_RX_DESC]; /* RX descriptor ring         */
+static struct TxFD tx_ring[NUM_TX_DESC]; /* TX descriptor ring         */
+static int rx_next;                      /* RX descriptor ring pointer */
+static int tx_next;                      /* TX descriptor ring pointer */
+static int tx_threshold;
+
+static u_long iobase = 0;
+
+static void  init_rx_ring(void);
+static void  purge_tx_ring(void);
+
+static void  check_hw_addr(bd_t * bis);
+
+static inline int INL(u_long addr)
+{
+       return le32_to_cpu(*(volatile u32 *)pci_mem_to_phys(addr + iobase));
+}
+
+static inline int INW(u_long addr)
+{
+       return le16_to_cpu(*(volatile u16 *)pci_mem_to_phys(addr + iobase));
+}
+
+static inline int INB(u_long addr)
+{
+       return *(volatile u8 *)(pci_mem_to_phys(addr + iobase));
+}
+
+static inline void OUTB(int command, u_long addr)
+{
+       *(volatile u8 *)(pci_mem_to_phys(addr + iobase)) = command;
+}
+
+static inline void OUTW(int command, u_long addr)
+{
+       *(volatile u16 *)(pci_mem_to_phys(addr + iobase)) = cpu_to_le16(command);
+}
+
+static inline void OUTL(int command, u_long addr)
+{
+       *(volatile u32 *)(pci_mem_to_phys(addr + iobase)) = cpu_to_le32(command);
+}
+
+       /* Wait for the chip get the command.
+        */
+static int wait_for_eepro100(void) 
+{
+       int i;
+
+       for(i = 0; INW(SCBCmd) & (CU_CMD_MASK | RU_CMD_MASK); i++)
+       {
+               if (i >= TOUT_LOOP)
+               {
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+int eth_init(bd_t *bis)
+{
+       int i, status = 0;
+       int devno;
+       int tx_cur;
+       struct descriptor *ias_cmd;
+
+       /* Find PCI device 
+        */
+       if ((devno = PCI_Find_Device(PCI_VENDOR_ID_INTEL,
+                                    PCI_DEVICE_ID_INTEL_82559ER)) < 0)
+       {
+               printf("Error: Can not find an ethernet card on the PCI bus\n");
+               goto Done;
+       }
+
+       iobase = PCI_Read_CFG_Reg(devno, PCI_CFG_BASE_ADDRESS_0, 4) & ~0xf;
+
+       printf("eth: Intel i82559 PCI EtherExpressPro @0x%lx\n", iobase);
+  
+       PCI_Write_CFG_Reg(devno, 
+                         PCI_CFG_COMMAND, 
+                         PCI_CMD_MEMEN | 
+                         PCI_CMD_MASTER, 4);
+
+        /* Check if I/O accesses and Bus Mastering are enabled.
+         */
+       status = PCI_Read_CFG_Reg(devno, PCI_CFG_COMMAND, 4);
+       if (!(status & PCI_CMD_MEMEN))
+       {
+               printf("Error: Can not enable MEM access.\n");
+               goto Done;
+       }
+
+       if (!(status & PCI_CMD_MASTER))
+       {
+               printf("Error: Can not enable Bus Mastering.\n");
+               goto Done;
+       }
+
+               /* Set the latency timer for value.
+                */
+       PCI_Write_CFG_Reg(devno, PCI_CFG_LATENCY_TIMER, 0x20, 1);
+
+       udelay(10 * 1000);
+
+       check_hw_addr(bis);
+
+       /* Reset the ethernet controller
+        */
+       OUTL(I82559_SELECTIVE_RESET, SCBPort);
+       udelay(20);
+
+       OUTL(I82559_RESET, SCBPort);
+       udelay(20);
+
+       if (!wait_for_eepro100())
+       {
+               printf("Error: Can not reset ethernet controller.\n");
+               goto Done;
+       }
+       OUTL(0, SCBPointer);
+       OUTW(SCB_M | RUC_ADDR_LOAD, SCBCmd);
+
+       if (!wait_for_eepro100())
+       {
+               printf("Error: Can not reset ethernet controller.\n");
+               goto Done;
+       }
+       OUTL(0, SCBPointer);
+       OUTW(SCB_M | CU_ADDR_LOAD, SCBCmd);
+
+               /* Initialize Rx and Tx rings.
+                */
+       init_rx_ring();
+       purge_tx_ring();
+
+               /* Tell the adapter where the RX ring is located.
+                */
+       if (!wait_for_eepro100())
+       {
+               printf("Error: Can not reset ethernet controller.\n");
+               goto Done;
+       }
+
+       OUTL(pci_ram_to_mem((u32) &rx_ring[rx_next]), SCBPointer);
+       OUTW(SCB_M | RUC_START, SCBCmd);
+
+               /* Send the Individual Address Setup frame
+                */
+       tx_cur       = tx_next;
+       tx_next      = ((tx_next+1) % NUM_TX_DESC);
+
+       ias_cmd             = (struct descriptor *)&tx_ring[tx_cur];
+       ias_cmd->command    = cpu_to_le16((CFG_CMD_SUSPEND | CFG_CMD_IAS));
+       ias_cmd->status     = 0;
+       ias_cmd->link       = cpu_to_le32(pci_ram_to_mem((u32) &tx_ring[tx_next]));
+
+       memcpy(ias_cmd->params, bis->bi_enetaddr, 6);
+
+               /* Tell the adapter where the TX ring is located.
+                */
+       if (!wait_for_eepro100())
+       {
+               printf("Error: Can not reset ethernet controller.\n");
+               goto Done;
+       }
+
+       OUTL(pci_ram_to_mem((u32) &tx_ring[tx_cur]), SCBPointer);
+       OUTW(SCB_M | CU_START, SCBCmd);
+
+       for (i=0; !(le16_to_cpu(tx_ring[tx_cur].status) & CFG_STATUS_C); i++)
+       {
+               if (i >= TOUT_LOOP)
+               {
+                       printf("eth: Tx error buffer not ready\n");
+                       goto Done;
+               }
+       }
+
+       if (!(le16_to_cpu(tx_ring[tx_cur].status) & CFG_STATUS_OK))
+       {
+               printf("TX error status = 0x%08X\n",
+                      le16_to_cpu(tx_ring[tx_cur].status));
+               status++;
+       }
+
+Done:
+       return status;
+}
+
+int eth_send(volatile void *packet, int length)
+{
+       int i, status = 0;
+       int tx_cur;
+
+       if (length <= 0)
+       {
+               printf("eth: bad packet size: %d\n", length);
+               goto Done;
+       }
+
+       tx_cur  = tx_next;
+       tx_next = (tx_next+1) % NUM_TX_DESC;
+
+       tx_ring[tx_cur].command      = cpu_to_le16(TxCB_CMD_TRANSMIT | TxCB_CMD_SF | \
+                                                  TxCB_CMD_S | TxCB_CMD_EL);
+       tx_ring[tx_cur].status       = 0;
+       tx_ring[tx_cur].count        = cpu_to_le32(tx_threshold);
+       tx_ring[tx_cur].link         = cpu_to_le32(pci_ram_to_mem((u32) &tx_ring[tx_next]));
+       tx_ring[tx_cur].tx_desc_addr = cpu_to_le32(pci_ram_to_mem((u32) &tx_ring[tx_cur].tx_buf_addr0));
+       tx_ring[tx_cur].tx_buf_addr0 = cpu_to_le32(pci_ram_to_mem((u_long) packet));
+       tx_ring[tx_cur].tx_buf_size0 = cpu_to_le32(length);
+
+       if (!wait_for_eepro100())
+       {
+               printf("eth: Tx error ethernet controller not ready.\n");
+               goto Done;
+       }
+
+       /* Send the packet.
+        */
+       OUTL(pci_ram_to_mem((u32) &tx_ring[tx_cur]), SCBPointer);
+       OUTW(SCB_M | CU_START, SCBCmd);
+
+       for(i = 0; !(le16_to_cpu(tx_ring[tx_cur].status) & CFG_STATUS_C); i++)
+       {
+               if (i >= TOUT_LOOP)
+               {
+                       printf("eth: Tx error buffer not ready\n");
+                       goto Done;
+               }
+       }
+
+        if (!(le16_to_cpu(tx_ring[tx_cur].status) & CFG_STATUS_OK))
+       {
+               printf("TX error status = 0x%08X\n",
+                      le16_to_cpu(tx_ring[tx_cur].status));
+               status++;
+       }
+
+ Done:
+       return status;
+}
+
+int eth_rx(void)
+{
+       u16 status, stat;
+       int rx_prev, length = 0;
+
+       stat = INW(SCBStatus);
+       OUTW(stat & SCB_STATUS_RNR, SCBStatus);
+
+       for ( ; ; )
+       {
+               status = le16_to_cpu(rx_ring[rx_next].status);
+
+               if (!(status & RFD_STATUS_C))
+               {
+                       break;
+               }
+
+                       /* Valid frame status.
+                        */
+               if ((status & RFD_STATUS_OK))
+               {
+                               /* A valid frame received.
+                                */
+                       length = le32_to_cpu(rx_ring[rx_next].count) & 0x3fff;
+
+                               /* Pass the packet up to the protocol
+                                * layers.
+                                */
+                       NetReceive(rx_ring[rx_next].data, length);
+               }
+               else
+               {
+                               /* There was an error.
+                                */
+                       printf("RX error status = 0x%08X\n", status);
+               }
+
+               rx_ring[rx_next].control = cpu_to_le16(RFD_CONTROL_S);
+               rx_ring[rx_next].status  = 0;
+               rx_ring[rx_next].count   = cpu_to_le32(PKTSIZE_ALIGN << 16);
+
+               rx_prev                  = (rx_next + NUM_RX_DESC - 1) % NUM_RX_DESC;
+               rx_ring[rx_prev].control = 0;
+
+               /* Update entry information.
+                */
+               rx_next = (rx_next + 1) % NUM_RX_DESC;
+       }
+
+       if (stat & SCB_STATUS_RNR)
+       {
+
+               printf("eth: Receiver is not ready, restart it !\n");
+
+               /* Reinitialize Rx ring.
+                */
+               init_rx_ring();
+
+               if (!wait_for_eepro100())
+               {
+                       printf("Error: Can not restart ethernet controller.\n");
+                       goto Done;
+               }
+
+               OUTL(pci_ram_to_mem((u32) &rx_ring[rx_next]), SCBPointer);
+               OUTW(SCB_M | RUC_START, SCBCmd);
+       }
+
+ Done:
+       return length;
+}
+
+void eth_halt(void)
+{
+       if (!iobase) 
+       {
+               goto Done;
+       }
+
+       /* Reset the ethernet controller
+        */
+       OUTL(I82559_SELECTIVE_RESET, SCBPort);
+       udelay(20);
+
+       OUTL(I82559_RESET, SCBPort);
+       udelay(20);
+
+       if (!wait_for_eepro100())
+       {
+               printf("Error: Can not reset ethernet controller.\n");
+               goto Done;
+       }
+       OUTL(0, SCBPointer);
+       OUTW(SCB_M | RUC_ADDR_LOAD, SCBCmd);
+
+       if (!wait_for_eepro100())
+       {
+               printf("Error: Can not reset ethernet controller.\n");
+               goto Done;
+       }
+       OUTL(0, SCBPointer);
+       OUTW(SCB_M | CU_ADDR_LOAD, SCBCmd);
+
+ Done:
+       return;
+}
+
+       /* SROM Read.
+        */
+static int read_eeprom(long iobase, int location, int addr_len)
+{
+       unsigned short retval = 0;
+       int read_cmd = location | EE_READ_CMD;
+       int i;
+
+       OUTW(EE_ENB & ~EE_CS, SCBeeprom);
+       OUTW(EE_ENB, SCBeeprom);
+
+       /* Shift the read command bits out. */
+       for (i = 12; i >= 0; i--) 
+       {
+               short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+               OUTW(EE_ENB | dataval, SCBeeprom);
+               udelay(1);
+               OUTW(EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+               udelay(1);
+       }
+       OUTW(EE_ENB, SCBeeprom);
+
+       for (i = 15; i >= 0; i--) 
+       {
+               OUTW(EE_ENB | EE_SHIFT_CLK, SCBeeprom);
+               udelay(1);
+               retval = (retval << 1) | 
+                       ((INW(SCBeeprom) & EE_DATA_READ) ? 1 : 0);
+               OUTW(EE_ENB, SCBeeprom);
+               udelay(1);
+       }
+
+       /* Terminate the EEPROM access. */
+       OUTW(EE_ENB & ~EE_CS, SCBeeprom);
+       return retval;
+}
+
+static void init_rx_ring(void) 
+{
+       int i;
+
+       for (i = 0; i < NUM_RX_DESC; i++)
+       {
+               rx_ring[i].status      = 0;
+               rx_ring[i].control     = (i == NUM_RX_DESC-1) ? cpu_to_le16(RFD_CONTROL_S) : 0;
+               rx_ring[i].link        = cpu_to_le32(pci_ram_to_mem((u32) &rx_ring[(i+1) % NUM_RX_DESC]));
+               rx_ring[i].rx_buf_addr = 0xffffffff;
+               rx_ring[i].count       = cpu_to_le32(PKTSIZE_ALIGN << 16);
+       }
+
+       rx_next = 0;
+}
+
+static void purge_tx_ring(void) 
+{
+       int i;
+
+       tx_next      = 0;
+       tx_threshold = 0x01208000;
+
+       for (i = 0; i < NUM_TX_DESC; i++)
+       {
+               tx_ring[i].status       = 0;
+               tx_ring[i].command      = 0;
+               tx_ring[i].link         = 0;
+               tx_ring[i].tx_desc_addr = 0;
+               tx_ring[i].count        = 0;
+
+               tx_ring[i].tx_buf_addr0 = 0;
+               tx_ring[i].tx_buf_size0 = 0;
+               tx_ring[i].tx_buf_addr1 = 0;
+               tx_ring[i].tx_buf_size1 = 0;
+       }
+}
+
+static void check_hw_addr(bd_t *bis) 
+{
+       u16 eeprom[0x40];
+       u16 sum = 0;
+       u8 hw_addr[ETH_ALEN];
+       int i, j;
+       int addr_len = read_eeprom(iobase, 0, 6) == 0xffff ? 8 : 6;
+
+       for (j = 0, i = 0; i < 0x40; i++) 
+       {
+               u16 value = read_eeprom(iobase, i, addr_len);
+               eeprom[i] = value;
+               sum += value;
+               if (i < 3) 
+               {
+                       hw_addr[j++] = value;
+                       hw_addr[j++] = value >> 8;
+               }
+       }
+
+       if (sum != 0xBABA)
+               printf("eth: Invalid EEPROM checksum %#4.4x, "
+                      "check settings before activating this device!\n",
+                      sum);
+
+       for (i=0;i<ETH_ALEN;i++) 
+       {
+               if (hw_addr[i] != bis->bi_enetaddr[i]) 
+               {
+                       printf("Warning: HW address don't match:\n");
+                       printf("Address in SROM is         "
+                              "%02X:%02X:%02X:%02X:%02X:%02X\n",
+                              hw_addr[0], hw_addr[1], hw_addr[2],
+                              hw_addr[3], hw_addr[4], hw_addr[5]);
+                       printf("Address used by ppcboot is "
+                              "%02X:%02X:%02X:%02X:%02X:%02X\n",
+                              bis->bi_enetaddr[0], bis->bi_enetaddr[1], 
+                              bis->bi_enetaddr[2], bis->bi_enetaddr[3], 
+                              bis->bi_enetaddr[4], bis->bi_enetaddr[5]);
+                       goto Done;
+               }
+       }
+
+Done:
+       return;
+}
diff --git a/board/pcippc2/flash.c b/board/pcippc2/flash.c
new file mode 100644 (file)
index 0000000..e8da9f4
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <flash.h>
+#include <asm/io.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS];
+
+static ulong flash_get_size (u32 addr, flash_info_t *info);
+static int flash_get_offsets (u32 base, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_reset (u32 addr);
+
+unsigned long flash_init (void)
+{
+       unsigned int i;
+       unsigned long flash_size = 0;
+       unsigned long bank_size;
+       unsigned int bank = 0;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+               flash_info[i].sector_count = 0;
+               flash_info[i].size = 0;
+       }
+
+       /* Initialise the BOOT Flash */
+       if (bank == CFG_MAX_FLASH_BANKS)
+       {
+               puts ("Warning: not all Flashes are initialised !");
+               return flash_size;
+       }
+       
+       bank_size = flash_get_size (CFG_FLASH_BASE, flash_info + bank);
+       if (bank_size)
+       {
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE && \
+    CFG_MONITOR_BASE < CFG_FLASH_BASE + CFG_FLASH_MAX_SIZE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+                             flash_info + bank);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+                             flash_info + bank);
+#endif
+
+               flash_size += bank_size;
+               bank++;
+       }
+       else
+       {
+               puts ("Warning: the BOOT Flash is not initialised !");
+       }
+       
+       return flash_size;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (u32 addr, flash_info_t *info)
+{
+       short i;
+       uchar value;
+
+       /* Write auto select command: read Manufacturer ID */
+       out8(addr + 0x0555, 0xAA);
+       iobarrier_rw();
+       out8(addr + 0x02AA, 0x55);
+       iobarrier_rw();
+       out8(addr + 0x0555, 0x90);
+       iobarrier_rw();
+
+       value = in8(addr);
+       iobarrier_rw();
+       switch (value | (value << 16))
+       {
+               case AMD_MANUFACT:
+                       info->flash_id = FLASH_MAN_AMD;
+                       break;
+
+               case FUJ_MANUFACT:
+                       info->flash_id = FLASH_MAN_FUJ;
+                       break;
+
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       flash_reset (addr);
+                       return 0;
+       }
+
+       value = in8(addr + 1);                  /* device ID            */
+       iobarrier_rw();
+
+       switch (value)
+       {
+               case AMD_ID_F040B:
+                       info->flash_id += FLASH_AM040;
+                       info->sector_count = 8;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV040B:
+                       info->flash_id += FLASH_AM040;
+                       info->sector_count = 8;
+                       info->size = 0x80000;
+                       break;
+
+               case AMD_ID_LV400T:
+                       info->flash_id += FLASH_AM400T;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                          /* => 1 MB              */
+
+               case AMD_ID_LV400B:
+                       info->flash_id += FLASH_AM400B;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                          /* => 1 MB              */
+
+               case AMD_ID_LV800T:
+                       info->flash_id += FLASH_AM800T;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV800B:
+                       info->flash_id += FLASH_AM800B;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV160T:
+                       info->flash_id += FLASH_AM160T;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                          /* => 4 MB              */
+
+               case AMD_ID_LV160B:
+                       info->flash_id += FLASH_AM160B;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                          /* => 4 MB              */
+
+               case AMD_ID_LV320T:
+                       info->flash_id += FLASH_AM320T;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                          /* => 8 MB              */
+
+#if 0
+               /* Has the same ID as AMD_ID_LV320T, to be fixed */
+               case AMD_ID_LV320B:
+                       info->flash_id += FLASH_AM320B;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                          /* => 8 MB              */
+#endif
+
+               case AMD_ID_LV033C:
+                       info->flash_id += FLASH_AM033C;
+                       info->sector_count = 64;
+                       info->size = 0x01000000;
+                       break;                          /* => 16Mb              */
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       flash_reset (addr);
+                       return (0);                     /* => no or unknown flash */
+
+       }
+
+       if (! flash_get_offsets (addr, info))
+       {
+               flash_reset (addr);
+               return 0;
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++)
+       {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               value = in8(info->start[i] + 2);
+               iobarrier_rw();
+               info->protect[i] = (value & 1) != 0;
+       }
+
+       /*
+        * Reset bank to read mode
+        */
+       flash_reset (addr);
+
+       return (info->size);
+}
+
+static int flash_get_offsets (u32 base, flash_info_t *info)
+{
+       unsigned int i;
+
+       switch (info->flash_id & FLASH_TYPEMASK)
+       {
+               case FLASH_AM040:
+                       /* set sector offsets for uniform sector type   */
+                       for (i = 0; i < info->sector_count; i++) {
+                               info->start[i] = base + i * info->size /
+                                                           info->sector_count;
+                       }
+                       break;
+               default:
+                       return 0;
+       }
+
+       return 1;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       volatile u32 addr = info->start[0];
+       int flag, prot, sect, l_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_UNKNOWN ||
+           info->flash_id > FLASH_AMD_COMP) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               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");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       out8(addr + 0x555, 0xAA);
+       iobarrier_rw();
+       out8(addr + 0x2AA, 0x55);
+       iobarrier_rw();
+       out8(addr + 0x555, 0x80);
+       iobarrier_rw();
+       out8(addr + 0x555, 0xAA);
+       iobarrier_rw();
+       out8(addr + 0x2AA, 0x55);
+       iobarrier_rw();
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = info->start[sect];
+                       out8(addr, 0x30);
+                       iobarrier_rw();
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = info->start[l_sect];
+       while ((in8(addr) & 0x80) != 0x80) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+               iobarrier_rw();
+       }
+
+DONE:
+       /* reset to read mode */
+       flash_reset (info->start[0]);
+
+       printf (" done\n");
+       return 0;
+}
+
+/*
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       volatile u32 addr = info->start[0];
+       ulong start;
+       int flag, i;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((in32(dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       /* first, perform an unlock bypass command to speed up flash writes */
+       out8(addr + 0x555, 0xAA);
+       iobarrier_rw();
+       out8(addr + 0x2AA, 0x55);
+       iobarrier_rw();
+       out8(addr + 0x555, 0x20);
+       iobarrier_rw();
+
+       /* write each byte out */
+       for (i = 0; i < 4; i++) {
+               char *data_ch = (char *)&data;
+               out8(addr, 0xA0);
+               iobarrier_rw();
+               out8(dest+i, data_ch[i]);
+               iobarrier_rw();
+               udelay(10); /* XXX */
+       }
+
+       /* we're done, now do an unlock bypass reset */
+       out8(addr, 0x90);
+       iobarrier_rw();
+       out8(addr, 0x00);
+       iobarrier_rw();
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((in32(dest) & 0x80808080) != (data & 0x80808080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+               iobarrier_rw();
+       }
+
+       flash_reset (addr);
+       
+       return (0);
+}
+
+/*
+ * Reset bank to read mode
+ */
+static void flash_reset (u32 addr)
+{
+       out8(addr, 0xF0);       /* reset bank */
+       iobarrier_rw();
+}
+
+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_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM040:       printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+                               break;
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       if (info->size % 0x100000 == 0)
+       {
+               printf ("  Size: %ld MB in %d Sectors\n",
+                       info->size / 0x100000, info->sector_count);
+       }
+       else if (info->size % 0x400 == 0)
+       {
+               printf ("  Size: %ld KB in %d Sectors\n",
+                       info->size / 0x400, info->sector_count);
+       }
+       else
+       {
+               printf ("  Size: %ld B in %d Sectors\n",
+                       info->size, 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");
+}
diff --git a/board/pcippc2/fpga_serial.c b/board/pcippc2/fpga_serial.c
new file mode 100644 (file)
index 0000000..cacb60e
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <asm/io.h>
+
+#include "fpga_serial.h"
+#include "hardware.h"
+#include "pcippc2.h"
+
+  /* 8 data, 1 stop, no parity
+   */
+#define LCRVAL         0x03
+  /* RTS/DTR
+   */
+#define MCRVAL         0x03
+  /* Clear & enable FIFOs
+   */
+#define FCRVAL         0x07
+
+static void    fpga_serial_wait        (void);
+static void    fpga_serial_print       (char           c);
+
+void fpga_serial_init (
+  int                  baudrate)
+{
+  int                  clock_divisor = 115200 / baudrate;
+
+  out8(FPGA(INT, SERIAL_CONFIG), 0x24);
+  iobarrier_rw();
+
+  fpga_serial_wait();
+
+  out8(UART(IER), 0);
+  out8(UART(LCR), LCRVAL | 0x80);
+  iobarrier_rw();
+  out8(UART(DLL), clock_divisor & 0xff);
+  out8(UART(DLM), clock_divisor >> 8);
+  iobarrier_rw();
+  out8(UART(LCR), LCRVAL);
+  iobarrier_rw();
+  out8(UART(MCR), MCRVAL);
+  out8(UART(FCR), FCRVAL);
+  iobarrier_rw();
+}
+
+void fpga_serial_putc (
+  char                 c)
+{
+  if (c)
+  {
+    fpga_serial_print(c);
+  }
+}
+
+void fpga_serial_puts (
+  const char *         s)
+{
+  while (*s)
+  {
+    fpga_serial_print(*s++);
+  }
+}
+
+int fpga_serial_getc (void)
+{
+  while ((in8(UART(LSR)) & 0x01) == 0);
+
+  return in8(UART(RBR));
+}
+
+int fpga_serial_tstc (void)
+{
+  return (in8(UART(LSR)) & 0x01) != 0;
+}
+
+void fpga_serial_setbrg (
+  unsigned long        dummy,
+  int                  baudrate)
+{
+  int                  clock_divisor = 115200 / baudrate;
+
+  fpga_serial_wait();
+
+  out8(UART(LCR), LCRVAL | 0x80);
+  iobarrier_rw();
+  out8(UART(DLL), clock_divisor & 0xff);
+  out8(UART(DLM), clock_divisor >> 8);
+  iobarrier_rw();
+  out8(UART(LCR), LCRVAL);
+  iobarrier_rw();
+}
+
+static void fpga_serial_wait (void)
+{
+  while ((in8(UART(LSR)) & 0x40) == 0);
+}
+
+static void fpga_serial_print (
+  char                 c)
+{
+  if (c == '\n')
+  {
+    while ((in8(UART(LSR)) & 0x20) == 0);
+  
+    out8(UART(THR), '\r');
+    iobarrier_rw();
+  }
+
+  while ((in8(UART(LSR)) & 0x20) == 0);
+  
+  out8(UART(THR), c);
+  iobarrier_rw();
+
+  if (c == '\n')
+  {
+    fpga_serial_wait();
+  }
+}
diff --git a/board/pcippc2/fpga_serial.h b/board/pcippc2/fpga_serial.h
new file mode 100644 (file)
index 0000000..e069e8b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _FPGA_SERIAL_H_
+#define _FPGA_SERIAL_H_
+
+extern void            fpga_serial_init        (int            baudrate);
+extern void            fpga_serial_putc        (char           c);
+extern void            fpga_serial_puts        (const char *   c);
+extern int             fpga_serial_getc        (void);
+extern int             fpga_serial_tstc        (void);
+extern void            fpga_serial_setbrg      (unsigned long  dummy,
+                                                int            baudrate);
+
+#endif
diff --git a/board/pcippc2/hardware.h b/board/pcippc2/hardware.h
new file mode 100644 (file)
index 0000000..489929d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _HARDWARE_H_
+#define _HARDWARE_H_
+
+#include "cpc710.h"
+#include "cpc710_pci.h"
+#include "pcippc2_fpga.h"
+#include "ns16550.h"
+
+#define REG(r, x)      (HW_PHYS_##r + HW_##r##_##x)
+
+  /* Address map:
+   *
+   * 0x00000000-0x20000000     SDRAM
+   * 0x40000000-0x00008000     Init RAM in the CPU DCache
+   * 0xf0000000-0xf8000000     CPCI MEM
+   * 0xf8000000-0xfc000000     Local PCI MEM
+   * 0xfc000000-0xfe000000     CPCI I/O
+   * 0xfe000000-0xff000000     Local PCI I/O
+   * 0xff000000-0xff201000     System configuration space
+   * 0xff400000-0xff500000     Local PCI bridge space
+   * 0xff500000-0xff600000     CPCI bridge space
+   * 0xfff00000-0xfff80000     Boot Flash
+   */
+
+#endif
diff --git a/board/pcippc2/i2c.c b/board/pcippc2/i2c.c
new file mode 100644 (file)
index 0000000..d249e15
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <asm/io.h>
+
+#include "hardware.h"
+#include "i2c.h"
+
+static void            i2c_start       (void);
+static void            i2c_stop        (void);
+static int             i2c_write       (u8             data);
+static int             i2c_read        (u8 *           data);
+
+static inline void     i2c_port_start  (void);
+static inline void     i2c_port_stop   (void);
+static inline void     i2c_clock       (unsigned int   val);
+static inline void     i2c_data        (unsigned int   val);
+static inline unsigned int
+                       i2c_in          (void);
+static inline void     i2c_wait        (void);
+
+static inline void     i2c_write_bit   (unsigned int   val);
+static inline unsigned int
+                       i2c_read_bit    (void);
+
+static inline void     i2c_udelay      (unsigned int   time);
+
+int i2c_read_byte (
+  u8 *                 data,
+  u8                   dev)
+{
+  int                  err = 0;
+
+  i2c_start();
+  
+  if (! err)
+  {
+    err = ! i2c_write(dev | 0x01);
+  }
+
+  if (! err)
+  {
+    err = ! i2c_read(data);
+  }
+
+  i2c_stop();
+  
+  return ! err;
+}
+
+int i2c_write_byte (
+  u8                   dev,
+  u8                   data)
+{
+  int                  err = 0;
+
+  i2c_start();
+  
+  if (! err)
+  {
+    err = ! i2c_write(dev);
+  }
+
+  if (! err)
+  {
+    err = ! i2c_write(data);
+  }
+
+  i2c_stop();
+  
+  return ! err;
+}
+
+static inline void i2c_udelay (
+  unsigned int         time)
+{
+  int                  v;
+  
+  asm volatile("mtdec %0" : : "r" (time * (CFG_BUS_CLK / 4 / 1000000))); 
+  
+  do
+  {
+    asm volatile("isync; mfdec %0" : "=r" (v));
+  } while (v >= 0);
+}
+
+  /* Low-level hardware access
+   */
+
+#define BIT_GPDATA             0x80000000
+#define BIT_GPCLK              0x40000000
+   
+static inline void i2c_port_start (void)
+{
+  out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) & ~(BIT_GPCLK | BIT_GPDATA));
+  out32(REG(CPC0, GPOUT), in32(REG(CPC0, GPOUT)) & ~(BIT_GPCLK | BIT_GPDATA));
+  iobarrier_rw();
+  
+  i2c_udelay(1);
+}
+
+static inline void i2c_port_stop (void)
+{
+  out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) & ~(BIT_GPCLK | BIT_GPDATA));
+  iobarrier_rw();
+  
+  i2c_udelay(1);
+}
+
+static inline void i2c_clock (
+  unsigned int         val)
+{
+  if (val)
+  {
+    out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) & ~BIT_GPCLK);
+  }
+  else
+  {
+    out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) | BIT_GPCLK);
+  }
+  
+  iobarrier_rw();
+  
+  i2c_udelay(1);
+}
+
+static inline void i2c_data (
+  unsigned int         val)
+{
+  if (val)
+  {
+    out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) & ~BIT_GPDATA);
+  }
+  else
+  {
+    out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) | BIT_GPDATA);
+  }
+  
+  iobarrier_rw();
+
+  i2c_udelay(1);
+}
+
+static inline unsigned int i2c_in (void)
+{
+  unsigned int         val = (in32(REG(CPC0, GPIN)) & BIT_GPDATA) != 0;
+  
+  iobarrier_rw();
+  
+  return val;  
+}
+
+static inline void i2c_wait (void)
+{
+  i2c_udelay(10);
+}
+
+  /* Protocol implementation
+   */
+
+static inline void i2c_write_bit (
+  unsigned int         val)
+{
+  if (val == 0)
+  {
+    i2c_data(0);
+  }
+  
+  i2c_clock(1);
+  i2c_wait();
+  
+  i2c_clock(0);
+  i2c_wait();
+
+  if (val == 0)
+  {
+    i2c_data(1);
+  }
+}
+
+static inline unsigned int i2c_read_bit (void)
+{
+  unsigned int         val;
+  
+  i2c_clock(1);
+  i2c_wait();
+  
+  val = i2c_in();
+  
+  i2c_clock(0);
+  i2c_wait();
+  
+  return val;
+}
+
+static void i2c_start (void)
+{
+  i2c_port_start();
+  
+  i2c_clock(0);
+  i2c_data(1);
+
+  i2c_clock(1);
+  i2c_wait();
+  
+  i2c_data(0);
+  i2c_wait();
+  
+  i2c_clock(0);
+  i2c_wait();
+  
+  i2c_data(1);
+}
+
+static void i2c_stop (void)
+{
+  i2c_data(0);
+
+  i2c_clock(1);
+  i2c_wait();
+  
+  i2c_data(1);
+  i2c_wait();
+
+  i2c_port_stop();
+}
+
+static int i2c_write (
+  u8                   data)
+{
+  unsigned int         i;
+  
+  for (i = 0; i < 8; i++)
+  {
+    i2c_write_bit(data >> 7);
+    data <<= 1;
+  }
+  
+  return i2c_read_bit() == 0;
+}
+
+static int i2c_read (
+  u8 *                 data)
+{
+  unsigned int         i;
+  u8                   val = 0;
+  
+  for (i = 0; i < 8; i++)
+  {
+    val <<= 1;
+    val |= i2c_read_bit();
+  }
+  
+  *data = val;
+
+  return 1;
+}
diff --git a/board/pcippc2/i2c.h b/board/pcippc2/i2c.h
new file mode 100644 (file)
index 0000000..c32acd8
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _I2C_H_
+#define _I2C_H_
+
+#include <ppcboot.h>
+
+extern int     i2c_read_byte   (u8 *           data,
+                                u8             dev);
+extern int     i2c_write_byte  (u8             dev,
+                                u8             data);
+
+#endif
diff --git a/board/pcippc2/ns16550.h b/board/pcippc2/ns16550.h
new file mode 100644 (file)
index 0000000..7023f13
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _NS16550_H_
+#define _NS16550_H_
+
+#define NS16550_RBR    0x00
+#define NS16550_IER    0x01
+#define NS16550_FCR    0x02
+#define NS16550_LCR    0x03
+#define NS16550_MCR    0x04
+#define NS16550_LSR    0x05
+#define NS16550_MSR    0x06
+#define NS16550_SCR    0x07
+
+#define NS16550_THR    NS16550_RBR
+#define NS16550_IIR    NS16550_FCR
+#define NS16550_DLL    NS16550_RBR
+#define NS16550_DLM    NS16550_IER
+
+#endif
diff --git a/board/pcippc2/pci.c b/board/pcippc2/pci.c
new file mode 100644 (file)
index 0000000..6756ffd
--- /dev/null
@@ -0,0 +1,719 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * 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
+ */
+
+/*
+ * PCI routines
+ */
+
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <asm/processor.h>
+
+#include "pci.h"
+#include "hardware.h"
+
+/*
+ * These are the lowest addresses allowed for PCI configuration.
+ * They correspond to lowest available I/O and Memory addresses.
+ * In the case where where multiple PMM regs are being used to map
+ * different PLB to PCI regions, each region should have it's own
+ * minimum address.
+ */
+unsigned long    LowestMemAddr = PCI_LOWEST_MEMADDR;
+unsigned long    LowestIOAddr  = PCI_LOWEST_IOADDR;
+
+unsigned long    MaxBusNum = 0;
+
+unsigned char  ShortPCIListing = 0;
+
+/*
+ * Subroutine:  PCI_Scan
+ *
+ * Description: Scan through all allowable PCI IDs and configure
+ *              those for which the vendor ID indicates there is a
+ *              device present. Routine scans only function 0.
+ *
+ * Inputs:      BusNum  Bus number where scanning begins
+ *
+ * Return:      Number of devices found on the bus.
+ *
+ */
+int PCI_Scan(int BusNum)
+{
+       int     Device;
+       int Function;
+       int     BusDevFunc;
+       int Found = 0;
+       unsigned int HeaderType = 0;
+       unsigned int VendorID = 0;
+
+#ifdef DEBUG
+       printf("Scanning PCI bus %d\n", BusNum);
+#endif
+
+       /*
+        * Start with device 0
+        */
+       for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
+               HeaderType = 0;
+               VendorID = 0;
+               for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
+                       /*
+                        * If this is not a multi-function device, we skip the rest
+                        */
+                       if (Function && !(HeaderType & 0x80))
+                               break;
+
+                       BusDevFunc = (BusNum << 16) |
+                                    (Device << 11) |
+                                    (Function << 8);
+
+                       VendorID = PCI_Read_CFG_Reg (BusDevFunc,
+                                                    PCI_CFG_VENDOR_ID, 2);
+                       if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
+                               continue;
+
+                       HeaderType = PCI_Read_CFG_Reg(BusDevFunc,
+                                                     PCI_CFG_HEADER_TYPE, 1);
+#ifdef DEBUG
+                       printf("\nPCI Device %d Function %d is present\n",
+                               Device, Function);
+#endif
+                       if (HeaderType & 0x01) {
+                               /*  PCI-PCI Bridge */
+                               PCI_Config_Bridge(BusDevFunc);
+                       } else {
+                               PCI_Config_Device(BusDevFunc, 6);
+                       }
+                       Found++;
+               }
+       }
+       return Found;
+}
+
+/*
+ * Subroutine:  PCI_Config_Device
+ *
+ * Description: Configure a PCI device by examining its I/O and memory
+ *              address space needs and allocating address space to it by
+ *              programming the address decoders in the Base Address Registers.
+ *
+ * Inputs:             BusDevFunc    Bus+Device+Function number
+ *              NumBaseAddr   Number of base address registers to
+ *                            configure
+ *
+ * Return:      None
+ *
+ */
+void PCI_Config_Device(int BusDevFunc, int NumBaseAddr)
+{
+       int     AddrSlot, i;
+       unsigned long  AddrDesc, AddrProg, Min_Gnt_Val;
+
+       unsigned long pcicmd;
+       pcicmd = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2);
+       PCI_Write_CFG_Reg (BusDevFunc, PCI_CFG_COMMAND,
+                          pcicmd & ~(PCI_CMD_MEMEN|PCI_CMD_IOEN), 2);
+
+       for (AddrSlot = 0; AddrSlot < NumBaseAddr; AddrSlot++) {
+               /*
+                * Write virtual address into register to check LSB.
+                * LSB == 1 => IO space, else memory space.
+                */
+               PCI_Write_CFG_Reg (BusDevFunc,
+                                  PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
+                                  0xFFFFFFFF, 4);
+
+               AddrDesc = PCI_Read_CFG_Reg (BusDevFunc,
+                                            PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
+                                            4);
+
+               if (AddrDesc == 0)              /* unimplemented, stop looking */
+                       continue;               /* 01/04/99 MCG */
+
+#ifdef DEBUG
+               printf ("Read Base Addr Reg %d = 0x%08lx\n",
+                       AddrSlot, AddrDesc);
+#endif
+
+               if ((AddrDesc & 1) == 1) {        /* I/O space */
+                       AddrDesc &= 0xFFFFFFFC;
+
+                       for (i = 0; (AddrDesc & 1) != 1; i++)
+                               AddrDesc = AddrDesc >> 1;
+
+                       AddrDesc = 1 << i;
+#ifdef DEBUG
+                       printf("  PCI I/O space = 0x%lx bytes\n", AddrDesc);
+#endif
+                       for (AddrProg = PCI_LOWEST_IOADDR;
+                            AddrProg < LowestIOAddr;
+                            AddrProg += AddrDesc) {
+                               ;       /* empty */
+                       }
+                       PCI_Write_CFG_Reg (BusDevFunc,
+                                          PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
+                                          AddrProg, 4);
+#ifdef DEBUG
+                       printf("  PCI I/O addr = 0x%lx\n", AddrProg);
+#endif
+                       LowestIOAddr = AddrProg + AddrDesc;
+               } else {                          /* memory space */
+                       AddrDesc &= 0xFFFFFFF0;
+
+                       for (i = 0; (AddrDesc & 1) != 1; i++)
+                               AddrDesc = AddrDesc >> 1;
+
+                       AddrDesc = 1 << i;
+
+                       if ((unsigned long)AddrDesc < 4096)
+                               AddrDesc = 4096;
+#ifdef DEBUG
+                       printf("  PCI memory space = 0x%lx bytes \n",AddrDesc);
+#endif
+                       for (AddrProg = PCI_LOWEST_MEMADDR;
+                            AddrProg < LowestMemAddr;
+                            AddrProg += AddrDesc) {
+                               ;       /* empty */
+                       }
+
+                       PCI_Write_CFG_Reg (BusDevFunc,
+                                          PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
+                                          AddrProg, 4);
+#ifdef DEBUG
+                       printf("  PCI memory addr = 0x%lx\n", AddrProg);
+#endif
+                       LowestMemAddr = AddrProg + AddrDesc;
+               }
+       }
+
+       /*
+        * Assign expansion ROM address
+        */
+       PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 0xFFFFFFFE, 4);
+
+       AddrDesc = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 4);
+
+       if (AddrDesc != 0) {
+#ifdef DEBUG
+               printf("Read Expansion ROM Addr Reg = 0x%08lx\n" , AddrDesc);
+#endif
+               for (i = 0; (AddrDesc & 1) != 1; i++)
+                       AddrDesc = AddrDesc >> 1;
+
+               AddrDesc = 1 << i;
+#ifdef DEBUG
+               printf("  PCI Expansion ROM space = 0x%lx bytes\n", AddrDesc);
+#endif
+               for (AddrProg = PCI_LOWEST_MEMADDR;
+                    AddrProg < LowestMemAddr;
+                    AddrProg += AddrDesc) {
+                       ;       /* empty */
+               }
+               PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, AddrProg, 4);
+#ifdef DEBUG
+               printf("  PCI Expansion ROM addr = 0x%lx\n", AddrProg);
+#endif
+               LowestMemAddr = AddrProg + AddrDesc;
+       }
+
+       Min_Gnt_Val = 0x80;
+       PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_LATENCY_TIMER, Min_Gnt_Val, 1);
+
+       /*
+        * Disable interrupt line, if device says it wants to use interrupts
+        */
+       if (PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_PIN, 1) != 0)
+               PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_LINE, 0xFF, 1);
+       /*
+        * Enable i/o space and memory space on this device
+        */
+       PCI_Write_CFG_Reg (BusDevFunc, PCI_CFG_COMMAND,
+                          pcicmd | PCI_CMD_MEMEN | PCI_CMD_IOEN, 2);
+}
+
+/*
+ * Subroutine:  PCI_Config_Bridge
+ *
+ * Description: Configure a PCI-PCI bridge
+ *
+ * Inputs:             BusDevFunc      Bus+Device+Function number
+ *
+ * Return:      None
+ *
+ */
+void PCI_Config_Bridge(int BusDevFunc)
+{
+       int     SecondaryBus;
+       int     PrimaryBus;
+       int     CommandReg_Val;
+       int     InitialLowestIOAddr, InitialLowestMemAddr;
+       int     IOBase, MemBase;
+       int     IOLimit, MemLimit;
+
+       InitialLowestIOAddr = LowestIOAddr;
+       InitialLowestMemAddr = LowestMemAddr;
+
+       CommandReg_Val = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2);
+
+       /* Configure bridge's base address registers */
+       PCI_Config_Device(BusDevFunc, 2);
+
+       /*
+        * PCI_config_device() for the bridge could have changed the values in
+        * LowestIOAddr and LowestMemAddr, if the bridge itself uses
+        * I/O and/or memory space.
+        */
+       if ( LowestIOAddr > InitialLowestIOAddr )       /* bridge uses IO space? */
+               CommandReg_Val |= 0x01;                 /* enable I/O Space */
+
+       if ( LowestMemAddr > InitialLowestMemAddr ) /* bridge uses memory space? */
+       CommandReg_Val |= 0x02;                         /* enable Memory Space */
+
+       PrimaryBus = (BusDevFunc >> 16) & 0xFF;
+       PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_PRIMARYBUS, PrimaryBus, 1);
+
+       SecondaryBus = ++MaxBusNum;
+       PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_SECONDARYBUS, SecondaryBus, 1);
+
+       /*
+        * Start with max. possible value for subordinate bus number
+        * Later, after any additional child busses are found, we'll update this
+        */
+       PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_SUBORDINATEBUS, 0xFF, 1);
+
+       /* IO Base must be on 4Kb boundary.  Adjust if needed */
+       if ((LowestIOAddr % 4096) != 0)
+       LowestIOAddr += 4096 - (LowestIOAddr % 4096);
+
+       PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOBASE,
+                          (LowestIOAddr>>8) & 0xF0, 1);
+       PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOBASEUPPER16,
+                          (LowestIOAddr>>16) & 0xFFFF, 2);
+
+       IOBase = LowestIOAddr;
+
+       /* Mem Base must be on 1 MB boundary.  adjust if needed */
+       if ((LowestMemAddr % 0x100000) != 0)
+       LowestMemAddr += 0x100000 - (LowestMemAddr % 0x100000);
+
+       PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_MEMBASE,
+                          (LowestMemAddr>>16) & 0xFFF0, 2);
+       MemBase = LowestMemAddr;
+
+       /*
+        * secondary bus on this bridge
+        */
+       PCI_Scan(SecondaryBus);
+
+       PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_SUBORDINATEBUS, MaxBusNum, 1);
+
+       IOLimit = LowestIOAddr;
+       if (LowestIOAddr > IOBase) {    /* IO space used on secondary bus?   */
+               CommandReg_Val |= 0x01; /*   enable IO Space                 */
+               IOLimit--;              /*   IOLimit is highest used address */
+       }
+
+       PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOLIMIT,
+                          ((IOLimit)>>8) & 0xF0, 1);
+       PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOLIMITUPPER16,
+                          ((IOLimit)>>16) & 0xFFFF, 2);
+
+       /*
+        * IOLIMIT is the starting address of a 4K block forwarded by the bridge.
+        * Round LowestIOAddr up to the next 4K boundary if IO space is enabled.
+        */
+       if ((CommandReg_Val & 0x01) == 0x01)
+       LowestIOAddr = (IOLimit | 0xFFF) + 1;
+
+       MemLimit = LowestMemAddr;
+       if ( LowestMemAddr > MemBase ) { /* mem. space is used on secondary bus? */
+               CommandReg_Val |= 0x02; /*   enable Memory Space                */
+               MemLimit--;             /*   MemLimit is highest used address   */
+       }
+
+       PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_MEMLIMIT,
+                          ((MemLimit)>>16) & 0xFFF0, 2);
+
+       /*
+        * MEMLIMIT is the starting address of a 1M block forwarded by the bridge.
+        * Round LowestMemAddr up to the next 1M boundary
+        * if Memory space is enabled.
+        */
+
+       if ( (CommandReg_Val & 0x02) == 0x02 )
+               LowestMemAddr = (MemLimit | 0xFFFFF) + 1;
+
+       /* Enable Bus Master on secondary bus */
+       CommandReg_Val |= 0x04;
+
+       PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, CommandReg_Val, 2);
+}
+
+/*
+ * Subroutine:  PCI_Find_Device
+ *
+ * Description: Locate a PCI device by vendor and device number on any bus.
+ *
+ * Inputs:             VendorID        Value of the device's Vendor ID field
+ *              DeviceID        Value of the device's Device ID field
+ *
+ * Return:      < 0     Device not found
+ *              (int)   PCI Bus+Device+Function number
+ *
+ */
+int PCI_Find_Device(unsigned short VendorID, unsigned short DeviceID)
+{
+       int     Device;
+       int     BusDevFunc;
+       int     BusNum;
+
+#if CFG_SCSI_SCAN_BUS_REVERSE
+       for (BusNum = MaxBusNum; BusNum >= 0; BusNum--) {
+#else
+       for (BusNum = 0; BusNum <= MaxBusNum; BusNum++) {
+#endif
+               for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
+               BusDevFunc = (BusNum << 16) | (Device << 11);
+
+                       if (PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_VENDOR_ID, 2) == VendorID
+                        && PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEVICE_ID, 2) == DeviceID) {
+                               return (BusDevFunc);
+                       }
+               }
+       }
+       return (-1);
+}
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCI)
+/*
+ * Follows routines for the output of infos about devices on PCI bus.
+ */
+
+void pciinfo(int BusNum);
+
+/*
+ * Subroutine:  do_pciinfo
+ *
+ * Description: Handler for 'pciinfo' command..
+ *
+ * Inputs:             argv[1] may contain the number of the bus to be scanned.
+ *                             Default is bus 0.
+ *
+ * Return:      None
+ *
+ */
+void do_pciinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       char *s;
+       int     bus_no = 0;
+
+       if (argc == 2)
+       {
+               bus_no = (int)simple_strtoul(argv[1], NULL, 10);
+       }
+
+       if ((s = getenv("pci_listing")) != NULL)
+               ShortPCIListing = (strcmp(s, "short") == 0) ? 1 : 0;
+       else
+               ShortPCIListing = 0;
+
+       pciinfo(bus_no);
+}
+
+
+/*
+ * Subroutine:  pciinfo
+ *
+ * Description: Show information about devices on PCI bus.
+ *                             Depending on the define CFG_SHORT_PCI_LISTING
+ *                             the output will be more or less exhaustive.
+ *
+ * Inputs:             bus_no          the number of the bus to be scanned.
+ *
+ * Return:      None
+ *
+ */
+void pciinfo(int BusNum)
+{
+       int Device;
+       int Function;
+       unsigned int HeaderType;
+       unsigned int VendorID;
+       int BusDevFunc;
+
+       printf("Scanning PCI devices on bus %d\n", BusNum);
+
+       if (ShortPCIListing) {
+               printf("No.   VendorId   DeviceId   Device Class       Sub-Class\n");
+               printf("________________________________________________________\n");
+       }
+
+       for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
+               HeaderType = 0;
+               VendorID = 0;
+               for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
+                       /*
+                        * If this is not a multi-function device, we skip the rest.
+                        */
+                       if (Function && !(HeaderType & 0x80))
+                               break;
+
+                       BusDevFunc = (BusNum << 16) |
+                                    (Device << 11) |
+                                    (Function << 8);
+
+                       VendorID = PCI_Read_CFG_Reg (BusDevFunc, PCI_CFG_VENDOR_ID, 2);
+                       if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
+                               continue;
+
+                       HeaderType = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1);
+
+                       if (ShortPCIListing)
+                               printf("%02d.%d  ", Device, Function);
+                       else
+                       printf("\nFound PCI device %d, function %d:\n",
+                               Device, Function);
+
+                       PCI_Header_Show(BusDevFunc);
+           }
+    }
+}
+
+
+/*
+ * Subroutine:  PCI_Header_Show
+ *
+ * Description: Reads the header of the specified PCI device.
+ *
+ * Inputs:             BusDevFunc      Bus+Device+Function number
+ *
+ * Return:      None
+ *
+ */
+void PCI_Header_Show(int BusDevFunc)
+{
+    PCI_HEADER_DEVICE headerDevice;
+    PCI_HEADER_BRIDGE headerBridge;
+    PCI_HEADER_DEVICE * pD = &headerDevice;
+    PCI_HEADER_BRIDGE * pB = &headerBridge;
+
+    pD->headerType = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1);
+
+    if (pD->headerType & 0x01) {               /* PCI-to-PCI bridge */
+       pB->vendorId      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_VENDOR_ID, 2);
+       pB->deviceId      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEVICE_ID, 2);
+       pB->command       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2);
+       pB->status        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_STATUS, 2);
+       pB->revisionId    = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_REVISION, 1);
+       pB->progIf        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PROGRAMMING_IF, 1);
+       pB->subClass      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUBCLASS, 1);
+       pB->classCode     = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CLASS, 1);
+       pB->cacheLine     = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CACHE_LINE_SIZE, 1);
+       pB->latency       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_LATENCY_TIMER, 1);
+       pB->headerType    = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1);
+       pB->bist          = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BIST, 1);
+       pB->base0         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_0, 4);
+       pB->base1         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_1, 4);
+       pB->priBus        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRIMARY_BUS, 1);
+       pB->secBus        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SECONDARY_BUS, 1);
+       pB->subBus        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUBORDINATE_BUS, 1);
+       pB->secLatency    = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SEC_LATENCY, 1);
+       pB->ioBase        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_BASE, 1);
+       pB->ioLimit       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_LIMIT, 1);
+       pB->secStatus     = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SEC_STATUS, 2);
+       pB->memBase       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MEM_BASE, 2);
+       pB->memLimit      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MEM_LIMIT, 2);
+       pB->preBase       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_BASE, 2);
+       pB->preLimit      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_LIMIT, 2);
+       pB->preBaseUpper  = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_BASE_U, 4);
+       pB->preLimitUpper = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_LIMIT_U, 4);
+       pB->ioBaseUpper   = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_BASE_U, 2);
+       pB->ioLimitUpper  = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_LIMIT_U, 2);
+       pB->romBase       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_ROM_BASE, 4);
+       pB->intLine       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BRG_INT_LINE, 1);
+       pB->intPin        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BRG_INT_PIN, 1);
+       pB->control       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BRIDGE_CONTROL, 2);
+       PCI_Bheader_Print(pB);
+    } else {                                   /* PCI device */
+       pD->vendorId      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_VENDOR_ID, 2);
+       pD->deviceId      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEVICE_ID, 2);
+               pD->command       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2);
+       pD->status        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_STATUS, 1);
+       pD->revisionId    = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_REVISION, 1);
+       pD->progIf        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PROGRAMMING_IF, 1);
+       pD->subClass      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUBCLASS, 1);
+       pD->classCode     = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CLASS, 1);
+       pD->cacheLine     = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CACHE_LINE_SIZE, 1);
+       pD->latency       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_LATENCY_TIMER, 1);
+       pD->headerType    = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1);
+       pD->bist          = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BIST, 1);
+       pD->base0         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_0, 4);
+       pD->base1         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_1, 4);
+       pD->base2         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_2, 4);
+       pD->base3         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_3, 4);
+       pD->base4         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_4, 4);
+       pD->base5         = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_5, 4);
+       pD->cis           = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CIS, 4);
+       pD->subVendorId   = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUB_VENDER_ID, 2);
+       pD->subSystemId   = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUB_SYSTEM_ID, 2);
+       pD->romBase       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 4);
+       pD->intLine       = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_LINE, 1);
+       pD->intPin        = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_PIN, 1);
+       pD->minGrant      = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MIN_GRANT, 1);
+       pD->maxLatency    = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MAX_LATENCY, 1);
+       PCI_Dheader_Print(pD);
+    }
+}
+
+static char *PCI_classes[] = {
+       "Build before PCI Rev2.0",
+       "Mass storage controller",
+       "Network controller     ",
+       "Display controller     ",
+       "Multimedia device      ",
+       "Memory controller      ",
+       "Bridge device          ",
+       "Simple comm. controller",
+       "Base system peripheral ",
+       "Input device           ",
+       "Docking station        ",
+       "Processor              ",
+       "Serial bus controller  ",
+       "Reserved entry         ",
+       "Does not fit any class "
+};
+
+/*
+ * Subroutine:  PCI_Dheader_Print
+ *
+ * Description: Prints the header of the specified PCI device.
+ *
+ * Inputs:             pD      pointer to device header info
+ *
+ * Return:      None
+ *
+ */
+void PCI_Dheader_Print(PCI_HEADER_DEVICE * pD)
+{
+    if (ShortPCIListing) {
+       printf("0x%.4x     0x%.4x     %s 0x%.2x\n",
+               (ushort)pD->vendorId,
+               (ushort)pD->deviceId,
+               PCI_classes[(uchar)pD->classCode],
+               (uchar)pD->subClass);
+    } else {
+       printf("  vendor ID =                   0x%.4x\n", (ushort)pD->vendorId);
+       printf("  device ID =                   0x%.4x\n", (ushort)pD->deviceId);
+       printf("  command register =            0x%.4x\n", (ushort)pD->command);
+       printf("  status register =             0x%.4x\n", (ushort)pD->status);
+       printf("  revision ID =                 0x%.2x\n", (uchar)pD->revisionId);
+       printf("  class code =                  0x%.2x (%s)\n",
+               (uchar)pD->classCode,
+               PCI_classes[(int)pD->classCode]);
+       printf("  sub class code =              0x%.2x\n", (uchar)pD->subClass);
+       printf("  programming interface =       0x%.2x\n", (uchar)pD->progIf);
+       printf("  cache line =                  0x%.2x\n", (uchar)pD->cacheLine);
+       printf("  latency time =                0x%.2x\n", (uchar)pD->latency);
+       printf("  header type =                 0x%.2x\n", (uchar)pD->headerType);
+       printf("  BIST =                        0x%.2x\n", (uchar)pD->bist);
+       printf("  base address 0 =              0x%.8x\n", pD->base0);
+       printf("  base address 1 =              0x%.8x\n", pD->base1);
+       printf("  base address 2 =              0x%.8x\n", pD->base2);
+       printf("  base address 3 =              0x%.8x\n", pD->base3);
+       printf("  base address 4 =              0x%.8x\n", pD->base4);
+       printf("  base address 5 =              0x%.8x\n", pD->base5);
+       printf("  cardBus CIS pointer =         0x%.8x\n", pD->cis);
+       printf("  sub system vendor ID =        0x%.4x\n", (ushort)pD->subVendorId);
+       printf("  sub system ID =               0x%.4x\n", (ushort)pD->subSystemId);
+       printf("  expansion ROM base address =  0x%.8x\n", pD->romBase);
+       printf("  interrupt line =              0x%.2x\n", (uchar)pD->intLine);
+       printf("  interrupt pin =               0x%.2x\n", (uchar)pD->intPin);
+       printf("  min Grant =                   0x%.2x\n", (uchar)pD->minGrant);
+       printf("  max Latency =                 0x%.2x\n", (uchar)pD->maxLatency);
+    }
+}
+
+/*
+ * Subroutine:  PCI_Bheader_Print
+ *
+ * Description: Prints the header of the specified PCI-to-PCI bridge.
+ *
+ * Inputs:             pB      pointer to bridge header info
+ *
+ * Return:      None
+ *
+ */
+void PCI_Bheader_Print (PCI_HEADER_BRIDGE * pB)
+{
+     if (ShortPCIListing) {
+       printf("0x%.4x     0x%.4x     %s 0x%.2x\n",
+               (ushort)pB->vendorId,
+               (ushort)pB->deviceId,
+               PCI_classes[(uchar)pB->classCode],
+               (uchar)pB->subClass);
+     } else {
+       printf ("  vendor ID =                   0x%.4x\n", (ushort)pB->vendorId);
+       printf ("  device ID =                   0x%.4x\n", (ushort)pB->deviceId);
+       printf ("  command register =            0x%.4x\n", (ushort)pB->command);
+       printf ("  status register =             0x%.4x\n", (ushort)pB->status);
+       printf ("  revision ID =                 0x%.2x\n", (uchar)pB->revisionId);
+       printf ("  class code =                  0x%.2x (%s)\n",
+               (uchar)pB->classCode,
+               PCI_classes[(int)pB->classCode]);
+       printf ("  sub class code =              0x%.2x\n", (uchar)pB->subClass);
+       printf ("  programming interface =       0x%.2x\n", (uchar)pB->progIf);
+       printf ("  cache line =                  0x%.2x\n", (uchar)pB->cacheLine);
+       printf ("  latency time =                0x%.2x\n", (uchar)pB->latency);
+       printf ("  header type =                 0x%.2x\n", (uchar)pB->headerType);
+       printf ("  BIST =                        0x%.2x\n", (uchar)pB->bist);
+       printf ("  base address 0 =              0x%.8x\n", pB->base0);
+       printf ("  base address 1 =              0x%.8x\n", pB->base1);
+       printf ("  primary bus number =          0x%.2x\n", (uchar)pB->priBus);
+       printf ("  secondary bus number =        0x%.2x\n", (uchar)pB->secBus);
+       printf ("  subordinate bus number =      0x%.2x\n", (uchar)pB->subBus);
+       printf ("  secondary latency timer =     0x%.2x\n", (uchar)pB->secLatency);
+       printf ("  IO base =                     0x%.2x\n", (uchar)pB->ioBase);
+       printf ("  IO limit =                    0x%.2x\n", (uchar)pB->ioLimit);
+       printf ("  secondary status =            0x%.4x\n", (ushort)pB->secStatus);
+       printf ("  memory base =                 0x%.4x\n", (ushort)pB->memBase);
+       printf ("  memory limit =                0x%.4x\n", (ushort)pB->memLimit);
+       printf ("  prefetch memory base =        0x%.4x\n", (ushort)pB->preBase);
+       printf ("  prefetch memory limit =       0x%.4x\n", (ushort)pB->preLimit);
+       printf ("  prefetch memory base upper =  0x%.8x\n", pB->preBaseUpper);
+       printf ("  prefetch memory limit upper = 0x%.8x\n", pB->preLimitUpper);
+       printf ("  IO base upper 16 bits =       0x%.4x\n", (ushort)pB->ioBaseUpper);
+       printf ("  IO limit upper 16 bits =      0x%.4x\n", (ushort)pB->ioLimitUpper);
+       printf ("  expansion ROM base address =  0x%.8x\n", pB->romBase);
+       printf ("  interrupt line =              0x%.2x\n", (uchar)pB->intLine);
+       printf ("  interrupt pin =               0x%.2x\n", (uchar)pB->intPin);
+       printf ("  bridge control =              0x%.4x\n", (ushort)pB->control);
+     }
+}
+
+#endif /* CONFIG_COMMANDS & CFG_CMD_PCI */
diff --git a/board/pcippc2/pci.h b/board/pcippc2/pci.h
new file mode 100644 (file)
index 0000000..413f4d4
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _PCI_H
+#define _PCI_H
+
+typedef struct pciHeaderDevice {
+    short      vendorId;       /* vendor ID */
+    short      deviceId;       /* device ID */
+    short      command;        /* command register */
+    short      status;         /* status register */
+    char       revisionId;     /* revision ID */
+    char       classCode;      /* class code */
+    char       subClass;       /* sub class code */
+    char       progIf;         /* programming interface */
+    char       cacheLine;      /* cache line */
+    char       latency;        /* latency time */
+    char       headerType;     /* header type */
+    char       bist;           /* BIST */
+    int                base0;          /* base address 0 */
+    int                base1;          /* base address 1 */
+    int                base2;          /* base address 2 */
+    int                base3;          /* base address 3 */
+    int                base4;          /* base address 4 */
+    int                base5;          /* base address 5 */
+    int                cis;            /* cardBus CIS pointer */
+    short      subVendorId;    /* sub system vendor ID */
+    short      subSystemId;    /* sub system ID */
+    int                romBase;        /* expansion ROM base address */
+    int                reserved0;      /* reserved */
+    int                reserved1;      /* reserved */
+    char       intLine;        /* interrupt line */
+    char       intPin;         /* interrupt pin */
+    char       minGrant;       /* min Grant */
+    char       maxLatency;     /* max Latency */
+} PCI_HEADER_DEVICE;
+
+typedef struct pciHeaderBridge {
+    short      vendorId;       /* vendor ID */
+    short      deviceId;       /* device ID */
+    short      command;        /* command register */
+    short      status;         /* status register */
+    char       revisionId;     /* revision ID */
+    char       classCode;      /* class code */
+    char       subClass;       /* sub class code */
+    char       progIf;         /* programming interface */
+    char       cacheLine;      /* cache line */
+    char       latency;        /* latency time */
+    char       headerType;     /* header type */
+    char       bist;           /* BIST */
+    int                base0;          /* base address 0 */
+    int                base1;          /* base address 1 */
+    char       priBus;         /* primary bus number */
+    char       secBus;         /* secondary bus number */
+    char       subBus;         /* subordinate bus number */
+    char       secLatency;     /* secondary latency timer */
+    char       ioBase;         /* IO base */
+    char       ioLimit;        /* IO limit */
+    short      secStatus;      /* secondary status */
+    short      memBase;        /* memory base */
+    short      memLimit;       /* memory limit */
+    short      preBase;        /* prefetchable memory base */
+    short      preLimit;       /* prefetchable memory limit */
+    int                preBaseUpper;   /* prefetchable memory base upper 32 bits */
+    int                preLimitUpper;  /* prefetchable memory base upper 32 bits */
+    short      ioBaseUpper;    /* IO base upper 16 bits */
+    short      ioLimitUpper;   /* IO limit upper 16 bits */
+    int                reserved;       /* reserved */
+    int                romBase;        /* expansion ROM base address */
+    char       intLine;        /* interrupt line */
+    char       intPin;         /* interrupt pin */
+    short      control;        /* bridge control */
+} PCI_HEADER_BRIDGE;
+
+#define PCI_CMD_MASTER 0x0004
+#define PCI_CMD_MEMEN  0x0002
+#define PCI_CMD_IOEN   0x0001
+
+#define PCI_BUSNUM       0x40
+#define PCI_SUBBUSNUM    0x41
+#define PCI_DISCOUNT     0x42
+
+/*
+ * PCI-PCI bridge header
+ */
+#define PCIPCI_PRIMARYBUS       0x18
+#define PCIPCI_SECONDARYBUS     0x19
+#define PCIPCI_SUBORDINATEBUS   0x1A
+#define PCIPCI_SECONDARYLATENCY 0x1B
+#define PCIPCI_IOBASE           0x1C
+#define PCIPCI_IOLIMIT          0x1D
+#define PCIPCI_SECONDARYSTATUS  0x1E
+#define PCIPCI_MEMBASE          0x20
+#define PCIPCI_MEMLIMIT         0x22
+#define PCIPCI_PREFETCHMEMBASE  0x24
+#define PCIPCI_PREFETCHMEMLIMIT 0x26
+#define PCIPCI_IOBASEUPPER16    0x30
+#define PCIPCI_IOLIMITUPPER16   0x32
+
+/*
+ * Standard device configuration register offsets
+ * Note that only modulo-4 addresses are written to the address register
+ */
+#define        PCI_CFG_VENDOR_ID       0x00
+#define        PCI_CFG_DEVICE_ID       0x02
+#define        PCI_CFG_COMMAND         0x04
+#define        PCI_CFG_STATUS          0x06
+#define        PCI_CFG_REVISION        0x08
+#define        PCI_CFG_PROGRAMMING_IF  0x09
+#define        PCI_CFG_SUBCLASS        0x0a
+#define        PCI_CFG_CLASS           0x0b
+#define        PCI_CFG_CACHE_LINE_SIZE 0x0c
+#define        PCI_CFG_LATENCY_TIMER   0x0d
+#define        PCI_CFG_HEADER_TYPE     0x0e
+#define        PCI_CFG_BIST            0x0f
+#define        PCI_CFG_BASE_ADDRESS_0  0x10
+#define        PCI_CFG_BASE_ADDRESS_1  0x14
+#define        PCI_CFG_BASE_ADDRESS_2  0x18
+#define        PCI_CFG_BASE_ADDRESS_3  0x1c
+#define        PCI_CFG_BASE_ADDRESS_4  0x20
+#define        PCI_CFG_BASE_ADDRESS_5  0x24
+#define        PCI_CFG_CIS             0x28
+#define        PCI_CFG_SUB_VENDER_ID   0x2c
+#define        PCI_CFG_SUB_SYSTEM_ID   0x2e
+#define        PCI_CFG_EXPANSION_ROM   0x30
+#define        PCI_CFG_RESERVED_0      0x34
+#define        PCI_CFG_RESERVED_1      0x38
+#define        PCI_CFG_DEV_INT_LINE    0x3c
+#define        PCI_CFG_DEV_INT_PIN     0x3d
+#define        PCI_CFG_MIN_GRANT       0x3e
+#define        PCI_CFG_MAX_LATENCY     0x3f
+#define PCI_CFG_SPECIAL_USE     0x41
+#define PCI_CFG_MODE            0x43
+
+/*
+ * PCI-to-PCI bridge configuration register offsets
+ * Note that only modulo-4 addresses are written to the address register
+ */
+#define        PCI_CFG_PRIMARY_BUS     0x18
+#define        PCI_CFG_SECONDARY_BUS   0x19
+#define        PCI_CFG_SUBORDINATE_BUS 0x1a
+#define        PCI_CFG_SEC_LATENCY     0x1b
+#define        PCI_CFG_IO_BASE         0x1c
+#define        PCI_CFG_IO_LIMIT        0x1d
+#define        PCI_CFG_SEC_STATUS      0x1e
+#define        PCI_CFG_MEM_BASE        0x20
+#define        PCI_CFG_MEM_LIMIT       0x22
+#define        PCI_CFG_PRE_MEM_BASE    0x24
+#define        PCI_CFG_PRE_MEM_LIMIT   0x26
+#define        PCI_CFG_PRE_MEM_BASE_U  0x28
+#define        PCI_CFG_PRE_MEM_LIMIT_U 0x2c
+#define        PCI_CFG_IO_BASE_U       0x30
+#define        PCI_CFG_IO_LIMIT_U      0x32
+#define        PCI_CFG_ROM_BASE        0x38
+#define        PCI_CFG_BRG_INT_LINE    0x3c
+#define        PCI_CFG_BRG_INT_PIN     0x3d
+#define        PCI_CFG_BRIDGE_CONTROL  0x3e
+
+#define PCI_MAX_PCI_DEVICES    32
+#define PCI_MAX_PCI_FUNCTIONS  8
+
+unsigned int    PCI_Read_CFG_Reg(int BusDevFunc, int Reg, int Width);
+int            PCI_Write_CFG_Reg(int BusDevFunc, int Reg, unsigned int Value, int Width);
+int             PCI_Scan(int BusNum);
+void            PCI_Config_Device(int BusDevFunc, int NumBaseAddr);
+void            PCI_Config_VGA_Device(int BusDevFunc, int NumBaseAddr);
+void            PCI_Config_Bridge(int BusDevFunc);
+int             PCI_Find_Device(unsigned short VendorID, unsigned short DeviceID);
+void            PCI_Header_Show(int BusDevFunc);
+void            PCI_Dheader_Print(PCI_HEADER_DEVICE * pD);
+void            PCI_Bheader_Print(PCI_HEADER_BRIDGE * pB);
+
+extern u32     pci_phys_to_io          (u32            p);
+extern u32     pci_io_to_phys          (u32            i);
+extern u32     pci_phys_to_mem         (u32            p);
+extern u32     pci_mem_to_phys         (u32            m);
+extern u32     pci_ram_to_mem          (u32            r);
+extern u32     pci_mem_to_ram          (u32            m);
+
+#endif
diff --git a/board/pcippc2/pcippc2.c b/board/pcippc2/pcippc2.c
new file mode 100644 (file)
index 0000000..4aa380b
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <command.h>
+#include <asm/io.h>
+#include <linux/mtd/doc2000.h>
+
+#include "pci.h"
+
+#include "hardware.h"
+#include "pcippc2.h"
+#include "sconsole.h"
+#include "fpga_serial.h"
+
+  /* Check board identity
+   */
+int checkboard (void)
+{
+  printf("PCIPPC-2\n");
+
+  return 1;
+}
+
+  /* RAM size is stored in CPC0_RGBAN1
+   */
+u32 pcippc2_sdram_size (void)
+{
+  return in32(REG(CPC0, RGBAN1));
+}
+
+long initdram (
+  int                  board_type)
+{
+  return cpc710_ram_init();
+}
+
+void do_reset (
+  cmd_tbl_t *          cmdtp,
+  bd_t *               bd,
+  int                  flag,
+  int                  argc,
+  char *               argv [])
+{
+  out32(REG(CPC0, SPOR), 0);
+  iobarrier_rw();
+  while (1);
+}
+
+int board_pre_init (void)
+{
+  out32(REG(CPC0, RSTR), 0xc0000000);
+  iobarrier_rw();
+
+  out32(REG(CPC0, RSTR), 0xf0000000);
+  iobarrier_rw();
+
+  out32(REG(CPC0, UCTL), 0x00f80000);
+
+  out32(REG(CPC0, SIOC0), 0x30000000);
+
+  out32(REG(CPC0, ABCNTL), 0xb0000000);
+
+  out32(REG(CPC0, SESR), 0x00000000);
+  out32(REG(CPC0, SEAR), 0x00000000);
+
+  out32(REG(CPC0, PGCHP), 0x80800040);
+
+  out32(REG(CPC0, ATAS), 0x709c2508);
+
+  iobarrier_rw();
+  
+  return 0;
+}
+
+void after_reloc (
+  bd_t *               bd,
+  ulong                        dest_addr)
+{
+    /* Jump to the main ppcboot board init code
+     */
+  board_init_r(bd, dest_addr);
+}
+
+void misc_init_r (
+  bd_t *               bd)
+{
+  pcippc2_fpga_init();
+  
+  fpga_serial_init(sconsole_get_baudrate());
+
+  sconsole_putc   = fpga_serial_putc;
+  sconsole_puts   = fpga_serial_puts;
+  sconsole_getc   = fpga_serial_getc;
+  sconsole_tstc   = fpga_serial_tstc;
+  sconsole_setbrg = fpga_serial_setbrg;
+  
+  sconsole_flush();
+}
+
+void pci_init (
+  bd_t *               bd)
+{
+  cpc710_pci_init();
+
+#ifdef CONFIG_PCI_PNP
+  PCI_Scan(0);
+#endif
+
+    /* FPGA requires no retry timeouts to be enabled
+     */
+  cpc710_pci_enable_timeout();
+}
+
+void doc_init (void)
+{
+  doc_probe(pcippc2_fpga1_phys + HW_FPGA1_DOC);
+}
diff --git a/board/pcippc2/pcippc2.h b/board/pcippc2/pcippc2.h
new file mode 100644 (file)
index 0000000..fc0b24e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _PCIPPC2_H_
+#define _PCIPPC2_H_
+
+#include <config.h>
+#include <ppcboot.h>
+
+#include "hardware.h"
+
+#define FPGA(r, p)     (pcippc2_fpga0_phys + HW_FPGA0_##r##_##p)
+#define UART(r)                (pcippc2_fpga0_phys + HW_FPGA0_UART1 + NS16550_##r * 4)
+
+extern u32             pcippc2_fpga0_phys;
+extern u32             pcippc2_fpga1_phys;
+
+extern u32     pcippc2_sdram_size              (void);
+
+extern void    pcippc2_fpga_init               (void);
+
+extern void    cpc710_pci_init                 (void);
+extern void    cpc710_pci_enable_timeout       (void);
+
+extern unsigned long
+               cpc710_ram_init                 (void);
+
+#endif
diff --git a/board/pcippc2/pcippc2_fpga.c b/board/pcippc2/pcippc2_fpga.c
new file mode 100644 (file)
index 0000000..88aa4ae
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <asm/io.h>
+
+#include "pci.h"
+
+#include "hardware.h"
+#include "pcippc2.h"
+
+u32            pcippc2_fpga0_phys;
+u32            pcippc2_fpga1_phys;
+
+void pcippc2_fpga_init (void)
+{
+  u32                  bdf = PCI_Find_Device(FPGA_VENDOR_ID, FPGA_DEVICE_ID);
+  u32                  addr;
+
+  if (bdf == -1)
+  {
+    puts("Unable to find FPGA !\n");
+    hang();
+  }
+
+  if ((PCI_Read_CFG_Reg(bdf, PCI_CFG_COMMAND, 2) &
+       (PCI_CMD_MEMEN | PCI_CMD_IOEN)) != (PCI_CMD_MEMEN | PCI_CMD_IOEN))
+  {
+    puts("FPGA is not configured !\n");
+    hang();
+  }
+
+  addr = PCI_Read_CFG_Reg(bdf, PCI_CFG_BASE_ADDRESS_0, 4);
+  if (addr & 0x1)
+  {
+      /* IO space
+       */
+    pcippc2_fpga0_phys = pci_io_to_phys(addr & 0xfffffffc);
+  }
+  else
+  {
+      /* Memory space
+       */
+    pcippc2_fpga0_phys = pci_mem_to_phys(addr & 0xfffffff0);
+  }
+
+  addr = PCI_Read_CFG_Reg(bdf, PCI_CFG_BASE_ADDRESS_1, 4);
+  if (addr & 0x1)
+  {
+      /* IO space
+       */
+    pcippc2_fpga1_phys = pci_io_to_phys(addr & 0xfffffffc);
+  }
+  else
+  {
+      /* Memory space
+       */
+    pcippc2_fpga1_phys = pci_mem_to_phys(addr & 0xfffffff0);
+  }
+
+    /* Interrupts are not used
+     */
+  out32(FPGA(INT, INTR_MASK), 0xffffffff);
+  iobarrier_rw();
+}
diff --git a/board/pcippc2/pcippc2_fpga.h b/board/pcippc2/pcippc2_fpga.h
new file mode 100644 (file)
index 0000000..44a1a6d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _PCIPPC2_FPGA_H_
+#define _PCIPPC2_FPGA_H_
+
+#define FPGA_VENDOR_ID                 0x1310
+#define FPGA_DEVICE_ID                 0x000d
+
+#define HW_FPGA0_INT                   0x0000
+#define HW_FPGA0_UART1                 0x0080
+#define HW_FPGA0_UART2                 0x0100
+#define HW_FPGA0_RTC                   0x2000
+#define HW_FPGA0_DOC                   0x4000
+#define HW_FPGA1_RTC                   0x0000
+#define HW_FPGA1_DOC                   0x4000
+
+#define HW_FPGA0_INT_INTR_MASK         0x30
+#define HW_FPGA0_INT_INTR_STATUS       0x34
+#define HW_FPGA0_INT_INTR_EOI          0x40
+#define HW_FPGA0_INT_SERIAL_CONFIG     0x5c
+
+#endif
diff --git a/board/pcippc2/ppcboot.lds b/board/pcippc2/ppcboot.lds
new file mode 100644 (file)
index 0000000..beb77ea
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (C) Copyright 2002
+ * 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
+ */
+
+/*
+ * ppcboot.lds - linker script for ppcboot on the Galileo Eval Board.
+ */
+
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+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/74xx_7xx/start.o       (.text)
+
+/* store the environment in a seperate sector in the boot flash */
+/*    . = 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 = .);
+}
diff --git a/board/pcippc2/sconsole.c b/board/pcippc2/sconsole.c
new file mode 100644 (file)
index 0000000..cfbec50
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * (C) Copyright 2002
+ * 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 <config.h>
+#include <ppcboot.h>
+
+#include "sconsole.h"
+
+void           (* sconsole_putc)       (char           c)      = 0;
+void           (* sconsole_puts)       (const char *   c)      = 0;
+int            (* sconsole_getc)       (void)                  = 0;
+int            (* sconsole_tstc)       (void)                  = 0;
+void           (* sconsole_setbrg)     (unsigned long  dummy,
+                                        int            baud)   = 0;
+
+void serial_init (
+  unsigned long        dummy,
+  int                  baudrate)
+{
+  sconsole_buffer_t *  sb = SCONSOLE_BUFFER;
+  
+  sb->pos = 0;
+  sb->size = 0;
+  sb->baud = baudrate;
+  sb->max_size = CFG_SCONSOLE_SIZE - sizeof(sconsole_buffer_t);
+}
+
+void serial_putc (
+  char                         c)
+{
+  if (sconsole_putc)
+  {
+    (*sconsole_putc)(c);
+  }
+  else
+  {
+    sconsole_buffer_t * sb = SCONSOLE_BUFFER;
+  
+    if (c)
+    {
+      sb->data[sb->pos++] = c;
+      if (sb->pos == sb->max_size)
+      {
+        sb->pos = 0;
+      }
+      if (sb->size < sb->max_size)
+      {
+        sb->size++;
+      }
+    }
+  }
+}
+
+void serial_puts (
+  const char *         s)
+{
+  if (sconsole_puts)
+  {
+    (*sconsole_puts)(s);
+  }
+  else
+  {
+    sconsole_buffer_t * sb = SCONSOLE_BUFFER;
+
+    while (*s)
+    {
+      sb->data[sb->pos++] = *s++;
+      if (sb->pos == sb->max_size)
+      {
+        sb->pos = 0;
+      }
+      if (sb->size < sb->max_size)
+      {
+        sb->size++;
+      }
+    }
+  }
+}
+
+int serial_getc (void)
+{
+  if (sconsole_getc)
+  {
+    return (*sconsole_getc)();
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+int serial_tstc (void)
+{
+  if (sconsole_tstc)
+  {
+    return (*sconsole_tstc)();
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+void serial_setbrg (
+  unsigned long        dummy,
+  int                  baudrate)
+{
+  if (sconsole_setbrg)
+  {
+    (*sconsole_setbrg)(dummy, baudrate);
+  }
+  else
+  {
+    sconsole_buffer_t * sb = SCONSOLE_BUFFER;
+    
+    sb->baud = baudrate;
+  }
+}
+
+int sconsole_get_baudrate (void)
+{
+  sconsole_buffer_t *  sb = SCONSOLE_BUFFER;
+  
+  return sb->baud;
+}
+
+void sconsole_flush (void)
+{
+  if (sconsole_putc)
+  {
+    sconsole_buffer_t * sb = SCONSOLE_BUFFER;
+    unsigned int       end = sb->pos < sb->size ?
+                             sb->pos + sb->max_size - sb->size :
+                             sb->pos - sb->size;
+  
+    while (sb->size)
+    {
+      (*sconsole_putc)(sb->data[end++]);
+      if (end == sb->max_size)
+      {
+        end = 0;
+      }
+      sb->size--;
+    }
+  }
+}
diff --git a/board/pcippc2/sconsole.h b/board/pcippc2/sconsole.h
new file mode 100644 (file)
index 0000000..c6c4fb5
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+#ifndef _SCONSOLE_H_
+#define _SCONSOLE_H_
+
+#include <config.h>
+
+typedef struct sconsole_buffer_s
+{
+  unsigned long                size;
+  unsigned long                max_size;
+  unsigned long        pos;
+  unsigned long        baud;
+  char                 data [1];
+} sconsole_buffer_t;
+
+#define SCONSOLE_BUFFER                ((sconsole_buffer_t *) CFG_SCONSOLE_ADDR)
+
+extern void    (* sconsole_putc)       (char           c);
+extern void    (* sconsole_puts)       (const char *   c);
+extern int     (* sconsole_getc)       (void);
+extern int     (* sconsole_tstc)       (void);
+extern void    (* sconsole_setbrg)     (unsigned long  dummy,
+                                        int            baudrate);
+
+extern void    sconsole_flush          (void);
+extern int     sconsole_get_baudrate   (void);
+
+#endif
index 6c32caa114db237594a94254a736c5f89414fcd8..ae5706eea0c02d238562d09280e1ba496f2c54ef 100644 (file)
@@ -34,12 +34,12 @@ COBJS       = board.o main.o command.o environment.o bedbug.o \
          cmd_ide.o cmd_immap.o cmd_mem.o \
          cmd_mii.o cmd_misc.o cmd_net.o \
          cmd_nvedit.o cmd_pcmcia.o \
-         cmd_reginfo.o cmd_scsi.o \
+         cmd_reginfo.o cmd_scsi.o cmd_doc.o \
          console.o devices.o dlmalloc.o \
          usb.o usb_storage.o usb_kbd.o cmd_usb.o \
          flash.o hush.o kgdb.o \
          lists.o miiphybb.o miiphyutil.o \
-         s_record.o
+         s_record.o docecc.o
 
 OBJS   = $(AOBJS) $(COBJS)
 
index 09e4cde23fcb9d39313e1dc3753fc3fe5cd46bfa..d9985a02d45c37ca3d5426120df6d5eea6ef3587 100644 (file)
 #include <w83c553f.h>
 #endif
 
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+void doc_init (void);
+#endif
+
 static char *failed = "*** failed ***\n";
 
 #ifdef CONFIG_PCU_E
@@ -783,6 +787,12 @@ void    board_init_r  (bd_t *bd, ulong dest_addr)
     scsi_init();
 #endif
 
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+    WATCHDOG_RESET();
+    puts ("DOC:   ");
+    doc_init();
+#endif
+
 #ifdef CONFIG_LAST_STAGE_INIT
     WATCHDOG_RESET();
     /*
diff --git a/common/cmd_doc.c b/common/cmd_doc.c
new file mode 100644 (file)
index 0000000..b461ad2
--- /dev/null
@@ -0,0 +1,1246 @@
+/*
+ * Driver for Disk-On-Chip 2000 and Millennium
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2000.c,v 1.46 2001/10/02 15:05:13 dwmw2 Exp $
+ */
+
+#include <ppcboot.h>
+#include <config.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/doc2000.h>
+
+#ifdef CFG_DOC_SUPPORT_2000
+#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
+#else
+#define DoC_is_2000(doc) (0)
+#endif
+
+#ifdef CFG_DOC_SUPPORT_MILLENNIUM
+#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
+#else
+#define DoC_is_Millennium(doc) (0)
+#endif
+
+/* CFG_DOC_PASSIVE_PROBE:
+   In order to ensure that the BIOS checksum is correct at boot time, and 
+   hence that the onboard BIOS extension gets executed, the DiskOnChip 
+   goes into reset mode when it is read sequentially: all registers 
+   return 0xff until the chip is woken up again by writing to the 
+   DOCControl register. 
+
+   Unfortunately, this means that the probe for the DiskOnChip is unsafe, 
+   because one of the first things it does is write to where it thinks 
+   the DOCControl register should be - which may well be shared memory 
+   for another device. I've had machines which lock up when this is 
+   attempted. Hence the possibility to do a passive probe, which will fail 
+   to detect a chip in reset mode, but is at least guaranteed not to lock
+   the machine.
+
+   If you have this problem, uncomment the following line:
+#define CFG_DOC_PASSIVE_PROBE
+*/
+
+#undef DOC_DEBUG 
+#undef ECC_DEBUG
+#undef PSYCHO_DEBUG 
+
+static struct DiskOnChip doc_dev_desc[CFG_MAX_DOC_DEVICE];
+
+/* Current DOC Device  */
+static int curr_device = -1;
+
+/* ------------------------------------------------------------------------- */
+
+int do_doc (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+    int rcode = 0;
+    
+    switch (argc) {
+    case 0:
+    case 1:
+       printf ("Usage:\n%s\n", cmdtp->usage);
+       return 1;
+    case 2:
+        if (strcmp(argv[1],"info") == 0) {
+               int i;
+
+               putc ('\n');
+
+               for (i=0; i<CFG_MAX_DOC_DEVICE; ++i) {
+                       if(doc_dev_desc[i].ChipID == DOC_ChipID_UNKNOWN)
+                               continue; /* list only known devices */
+                       printf ("Device %d: ", i);
+                       doc_print(&doc_dev_desc[i]);
+               }
+               return 0;
+
+       } else if (strcmp(argv[1],"device") == 0) {
+               if ((curr_device < 0) || (curr_device >= CFG_MAX_DOC_DEVICE)) {
+                       puts ("\nno devices available\n");
+                       return 1;
+               }
+               printf ("\nDevice %d: ", curr_device);
+               doc_print(&doc_dev_desc[curr_device]);
+               return 0;
+       }
+       printf ("Usage:\n%s\n", cmdtp->usage);
+       return 1;
+    case 3:
+       if (strcmp(argv[1],"device") == 0) {
+               int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+               printf ("\nDevice %d: ", dev);
+               if (dev >= CFG_MAX_DOC_DEVICE) {
+                       puts ("unknown device\n");
+                       return 1;
+               }
+               doc_print(&doc_dev_desc[dev]);
+               /*doc_print (dev);*/
+
+               if (doc_dev_desc[dev].ChipID == DOC_ChipID_UNKNOWN) {
+                       return 1;
+               }
+
+               curr_device = dev;
+
+               puts ("... is now current device\n");
+
+               return 0;
+       } 
+
+       printf ("Usage:\n%s\n", cmdtp->usage);
+       return 1;
+    default:
+       /* at least 4 args */
+
+       if (strcmp(argv[1],"read") == 0 || strcmp(argv[1],"write") == 0) {
+               ulong addr = simple_strtoul(argv[2], NULL, 16);
+               ulong off  = simple_strtoul(argv[3], NULL, 16);
+               ulong size = simple_strtoul(argv[4], NULL, 16);
+               int cmd    = (strcmp(argv[1],"read") == 0);
+               int n, ret, total = 0;
+               char eccbuf[6];
+
+               printf ("\nDOC %s: device %d offset %ld, size %ld ... ",
+                       cmd ? "read" : "write", curr_device, off, size);
+
+               while(size) {
+                       if (cmd)
+                               ret = doc_read_ecc(doc_dev_desc + curr_device, off, size, 
+                                                  &n, (u_char*)addr, eccbuf);
+                       else
+                               ret = doc_write_ecc(doc_dev_desc + curr_device, off, size, 
+                                                   &n, (u_char*)addr, eccbuf);
+
+                       if (ret) 
+                               break;
+
+                       off   += n;
+                       addr  += n;
+                       total += n;
+                       size  -= n;
+               }
+
+               printf ("%d bytes %s: %s\n", total, cmd ? "read" : "write", 
+                       ret ? "ERROR" : "OK");
+
+               return ret;
+       } else if (strcmp(argv[1],"erase") == 0) {
+               ulong off = simple_strtoul(argv[2], NULL, 16);
+               ulong size = simple_strtoul(argv[3], NULL, 16);
+               int ret;
+
+               printf ("\nDOC erase: device %d offset %ld, size %ld ... ",
+                       curr_device, off, size);
+
+               ret = doc_erase (doc_dev_desc + curr_device, off, size);
+
+               printf("%s\n", ret ? "ERROR" : "OK");
+
+               return ret;
+       } else {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               rcode = 1;
+       }
+
+       return rcode;
+    }
+}
+
+void doc_print(struct DiskOnChip *this) {
+       printf("%s at 0x%lX,\n"
+              "\t  %d chip%s %s, size %d MB, \n"
+              "\t  total size %ld MB, sector size %ld kB\n", 
+              this->name, this->physadr, this->numchips, 
+              this->numchips>1 ? "s" : "", this->chips_name, 
+              1 << (this->chipshift - 20), 
+              this->totlen >> 20, this->erasesize >> 10);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* This function is needed to avoid calls of the __ashrdi3 function. */
+static int shr(int val, int shift) {
+       return val >> shift;
+}
+
+/* Perform the required delay cycles by reading from the appropriate register */
+static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles)
+{
+       volatile char dummy;
+       int i;
+       
+       for (i = 0; i < cycles; i++) {
+               if (DoC_is_Millennium(doc))
+                       dummy = ReadDOC(doc->virtadr, NOP);
+               else
+                       dummy = ReadDOC(doc->virtadr, DOCStatus);
+       }
+       
+}
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(struct DiskOnChip *doc)
+{
+       unsigned long docptr = doc->virtadr;
+       unsigned long start = get_timer(0);
+
+#ifdef PSYCHO_DEBUG
+       printf("_DoC_WaitReady called for out-of-line wait\n");
+#endif
+
+       /* Out-of-line routine to wait for chip response */
+       while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+               if (get_timer(start) > 10 * 1000) {
+                       printf("_DoC_WaitReady timed out.\n");
+                       return DOC_ETIMEOUT;
+               }
+               udelay(1);
+       }
+
+       return 0;
+}
+
+static inline int DoC_WaitReady(struct DiskOnChip *doc)
+{
+       unsigned long docptr = doc->virtadr;
+       /* This is inline, to optimise the common case, where it's ready instantly */
+       int ret = 0;
+
+       /* 4 read form NOP register should be issued in prior to the read from CDSNControl
+          see Software Requirement 11.4 item 2. */
+       DoC_Delay(doc, 4);
+
+       if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+               /* Call the out-of-line routine to wait */
+               ret = _DoC_WaitReady(doc);
+
+       /* issue 2 read from NOP register after reading from CDSNControl register
+          see Software Requirement 11.4 item 2. */
+       DoC_Delay(doc, 2);
+
+       return ret;
+}
+
+/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+                             unsigned char xtraflags)
+{
+       unsigned long docptr = doc->virtadr;
+
+       if (DoC_is_2000(doc))
+               xtraflags |= CDSN_CTRL_FLASH_IO;
+
+       /* Assert the CLE (Command Latch Enable) line to the flash chip */
+       WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       if (DoC_is_Millennium(doc))
+               WriteDOC(command, docptr, CDSNSlowIO);
+
+       /* Send the command */
+       WriteDOC_(command, docptr, doc->ioreg);
+
+       /* Lower the CLE line */
+       WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       /* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */
+       return DoC_WaitReady(doc);
+}
+
+/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
+                      unsigned char xtraflags1, unsigned char xtraflags2)
+{
+       unsigned long docptr;
+       int i;
+
+       docptr = doc->virtadr;
+
+       if (DoC_is_2000(doc))
+               xtraflags1 |= CDSN_CTRL_FLASH_IO;
+
+       /* Assert the ALE (Address Latch Enable) line to the flash chip */
+       WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
+
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       /* Send the address */
+       /* Devices with 256-byte page are addressed as:
+          Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
+          * there is no device on the market with page256
+          and more than 24 bits.
+          Devices with 512-byte page are addressed as:
+          Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
+          * 25-31 is sent only if the chip support it.
+          * bit 8 changes the read command to be sent
+          (NAND_CMD_READ0 or NAND_CMD_READ1).
+        */
+
+       if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) {
+               if (DoC_is_Millennium(doc))
+                       WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+               WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+       }
+
+       if (doc->page256) {
+               ofs = ofs >> 8;
+       } else {
+               ofs = ofs >> 9;
+       }
+
+       if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+               for (i = 0; i < doc->pageadrlen; i++, ofs = ofs >> 8) {
+                       if (DoC_is_Millennium(doc))
+                               WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+                       WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+               }
+       }
+
+       DoC_Delay(doc, 2);      /* Needed for some slow flash chips. mf. */
+       
+       /* FIXME: The SlowIO's for millennium could be replaced by 
+          a single WritePipeTerm here. mf. */
+
+       /* Lower the ALE line */
+       WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr,
+                CDSNControl);
+
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       /* Wait for the chip to respond - Software requirement 11.4.1 */
+       return DoC_WaitReady(doc);
+}
+
+/* Read a buffer from DoC, taking care of Millennium odditys */
+static void DoC_ReadBuf(struct DiskOnChip *doc, u_char * buf, int len)
+{
+       volatile int dummy;
+       int modulus = 0xffff;
+       unsigned long docptr;
+       int i;
+
+       docptr = doc->virtadr;
+
+       if (len <= 0)
+               return;
+
+       if (DoC_is_Millennium(doc)) {
+               /* Read the data via the internal pipeline through CDSN IO register,
+                  see Pipelined Read Operations 11.3 */
+               dummy = ReadDOC(docptr, ReadPipeInit);
+
+               /* Millennium should use the LastDataRead register - Pipeline Reads */
+               len--;
+
+               /* This is needed for correctly ECC calculation */
+               modulus = 0xff;
+       }
+
+       for (i = 0; i < len; i++)
+               buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus));
+
+       if (DoC_is_Millennium(doc)) {
+               buf[i] = ReadDOC(docptr, LastDataRead);
+       }
+}
+
+/* Write a buffer to DoC, taking care of Millennium odditys */
+static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len)
+{
+       unsigned long docptr;
+       int i;
+
+       docptr = doc->virtadr;
+
+       if (len <= 0)
+               return;
+
+       for (i = 0; i < len; i++)
+               WriteDOC_(buf[i], docptr, doc->ioreg + i);
+
+       if (DoC_is_Millennium(doc)) {
+               WriteDOC(0x00, docptr, WritePipeTerm);
+       }
+}
+
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+
+static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
+{
+       unsigned long docptr = doc->virtadr;
+
+       /* Software requirement 11.4.4 before writing DeviceSelect */
+       /* Deassert the CE line to eliminate glitches on the FCE# outputs */
+       WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       /* Select the individual flash chip requested */
+       WriteDOC(chip, docptr, CDSNDeviceSelect);
+       DoC_Delay(doc, 4);
+
+       /* Reassert the CE line */
+       WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr,
+                CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       /* Wait for it to be ready */
+       return DoC_WaitReady(doc);
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+
+static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
+{
+       unsigned long docptr = doc->virtadr;
+
+       /* Select the floor (bank) of chips required */
+       WriteDOC(floor, docptr, FloorSelect);
+
+       /* Wait for the chip to be ready */
+       return DoC_WaitReady(doc);
+}
+
+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
+
+static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
+{
+       int mfr, id, i;
+       volatile char dummy;
+
+       /* Page in the required floor/chip */
+       DoC_SelectFloor(doc, floor);
+       DoC_SelectChip(doc, chip);
+
+       /* Reset the chip */
+       if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) {
+#ifdef DOC_DEBUG
+               printf("DoC_Command (reset) for %d,%d returned true\n",
+                      floor, chip);
+#endif
+               return 0;
+       }
+
+
+       /* Read the NAND chip ID: 1. Send ReadID command */
+       if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) {
+#ifdef DOC_DEBUG
+               printf("DoC_Command (ReadID) for %d,%d returned true\n",
+                      floor, chip);
+#endif
+               return 0;
+       }
+
+       /* Read the NAND chip ID: 2. Send address byte zero */
+       DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0);
+
+       /* Read the manufacturer and device id codes from the device */
+
+       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+       DoC_Delay(doc, 2);
+       mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+
+       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+       DoC_Delay(doc, 2);
+       id = ReadDOC_(doc->virtadr, doc->ioreg);
+
+       /* No response - return failure */
+       if (mfr == 0xff || mfr == 0)
+               return 0;
+
+       /* Check it's the same as the first chip we identified. 
+        * M-Systems say that any given DiskOnChip device should only
+        * contain _one_ type of flash part, although that's not a 
+        * hardware restriction. */
+       if (doc->mfr) {
+               if (doc->mfr == mfr && doc->id == id)
+                       return 1;       /* This is another the same the first */
+               else
+                       printf("Flash chip at floor %d, chip %d is different:\n",
+                              floor, chip);
+       }
+
+       /* Print and store the manufacturer and ID codes. */
+       for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+               if (mfr == nand_flash_ids[i].manufacture_id &&
+                   id == nand_flash_ids[i].model_id) {
+#ifdef DOC_DEBUG
+                       printf("Flash chip found: Manufacturer ID: %2.2X, "
+                              "Chip ID: %2.2X (%s)\n", mfr, id,
+                              nand_flash_ids[i].name);
+#endif
+                       if (!doc->mfr) {
+                               doc->mfr = mfr;
+                               doc->id = id;
+                               doc->chipshift =
+                                   nand_flash_ids[i].chipshift;
+                               doc->page256 = nand_flash_ids[i].page256;
+                               doc->pageadrlen =
+                                   nand_flash_ids[i].pageadrlen;
+                               doc->erasesize =
+                                   nand_flash_ids[i].erasesize;
+                               doc->chips_name = 
+                                   nand_flash_ids[i].name;
+                               return 1;
+                       }
+                       return 0;
+               }
+       }
+
+
+#ifdef DOC_DEBUG
+       /* We haven't fully identified the chip. Print as much as we know. */
+       printf("Unknown flash chip found: %2.2X %2.2X\n",
+              id, mfr);
+#endif
+
+       return 0;
+}
+
+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
+
+static void DoC_ScanChips(struct DiskOnChip *this)
+{
+       int floor, chip;
+       int numchips[MAX_FLOORS];
+       int maxchips = MAX_CHIPS;
+       int ret = 1;
+
+       this->numchips = 0;
+       this->mfr = 0;
+       this->id = 0;
+
+       if (DoC_is_Millennium(this))
+               maxchips = MAX_CHIPS_MIL;
+
+       /* For each floor, find the number of valid chips it contains */
+       for (floor = 0; floor < MAX_FLOORS; floor++) {
+               ret = 1;
+               numchips[floor] = 0;
+               for (chip = 0; chip < maxchips && ret != 0; chip++) {
+
+                       ret = DoC_IdentChip(this, floor, chip);
+                       if (ret) {
+                               numchips[floor]++;
+                               this->numchips++;
+                       }
+               }
+       }
+
+       /* If there are none at all that we recognise, bail */
+       if (!this->numchips) {
+               printf("No flash chips recognised.\n");
+               return;
+       }
+
+       /* Allocate an array to hold the information for each chip */
+       this->chips = malloc(sizeof(struct Nand) * this->numchips);
+       if (!this->chips) {
+               printf("No memory for allocating chip info structures\n");
+               return;
+       }
+
+       ret = 0;
+
+       /* Fill out the chip array with {floor, chipno} for each 
+        * detected chip in the device. */
+       for (floor = 0; floor < MAX_FLOORS; floor++) {
+               for (chip = 0; chip < numchips[floor]; chip++) {
+                       this->chips[ret].floor = floor;
+                       this->chips[ret].chip = chip;
+                       this->chips[ret].curadr = 0;
+                       this->chips[ret].curmode = 0x50;
+                       ret++;
+               }
+       }
+
+       /* Calculate and print the total size of the device */
+       this->totlen = this->numchips * (1 << this->chipshift);
+
+#ifdef DOC_DEBUG
+       printf("%d flash chips found. Total DiskOnChip size: %ld MB\n",
+              this->numchips, this->totlen >> 20);
+#endif
+}
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void DoC2k_init(struct DiskOnChip* this)
+{
+       switch (this->ChipID) {
+       case DOC_ChipID_Doc2k:
+               this->name = "DiskOnChip 2000";
+               this->ioreg = DoC_2k_CDSN_IO;
+               break;
+       case DOC_ChipID_DocMil:
+               this->name = "DiskOnChip Millennium";
+               this->ioreg = DoC_Mil_CDSN_IO;
+               break;
+       }
+
+#ifdef DOC_DEBUG
+       printf("%s found at address 0x%lX\n", this->name,
+              this->physadr);
+#endif
+
+       this->totlen = 0;
+       this->numchips = 0;
+
+       this->curfloor = -1;
+       this->curchip = -1;
+
+       /* Ident all the chips present. */
+       DoC_ScanChips(this);
+
+       printf("%s @ 0x%lX, %ld MB\n", this->name, this->physadr, this->totlen >> 20);
+}
+
+int doc_read_ecc(struct DiskOnChip* this, loff_t from, size_t len,
+                size_t * retlen, u_char * buf, u_char * eccbuf)
+{
+       unsigned long docptr;
+       struct Nand *mychip;
+       unsigned char syndrome[6];
+       volatile char dummy;
+       int i, len256 = 0, ret=0;
+
+       docptr = this->virtadr;
+
+       /* Don't allow read past end of device */
+       if (from >= this->totlen) {
+               printf("Out of flash\n");
+               return DOC_EINVAL;
+       }
+
+       /* Don't allow a single read to cross a 512-byte block boundary */
+       if (from + len > ((from | 0x1ff) + 1))
+               len = ((from | 0x1ff) + 1) - from;
+
+       /* The ECC will not be calculated correctly if less than 512 is read */
+       if (len != 0x200 && eccbuf)
+               printf("ECC needs a full sector read (adr: %lx size %lx)\n",
+                      (long) from, (long) len);
+
+#ifdef PHYCH_DEBUG
+       printf("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len);
+#endif
+
+       /* Find the chip which is to be used and select it */
+       mychip = &this->chips[shr(from, this->chipshift)];
+
+       if (this->curfloor != mychip->floor) {
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
+       }
+
+       this->curfloor = mychip->floor;
+       this->curchip = mychip->chip;
+
+       DoC_Command(this,
+                   (!this->page256
+                    && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                   CDSN_CTRL_WP);
+       DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+                   CDSN_CTRL_ECC_IO);
+
+       if (eccbuf) {
+               /* Prime the ECC engine */
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+       } else {
+               /* disable the ECC engine */
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+       }
+
+       /* treat crossing 256-byte sector for 2M x 8bits devices */
+       if (this->page256 && from + len > (from | 0xff) + 1) {
+               len256 = (from | 0xff) + 1 - from;
+               DoC_ReadBuf(this, buf, len256);
+
+               DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+               DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+                           CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
+       }
+
+       DoC_ReadBuf(this, &buf[len256], len - len256);
+
+       /* Let the caller know we completed it */
+       *retlen = len;
+
+       if (eccbuf) {
+               /* Read the ECC data through the DiskOnChip ECC logic */
+               /* Note: this will work even with 2M x 8bit devices as   */
+               /*       they have 8 bytes of OOB per 256 page. mf.      */
+               DoC_ReadBuf(this, eccbuf, 6);
+
+               /* Flush the pipeline */
+               if (DoC_is_Millennium(this)) {
+                       dummy = ReadDOC(docptr, ECCConf);
+                       dummy = ReadDOC(docptr, ECCConf);
+                       i = ReadDOC(docptr, ECCConf);
+               } else {
+                       dummy = ReadDOC(docptr, 2k_ECCStatus);
+                       dummy = ReadDOC(docptr, 2k_ECCStatus);
+                       i = ReadDOC(docptr, 2k_ECCStatus);
+               }
+
+               /* Check the ECC Status */
+               if (i & 0x80) {
+                       int nb_errors;
+                       /* There was an ECC error */
+#ifdef ECC_DEBUG
+                       printf("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+#endif
+                       /* Read the ECC syndrom through the DiskOnChip ECC logic.
+                          These syndrome will be all ZERO when there is no error */
+                       for (i = 0; i < 6; i++) {
+                               syndrome[i] =
+                                   ReadDOC(docptr, ECCSyndrome0 + i);
+                       }
+                        nb_errors = doc_decode_ecc(buf, syndrome);
+
+#ifdef ECC_DEBUG
+                       printf("Errors corrected: %x\n", nb_errors);
+#endif
+                        if (nb_errors < 0) {
+                               /* We return error, but have actually done the read. Not that
+                                  this can be told to user-space, via sys_read(), but at least
+                                  MTD-aware stuff can know about it by checking *retlen */
+                               printf("ECC Errors at %lx\n", (long)from);
+                               ret = DOC_EECC;
+                        }
+               }
+
+#ifdef PSYCHO_DEBUG
+               printf("ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                            (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+                            eccbuf[3], eccbuf[4], eccbuf[5]);
+#endif
+               
+               /* disable the ECC engine */
+               WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+       }
+
+       /* according to 11.4.1, we need to wait for the busy line 
+         * drop if we read to the end of the page.  */
+       if(0 == ((from + *retlen) & 0x1ff))
+       {
+           DoC_WaitReady(this);
+       }
+
+       return ret;
+}
+
+int doc_write_ecc(struct DiskOnChip* this, loff_t to, size_t len,
+                 size_t * retlen, const u_char * buf,
+                 u_char * eccbuf)
+{
+       int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
+       unsigned long docptr;
+       volatile char dummy;
+       int len256 = 0;
+       struct Nand *mychip;
+
+       docptr = this->virtadr;
+
+       /* Don't allow write past end of device */
+       if (to >= this->totlen) {
+               printf("Out of flash\n");
+               return DOC_EINVAL;
+       }
+
+       /* Don't allow a single write to cross a 512-byte block boundary */
+       if (to + len > ((to | 0x1ff) + 1))
+               len = ((to | 0x1ff) + 1) - to;
+
+       /* The ECC will not be calculated correctly if less than 512 is written */
+       if (len != 0x200 && eccbuf)
+               printf("ECC needs a full sector write (adr: %lx size %lx)\n",
+                      (long) to, (long) len);
+
+       /* printf("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+
+       /* Find the chip which is to be used and select it */
+       mychip = &this->chips[shr(to, this->chipshift)];
+
+       if (this->curfloor != mychip->floor) {
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
+       }
+
+       this->curfloor = mychip->floor;
+       this->curchip = mychip->chip;
+
+       /* Set device to main plane of flash */
+       DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+       DoC_Command(this,
+                   (!this->page256
+                    && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                   CDSN_CTRL_WP);
+
+       DoC_Command(this, NAND_CMD_SEQIN, 0);
+       DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+
+       if (eccbuf) {
+               /* Prime the ECC engine */
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+       } else {
+               /* disable the ECC engine */
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+       }
+
+       /* treat crossing 256-byte sector for 2M x 8bits devices */
+       if (this->page256 && to + len > (to | 0xff) + 1) {
+               len256 = (to | 0xff) + 1 - to;
+               DoC_WriteBuf(this, buf, len256);
+
+               DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+               DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+               /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+               dummy = ReadDOC(docptr, CDSNSlowIO);
+               DoC_Delay(this, 2);
+
+               if (ReadDOC_(docptr, this->ioreg) & 1) {
+                       printf("Error programming flash\n");
+                       /* Error in programming */
+                       *retlen = 0;
+                       return DOC_EIO;
+               }
+
+               DoC_Command(this, NAND_CMD_SEQIN, 0);
+               DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+                           CDSN_CTRL_ECC_IO);
+       }
+
+       DoC_WriteBuf(this, &buf[len256], len - len256);
+
+       if (eccbuf) {
+               WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+                        CDSNControl);
+
+               if (DoC_is_Millennium(this)) {
+                       WriteDOC(0, docptr, NOP);
+                       WriteDOC(0, docptr, NOP);
+                       WriteDOC(0, docptr, NOP);
+               } else {
+                       WriteDOC_(0, docptr, this->ioreg);
+                       WriteDOC_(0, docptr, this->ioreg);
+                       WriteDOC_(0, docptr, this->ioreg);
+               }
+
+               /* Read the ECC data through the DiskOnChip ECC logic */
+               for (di = 0; di < 6; di++) {
+                       eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+               }
+
+               /* Reset the ECC engine */
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
+#ifdef PSYCHO_DEBUG
+               printf
+                   ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                    (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+                    eccbuf[4], eccbuf[5]);
+#endif
+       }
+
+       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+       DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+       /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+       dummy = ReadDOC(docptr, CDSNSlowIO);
+       DoC_Delay(this, 2);
+
+       if (ReadDOC_(docptr, this->ioreg) & 1) {
+               printf("Error programming flash\n");
+               /* Error in programming */
+               *retlen = 0;
+               return DOC_EIO;
+       }
+
+       /* Let the caller know we completed it */
+       *retlen = len;
+               
+       if (eccbuf) {
+               unsigned char x[8];
+               size_t dummy;
+               int ret;
+
+               /* Write the ECC data to flash */
+               for (di=0; di<6; di++)
+                       x[di] = eccbuf[di];
+               
+               x[6]=0x55;
+               x[7]=0x55;
+               
+               ret = doc_write_oob(this, to, 8, &dummy, x);
+               return ret;
+       }
+       return 0;
+}
+
+int doc_read_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+                size_t * retlen, u_char * buf)
+{
+       int len256 = 0, ret;
+       unsigned long docptr;
+       struct Nand *mychip;
+
+       docptr = this->virtadr;
+
+       mychip = &this->chips[shr(ofs, this->chipshift)];
+
+       if (this->curfloor != mychip->floor) {
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
+       }
+       this->curfloor = mychip->floor;
+       this->curchip = mychip->chip;
+
+       /* update address for 2M x 8bit devices. OOB starts on the second */
+       /* page to maintain compatibility with doc_read_ecc. */
+       if (this->page256) {
+               if (!(ofs & 0x8))
+                       ofs += 0x100;
+               else
+                       ofs -= 0x8;
+       }
+
+       DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+       DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0);
+
+       /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+       /* Note: datasheet says it should automaticaly wrap to the */
+       /*       next OOB block, but it didn't work here. mf.      */
+       if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+               len256 = (ofs | 0x7) + 1 - ofs;
+               DoC_ReadBuf(this, buf, len256);
+
+               DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+               DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff),
+                           CDSN_CTRL_WP, 0);
+       }
+
+       DoC_ReadBuf(this, &buf[len256], len - len256);
+
+       *retlen = len;
+       /* Reading the full OOB data drops us off of the end of the page,
+         * causing the flash device to go into busy mode, so we need
+         * to wait until ready 11.4.1 and Toshiba TC58256FT docs */
+       
+       ret = DoC_WaitReady(this);
+
+       return ret;
+
+}
+
+int doc_write_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+                 size_t * retlen, const u_char * buf)
+{
+       int len256 = 0;
+       unsigned long docptr = this->virtadr;
+       struct Nand *mychip = &this->chips[shr(ofs, this->chipshift)];
+       volatile int dummy;
+
+#ifdef PSYCHO_DEBUG
+       printf("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",
+              (long)ofs, len, buf[0], buf[1], buf[2], buf[3], 
+              buf[8], buf[9], buf[14],buf[15]);
+#endif
+
+       /* Find the chip which is to be used and select it */
+       if (this->curfloor != mychip->floor) {
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
+       }
+       this->curfloor = mychip->floor;
+       this->curchip = mychip->chip;
+
+       /* disable the ECC engine */
+       WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+       WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+
+       /* Reset the chip, see Software Requirement 11.4 item 1. */
+       DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+
+       /* issue the Read2 command to set the pointer to the Spare Data Area. */
+       DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+       /* update address for 2M x 8bit devices. OOB starts on the second */
+       /* page to maintain compatibility with doc_read_ecc. */
+       if (this->page256) {
+               if (!(ofs & 0x8))
+                       ofs += 0x100;
+               else
+                       ofs -= 0x8;
+       }
+
+       /* issue the Serial Data In command to initial the Page Program process */
+       DoC_Command(this, NAND_CMD_SEQIN, 0);
+       DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0);
+
+       /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+       /* Note: datasheet says it should automaticaly wrap to the */
+       /*       next OOB block, but it didn't work here. mf.      */
+       if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+               len256 = (ofs | 0x7) + 1 - ofs;
+               DoC_WriteBuf(this, buf, len256);
+
+               DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+               DoC_Command(this, NAND_CMD_STATUS, 0);
+               /* DoC_WaitReady() is implicit in DoC_Command */
+
+               dummy = ReadDOC(docptr, CDSNSlowIO);
+               DoC_Delay(this, 2);
+
+               if (ReadDOC_(docptr, this->ioreg) & 1) {
+                       printf("Error programming oob data\n");
+                       /* There was an error */
+                       *retlen = 0;
+                       return DOC_EIO;
+               }
+               DoC_Command(this, NAND_CMD_SEQIN, 0);
+               DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0);
+       }
+
+       DoC_WriteBuf(this, &buf[len256], len - len256);
+
+       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+       DoC_Command(this, NAND_CMD_STATUS, 0);
+       /* DoC_WaitReady() is implicit in DoC_Command */
+
+       dummy = ReadDOC(docptr, CDSNSlowIO);
+       DoC_Delay(this, 2);
+
+       if (ReadDOC_(docptr, this->ioreg) & 1) {
+               printf("Error programming oob data\n");
+               /* There was an error */
+               *retlen = 0;
+               return DOC_EIO;
+       }
+
+       *retlen = len;
+       return 0;
+
+}
+int doc_erase(struct DiskOnChip* this, loff_t ofs, size_t len)
+{
+       volatile int dummy;
+       unsigned long docptr;
+       struct Nand *mychip;
+
+       if (ofs & (this->erasesize-1) || len & (this->erasesize-1)) {
+               printf("Offset and size must be sector aligned\n");
+               return DOC_EINVAL;
+       }
+
+       docptr = this->virtadr;
+
+       /* FIXME: Do this in the background. Use timers or schedule_task() */
+       while(len) {
+               mychip = &this->chips[shr(ofs, this->chipshift)];
+
+               if (this->curfloor != mychip->floor) {
+                       DoC_SelectFloor(this, mychip->floor);
+                       DoC_SelectChip(this, mychip->chip);
+               } else if (this->curchip != mychip->chip) {
+                       DoC_SelectChip(this, mychip->chip);
+               }
+               this->curfloor = mychip->floor;
+               this->curchip = mychip->chip;
+
+               DoC_Command(this, NAND_CMD_ERASE1, 0);
+               DoC_Address(this, ADDR_PAGE, ofs, 0, 0);
+               DoC_Command(this, NAND_CMD_ERASE2, 0);
+
+               DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+
+               dummy = ReadDOC(docptr, CDSNSlowIO);
+               DoC_Delay(this, 2);
+               
+               if (ReadDOC_(docptr, this->ioreg) & 1) {
+                       printf("Error erasing at 0x%lx\n", (long)ofs);
+                       /* There was an error */
+                       goto callback;
+               }
+               ofs += this->erasesize;
+               len -= this->erasesize;
+       }
+
+ callback:
+       return 0;
+}
+
+static inline int doccheck(unsigned long potential, unsigned long physadr)
+{
+       unsigned long window=potential;
+       unsigned char tmp, ChipID;
+#ifndef DOC_PASSIVE_PROBE
+       unsigned char tmp2;
+#endif
+
+       /* Routine copied from the Linux DOC driver */
+
+#ifdef CFG_DOCPROBE_55AA
+       /* Check for 0x55 0xAA signature at beginning of window,
+          this is no longer true once we remove the IPL (for Millennium */
+       if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
+               return 0;
+#endif /* CFG_DOCPROBE_55AA */
+
+#ifndef DOC_PASSIVE_PROBE      
+       /* It's not possible to cleanly detect the DiskOnChip - the
+        * bootup procedure will put the device into reset mode, and
+        * it's not possible to talk to it without actually writing
+        * to the DOCControl register. So we store the current contents
+        * of the DOCControl register's location, in case we later decide
+        * that it's not a DiskOnChip, and want to put it back how we
+        * found it. 
+        */
+       tmp2 = ReadDOC(window, DOCControl);
+       
+       /* Reset the DiskOnChip ASIC */
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+                window, DOCControl);
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+                window, DOCControl);
+       
+       /* Enable the DiskOnChip ASIC */
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+                window, DOCControl);
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+                window, DOCControl);
+#endif /* !DOC_PASSIVE_PROBE */        
+
+       ChipID = ReadDOC(window, ChipID);
+  
+       switch (ChipID) {
+       case DOC_ChipID_Doc2k:
+               /* Check the TOGGLE bit in the ECC register */
+               tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
+               if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
+                               return ChipID;
+               break;
+               
+       case DOC_ChipID_DocMil:
+               /* Check the TOGGLE bit in the ECC register */
+               tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+               if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
+                               return ChipID;
+               break;
+               
+       default:
+#ifndef CFG_DOCPROBE_55AA
+               printf("Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+                      ChipID, physadr);
+#endif
+#ifndef DOC_PASSIVE_PROBE
+               /* Put back the contents of the DOCControl register, in case it's not
+                * actually a DiskOnChip.
+                */
+               WriteDOC(tmp2, window, DOCControl);
+#endif
+               return 0;
+       }
+
+       printf("DiskOnChip failed TOGGLE test, dropping.\n");
+
+#ifndef DOC_PASSIVE_PROBE
+       /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
+       WriteDOC(tmp2, window, DOCControl);
+#endif
+       return 0;
+}   
+
+void doc_probe(unsigned long physadr)
+{
+       struct DiskOnChip *this = NULL;
+       int i=0, ChipID;
+
+       if ((ChipID = doccheck(physadr, physadr))) {
+
+               for (i=0; i<CFG_MAX_DOC_DEVICE; i++) {
+                       if (doc_dev_desc[i].ChipID == DOC_ChipID_UNKNOWN) {
+                               this = doc_dev_desc + i;
+                               break;
+                       }
+               }
+
+               if (!this) {
+                       printf("Cannot allocate memory for data structures.\n");
+                       return;
+               }
+
+               if (curr_device == -1)
+                       curr_device = i;
+
+               memset((char *)this, 0, sizeof(struct DiskOnChip));
+
+               this->virtadr = physadr;
+               this->physadr = physadr;
+               this->ChipID = ChipID;
+
+               DoC2k_init(this);
+       }
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */
index e6f5ee406a7fe2d047fbfd4b622ffb1687f0419c..8a6483a4f0f6966013b20973fbdb27bb2eca055a 100644 (file)
@@ -53,6 +53,7 @@
 #include <cmd_scsi.h>
 #include <cmd_mii.h>
 #include <cmd_dcr.h>           /* 4xx DCR register access */
+#include <cmd_doc.h>
 
 #include <cmd_bsp.h>           /* board special functions */
 
@@ -279,6 +280,7 @@ cmd_tbl_t cmd_tbl[] = {
        CMD_TBL_SCSIBOOT
        CMD_TBL_SCSI
        CMD_TBL_SETDCR
+       CMD_TBL_DOC
        CMD_TBL_SETENV
        CMD_TBL_SIINFO
        CMD_TBL_SITINFO
diff --git a/common/docecc.c b/common/docecc.c
new file mode 100644 (file)
index 0000000..e9acd4d
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * ECC algorithm for M-systems disk on chip. We use the excellent Reed
+ * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
+ * GNU GPL License. The rest is simply to convert the disk on chip
+ * syndrom into a standard syndom.
+ *
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ *
+ * $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $
+ *
+ * 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 <config.h>
+#include <ppcboot.h>
+#include <malloc.h>
+
+#include <linux/mtd/doc2000.h>
+
+#undef ECC_DEBUG
+#undef PSYCHO_DEBUG
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+/* need to undef it (from asm/termbits.h) */
+#undef B0
+
+#define MM 10 /* Symbol size in bits */
+#define KK (1023-4) /* Number of data symbols per block */
+#define B0 510 /* First root of generator polynomial, alpha form */
+#define PRIM 1 /* power of alpha used to generate roots of generator poly */
+#define        NN ((1 << MM) - 1)
+
+typedef unsigned short dtype;
+
+/* 1+x^3+x^10 */
+static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
+
+/* This defines the type used to store an element of the Galois Field
+ * used by the code. Make sure this is something larger than a char if
+ * if anything larger than GF(256) is used.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium.
+ */
+typedef int gf;
+
+/* No legal value in index form represents zero, so
+ * we need a special value for this purpose
+ */
+#define A0     (NN)
+
+/* Compute x % NN, where NN is 2**MM - 1,
+ * without a slow divide
+ */
+static inline gf
+modnn(int x)
+{
+  while (x >= NN) {
+    x -= NN;
+    x = (x >> MM) + (x & NN);
+  }
+  return x;
+}
+
+#define        CLEAR(a,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = 0;\
+}
+
+#define        COPY(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define        COPYDOWN(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define Ldec 1
+
+/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
+   lookup tables:  index->polynomial form   alpha_to[] contains j=alpha**i;
+                   polynomial form -> index form  index_of[j=alpha**i] = i
+   alpha=2 is the primitive element of GF(2**m)
+   HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
+        Let @ represent the primitive element commonly called "alpha" that
+   is the root of the primitive polynomial p(x). Then in GF(2^m), for any
+   0 <= i <= 2^m-2,
+        @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
+   of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
+   example the polynomial representation of @^5 would be given by the binary
+   representation of the integer "alpha_to[5]".
+                   Similarily, index_of[] can be used as follows:
+        As above, let @ represent the primitive element of GF(2^m) that is
+   the root of the primitive polynomial p(x). In order to find the power
+   of @ (alpha) that has the polynomial representation
+        a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   we consider the integer "i" whose binary representation with a(0) being LSB
+   and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
+   "index_of[i]". Now, @^index_of[i] is that element whose polynomial 
+    representation is (a(0),a(1),a(2),...,a(m-1)).
+   NOTE:
+        The element alpha_to[2^m-1] = 0 always signifying that the
+   representation of "@^infinity" = 0 is (0,0,0,...,0).
+        Similarily, the element index_of[0] = A0 always signifying
+   that the power of alpha which has the polynomial representation
+   (0,0,...,0) is "infinity".
+*/
+
+static void
+generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
+{
+  register int i, mask;
+
+  mask = 1;
+  Alpha_to[MM] = 0;
+  for (i = 0; i < MM; i++) {
+    Alpha_to[i] = mask;
+    Index_of[Alpha_to[i]] = i;
+    /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
+    if (Pp[i] != 0)
+      Alpha_to[MM] ^= mask;    /* Bit-wise EXOR operation */
+    mask <<= 1;        /* single left-shift */
+  }
+  Index_of[Alpha_to[MM]] = MM;
+  /*
+   * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
+   * poly-repr of @^i shifted left one-bit and accounting for any @^MM
+   * term that may occur when poly-repr of @^i is shifted.
+   */
+  mask >>= 1;
+  for (i = MM + 1; i < NN; i++) {
+    if (Alpha_to[i - 1] >= mask)
+      Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
+    else
+      Alpha_to[i] = Alpha_to[i - 1] << 1;
+    Index_of[Alpha_to[i]] = i;
+  }
+  Index_of[0] = A0;
+  Alpha_to[NN] = 0;
+}
+
+/*
+ * Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
+ * of the feedback shift register after having processed the data and
+ * the ECC.
+ *
+ * Return number of symbols corrected, or -1 if codeword is illegal
+ * or uncorrectable. If eras_pos is non-null, the detected error locations
+ * are written back. NOTE! This array must be at least NN-KK elements long.
+ * The corrected data are written in eras_val[]. They must be xor with the data
+ * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
+ * 
+ * First "no_eras" erasures are declared by the calling program. Then, the
+ * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
+ * If the number of channel errors is not greater than "t_after_eras" the
+ * transmitted codeword will be recovered. Details of algorithm can be found
+ * in R. Blahut's "Theory ... of Error-Correcting Codes".
+
+ * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
+ * will result. The decoder *could* check for this condition, but it would involve
+ * extra time on every decoding operation.
+ * */
+static int
+eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
+            gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], 
+            int no_eras)
+{
+  int deg_lambda, el, deg_omega;
+  int i, j, r,k;
+  gf u,q,tmp,num1,num2,den,discr_r;
+  gf lambda[NN-KK + 1], s[NN-KK + 1];  /* Err+Eras Locator poly
+                                        * and syndrome poly */
+  gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
+  gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
+  int syn_error, count;
+
+  syn_error = 0;
+  for(i=0;i<NN-KK;i++)
+      syn_error |= bb[i];
+
+  if (!syn_error) {
+    /* if remainder is zero, data[] is a codeword and there are no
+     * errors to correct. So return data[] unmodified
+     */
+    count = 0;
+    goto finish;
+  }
+  
+  for(i=1;i<=NN-KK;i++){
+    s[i] = bb[0];
+  }
+  for(j=1;j<NN-KK;j++){
+    if(bb[j] == 0)
+      continue;
+    tmp = Index_of[bb[j]];
+    
+    for(i=1;i<=NN-KK;i++)
+      s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
+  }
+
+  /* undo the feedback register implicit multiplication and convert
+     syndromes to index form */
+
+  for(i=1;i<=NN-KK;i++) {
+      tmp = Index_of[s[i]];
+      if (tmp != A0)
+          tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
+      s[i] = tmp;
+  }
+  
+  CLEAR(&lambda[1],NN-KK);
+  lambda[0] = 1;
+
+  if (no_eras > 0) {
+    /* Init lambda to be the erasure locator polynomial */
+    lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
+    for (i = 1; i < no_eras; i++) {
+      u = modnn(PRIM*eras_pos[i]);
+      for (j = i+1; j > 0; j--) {
+       tmp = Index_of[lambda[j - 1]];
+       if(tmp != A0)
+         lambda[j] ^= Alpha_to[modnn(u + tmp)];
+      }
+    }
+#ifdef ECC_DEBUG
+    /* Test code that verifies the erasure locator polynomial just constructed
+       Needed only for decoder debugging. */
+    
+    /* find roots of the erasure location polynomial */
+    for(i=1;i<=no_eras;i++)
+      reg[i] = Index_of[lambda[i]];
+    count = 0;
+    for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+      q = 1;
+      for (j = 1; j <= no_eras; j++)
+       if (reg[j] != A0) {
+         reg[j] = modnn(reg[j] + j);
+         q ^= Alpha_to[reg[j]];
+       }
+      if (q != 0)
+       continue;
+      /* store root and error location number indices */
+      root[count] = i;
+      loc[count] = k;
+      count++;
+    }
+    if (count != no_eras) {
+      printf("\n lambda(x) is WRONG\n");
+      count = -1;
+      goto finish;
+    }
+#ifdef PSYCHO_DEBUG
+    printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
+    for (i = 0; i < count; i++)
+      printf("%d ", loc[i]);
+    printf("\n");
+#endif
+#endif
+  }
+  for(i=0;i<NN-KK+1;i++)
+    b[i] = Index_of[lambda[i]];
+  
+  /*
+   * Begin Berlekamp-Massey algorithm to determine error+erasure
+   * locator polynomial
+   */
+  r = no_eras;
+  el = no_eras;
+  while (++r <= NN-KK) {       /* r is the step number */
+    /* Compute discrepancy at the r-th step in poly-form */
+    discr_r = 0;
+    for (i = 0; i < r; i++){
+      if ((lambda[i] != 0) && (s[r - i] != A0)) {
+       discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
+      }
+    }
+    discr_r = Index_of[discr_r];       /* Index form */
+    if (discr_r == A0) {
+      /* 2 lines below: B(x) <-- x*B(x) */
+      COPYDOWN(&b[1],b,NN-KK);
+      b[0] = A0;
+    } else {
+      /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
+      t[0] = lambda[0];
+      for (i = 0 ; i < NN-KK; i++) {
+       if(b[i] != A0)
+         t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
+       else
+         t[i+1] = lambda[i+1];
+      }
+      if (2 * el <= r + no_eras - 1) {
+       el = r + no_eras - el;
+       /*
+        * 2 lines below: B(x) <-- inv(discr_r) *
+        * lambda(x)
+        */
+       for (i = 0; i <= NN-KK; i++)
+         b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
+      } else {
+       /* 2 lines below: B(x) <-- x*B(x) */
+       COPYDOWN(&b[1],b,NN-KK);
+       b[0] = A0;
+      }
+      COPY(lambda,t,NN-KK+1);
+    }
+  }
+
+  /* Convert lambda to index form and compute deg(lambda(x)) */
+  deg_lambda = 0;
+  for(i=0;i<NN-KK+1;i++){
+    lambda[i] = Index_of[lambda[i]];
+    if(lambda[i] != A0)
+      deg_lambda = i;
+  }
+  /*
+   * Find roots of the error+erasure locator polynomial by Chien
+   * Search
+   */
+  COPY(&reg[1],&lambda[1],NN-KK);
+  count = 0;           /* Number of roots of lambda(x) */
+  for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+    q = 1;
+    for (j = deg_lambda; j > 0; j--){
+      if (reg[j] != A0) {
+       reg[j] = modnn(reg[j] + j);
+       q ^= Alpha_to[reg[j]];
+      }
+    }
+    if (q != 0)
+      continue;
+    /* store root (index-form) and error location number */
+    root[count] = i;
+    loc[count] = k;
+    /* If we've already found max possible roots,
+     * abort the search to save time
+     */
+    if(++count == deg_lambda)
+      break;
+  }
+  if (deg_lambda != count) {
+    /*
+     * deg(lambda) unequal to number of roots => uncorrectable
+     * error detected
+     */
+    count = -1;
+    goto finish;
+  }
+  /*
+   * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
+   * x**(NN-KK)). in index form. Also find deg(omega).
+   */
+  deg_omega = 0;
+  for (i = 0; i < NN-KK;i++){
+    tmp = 0;
+    j = (deg_lambda < i) ? deg_lambda : i;
+    for(;j >= 0; j--){
+      if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
+       tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
+    }
+    if(tmp != 0)
+      deg_omega = i;
+    omega[i] = Index_of[tmp];
+  }
+  omega[NN-KK] = A0;
+  
+  /*
+   * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
+   * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
+   */
+  for (j = count-1; j >=0; j--) {
+    num1 = 0;
+    for (i = deg_omega; i >= 0; i--) {
+      if (omega[i] != A0)
+       num1  ^= Alpha_to[modnn(omega[i] + i * root[j])];
+    }
+    num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
+    den = 0;
+    
+    /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
+    for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
+      if(lambda[i+1] != A0)
+       den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
+    }
+    if (den == 0) {
+#ifdef ECC_DEBUG
+      printf("\n ERROR: denominator = 0\n");
+#endif
+      /* Convert to dual- basis */
+      count = -1;
+      goto finish;
+    }
+    /* Apply error to data */
+    if (num1 != 0) {
+        eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
+    } else {
+        eras_val[j] = 0;
+    }
+  }
+ finish:
+  for(i=0;i<count;i++)
+      eras_pos[i] = loc[i];
+  return count;
+}
+
+/***************************************************************************/
+/* The DOC specific code begins here */
+
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA MM bits words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
+
+/* 
+ * Correct the errors in 'sector[]' by using 'ecc1[]' which is the
+ * content of the feedback shift register applyied to the sector and
+ * the ECC. Return the number of errors corrected (and correct them in
+ * sector), or -1 if error 
+ */
+int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
+{
+    int parity, i, nb_errors;
+    gf bb[NN - KK + 1];
+    gf error_val[NN-KK];
+    int error_pos[NN-KK], pos, bitpos, index, val;
+    dtype *Alpha_to, *Index_of;
+
+    /* init log and exp tables here to save memory. However, it is slower */
+    Alpha_to = malloc((NN + 1) * sizeof(dtype));
+    if (!Alpha_to)
+        return -1;
+    
+    Index_of = malloc((NN + 1) * sizeof(dtype));
+    if (!Index_of) {
+        free(Alpha_to);
+        return -1;
+    }
+
+    generate_gf(Alpha_to, Index_of);
+
+    parity = ecc1[1];
+
+    bb[0] =  (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
+    bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
+    bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
+    bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
+
+    nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, 
+                            error_val, error_pos, 0);
+    if (nb_errors <= 0)
+        goto the_end;
+
+    /* correct the errors */
+    for(i=0;i<nb_errors;i++) {
+        pos = error_pos[i];
+        if (pos >= NB_DATA && pos < KK) {
+            nb_errors = -1;
+            goto the_end;
+        }
+        if (pos < NB_DATA) {
+            /* extract bit position (MSB first) */
+            pos = 10 * (NB_DATA - 1 - pos) - 6;
+            /* now correct the following 10 bits. At most two bytes
+               can be modified since pos is even */
+            index = (pos >> 3) ^ 1;
+            bitpos = pos & 7;
+            if ((index >= 0 && index < SECTOR_SIZE) || 
+                index == (SECTOR_SIZE + 1)) {
+                val = error_val[i] >> (2 + bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[index] ^= val;
+            }
+            index = ((pos >> 3) + 1) ^ 1;
+            bitpos = (bitpos + 10) & 7;
+            if (bitpos == 0)
+                bitpos = 8;
+            if ((index >= 0 && index < SECTOR_SIZE) || 
+                index == (SECTOR_SIZE + 1)) {
+                val = error_val[i] << (8 - bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[index] ^= val;
+            }
+        }
+    }
+    
+    /* use parity to test extra errors */
+    if ((parity & 0xff) != 0)
+        nb_errors = -1;
+
+ the_end:
+    free(Alpha_to);
+    free(Index_of);
+    return nb_errors;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */
index 13bb312427925b4b15c1cbd91f33f9b316c49a77..fc29c33dbc4dad03402a0bf9658d952317d83d94 100644 (file)
@@ -25,13 +25,13 @@ include $(TOPDIR)/config.mk
 
 LIB    = lib$(CPU).a
 
-START  = start.o kgdb.o
+START  = start.o kgdb.o io.o
 OBJS   = traps.o cpu.o cpu_init.o speed.o interrupts.o
 
 all:   .depend $(START) $(LIB)
 
 $(LIB):        $(OBJS)
-       $(AR) crv $@ $(OBJS) kgdb.o
+       $(AR) crv $@ $(OBJS) kgdb.o io.o
 
 #########################################################################
 
index 19f9ef509400d03129ac7934bba8054260922def..7a1783f600db630fa6e0a3def1fe2c8bef9cca07 100644 (file)
@@ -147,6 +147,7 @@ checkdcache(void)
  * didn't seem to work either.  so, currently there is no way to
  * software reset the galileo eval board. [josh] */
 
+#ifndef CONFIG_PCIPPC2
 void
 do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
 {
@@ -178,6 +179,7 @@ do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
 #endif
        ((void (*)(void ))addr)();
 }
+#endif
 
 /* ------------------------------------------------------------------------- */
 
diff --git a/cpu/74xx_7xx/io.S b/cpu/74xx_7xx/io.S
new file mode 100644 (file)
index 0000000..af2e6d1
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *                     Andreas Heppel <aheppel@sysgo.de>
+ *  Copyright (C) 2002 Wolfgang Denk <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 <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in8 */
+/*  Description:  Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  in8
+in8:
+       lbz     r3,0(r3)
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in16 */
+/*  Description:  Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  in16
+in16:
+       lhz     r3,0(r3)
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in16r */
+/*  Description:  Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+       .globl  in16r
+in16r:
+       lhbrx   r3,0,r3
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in32 */
+/*  Description:  Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  in32
+in32:
+       lwz     3,0(3)
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in32r */
+/*  Description:  Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+    .globl  in32r
+in32r:
+       lwbrx   r3,0,r3
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out8 */
+/*  Description:  Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  out8
+out8:
+       stb     r4,0(r3)
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out16 */
+/*  Description:  Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  out16
+out16:
+       sth     r4,0(r3)
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out16r */
+/*  Description:  Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  out16r
+out16r:
+       sthbrx  r4,0,r3
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out32 */
+/*  Description:  Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  out32
+out32:
+       stw     r4,0(r3)
+       sync
+       blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out32r */
+/*  Description:  Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+       .globl  out32r
+out32r:
+       stwbrx  r4,0,r3
+       sync
+       blr
index a99b46d967585de56e150114027ed349a5b19460..ba08573c1c97e62498e50eafcad662c96e1b584d 100644 (file)
@@ -261,26 +261,28 @@ in_flash:
        /* enable address translation */
        bl      enable_addr_trans
 
+#ifdef CFG_INIT_RAM_LOCK
        /* Allocate Initial RAM in data cache.
         */
-       lis     r3, CFG_INIT_RAM_ADDR@h
-       ori     r3, r3, CFG_INIT_RAM_ADDR@l
-       li      r2, 128
+       lis     r3, (CFG_INIT_RAM_ADDR & ~31)@h
+       ori     r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l
+       li      r2, ((CFG_INIT_RAM_END & ~31) + \
+                    (CFG_INIT_RAM_ADDR & 31) + 31) / 32
        mtctr   r2
 1:
        dcbz    r0, r3
        addi    r3, r3, 32
        bdnz    1b
 
-#if 0
+       /* Lock the data cache
+         */
        mfspr   r0, HID0
-       rlwinm  r3, r0, 15, 31, 31
-       xor     r4, r4, r4
-       lis     r4, 0x2
-       or      r0, r0, r4
+       ori     r0, r0, 0x1000
+       sync
        mtspr   HID0, r0
-       li      r0, 0
+       sync
 #endif
+
        /* set up the stack pointer in our newly created
         * cache-ram (r1) */
        lis     r1, (CFG_INIT_RAM_ADDR + CFG_INIT_DATA_OFFSET)@h
index 824293070309ad87bf0cc7a6bc7585988bc76821..09825d61293a8968e74c84a58f6bab31c70e5db3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2000
+ * (C) Copyright 2000-2002
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  *
  * See file CREDITS for list of people who contributed to this
@@ -56,7 +56,7 @@
 #define        CFG_CMD_IMMAP           0x00400000      /* IMMR dump support            */
 #define        CFG_CMD_DATE            0x00800000      /* support for RTC, date/time...*/
 #define CFG_CMD_DHCP           0x01000000      /* DHCP Support                 */
-#define CFG_CMD_BEDBUG         0x02000000      /* Include BedBug Debugger      */
+#define CFG_CMD_BEDBUG         0x02000000      /* Include BedBug Debugger      */
 #define        CFG_CMD_FDC             0x04000000      /* Floppy Disk Support          */
 #define        CFG_CMD_SCSI            0x08000000      /* SCSI Support                 */
 #define        CFG_CMD_AUTOSCRIPT      0x10000000      /* Autoscript Support           */
 
 #define CFG_CMD_ELF    0x0000000100000000      /* ELF (VxWorks) load/boot cmd  */
 #define CFG_CMD_MISC   0x0000000200000000      /* Misc functions like sleep etc*/
-#define CFG_CMD_USB     0x0000000400000000      /* USB Support                 */
+#define CFG_CMD_USB    0x0000000400000000      /* USB Support                  */
+#define CFG_CMD_DOC    0x0000000800000000      /* Disk-On-Chip Support         */
 
 #define CFG_CMD_ALL    0xFFFFFFFFFFFFFFFF      /* ALL commands                 */
 
 /* Commands that are considered "non-standard" for some reason
  * (memory hogs, requires special hardware, not fully tested, etc.)
  */
-#define CFG_CMD_NONSTD (CFG_CMD_KGDB   | \
-                       CFG_CMD_IDE     | \
-                       CFG_CMD_PCMCIA  | \
+#define CFG_CMD_NONSTD (CFG_CMD_ASKENV | \
+                       CFG_CMD_BEDBUG  | \
+                       CFG_CMD_BSP     | \
+                       CFG_CMD_DATE    | \
                        CFG_CMD_DHCP    | \
-                       CFG_CMD_PCI     | \
-                       CFG_CMD_IRQ     | \
-                       CFG_CMD_EEPROM  | \
-                       CFG_CMD_ASKENV  | \
+                       CFG_CMD_DOC     | \
                        CFG_CMD_ECHO    | \
+                       CFG_CMD_EEPROM  | \
+                       CFG_CMD_ELF     | \
+                       CFG_CMD_FDC     | \
                        CFG_CMD_I2C     | \
-                       CFG_CMD_REGINFO | \
+                       CFG_CMD_IDE     | \
                        CFG_CMD_IMMAP   | \
-                       CFG_CMD_FDC     | \
-                       CFG_CMD_SCSI    | \
-                       CFG_CMD_DATE    | \
-                       CFG_CMD_BEDBUG  | \
-                       CFG_CMD_ELF     | \
-                       CFG_CMD_USB     | \
+                       CFG_CMD_IRQ     | \
+                       CFG_CMD_KGDB    | \
                        CFG_CMD_MII     | \
-                       CFG_CMD_BSP     )
+                       CFG_CMD_PCI     | \
+                       CFG_CMD_PCMCIA  | \
+                       CFG_CMD_REGINFO | \
+                       CFG_CMD_SCSI    | \
+                       CFG_CMD_USB     )
 
 /* Default configuration
  */
diff --git a/include/cmd_doc.h b/include/cmd_doc.h
new file mode 100644 (file)
index 0000000..7b886b1
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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
+ */
+
+/*
+ * Disk-On-Chip support
+ */
+#ifndef        _CMD_DOC_H
+#define        _CMD_DOC_H
+
+#include <ppcboot.h>
+#include <command.h>
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+#define        CMD_TBL_DOC     MK_CMD_TBL_ENTRY(                                       \
+       "doc",  3,      5,      1,      do_doc,                                 \
+       "doc     - Disk-On-Chip sub-system\n",                                  \
+       "info  - show available DOC devices\n"                                  \
+       "doc device [dev] - show or set current device\n"                       \
+       "doc read  addr off size\n"                                             \
+       "doc write addr off size - read/write `size'"                           \
+       " bytes starting at offset `off'\n"                                     \
+       "    to/from memory address `addr'\n"                                   \
+       "doc erase off size - erase `size' bytes of DOC from offset `off'\n"    \
+),
+
+int do_doc (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#else
+#define CMD_TBL_DOC
+#endif
+
+#endif /* _CMD_DOC_H */
index 1be4dcec2b6b7dbc8f85a665b384a7ee8f1c7b2f..922487edb2e9fab89a6bf6956d4b7e4321c51002 100644 (file)
 #define CONFIG_CMD_NORMAL      (CONFIG_CMD_DFL & ~CFG_CMD_BOOTD)
 #define CONFIG_CMD_GDB         (CONFIG_CMD_NORMAL | CFG_CMD_KGDB)
 #define CONFIG_CMD_FULL                (CFG_CMD_ALL & ~CFG_CMD_BEDBUG  \
-                                            & ~CFG_CMD_ELF     \
                                             & ~CFG_CMD_BSP     \
+                                            & ~CFG_CMD_DOC     \
                                             & ~CFG_CMD_EEPROM  \
+                                            & ~CFG_CMD_ELF     \
                                             & ~CFG_CMD_FDC     \
                                             & ~CFG_CMD_I2C     \
                                             & ~CFG_CMD_IDE     \
@@ -95,8 +96,8 @@
                                             & ~CFG_CMD_MII     \
                                             & ~CFG_CMD_PCI     \
                                             & ~CFG_CMD_PCMCIA  \
-                                            & ~CFG_CMD_USB     \
-                                            & ~CFG_CMD_SCSI    )
+                                            & ~CFG_CMD_SCSI    \
+                                            & ~CFG_CMD_USB     )
 
 #if CONFIG_LANTEC >= 2
 #define        CONFIG_RTC_MPC8xx               /* use internal RTC of MPC8xx   */
index 942e3ca9e57c8c2102cb442d2166cc41ed918169..6427de766c9d2757f124a9751f42176a2d4e3e13 100644 (file)
 
 #define CONFIG_COMMANDS                (CFG_CMD_ALL & ~( \
                                 CFG_CMD_BEDBUG | \
-                                CFG_CMD_ELF    | \
                                 CFG_CMD_BSP    | \
                                 CFG_CMD_DATE   | \
+                                CFG_CMD_DOC    | \
                                 CFG_CMD_EEPROM | \
+                                CFG_CMD_ELF    | \
                                 CFG_CMD_FDC    | \
                                 CFG_CMD_IDE    | \
-                                CFG_CMD_USB    | \
                                 CFG_CMD_KGDB   | \
                                 CFG_CMD_MII    | \
                                 CFG_CMD_PCI    | \
                                 CFG_CMD_PCMCIA | \
-                                CFG_CMD_SCSI   ) )
+                                CFG_CMD_SCSI   | \
+                                CFG_CMD_USB    ) )
 
 /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
 #include <cmd_confdefs.h>
diff --git a/include/config_PCIPPC2.h b/include/config_PCIPPC2.h
new file mode 100644 (file)
index 0000000..7e0b714
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * (C) Copyright 2002
+ * 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
+ */
+
+/*
+ *
+ * Configuration settings for the PCIPPC-2 board.
+ *
+ */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * board/config.h - configuration options, board specific
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ * (easy to change)
+ */
+
+#define CONFIG_PCIPPC2         1       /* this is a PCIPPC2 board      */
+
+#define CONFIG_BOARD_PRE_INIT  1
+#define CONFIG_MISC_INIT_R     1
+
+#define CONFIG_CONS_INDEX      1
+#define CONFIG_BAUDRATE                9600
+#define CFG_BAUDRATE_TABLE     { 9600, 19200, 38400, 57600, 115200 }
+
+#define CONFIG_CLOCKS_IN_MHZ   1       /* clocks passed to Linux in MHz */
+
+#define CONFIG_PREBOOT         ""
+#define CONFIG_BOOTDELAY       -1
+
+#define CONFIG_BOOTP_MASK      (CONFIG_BOOTP_DEFAULT | \
+                                CONFIG_BOOTP_BOOTFILESIZE)
+
+#define CONFIG_COMMANDS                (CONFIG_CMD_DFL | CFG_CMD_DHCP | \
+                                CFG_CMD_PCI | CFG_CMD_DOC)
+
+#define CONFIG_PCI             1
+#define CONFIG_PCI_PNP         1       /* PCI plug-and-play */
+
+/* This must be included AFTER the definition of CONFIG_COMMANDS (if any)
+ */
+#include <cmd_confdefs.h>
+
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CFG_LONGHELP                   /* undef to save memory         */
+#define CFG_PROMPT     "=> "           /* Monitor Command Prompt       */
+#define CFG_CBSIZE     256             /* Console I/O Buffer Size      */
+
+/* Print Buffer Size
+ */
+#define CFG_PBSIZE     (CFG_CBSIZE + sizeof(CFG_PROMPT) + 16)
+
+#define        CFG_MAXARGS     16              /* max number of command args   */
+#define CFG_BARGSIZE   CFG_CBSIZE      /* Boot Argument Buffer Size    */
+#define CFG_LOAD_ADDR  0x00100000      /* Default load address         */
+
+/*-----------------------------------------------------------------------
+ * Start addresses for the final memory configuration
+ * (Set up by the startup code)
+ * Please note that CFG_SDRAM_BASE _must_ start at 0
+ */
+#define CFG_SDRAM_BASE     0x00000000
+#define CFG_FLASH_BASE     0xFFF00000
+#define CFG_FLASH_MAX_SIZE  0x00100000
+/* Maximum amount of RAM.
+ */
+#define CFG_MAX_RAM_SIZE    0x20000000  /* 512Mb                       */
+
+#define CFG_RESET_ADDRESS   0xFFF00100
+
+#define CFG_MONITOR_BASE    TEXT_BASE
+
+#define CFG_MONITOR_LEN            (256 << 10) /* Reserve 256 kB for Monitor   */
+#define CFG_MALLOC_LEN     (128 << 10) /* Reserve 128 kB for malloc()  */
+
+#if CFG_MONITOR_BASE >= CFG_SDRAM_BASE && \
+    CFG_MONITOR_BASE < CFG_SDRAM_BASE + CFG_MAX_RAM_SIZE
+#define CFG_RAMBOOT
+#else
+#undef CFG_RAMBOOT
+#endif
+
+#define CFG_MEMTEST_START   0x00004000 /* memtest works on             */
+#define CFG_MEMTEST_END            0x02000000  /* 0 ... 32 MB in DRAM          */
+
+/*-----------------------------------------------------------------------
+ * Definitions for initial stack pointer and data area
+ */
+
+/* Size in bytes reserved for initial data
+ */
+#define CFG_INIT_DATA_SIZE    128
+
+#define CFG_INIT_RAM_ADDR     0x40000000
+#define CFG_INIT_RAM_END      0x8000
+#define CFG_INIT_DATA_OFFSET  (CFG_INIT_RAM_END - CFG_INIT_DATA_SIZE)
+#define CFG_INIT_SP_OFFSET    CFG_INIT_DATA_OFFSET
+
+#define CFG_INIT_RAM_LOCK
+
+/*
+ * Temporary buffer for serial data until the real serial driver
+ * is initialised (memtest will destroy this buffer)
+ */
+#define CFG_SCONSOLE_ADDR     CFG_INIT_RAM_ADDR
+#define CFG_SCONSOLE_SIZE     0x0002000
+
+/* SDRAM 0 - 256MB
+ */
+#define CFG_DBAT0L           (CFG_SDRAM_BASE | BATL_PP_10 | BATL_MEMCOHERENCE)
+#define CFG_DBAT0U           (CFG_SDRAM_BASE | \
+                              BATU_BL_256M | BATU_VS | BATU_VP)
+/* SDRAM 1 - 256MB
+ */
+#define CFG_DBAT1L           ((CFG_SDRAM_BASE + 0x10000000) | \
+                              BATL_PP_10 | BATL_MEMCOHERENCE)
+#define CFG_DBAT1U           ((CFG_SDRAM_BASE + 0x10000000) | \
+                              BATU_BL_256M | BATU_VS | BATU_VP)
+
+/* Init RAM in the CPU DCache (no backing memory)
+ */
+#define CFG_DBAT2L           (CFG_INIT_RAM_ADDR | \
+                              BATL_PP_10 | BATL_MEMCOHERENCE)
+#define CFG_DBAT2U           (CFG_INIT_RAM_ADDR | \
+                              BATU_BL_128K | BATU_VS | BATU_VP)
+
+/* I/O and PCI memory at 0xf0000000
+ */
+#define CFG_DBAT3L           (0xf0000000 | BATL_PP_10 | BATL_CACHEINHIBIT)
+#define CFG_DBAT3U           (0xf0000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_IBAT0L           CFG_DBAT0L
+#define CFG_IBAT0U           CFG_DBAT0U
+#define CFG_IBAT1L           CFG_DBAT1L
+#define CFG_IBAT1U           CFG_DBAT1U
+#define CFG_IBAT2L           CFG_DBAT2L
+#define CFG_IBAT2U           CFG_DBAT2U
+#define CFG_IBAT3L           CFG_DBAT3L
+#define CFG_IBAT3U           CFG_DBAT3U
+
+/*
+ * Low Level Configuration Settings
+ * (address mappings, register initial values, etc.)
+ * You should know what you are doing if you make changes here.
+ * For the detail description refer to the PCIPPC2 user's manual.
+ */
+#define CFG_HZ               1000
+#define CFG_BUS_HZ            100000000 /* bus speed - 100 mhz          */
+#define CFG_CPU_CLK          300000000
+#define CFG_BUS_CLK          100000000
+
+/*
+ * For booting Linux, the board info and command line data
+ * have to be in the first 8 MB of memory, since this is
+ * the maximum mapped by the Linux kernel during initialization.
+ */
+#define CFG_BOOTMAPSZ        (8 << 20) /* Initial Memory map for Linux */
+
+/*-----------------------------------------------------------------------
+ * FLASH organization
+ */
+#define CFG_MAX_FLASH_BANKS    1       /* Max number of flash banks            */
+#define CFG_MAX_FLASH_SECT     16      /* Max number of sectors in one bank    */
+
+#define CFG_FLASH_ERASE_TOUT   120000  /* Timeout for Flash Erase (in ms)      */
+#define CFG_FLASH_WRITE_TOUT   500     /* Timeout for Flash Write (in ms)      */
+
+/*
+ * Warining: environment is not EMBEDDED in the ppcboot code.
+ * It's stored in flash separately.
+ */
+#define CFG_ENV_IS_IN_FLASH    1
+#define CFG_ENV_ADDR           (CFG_FLASH_BASE + 0x70000)
+#define CFG_ENV_SIZE           0x1000  /* Size of the Environment              */
+#define CFG_ENV_SECT_SIZE      0x10000 /* Size of the Environment Sector       */
+
+/*-----------------------------------------------------------------------
+ * Cache Configuration
+ */
+#define CFG_CACHELINE_SIZE     32
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+#  define CFG_CACHELINE_SHIFT  5       /* log base 2 of the above value        */
+#endif
+
+/*
+ * L2 cache
+ */
+#undef CFG_L2
+#define L2_INIT   (L2CR_L2SIZ_2M | L2CR_L2CLK_3 | L2CR_L2RAM_BURST | \
+                   L2CR_L2OH_5 | L2CR_L2CTL | L2CR_L2WT)
+#define L2_ENABLE (L2_INIT | L2CR_L2E)
+
+/*
+ * Internal Definitions
+ *
+ * Boot Flags
+ */
+#define BOOTFLAG_COLD          0x01    /* Normal Power-On: Boot from FLASH     */
+#define BOOTFLAG_WARM          0x02    /* Software reboot                      */
+
+/*-----------------------------------------------------------------------
+ * Disk-On-Chip configuration
+ */
+
+#define CFG_MAX_DOC_DEVICE     1       /* Max number of DOC devices            */
+
+#define CFG_DOC_SUPPORT_2000
+#undef CFG_DOC_SUPPORT_MILLENNIUM
+
+#endif /* __CONFIG_H */
index 9e3b5ebef83a7fa4be083cabb019734ccb493537..93abbb63a1557cd28bad66ad97ae40177c7cc5da 100644 (file)
 
 #define CONFIG_COMMANDS                (CFG_CMD_ALL & ~( \
                                        CFG_CMD_BEDBUG  | \
+                                       CFG_CMD_DOC     | \
                                        CFG_CMD_ELF     | \
                                        CFG_CMD_FDC     | \
                                        CFG_CMD_IDE     | \
diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h
new file mode 100644 (file)
index 0000000..4500786
--- /dev/null
@@ -0,0 +1,151 @@
+
+/* Linux driver for Disk-On-Chip 2000       */
+/* (c) 1999 Machine Vision Holdings, Inc.   */
+/* Author: David Woodhouse <dwmw2@mvhi.com> */
+/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */
+
+#ifndef __MTD_DOC2000_H__
+#define __MTD_DOC2000_H__
+
+#define DoC_Sig1 0
+#define DoC_Sig2 1
+
+#define DoC_ChipID             0x1000
+#define DoC_DOCStatus          0x1001
+#define DoC_DOCControl         0x1002
+#define DoC_FloorSelect                0x1003
+#define DoC_CDSNControl                0x1004
+#define DoC_CDSNDeviceSelect   0x1005
+#define DoC_ECCConf            0x1006
+#define DoC_2k_ECCStatus       0x1007
+
+#define DoC_CDSNSlowIO         0x100d
+#define DoC_ECCSyndrome0       0x1010
+#define DoC_ECCSyndrome1       0x1011
+#define DoC_ECCSyndrome2       0x1012
+#define DoC_ECCSyndrome3       0x1013
+#define DoC_ECCSyndrome4       0x1014
+#define DoC_ECCSyndrome5       0x1015
+#define DoC_AliasResolution    0x101b
+#define DoC_ConfigInput                0x101c
+#define DoC_ReadPipeInit       0x101d
+#define DoC_WritePipeTerm      0x101e
+#define DoC_LastDataRead       0x101f
+#define DoC_NOP                0x1020
+
+#define DoC_Mil_CDSN_IO        0x0800
+#define DoC_2k_CDSN_IO                 0x1800
+
+#define ReadDOC_(adr, reg)      ((volatile unsigned char)(*(volatile __u8 *)(((unsigned long)adr)+((reg)))))
+#define WriteDOC_(d, adr, reg)  do{ *(volatile __u8 *)(((unsigned long)adr)+((reg))) = (__u8)d; eieio();} while(0)
+
+#define DOC_IOREMAP_LEN                0x4000
+
+/* These are provided to directly use the DoC_xxx defines */
+#define ReadDOC(adr, reg)      ReadDOC_(adr,DoC_##reg)
+#define WriteDOC(d, adr, reg)  WriteDOC_(d,adr,DoC_##reg)
+
+#define DOC_MODE_RESET                 0
+#define DOC_MODE_NORMAL        1
+#define DOC_MODE_RESERVED1     2
+#define DOC_MODE_RESERVED2     3
+
+#define DOC_MODE_MDWREN        4
+#define DOC_MODE_CLR_ERR       0x80
+
+#define DOC_ChipID_UNKNOWN     0x00
+#define DOC_ChipID_Doc2k       0x20
+#define DOC_ChipID_DocMil      0x30
+
+#define CDSN_CTRL_FR_B                 0x80
+#define CDSN_CTRL_ECC_IO       0x20
+#define CDSN_CTRL_FLASH_IO     0x10
+#define CDSN_CTRL_WP           0x08
+#define CDSN_CTRL_ALE          0x04
+#define CDSN_CTRL_CLE          0x02
+#define CDSN_CTRL_CE           0x01
+
+#define DOC_ECC_RESET          0
+#define DOC_ECC_ERROR          0x80
+#define DOC_ECC_RW             0x20
+#define DOC_ECC__EN            0x08
+#define DOC_TOGGLE_BIT                 0x04
+#define DOC_ECC_RESV           0x02
+#define DOC_ECC_IGNORE         0x01
+
+/* We have to also set the reserved bit 1 for enable */
+#define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)
+#define DOC_ECC_DIS (DOC_ECC_RESV)
+
+struct Nand {
+       char floor, chip;
+       unsigned long curadr;
+       unsigned char curmode;
+       /* Also some erase/write/pipeline info when we get that far */
+};
+
+#define MAX_FLOORS 4
+#define MAX_CHIPS 4
+
+#define MAX_FLOORS_MIL 4
+#define MAX_CHIPS_MIL 1
+
+#define ADDR_COLUMN 1
+#define ADDR_PAGE 2
+#define ADDR_COLUMN_PAGE 3
+
+struct DiskOnChip {
+       unsigned long physadr;
+       unsigned long virtadr;
+       unsigned long totlen;
+       char* name;
+       char ChipID; /* Type of DiskOnChip */
+       int ioreg;
+       
+       char* chips_name;
+       unsigned long mfr; /* Flash IDs - only one type of flash per device */
+       unsigned long id;
+       int chipshift;
+       char page256;
+       char pageadrlen;
+       unsigned long erasesize;
+       
+       int curfloor;
+       int curchip;
+       
+       int numchips;
+       struct Nand *chips;
+};
+
+/* Return codes from doc_write(), doc_read(), and doc_erase().
+ */
+#define DOC_OK         0
+#define DOC_EIO                1
+#define DOC_EINVAL     2
+#define DOC_EECC       3
+#define DOC_ETIMEOUT   4
+
+/*
+ * Function Prototypes
+ */
+int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]);
+
+int doc_read(struct DiskOnChip* this, loff_t from, size_t len,
+            size_t *retlen, u_char *buf);
+int doc_write(struct DiskOnChip* this, loff_t to, size_t len,
+             size_t *retlen, const u_char *buf);
+int doc_read_ecc(struct DiskOnChip* this, loff_t from, size_t len,
+                size_t *retlen, u_char *buf, u_char *eccbuf);
+int doc_write_ecc(struct DiskOnChip* this, loff_t to, size_t len,
+                 size_t *retlen, const u_char *buf, u_char *eccbuf);
+int doc_read_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+                size_t *retlen, u_char *buf);
+int doc_write_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+                 size_t *retlen, const u_char *buf);
+int doc_erase (struct DiskOnChip* this, loff_t ofs, size_t len);
+
+void doc_probe(unsigned long physadr);
+
+void doc_print(struct DiskOnChip*);
+
+#endif /* __MTD_DOC2000_H__ */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
new file mode 100644 (file)
index 0000000..3020ec9
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  ppcboot/include/linux/mtd/nand.h
+ *
+ *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
+ *                     Steven J. Hill <sjhill@cotw.com>
+ *
+ * $Id: nand.h,v 1.8 2000/10/30 17:16:17 sjhill Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Info:
+ *   Contains standard defines and IDs for NAND flash devices
+ *
+ *  Changelog:
+ *   01-31-2000 DMW     Created
+ *   09-18-2000 SJH     Moved structure out of the Disk-On-Chip drivers
+ *                     so it can be used by other NAND flash device
+ *                     drivers. I also changed the copyright since none
+ *                     of the original contents of this file are specific
+ *                     to DoC devices. David can whack me with a baseball
+ *                     bat later if I did something naughty.
+ *   10-11-2000 SJH     Added private NAND flash structure for driver
+ *   10-24-2000 SJH     Added prototype for 'nand_scan' function
+ */
+#ifndef __LINUX_MTD_NAND_H
+#define __LINUX_MTD_NAND_H
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0         0
+#define NAND_CMD_READ1         1
+#define NAND_CMD_PAGEPROG      0x10
+#define NAND_CMD_READOOB       0x50
+#define NAND_CMD_ERASE1                0x60
+#define NAND_CMD_STATUS                0x70
+#define NAND_CMD_SEQIN         0x80
+#define NAND_CMD_READID                0x90
+#define NAND_CMD_ERASE2                0xd0
+#define NAND_CMD_RESET         0xff
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_TOSHIBA       0x98
+#define NAND_MFR_SAMSUNG       0xec
+
+/*
+ * NAND Flash Device ID Structure
+ *
+ * Structure overview:
+ *
+ *  name - Complete name of device
+ *
+ *  manufacture_id - manufacturer ID code of device.
+ *
+ *  model_id - model ID code of device.
+ *
+ *  chipshift - total number of address bits for the device which
+ *              is used to calculate address offsets and the total
+ *              number of bytes the device is capable of.
+ *
+ *  page256 - denotes if flash device has 256 byte pages or not.
+ *
+ *  pageadrlen - number of bytes minus one needed to hold the
+ *               complete address into the flash array. Keep in
+ *               mind that when a read or write is done to a
+ *               specific address, the address is input serially
+ *               8 bits at a time. This structure member is used
+ *               by the read/write routines as a loop index for
+ *               shifting the address out 8 bits at a time.
+ *
+ *  erasesize - size of an erase block in the flash device.
+ */
+struct nand_flash_dev {
+       char * name;
+       int manufacture_id;
+       int model_id;
+       int chipshift;
+       char page256;
+       char pageadrlen;
+       unsigned long erasesize;
+};
+
+#endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/mtd/nand_ids.h b/include/linux/mtd/nand_ids.h
new file mode 100644 (file)
index 0000000..3e3b63c
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  ppcboot/include/linux/mtd/nand_ids.h
+ *
+ *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
+ *                     Steven J. Hill <sjhill@cotw.com>
+ *
+ * $Id: nand_ids.h,v 1.1 2000/10/13 16:16:26 mdeans Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Info:
+ *   Contains standard defines and IDs for NAND flash devices
+ *
+ *  Changelog:
+ *   01-31-2000 DMW     Created
+ *   09-18-2000 SJH     Moved structure out of the Disk-On-Chip drivers
+ *                     so it can be used by other NAND flash device
+ *                     drivers. I also changed the copyright since none
+ *                     of the original contents of this file are specific
+ *                     to DoC devices. David can whack me with a baseball
+ *                     bat later if I did something naughty.
+ *   10-11-2000 SJH     Added private NAND flash structure for driver
+ *   2000-10-13 BE      Moved out of 'nand.h' - avoids duplication.
+ */
+
+#ifndef __LINUX_MTD_NAND_IDS_H
+#define __LINUX_MTD_NAND_IDS_H
+
+static struct nand_flash_dev nand_flash_ids[] = {
+       {"Toshiba TC5816BDC",     NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000},
+       {"Toshiba TC5832DC",      NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000},
+       {"Toshiba TH58V128DC",    NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000},
+       {"Toshiba TC58256FT/DC",  NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000},
+       {"Toshiba TH58512FT",     NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000},
+       {"Toshiba TC58V32DC",     NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000},
+       {"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000},
+       {"Toshiba TC58V16BDC",    NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000},
+       {"Samsung KM29N16000",    NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000},
+       {"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000},
+       {"Samsung KM29U128T",     NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000},
+       {"Samsung KM29U256T",     NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000},
+       {"Samsung unknown 64Mb",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000},
+       {"Samsung KM29W32000",    NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000},
+       {"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000},
+       {"Samsung KM29U64000",    NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000},
+       {"Samsung KM29W16000",    NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000},
+       {NULL,}
+};
+
+#endif /* __LINUX_MTD_NAND_IDS_H */
index 1b9ff10f29ee9fe54c5d9c8b0cecf74a56561d22..e296ee8ac5fecf162585df1579acb7d43b7552ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2000, 2001
+ * (C) Copyright 2000, 2001, 2002
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  *
  * See file CREDITS for list of people who contributed to this
@@ -193,14 +193,15 @@ void print_image_hdr (image_header_t *hdr);
 extern ulong load_addr;                /* Default Load Address */
 
 /* common/cmd_nvedit.c */
-void           env_init (init_data_t *);
-void           env_relocate (ulong);
-char          *getenv (uchar *);
-int          getenv_r (uchar *name, uchar *buf, unsigned len);
-void inline    setenv (char *, char *);
-int         saveenv(void);
-
-#if defined(CONFIG_AR405)      || \
+void   env_init (init_data_t *);
+void   env_relocate (ulong);
+char   *getenv (uchar *);
+int      getenv_r (uchar *name, uchar *buf, unsigned len);
+int    saveenv(void);
+void inline  setenv (char *, char *);
+
+#if defined(CONFIG_PCI)                || \
+    defined(CONFIG_AR405)      || \
     defined(CONFIG_BAB750)     || \
     defined(CONFIG_CPCI405)    || \
     defined(CONFIG_CPCIISER4)  || \
@@ -376,6 +377,7 @@ void        relocate_code (ulong, bd_t *, ulong);
 ulong  get_endaddr   (void);
 void   trap_init     (ulong);
 #if defined (CONFIG_4xx)       || \
+    defined (CONFIG_74xx_7xx)  || \
     defined (CONFIG_74x)       || \
     defined (CONFIG_75x)       || \
     defined (CONFIG_74xx)
@@ -419,6 +421,8 @@ ulong       get_OPB_freq (void);
 #ifdef CONFIG_4xx
 ulong  get_PCI_freq (void);
 #endif
+#elif defined(CONFIG_74xx_7xx)
+ulong  get_gclk_freq (void);
 #endif
 
 ulong  get_bus_freq  (ulong);