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
#########################################################################
LIST_74xx=" \
- EVB64260 \
+ EVB64260 PCIPPC2 \
"
#########################################################################
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
#
-# (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
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
#########################################################################
--- /dev/null
+#
+# (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
+
+#########################################################################
--- /dev/null
+#
+# (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)
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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;
+}
--- /dev/null
+/*
+ * (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;
+}
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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;
+}
--- /dev/null
+/*
+ * (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");
+}
--- /dev/null
+/*
+ * (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();
+ }
+}
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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;
+}
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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 */
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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);
+}
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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();
+}
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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 = .);
+}
--- /dev/null
+/*
+ * (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--;
+ }
+ }
+}
--- /dev/null
+/*
+ * (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
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)
#include <w83c553f.h>
#endif
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+void doc_init (void);
+#endif
+
static char *failed = "*** failed ***\n";
#ifdef CONFIG_PCU_E
scsi_init();
#endif
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+ WATCHDOG_RESET();
+ puts ("DOC: ");
+ doc_init();
+#endif
+
#ifdef CONFIG_LAST_STAGE_INIT
WATCHDOG_RESET();
/*
--- /dev/null
+/*
+ * 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) */
#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 */
CMD_TBL_SCSIBOOT
CMD_TBL_SCSI
CMD_TBL_SETDCR
+ CMD_TBL_DOC
CMD_TBL_SETENV
CMD_TBL_SIINFO
CMD_TBL_SITINFO
--- /dev/null
+/*
+ * 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(®[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) */
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
#########################################################################
* 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[])
{
#endif
((void (*)(void ))addr)();
}
+#endif
/* ------------------------------------------------------------------------- */
--- /dev/null
+/*
+ * 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
/* 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
/*
- * (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
#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
*/
--- /dev/null
+/*
+ * 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 */
#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 \
& ~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 */
#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>
--- /dev/null
+/*
+ * (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 */
#define CONFIG_COMMANDS (CFG_CMD_ALL & ~( \
CFG_CMD_BEDBUG | \
+ CFG_CMD_DOC | \
CFG_CMD_ELF | \
CFG_CMD_FDC | \
CFG_CMD_IDE | \
--- /dev/null
+
+/* 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__ */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
/*
- * (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
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) || \
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)
#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);