Browse Source

Initial revision

wdenk 22 năm trước cách đây
mục cha
commit
c609719b8d
100 tập tin đã thay đổi với 34854 bổ sung0 xóa
  1. 242 0
      CREDITS
  2. 2663 0
      README
  3. 190 0
      board/cogent/serial.c
  4. 119 0
      board/cu824/cu824.c
  5. 53 0
      board/dnp1110/u-boot.lds
  6. 301 0
      board/ebony/ebony.c
  7. 98 0
      board/ebony/init.S
  8. 1487 0
      board/eltec/bab7xx/asm_init.S
  9. 292 0
      board/eltec/bab7xx/el_srom.c
  10. 129 0
      board/eltec/bab7xx/u-boot.lds
  11. 877 0
      board/eltec/elppc/asm_init.S
  12. 129 0
      board/eltec/elppc/u-boot.lds
  13. 341 0
      board/ep7312/flash.c
  14. 53 0
      board/ep7312/u-boot.lds
  15. 262 0
      board/esd/common/fpga.c
  16. 202 0
      board/esd/common/pci.c
  17. 451 0
      board/esd/cpci405/cpci405.c
  18. 140 0
      board/esd/cpci440/cpci440.c
  19. 96 0
      board/esd/cpci440/init.S
  20. 254 0
      board/esd/pci405/pci405.c
  21. 225 0
      board/evb64260/eth_addrtbl.c
  22. 691 0
      board/evb64260/pci.c
  23. 629 0
      board/evb64260/sdram_init.c
  24. 191 0
      board/evb64260/serial.c
  25. 142 0
      board/gen860t/README
  26. 213 0
      board/gen860t/beeper.c
  27. 644 0
      board/gen860t/flash.c
  28. 401 0
      board/gen860t/fpga.c
  29. 299 0
      board/gen860t/gen860t.c
  30. 276 0
      board/gen860t/ioport.c
  31. 135 0
      board/gen860t/u-boot.lds
  32. 365 0
      board/impa7/flash.c
  33. 53 0
      board/impa7/u-boot.lds
  34. 53 0
      board/lart/u-boot.lds
  35. 379 0
      board/mbx8xx/mbx8xx.c
  36. 131 0
      board/ml2/serial.c
  37. 283 0
      board/mousse/pci.c
  38. 606 0
      board/mpl/common/common_util.c
  39. 102 0
      board/mpl/common/pci.c
  40. 192 0
      board/mpl/common/pci_parts.h
  41. 49 0
      board/mpl/mip405/Makefile
  42. 52 0
      board/mpl/pip405/Makefile
  43. 130 0
      board/musenki/musenki.c
  44. 40 0
      board/mvs1/Makefile
  45. 40 0
      board/netvia/Makefile
  46. 374 0
      board/netvia/netvia.c
  47. 132 0
      board/netvia/u-boot.lds
  48. 131 0
      board/netvia/u-boot.lds.debug
  49. 372 0
      board/oxc/flash.c
  50. 237 0
      board/oxc/oxc.c
  51. 254 0
      board/pcippc2/cpc710_init_ram.c
  52. 309 0
      board/pcippc2/cpc710_pci.c
  53. 257 0
      board/pcippc2/i2c.c
  54. 214 0
      board/pcippc2/pcippc2.c
  55. 164 0
      board/pn62/cmd_pn62.c
  56. 235 0
      board/pn62/misc.c
  57. 216 0
      board/pn62/pn62.c
  58. 423 0
      board/r360mpi/r360mpi.c
  59. 884 0
      board/sacsng/clkinit.c
  60. 218 0
      board/sacsng/ioconfig.h
  61. 127 0
      board/sandpoint/sandpoint.c
  62. 53 0
      board/shannon/u-boot.lds
  63. 440 0
      board/siemens/CCM/ccm.c
  64. 170 0
      board/siemens/CCM/fpga_ccm.c
  65. 104 0
      board/siemens/SCM/fpga_scm.c
  66. 27 0
      board/siemens/common/README
  67. 358 0
      board/siemens/common/fpga.c
  68. 54 0
      board/smdk2400/u-boot.lds
  69. 124 0
      board/smdk2410/smdk2410.c
  70. 569 0
      board/tqm8xx/flash.c
  71. 105 0
      board/tqm8xx/load_sernum_ethaddr.c
  72. 44 0
      board/trab/README.kbd
  73. 301 0
      board/trab/trab.c
  74. 63 0
      board/trab/u-boot.lds
  75. 414 0
      board/trab/vfd.c
  76. 152 0
      board/utx8245/utx8245.c
  77. 941 0
      board/w7o/flash.c
  78. 380 0
      board/w7o/fpga.c
  79. 264 0
      board/w7o/init.S
  80. 745 0
      board/w7o/post1.S
  81. 109 0
      board/w7o/post2.c
  82. 408 0
      board/w7o/vpd.c
  83. 135 0
      board/w7o/vpd.h
  84. 271 0
      board/w7o/w7o.c
  85. 1563 0
      common/cmd_doc.c
  86. 1563 0
      common/cmd_ide.c
  87. 578 0
      common/cmd_immap.c
  88. 179 0
      common/cmd_jffs2.c
  89. 477 0
      common/cmd_pci.c
  90. 2243 0
      common/cmd_pcmcia.c
  91. 377 0
      common/env_flash.c
  92. 138 0
      common/env_nvram.c
  93. 198 0
      common/environment.c
  94. 817 0
      common/main.c
  95. 172 0
      common/miiphyutil.c
  96. 416 0
      common/soft_i2c.c
  97. 43 0
      cpu/arm720t/Makefile
  98. 265 0
      cpu/arm720t/interrupts.c
  99. 43 0
      cpu/arm920t/Makefile
  100. 304 0
      cpu/arm920t/interrupts.c

+ 242 - 0
CREDITS

@@ -0,0 +1,242 @@
+#
+#   Parts of the development effort for this project have been
+#   sponsored by SIEMENS AG, Austria. Thanks to SIEMENS for
+#   supporting an Open Source project!
+#
+#
+#   This is at least a partial credits-file of individual people that
+#   have contributed to the U-Boot project. It is sorted by name and
+#   formatted to allow easy grepping and beautification by scripts.
+#   The fields are: name (N), email (E), web-address (W), PGP key ID
+#   and fingerprint (P), description (D), and snail-mail address (S).
+#   Thanks,
+#
+#                       Wolfgang Denk
+#----------
+
+N: Dr. Bruno Achauer
+E: bruno@exet-ag.de
+D: Support for NetBSD (both as host and target system)
+
+N: Swen Anderson
+E: sand@peppercon.de
+D: ERIC Support
+
+N: Guillaume Alexandre
+E: guillaume.alexandre@gespac.ch
+D: Add PCIPPC6 configuration
+
+N: Pierre Aubert
+E: <p.aubert@staubli.com>
+D: Support for RPXClassic board
+
+N: Andre Beaudin
+E: <andre.beaudin@colubris.com>
+D: PCMCIA, Ethernet, TFTP
+
+N: Jerry van Baren
+E: <vanbaren@cideas.com>
+D: BedBug port to 603e core (MPC82xx). Code for enhanced memory test.
+
+N: Raphael Bossek
+E: raphael.bossek@solutions4linux.de
+D: 8xxrom-0.3.0
+
+N: David Brown
+E: DBrown03@harris.com
+D: Extensions to 8xxrom-0.3.0
+
+N: Oliver Brown
+E: obrown@adventnetworks.com
+D: Port to the gw8260 board
+
+N: Jonathan De Bruyne
+E: jonathan.debruyne@siemens.atea.be
+D: Port to Siemens IAD210 board
+
+N: Conn Clark
+E: clark@esteem.com
+D: ESTEEM192E support
+
+N: Magnus Damm
+E: eramdam@kieray1.p.y.ki.era.ericsson.se
+D: 8xxrom
+
+N: Kári Davíðsson
+E: kd@flaga.is
+D: FLAGA DM Support
+
+N: Wolfgang Denk
+E: wd@denx.de
+D: U-Boot initial version, continuing maintenance, ARMBoot merge
+W: http://www.denx.de
+
+N: Dan A. Dickey
+E: ddickey@charter.net
+D: FADS Support
+
+N: James F. Dougherty
+E: jfd@GigabitNetworks.COM
+D: Port to the MOUSSE board
+
+N: Dave Ellis
+E: DGE@sixnetio.com
+D: EEPROM Speedup, SXNI855T port
+
+N: Dr. Wolfgang Grandegger
+E: wg@denx.de
+D: Support for Interphase 4539 T1/E1/J1 PMC, PN62, CCM, SCM boards
+W: www.denx.de
+
+N: Frank Gottschling
+E: fgottschling@eltec.de
+D: Support for ELTEC MHPC/BAB7xx/ELPPC boards, cfb-console, i8042, SMI LynxEM
+W: www.eltec.de
+
+N: Marius Groeger
+E: mgroeger@sysgo.de
+D: MBX Support, board specific function interface, EST SBC8260 support; initial support for StrongARM (LART), ARM720TDMI (implementa A7)
+W: www.elinos.com
+
+N: Kirk Haderlie
+E: khaderlie@vividimage.com
+D: Added TFTP to 8xxrom (-> 0.3.1)
+
+N: Chris Hallinan
+E: clh@net1plus.com
+D: DHCP Support
+
+N: Anne-Sophie Harnois
+E: Anne-Sophie.Harnois@nextream.fr
+D: Port to Walnut405 board
+
+N: Andreas Heppel
+E: aheppel@sysgo.de
+D: CPU Support for MPC 75x; board support for Eltec BAB750 [obsolete!]
+
+N: Josh Huber
+E: huber@alum.wpi.edu
+D: Port to the Galileo Evaluation Board, and the MPC74xx cpu series.
+W: http://www.mclx.com/
+
+H: Stuart Hughes
+E: stuarth@lineo.com
+D: Port to MPC8260ADS board
+
+H: Rich Ireland
+E: r.ireland@computer.org
+D: FPGA device configuration driver
+
+N: Gary Jennejohn
+E: garyj@jennejohn.org, gj@denx.de
+D: Support for Samsung ARM920T S3C2400X, ARM920T "TRAB"
+W: www.denx.de
+
+N: Murray Jensen
+E: Murray.Jensen@cmst.csiro.au
+D: Initial 8260 support; GDB support
+D: Port to Cogent+Hymod boards; Hymod Board Database
+W: http://www.msa.cmst.csiro.au/ourstaff/MurrayJensen/mjj.html
+
+N: Yoo. Jonghoon
+E: yooth@ipone.co.kr
+D: Added port to the RPXlite board
+
+N: Brad Kemp
+E: Brad.Kemp@seranoa.com
+D: Port to Windriver ppmc8260 board
+
+N: Thomas Koeller
+E: tkoeller@gmx.net
+D: Port to Motorola Sandpoint 3 (MPC8240)
+
+N: Thomas Lange
+E: thomas@corelatus.com
+D: Support for GTH board; lots of PCMCIA fixes
+
+N: Raymond Lo
+E: lo@routefree.com
+D: Support for DOS partitions
+
+N: Dan Malek
+E: dan@netx4.com
+D: FADSROM, the grandfather of all of this
+
+N: Jay Monkman
+E: jtm@smoothsmoothie.com
+D: EST SBC8260 support
+
+N: Frank Morauf
+E: frank.morauf@salzbrenner.com
+D: Support for Embedded Planet RPX Super Board
+
+N: David Müller
+E: d.mueller@elsoft.ch
+D: Support for Samsung ARM920T SMDK2410 eval board
+
+N: Rolf Offermanns
+E: rof@sysgo.de
+D: Initial support for SSV-DNP1110, SMC91111 driver
+W: www.elinos.com
+
+N: Keith Outwater
+E: Keith_Outwater@mvis.com
+D: Support for GEN860T board
+
+N: Keith Outwater
+E: keith_outwater@mvis.com
+D: Support for generic/custom MPC860T board (GEN860T)
+
+N: Frank Panno
+E: fpanno@delphintech.com
+D: Support for Embedded Planet EP8260 Board
+
+N: Denis Peter
+E: d.peter@mpl.ch
+D: Support for 4xx SCSI, floppy, CDROM, CT69000 video, ...
+D: Support for PIP405 board
+D: Support for MIP405 board
+
+N: Bill Pitts
+E: wlp@mindspring.com
+D: BedBug embedded debugger code
+
+N: Stefan Roese
+E: stefan.roese@esd-electronics.com
+D: IBM PPC401/403/405GP Support; Windows environment support
+
+N: Neil Russell
+E: caret@c-side.com
+D: Author of LiMon-1.4.2, which contributed some ideas
+
+N: Paolo Scaffardi
+E: arsenio@tin.it
+D: FADS823 configuration, MPC823 video support, I2C, wireless keyboard, lots more
+
+N: Robert Schwebel
+E: r.schwebel@pengutronix.de
+D: Support for csb226 board (xscale)
+N: Rob Taylor
+E: robt@flyingpig.com
+D: Port to MBX860T and Sandpoint8240
+
+N: Erik Theisen
+E: etheisen@mindspring.com
+D: MBX8xx and many other patches
+
+N: Jim Thompson
+E: jim@musenki.com
+D: Support for MUSENKI board
+
+N: David Updegraff
+E: dave@cray.com
+D: Port to Cray L1 board; DHCP vendor extensions
+
+N: Christian Vejlbo
+E: christian.vejlbo@tellabs.com
+D: FADS860T ethernet support
+
+N: Alex Zuepke
+E: azu@sysgo.de
+D: Overall improvements on StrongARM, ARM720TDMI; Support for Tuxscreen; initial PCMCIA support for ARM
+W: www.elinos.com

+ 2663 - 0
README

@@ -0,0 +1,2663 @@
+#
+# (C) Copyright 2000 - 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
+#
+
+Summary:
+========
+
+This directory contains the source code for U-Boot, a monitor for
+Embedded PowerPC boards, which can be installed in a boot ROM and
+used to test the hardware or download and run application code.
+
+The development of U-Boot is closely related to Linux: some parts of
+the source code originate in the Linux source tree, we still have
+some header files in common, and special provision has been made to
+support booting of Linux images.
+
+Some attention has been paid to make this software easily
+configurable and extendable. For instance, all monitor commands are
+implemented with the same call interface, so that it's very easy to
+add new commands. Also, instead of permanently adding rarely used
+code (for instance hardware test utilities) to the monitor, you can
+load and run it dynamically.
+
+
+Status:
+=======
+
+In general, all boards for which a configuration option exists in the
+Makefile have been tested  to  some  extent  and  can  be  considered
+"working". In fact, many of them are used in production systems.
+
+In case of problems see the CHANGELOG and CREDITS files to  find  out
+who contributed the specific port.
+
+Exception from this rule: the port to the Sandpoint 8240 has not been
+completed yet.
+
+
+Where to get help:
+==================
+
+In case you have questions about, problems with or contributions  for
+U-Boot	 you  should  send  a  message to the U-Boot mailing list at
+<u-boot-users@lists.sourceforge.net>. There is also  an  archive  of
+previous  traffic  on  the  mailing  list - please search the archive
+before asking FAQ's. Please see
+http://lists.sourceforge.net/lists/listinfo/u-boot-users/
+
+
+Where we come from:
+===================
+
+- start from 8xxrom sources
+- clean up code
+- make it easier to add custom boards
+- make it possible to add other [PowerPC] CPUs
+- extend functions, especially:
+  * Provide extended interface to Linux boot loader
+  * S-Record download
+  * network boot
+  * PCMCIA / CompactFLash / ATA disk / SCSI ... boot
+- add other CPU families (starting with ARM)
+
+
+Directory Hierarchy:
+====================
+
+- board		Board dependend files
+- common	Misc architecture independend functions
+- cpu		CPU specific files
+- disk		Code for disk drive partition handling
+- doc		Documentation (don't expect too much)
+- drivers	Common used device drivers
+- dtt		Digital Thermometer and Thermostat drivers
+- examples	Example code for standalone applications, etc.
+- include	Header Files
+- disk		Harddisk interface code
+- net		Networking code
+- ppc		Files generic to PowerPC architecture
+- post		Power On Self Test
+- post/arch		Symlink to architecture specific Power On Self Test
+- post/arch-ppc		PowerPC architecture specific Power On Self Test
+- post/cpu/mpc8260	MPC8260 CPU specific Power On Self Test
+- post/cpu/mpc8xx	MPC8xx CPU specific Power On Self Test
+- rtc		Real Time Clock drivers
+- tools		Tools to build S-Record or U-Boot images, etc.
+
+- cpu/74xx_7xx	Files specific to Motorola MPC74xx and 7xx CPUs
+- cpu/mpc8xx	Files specific to Motorola MPC8xx  CPUs
+- cpu/mpc824x	Files specific to Motorola MPC824x CPUs
+- cpu/mpc8260	Files specific to Motorola MPC8260 CPU
+- cpu/ppc4xx	Files specific to IBM	   4xx	   CPUs
+
+- board/RPXClassic
+		Files specific to RPXClassic boards
+- board/RPXlite	Files specific to RPXlite    boards
+- board/c2mon	Files specific to c2mon	     boards
+- board/cogent	Files specific to Cogent     boards
+		(need further configuration)
+		Files specific to CPCIISER4  boards
+- board/cpu86	Files specific to CPU86      boards
+- board/cray/	Files specific to boards manufactured by Cray
+- board/cray/L1		Files specific to L1         boards
+- board/cu824	Files specific to CU824	     boards
+- board/ebony   Files specific to IBM Ebony board
+- board/eric	Files specific to ERIC	     boards
+- board/esd/	Files specific to boards manufactured by ESD
+- board/esd/adciop	Files specific to ADCIOP     boards
+- board/esd/ar405	Files specific to AR405	     boards
+- board/esd/canbt	Files specific to CANBT	     boards
+- board/esd/cpci405	Files specific to CPCI405    boards
+- board/esd/cpciiser4	Files specific to CPCIISER4  boards
+- board/esd/common	Common files for ESD boards
+- board/esd/dasa_sim	Files specific to DASA_SIM   boards
+- board/esd/du405	Files specific to DU405      boards
+- board/esd/ocrtc	Files specific to OCRTC      boards
+- board/esd/pci405	Files specific to PCI405     boards
+- board/esteem192e
+		Files specific to ESTEEM192E boards
+- board/etx094	Files specific to ETX_094    boards
+- board/evb64260
+		Files specific to EVB64260   boards
+- board/fads	Files specific to FADS	     boards
+- board/flagadm Files specific to FLAGADM    boards
+- board/gen860t Files specific to GEN860T    boards
+- board/genietv Files specific to GENIETV    boards
+- board/gth	Files specific to GTH	     boards
+- board/hermes	Files specific to HERMES     boards
+- board/hymod	Files specific to HYMOD	     boards
+- board/icu862	Files specific to ICU862     boards
+- board/ip860	Files specific to IP860	     boards
+- board/iphase4539
+		Files specific to Interphase4539 boards
+- board/ivm	Files specific to IVMS8/IVML24 boards
+- board/lantec	Files specific to LANTEC     boards
+- board/lwmon	Files specific to LWMON	     boards
+- board/mbx8xx	Files specific to MBX	     boards
+- board/mpc8260ads
+		Files specific to MMPC8260ADS boards
+- board/mpl/	Files specific to boards manufactured by MPL
+- board/mpl/common	Common files for MPL boards
+- board/mpl/pip405	Files specific to PIP405     boards
+- board/mpl/mip405	Files specific to MIP405     boards
+- board/musenki	Files specific to MUSEKNI    boards
+- board/mvs1	Files specific to MVS1       boards
+- board/nx823   Files specific to NX823      boards
+- board/oxc	Files specific to OXC        boards
+- board/pcippc2	Files specific to PCIPPC2/PCIPPC6 boards
+- board/pm826	Files specific to PM826      boards
+- board/ppmc8260
+		Files specific to PPMC8260   boards
+- board/rpxsuper
+		Files specific to RPXsuper   boards
+- board/rsdproto
+		Files specific to RSDproto   boards
+- board/sandpoint
+		Files specific to Sandpoint  boards
+- board/sbc8260	Files specific to SBC8260    boards
+- board/sacsng	Files specific to SACSng     boards
+- board/siemens Files specific to boards manufactured by Siemens AG
+- board/siemens/CCM	Files specific to CCM	     boards
+- board/siemens/IAD210	Files specific to IAD210     boards
+- board/siemens/SCM	Files specific to SCM        boards
+- board/siemens/pcu_e	Files specific to PCU_E	     boards
+- board/sixnet	Files specific to SIXNET     boards
+- board/spd8xx	Files specific to SPD8xxTS   boards
+- board/tqm8260 Files specific to TQM8260    boards
+- board/tqm8xx	Files specific to TQM8xxL    boards
+- board/w7o	Files specific to W7O        boards
+- board/walnut405
+		Files specific to Walnut405  boards
+- board/westel/	Files specific to boards manufactured by Westel Wireless
+- board/westel/amx860	Files specific to AMX860     boards
+- board/utx8245	Files specific to UTX8245   boards
+
+Software Configuration:
+=======================
+
+Configuration is usually done using C preprocessor defines; the
+rationale behind that is to avoid dead code whenever possible.
+
+There are two classes of configuration variables:
+
+* Configuration _OPTIONS_:
+  These are selectable by the user and have names beginning with
+  "CONFIG_".
+
+* Configuration _SETTINGS_:
+  These depend on the hardware etc. and should not be meddled with if
+  you don't know what you're doing; they have names beginning with
+  "CFG_".
+
+Later we will add a configuration tool - probably similar to or even
+identical to what's used for the Linux kernel. Right now, we have to
+do the configuration by hand, which means creating some symbolic
+links and editing some configuration files. We use the TQM8xxL boards
+as an example here.
+
+
+Selection of Processor Architecture and Board Type:
+---------------------------------------------------
+
+For all supported boards there are ready-to-use default
+configurations available; just type "make <board_name>_config".
+
+Example: For a TQM823L module type:
+
+	cd u-boot
+	make TQM823L_config
+
+For the Cogent platform, you need to specify the cpu type as well;
+e.g. "make cogent_mpc8xx_config". And also configure the cogent
+directory according to the instructions in cogent/README.
+
+
+Configuration Options:
+----------------------
+
+Configuration depends on the combination of board and CPU type; all
+such information is kept in a configuration file
+"include/configs/<board_name>.h".
+
+Example: For a TQM823L module, all configuration settings are in
+"include/configs/TQM823L.h".
+
+
+The following options need to be configured:
+
+- CPU Type:	Define exactly one of
+
+		PowerPC based CPUs:
+		-------------------
+		CONFIG_MPC823,	CONFIG_MPC850,	CONFIG_MPC855,	CONFIG_MPC860
+	or	CONFIG_MPC824X, CONFIG_MPC8260
+	or	CONFIG_IOP480
+	or	CONFIG_405GP
+	or	CONFIG_440
+	or	CONFIG_MPC74xx
+
+		ARM based CPUs:
+		---------------
+		CONFIG_SA1110
+		CONFIG_ARM7
+		CONFIG_PXA250
+
+
+- Board Type:	Define exactly one of
+
+		PowerPC based boards:
+		---------------------
+
+		CONFIG_ADCIOP,     CONFIG_ICU862      CONFIG_RPXsuper,
+		CONFIG_ADS860,     CONFIG_IP860,      CONFIG_SM850,
+		CONFIG_AMX860,     CONFIG_IPHASE4539, CONFIG_SPD823TS,
+		CONFIG_AR405,      CONFIG_IVML24,     CONFIG_SXNI855T,
+		CONFIG_BAB7xx,     CONFIG_IVML24_128, CONFIG_Sandpoint8240,
+		CONFIG_CANBT,      CONFIG_IVML24_256, CONFIG_Sandpoint8245,
+		CONFIG_CCM,        CONFIG_IVMS8,      CONFIG_TQM823L,
+		CONFIG_CPCI405,    CONFIG_IVMS8_128,  CONFIG_TQM850L,
+		CONFIG_CPCI4052,   CONFIG_IVMS8_256,  CONFIG_TQM855L,
+		CONFIG_CPCIISER4,  CONFIG_LANTEC,     CONFIG_TQM860L,
+		CONFIG_CPU86,      CONFIG_MBX,        CONFIG_TQM8260,
+		CONFIG_CRAYL1,     CONFIG_MBX860T,    CONFIG_TTTech,
+		CONFIG_CU824,      CONFIG_MHPC,       CONFIG_UTX8245,
+		CONFIG_DASA_SIM,   CONFIG_MIP405,     CONFIG_W7OLMC,
+		CONFIG_DU405,      CONFIG_MOUSSE,     CONFIG_W7OLMG,
+		CONFIG_ELPPC,      CONFIG_MPC8260ADS, CONFIG_WALNUT405,
+		CONFIG_ERIC,       CONFIG_MUSENKI,    CONFIG_ZUMA,
+		CONFIG_ESTEEM192E, CONFIG_MVS1,       CONFIG_c2mon,
+		CONFIG_ETX094,     CONFIG_NX823,      CONFIG_cogent_mpc8260,
+		CONFIG_EVB64260,   CONFIG_OCRTC,      CONFIG_cogent_mpc8xx,
+		CONFIG_FADS823,    CONFIG_ORSG,       CONFIG_ep8260,
+		CONFIG_FADS850SAR, CONFIG_OXC,        CONFIG_gw8260,
+		CONFIG_FADS860T,   CONFIG_PCI405,     CONFIG_hermes,
+		CONFIG_FLAGADM,    CONFIG_PCIPPC2,    CONFIG_hymod,
+		CONFIG_FPS850L,    CONFIG_PCIPPC6,    CONFIG_lwmon,
+		CONFIG_GEN860T,    CONFIG_PIP405,     CONFIG_pcu_e,
+		CONFIG_GENIETV,    CONFIG_PM826,      CONFIG_ppmc8260,
+		CONFIG_GTH,        CONFIG_RPXClassic, CONFIG_rsdproto,
+		CONFIG_IAD210,     CONFIG_RPXlite,    CONFIG_sbc8260,
+		CONFIG_EBONY,      CONFIG_sacsng
+
+		ARM based boards:
+		-----------------
+
+		CONFIG_HHP_CRADLE,  CONFIG_DNP1110,    CONFIG_EP7312,
+		CONFIG_IMPA7,       CONFIG_LART,       CONFIG_LUBBOCK,
+		CONFIG_SHANNON,     CONFIG_SMDK2400,   CONFIG_SMDK2410,
+		CONFIG_TRAB
+
+
+- CPU Module Type: (if CONFIG_COGENT is defined)
+		Define exactly one of
+		CONFIG_CMA286_60_OLD
+--- FIXME --- not tested yet:
+		CONFIG_CMA286_60, CONFIG_CMA286_21, CONFIG_CMA286_60P,
+		CONFIG_CMA287_23, CONFIG_CMA287_50
+
+- Motherboard Type: (if CONFIG_COGENT is defined)
+		Define exactly one of
+		CONFIG_CMA101, CONFIG_CMA102
+
+- Motherboard I/O Modules: (if CONFIG_COGENT is defined)
+		Define one or more of
+		CONFIG_CMA302
+
+- Motherboard Options: (if CONFIG_CMA101 or CONFIG_CMA102 are defined)
+		Define one or more of
+		CONFIG_LCD_HEARTBEAT	- update a character position on
+					  the lcd display every second with
+					  a "rotator" |\-/|\-/
+
+- MPC824X Family Member (if CONFIG_MPC824X is defined)
+	Define exactly one of
+	CONFIG_MPC8240, CONFIG_MPC8245
+
+- 8xx CPU Options: (if using an 8xx cpu)
+		Define one or more of
+		CONFIG_8xx_GCLK_FREQ	- if get_gclk_freq() can not work e.g.
+					  no 32KHz reference PIT/RTC clock
+
+- Clock Interface:
+		CONFIG_CLOCKS_IN_MHZ
+
+		U-Boot stores all clock information in Hz
+		internally. For binary compatibility with older Linux
+		kernels (which expect the clocks passed in the
+		bd_info data to be in MHz) the environment variable
+		"clocks_in_mhz" can be defined so that U-Boot
+		converts clock data to MHZ before passing it to the
+		Linux kernel.
+
+		When CONFIG_CLOCKS_IN_MHZ is defined, a definition of
+		"clocks_in_mhz=1" is  automatically  included  in  the
+		default environment.
+
+- Console Interface:
+                Depending on board, define exactly one serial port
+                (like CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2,
+                CONFIG_8xx_CONS_SCC1, ...), or switch off the serial
+                console by defining CONFIG_8xx_CONS_NONE
+
+		Note: if CONFIG_8xx_CONS_NONE is defined, the serial
+		port routines must be defined elsewhere
+		(i.e. serial_init(), serial_getc(), ...)
+
+		CONFIG_CFB_CONSOLE
+		Enables console device for a color framebuffer. Needs following
+		defines (cf. smiLynxEM, i8042, board/eltec/bab7xx)
+			VIDEO_FB_LITTLE_ENDIAN	graphic memory organisation
+						(default big endian)
+			VIDEO_HW_RECTFILL	graphic chip supports
+						rectangle fill
+						(cf. smiLynxEM)
+			VIDEO_HW_BITBLT		graphic chip supports
+						bit-blit (cf. smiLynxEM)
+			VIDEO_VISIBLE_COLS	visible pixel columns
+						(cols=pitch)
+			VIDEO_VISIBLE_ROWS      visible pixel rows
+			VIDEO_PIXEL_SIZE        bytes per pixel
+			VIDEO_DATA_FORMAT	graphic data format
+						(0-5, cf. cfb_console.c)
+			VIDEO_FB_ADRS           framebuffer address
+			VIDEO_KBD_INIT_FCT	keyboard int fct
+						(i.e. i8042_kbd_init())
+			VIDEO_TSTC_FCT		test char fct
+						(i.e. i8042_tstc)
+			VIDEO_GETC_FCT		get char fct
+						(i.e. i8042_getc)
+			CONFIG_CONSOLE_CURSOR	cursor drawing on/off
+						(requires blink timer
+						cf. i8042.c)
+			CFG_CONSOLE_BLINK_COUNT blink interval (cf. i8042.c)
+			CONFIG_CONSOLE_TIME	display time/date info in
+						upper right corner
+						(requires CFG_CMD_DATE)
+			CONFIG_VIDEO_LOGO	display Linux logo in
+						upper left corner
+			CONFIG_CONSOLE_EXTRA_INFO
+						addional board info beside
+						the logo
+
+                When CONFIG_CFB_CONSOLE is defined, video console is
+                default i/o. Serial console can be forced with
+                environment 'console=serial'.
+
+- Console Baudrate:
+		CONFIG_BAUDRATE - in bps
+		Select one of the baudrates listed in
+		CFG_BAUDRATE_TABLE, see below.
+
+- Interrupt driven serial port input:
+		CONFIG_SERIAL_SOFTWARE_FIFO
+
+		PPC405GP only.
+		Use an interrupt handler for receiving data on the
+		serial port. It also enables using hardware handshake
+		(RTS/CTS) and UART's built-in FIFO. Set the number of
+		bytes the interrupt driven input buffer should have.
+
+		Set to 0 to disable this feature (this is the default).
+		This will also disable hardware handshake.
+
+- Boot Delay:	CONFIG_BOOTDELAY - in seconds
+		Delay before automatically booting the default image;
+		set to -1 to disable autoboot.
+
+		See doc/README.autoboot for these options that
+		work with CONFIG_BOOTDELAY. None are required.
+		CONFIG_BOOT_RETRY_TIME
+		CONFIG_BOOT_RETRY_MIN
+		CONFIG_AUTOBOOT_KEYED
+		CONFIG_AUTOBOOT_PROMPT
+		CONFIG_AUTOBOOT_DELAY_STR
+		CONFIG_AUTOBOOT_STOP_STR
+		CONFIG_AUTOBOOT_DELAY_STR2
+		CONFIG_AUTOBOOT_STOP_STR2
+		CONFIG_ZERO_BOOTDELAY_CHECK
+		CONFIG_RESET_TO_RETRY
+
+- Autoboot Command:
+		CONFIG_BOOTCOMMAND
+		Only needed when CONFIG_BOOTDELAY is enabled;
+		define a command string that is automatically executed
+		when no character is read on the console interface
+		within "Boot Delay" after reset.
+
+		CONFIG_BOOTARGS
+                This can be used to pass arguments to the bootm
+                command. The value of CONFIG_BOOTARGS goes into the
+                environment value "bootargs".
+
+		CONFIG_RAMBOOT and CONFIG_NFSBOOT
+                The value of these goes into the environment as
+                "ramboot" and "nfsboot" respectively, and can be used
+                as a convenience, when switching between booting from
+                ram and nfs.
+
+- Pre-Boot Commands:
+		CONFIG_PREBOOT
+
+		When this option is #defined, the existence of the
+		environment variable "preboot" will be checked
+		immediately before starting the CONFIG_BOOTDELAY
+		countdown and/or running the auto-boot command resp.
+		entering interactive mode.
+
+		This feature is especially useful when "preboot" is
+		automatically generated or modified. For an example
+		see the LWMON board specific code: here "preboot" is
+		modified when the user holds down a certain
+		combination of keys on the (special) keyboard when
+		booting the systems
+
+- Serial Download Echo Mode:
+		CONFIG_LOADS_ECHO
+		If defined to 1, all characters received during a
+		serial download (using the "loads" command) are
+		echoed back. This might be needed by some terminal
+		emulations (like "cu"), but may as well just take
+		time on others. This setting #define's the initial
+		value of the "loads_echo" environment variable.
+
+- Kgdb Serial Baudrate: (if CFG_CMD_KGDB is defined)
+		CONFIG_KGDB_BAUDRATE
+		Select one of the baudrates listed in
+		CFG_BAUDRATE_TABLE, see below.
+
+- Monitor Functions:
+		CONFIG_COMMANDS
+		Most monitor functions can be selected (or
+		de-selected) by adjusting the definition of
+		CONFIG_COMMANDS; to select individual functions,
+		#define CONFIG_COMMANDS by "OR"ing any of the
+		following values:
+
+		#define enables commands:
+		-------------------------
+		CFG_CMD_ASKENV	* ask for env variable
+		CFG_CMD_BDI	  bdinfo
+		CFG_CMD_BEDBUG	  Include BedBug Debugger
+		CFG_CMD_BOOTD	  bootd
+		CFG_CMD_CACHE	  icache, dcache
+		CFG_CMD_CONSOLE	  coninfo
+		CFG_CMD_DATE	* support for RTC, date/time...
+		CFG_CMD_DHCP	  DHCP support
+		CFG_CMD_ECHO	* echo arguments
+		CFG_CMD_EEPROM	* EEPROM read/write support
+		CFG_CMD_ELF	  bootelf, bootvx
+		CFG_CMD_ENV	  saveenv
+		CFG_CMD_FDC	* Floppy Disk Support
+		CFG_CMD_FLASH	  flinfo, erase, protect
+		CFG_CMD_FPGA	  FPGA device initialization support
+		CFG_CMD_I2C	* I2C serial bus support
+		CFG_CMD_IDE	* IDE harddisk support
+		CFG_CMD_IMI	  iminfo
+		CFG_CMD_IMMAP	* IMMR dump support
+		CFG_CMD_IRQ	* irqinfo
+		CFG_CMD_KGDB	* kgdb
+		CFG_CMD_LOADB	  loadb
+		CFG_CMD_LOADS	  loads
+		CFG_CMD_MEMORY	  md, mm, nm, mw, cp, cmp, crc, base,
+				  loop, mtest
+		CFG_CMD_MII	  MII utility commands
+		CFG_CMD_NET	  bootp, tftpboot, rarpboot
+		CFG_CMD_PCI	* pciinfo
+		CFG_CMD_PCMCIA	* PCMCIA support
+		CFG_CMD_REGINFO * Register dump
+		CFG_CMD_RUN	  run command in env variable
+		CFG_CMD_SCSI	* SCSI Support
+		CFG_CMD_SETGETDCR Support for DCR Register access (4xx only)
+		CFG_CMD_SPI	* SPI serial bus support
+		CFG_CMD_USB	* USB support
+		CFG_CMD_BSP	* Board SPecific functions
+		-----------------------------------------------
+		CFG_CMD_ALL	all
+
+		CFG_CMD_DFL	Default configuration; at the moment
+				this is includes all commands, except
+				the ones marked with "*" in the list
+				above.
+
+		If you don't define CONFIG_COMMANDS it defaults to
+		CFG_CMD_DFL in include/cmd_confdefs.h. A board can
+		override the default settings in the respective
+		include file.
+
+		EXAMPLE: If you want all functions except of network
+		support you can write:
+
+		#define CONFIG_COMMANDS (CFG_CMD_ALL & ~CFG_CMD_NET)
+
+
+	Note:	Don't enable the "icache" and "dcache" commands
+                (configuration option CFG_CMD_CACHE) unless you know
+                what you (and your U-Boot users) are doing. Data
+                cache cannot be enabled on systems like the 8xx or
+                8260 (where accesses to the IMMR region must be
+                uncached), and it cannot be disabled on all other
+                systems where we (mis-) use the data cache to hold an
+                initial stack and some data.
+
+
+		XXX - this list needs to get updated!
+
+- Watchdog:
+		CONFIG_WATCHDOG
+		If this variable is defined, it enables watchdog
+		support. There must support in the platform specific
+		code for a watchdog. For the 8xx and 8260 CPUs, the
+		SIU Watchdog feature is enabled in the SYPCR
+		register.
+
+- Real-Time Clock:
+
+		When CFG_CMD_DATE is selected, the type of the RTC
+		has to be selected, too. Define exactly one of the
+		following options:
+
+		CONFIG_RTC_MPC8xx	- use internal RTC of MPC8xx
+		CONFIG_RTC_PCF8563	- use Philips PCF8563 RTC
+		CONFIG_RTC_MC146818	- use MC146818 RTC
+		CONFIG_RTC_DS1337	- use Maxim, Inc. DS1337 RTC
+
+- Timestamp Support:
+
+                When CONFIG_TIMESTAMP is selected, the timestamp
+                (date and time) of an image is printed by image
+                commands like bootm or iminfo. This option is
+                automatically enabled when you select CFG_CMD_DATE .
+
+- Partition Support:
+		CONFIG_MAC_PARTITION and/or CONFIG_DOS_PARTITION
+		and/or CONFIG_ISO_PARTITION
+
+		If IDE or SCSI support	is  enabled  (CFG_CMD_IDE  or
+		CFG_CMD_SCSI) you must configure support for at least
+		one partition type as well.
+
+- IDE Reset method:
+		CONFIG_IDE_RESET_ROUTINE
+
+		Set this to define that instead of a reset Pin, the
+		routine ide_set_reset(int idereset) will be used.
+
+- ATAPI Support:
+		CONFIG_ATAPI
+
+		Set this to enable ATAPI support.
+
+- SCSI Support:
+		At the moment only there is only support for the
+		SYM53C8XX SCSI controller; define
+		CONFIG_SCSI_SYM53C8XX to enable it.
+
+		CFG_SCSI_MAX_LUN [8], CFG_SCSI_MAX_SCSI_ID [7] and
+		CFG_SCSI_MAX_DEVICE [CFG_SCSI_MAX_SCSI_ID *
+		CFG_SCSI_MAX_LUN] can be adjusted to define the
+		maximum numbers of LUNs, SCSI ID's and target
+		devices.
+		CFG_SCSI_SYM53C8XX_CCF to fix clock timing (80Mhz)
+
+- NETWORK Support (PCI):
+		CONFIG_EEPRO100
+		Support for Intel 82557/82559/82559ER chips.
+		Optional CONFIG_EEPRO100_SROM_WRITE enables eeprom
+		write routine for first time initialisation.
+
+		CONFIG_TULIP
+		Support for Digital 2114x chips.
+		Optional CONFIG_TULIP_SELECT_MEDIA for board specific
+		modem chip initialisation (KS8761/QS6611).
+
+		CONFIG_NATSEMI
+		Support for National dp83815 chips.
+
+		CONFIG_NS8382X
+		Support for National dp8382[01] gigabit chips.
+
+- USB Support:
+		At the moment only the UHCI host controller is
+		supported (PIP405, MIP405); define
+		CONFIG_USB_UHCI to enable it.
+		define CONFIG_USB_KEYBOARD to enable the USB Keyboard
+		end define CONFIG_USB_STORAGE to enable the USB
+		storage devices.
+		Note:
+		Supported are USB Keyboards and USB Floppy drives
+		(TEAC FD-05PUB).
+
+- Keyboard Support:
+		CONFIG_ISA_KEYBOARD
+
+		Define this to enable standard (PC-Style) keyboard
+		support
+
+		CONFIG_I8042_KBD
+		Standard PC keyboard driver with US (is default) and
+		GERMAN key layout (switch via environment 'keymap=de') support.
+		Export function i8042_kbd_init, i8042_tstc and i8042_getc
+		for cfb_console. Supports cursor blinking.
+
+- Video support:
+		CONFIG_VIDEO
+
+		Define this to enable video support (for output to
+		video).
+
+		CONFIG_VIDEO_CT69000
+
+		Enable Chips & Technologies 69000 Video chip
+
+		CONFIG_VIDEO_SMI_LYNXEM
+		Enable Silicon Motion SMI 712/710/810 Video chip
+		Videomode are selected via environment 'videomode' with
+		standard LiLo mode numbers.
+		Following modes are supported  (* is default):
+
+                            800x600  1024x768  1280x1024
+              256  (8bit)     303*      305       307
+            65536 (16bit)     314       317       31a
+        16,7 Mill (24bit)     315       318       31b
+		(i.e. setenv videomode 317; saveenv; reset;)
+
+- LCD Support:	CONFIG_LCD
+
+		Define this to enable LCD support (for output to LCD
+		display); also select one of the supported displays
+		by defining one of these:
+
+		CONFIG_NEC_NL6648AC33:
+
+			NEC NL6648AC33-18. Active, color, single scan.
+
+		CONFIG_NEC_NL6648BC20
+
+			NEC NL6648BC20-08. 6.5", 640x480.
+			Active, color, single scan.
+
+		CONFIG_SHARP_16x9
+
+			Sharp 320x240. Active, color, single scan.
+			It isn't 16x9, and I am not sure what it is.
+
+		CONFIG_SHARP_LQ64D341
+
+			Sharp LQ64D341 display, 640x480.
+			Active, color, single scan.
+
+		CONFIG_HLD1045
+
+			HLD1045 display, 640x480.
+			Active, color, single scan.
+
+		CONFIG_OPTREX_BW
+
+			Optrex	 CBL50840-2 NF-FW 99 22 M5
+			or
+			Hitachi	 LMG6912RPFC-00T
+			or
+			Hitachi	 SP14Q002
+
+			320x240. Black & white.
+
+		Normally display is black on white background; define
+		CFG_WHITE_ON_BLACK to get it inverted.
+
+- Ethernet address:
+		CONFIG_ETHADDR
+		CONFIG_ETH2ADDR
+		CONFIG_ETH3ADDR
+
+		Define a default value for ethernet address to use
+		for the respective ethernet interface, in case this
+		is not determined automatically.
+
+- IP address:
+		CONFIG_IPADDR
+
+		Define a default value for the IP address to use for
+		the default ethernet interface, in case this is not
+		determined through e.g. bootp.
+
+- Server IP address:
+		CONFIG_SERVERIP
+
+		Defines a default value for theIP address of a TFTP
+		server to contact when using the "tftboot" command.
+
+- BOOTP Recovery Mode:
+		CONFIG_BOOTP_RANDOM_DELAY
+
+		If you have many targets in a network that try to
+		boot using BOOTP, you may want to avoid that all
+		systems send out BOOTP requests at precisely the same
+		moment (which would happen for instance at recovery
+		from a power failure, when all systems will try to
+		boot, thus flooding the BOOTP server. Defining
+		CONFIG_BOOTP_RANDOM_DELAY causes a random delay to be
+		inserted before sending out BOOTP requests. The
+		following delays are insterted then:
+
+		1st BOOTP request:	delay 0 ... 1 sec
+		2nd BOOTP request:	delay 0 ... 2 sec
+		3rd BOOTP request:	delay 0 ... 4 sec
+		4th and following
+		BOOTP requests:		delay 0 ... 8 sec
+
+- Status LED:	CONFIG_STATUS_LED
+
+		Several configurations allow to display the current
+		status using a LED. For instance, the LED will blink
+		fast while running U-Boot code, stop blinking as
+		soon as a reply to a BOOTP request was received, and
+		start blinking slow once the Linux kernel is running
+		(supported by a status LED driver in the Linux
+		kernel). Defining CONFIG_STATUS_LED enables this
+		feature in U-Boot.
+
+- CAN Support:	CONFIG_CAN_DRIVER
+
+		Defining CONFIG_CAN_DRIVER enables CAN driver support
+		on those systems that support this (optional)
+		feature, like the TQM8xxL modules.
+
+- I2C Support:	CONFIG_HARD_I2C | CONFIG_SOFT_I2C
+
+		Enables I2C serial bus commands.  If this is selected,
+		either CONFIG_HARD_I2C or CONFIG_SOFT_I2C must be defined
+		to include the appropriate I2C driver.
+
+                See also: common/cmd_i2c.c for a description of the
+                command line interface.
+
+
+		CONFIG_HARD_I2C
+
+		Selects the CPM hardware driver for I2C.
+
+		CONFIG_SOFT_I2C
+
+		Use software (aka bit-banging) driver instead of CPM
+		or similar hardware support for I2C.  This is configured
+		via the following defines.
+
+		I2C_INIT
+
+                (Optional). Any commands necessary to enable I2C
+                controller or configure ports.
+
+		I2C_PORT
+
+                (Only for MPC8260 CPU). The I/O port to use (the code
+                assumes both bits are on the same port). Valid values
+                are 0..3 for ports A..D.
+
+		I2C_ACTIVE
+
+		The code necessary to make the I2C data line active
+		(driven).  If the data line is open collector, this
+		define can be null.
+
+		I2C_TRISTATE
+
+		The code necessary to make the I2C data line tri-stated
+		(inactive).  If the data line is open collector, this
+		define can be null.
+
+		I2C_READ
+
+		Code that returns TRUE if the I2C data line is high,
+		FALSE if it is low.
+
+		I2C_SDA(bit)
+
+		If <bit> is TRUE, sets the I2C data line high. If it
+		is FALSE, it clears it (low).
+
+		I2C_SCL(bit)
+
+		If <bit> is TRUE, sets the I2C clock line high. If it
+		is FALSE, it clears it (low).
+
+		I2C_DELAY
+
+		This delay is invoked four times per clock cycle so this
+		controls the rate of data transfer.  The data rate thus
+		is 1 / (I2C_DELAY * 4).
+
+- SPI Support:	CONFIG_SPI
+
+		Enables SPI driver (so far only tested with
+		SPI EEPROM, also an instance works with Crystal A/D and
+		D/As on the SACSng board)
+
+		CONFIG_SPI_X
+
+		Enables extended (16-bit) SPI EEPROM addressing.
+		(symmetrical to CONFIG_I2C_X)
+
+		CONFIG_SOFT_SPI
+
+                Enables a software (bit-bang) SPI driver rather than
+                using hardware support. This is a general purpose
+                driver that only requires three general I/O port pins
+                (two outputs, one input) to function. If this is
+                defined, the board configuration must define several
+                SPI configuration items (port pins to use, etc). For
+                an example, see include/configs/sacsng.h.
+
+- FPGA Support: CONFIG_FPGA_COUNT
+
+                Specify the number of FPGA devices to support.
+
+                CONFIG_FPGA
+
+                Used to specify the types of FPGA devices. For
+		example,
+ 		#define CONFIG_FPGA  CFG_XILINX_VIRTEX2
+
+ 		CFG_FPGA_PROG_FEEDBACK
+
+                Enable printing of hash marks during FPGA
+		configuration.
+
+		CFG_FPGA_CHECK_BUSY
+
+                Enable checks on FPGA configuration interface busy
+                status by the configuration function. This option
+                will require a board or device specific function to
+                be written.
+
+		CONFIG_FPGA_DELAY
+
+                If defined, a function that provides delays in the
+                FPGA configuration driver.
+
+		CFG_FPGA_CHECK_CTRLC
+
+		Allow Control-C to interrupt FPGA configuration
+
+		CFG_FPGA_CHECK_ERROR
+
+                Check for configuration errors during FPGA bitfile
+                loading. For example, abort during Virtex II
+                configuration if the INIT_B line goes low (which
+                indicated a CRC error).
+
+		CFG_FPGA_WAIT_INIT
+
+                Maximum time to wait for the INIT_B line to deassert
+                after PROB_B has been deasserted during a Virtex II
+                FPGA configuration sequence. The default time is 500 mS.
+
+		CFG_FPGA_WAIT_BUSY
+
+                Maximum time to wait for BUSY to deassert during
+                Virtex II FPGA configuration. The default is 5 mS.
+
+		CFG_FPGA_WAIT_CONFIG
+
+                Time to wait after FPGA configuration. The default is
+		200 mS.
+
+- FPGA Support:	CONFIG_FPGA_COUNT
+
+ 		Specify the number of FPGA devices to support.
+
+ 		CONFIG_FPGA
+
+ 		Used to specify the types of FPGA devices.  For example,
+ 		#define CONFIG_FPGA  CFG_XILINX_VIRTEX2
+
+ 		CFG_FPGA_PROG_FEEDBACK
+
+ 		Enable printing of hash marks during FPGA configuration.
+
+		CFG_FPGA_CHECK_BUSY
+
+                Enable checks on FPGA configuration interface busy
+                status by the configuration function. This option
+                will require a board or device specific function to
+                be written.
+
+		CONFIG_FPGA_DELAY
+
+		If defined, a function that provides delays in the FPGA
+		configuration driver.
+
+		CFG_FPGA_CHECK_CTRLC
+		Allow Control-C to interrupt FPGA configuration
+
+		CFG_FPGA_CHECK_ERROR
+
+                Check for configuration errors during FPGA bitfile
+                loading. For example, abort during Virtex II
+                configuration if the INIT_B line goes low (which
+                indicated a CRC error).
+
+		CFG_FPGA_WAIT_INIT
+
+                Maximum time to wait for the INIT_B line to deassert
+                after PROB_B has been deasserted during a Virtex II
+                FPGA configuration sequence. The default time is 500
+                mS.
+
+		CFG_FPGA_WAIT_BUSY
+
+                Maximum time to wait for BUSY to deassert during
+                Virtex II FPGA configuration. The default is 5 mS.
+
+		CFG_FPGA_WAIT_CONFIG
+
+                Time to wait after FPGA configuration. The default is
+                200 mS.
+
+- Configuration Management:
+		CONFIG_IDENT_STRING
+
+                If defined, this string will be added to the U-Boot
+                version information (U_BOOT_VERSION)
+
+- Vendor Parameter Protection:
+
+                U-Boot considers the values of the environment
+                variables "serial#" (Board Serial Number) and
+                "ethaddr" (Ethernet Address) to bb parameters that
+                are set once by the board vendor / manufacturer, and
+                protects these variables from casual modification by
+                the user. Once set, these variables are read-only,
+                and write or delete attempts are rejected. You can
+                change this behviour:
+
+		If CONFIG_ENV_OVERWRITE is #defined in your config
+		file, the write protection for vendor parameters is
+		completely disabled. Anybody can change or delte
+		these parameters.
+
+		Alternatively, if you #define _both_ CONFIG_ETHADDR
+		_and_ CONFIG_OVERWRITE_ETHADDR_ONCE, a default
+		ethernet address is installed in the environment,
+		which can be changed exactly ONCE by the user. [The
+		serial# is unaffected by this, i. e. it remains
+		read-only.]
+
+- Protected RAM:
+		CONFIG_PRAM
+
+		Define this variable to enable the reservation of
+		"protected RAM", i. e. RAM which is not overwritten
+		by U-Boot. Define CONFIG_PRAM to hold the number of
+		kB you want to reserve for pRAM. You can overwrite
+		this default value by defining an environment
+		variable "pram" to the number of kB you want to
+		reserve. Note that the board info structure will
+		still show the full amount of RAM. If pRAM is
+		reserved, a new environment variable "mem" will
+		automatically be defined to hold the amount of
+		remaining RAM in a form that can be passed as boot
+		argument to Linux, for instance like that:
+
+			setenv bootargs ... mem=\$(mem)
+			saveenv
+
+		This way you can tell Linux not to use this memory,
+		either, which results in a memory region that will
+		not be affected by reboots.
+
+		*WARNING* If your board configuration uses automatic
+		detection of the RAM size, you must make sure that
+		this memory test is non-destructive. So far, the
+		following board configurations are known to be
+		"pRAM-clean":
+
+			ETX094, IVMS8, IVML24, SPD8xx, TQM8xxL,
+			HERMES, IP860, RPXlite, LWMON, LANTEC,
+			PCU_E, FLAGADM, TQM8260
+
+- Error Recovery:
+		CONFIG_PANIC_HANG
+
+		Define this variable to stop the system in case of a
+		fatal error, so that you have to reset it manually.
+		This is probably NOT a good idea for an embedded
+		system where you want to system to reboot
+		automatically as fast as possible, but it may be
+		useful during development since you can try to debug
+		the conditions that lead to the situation.
+
+		CONFIG_NET_RETRY_COUNT
+
+                This variable defines the number of retries for
+                network operations like ARP, RARP, TFTP, or BOOTP
+                before giving up the operation. If not defined, a
+                default value of 5 is used.
+
+- Command Interpreter:
+		CFG_HUSH_PARSER
+
+		Define this variable to enable the "hush" shell (from
+		Busybox) as command line interpreter, thus enabling
+		powerful command line syntax like
+		if...then...else...fi conditionals or `&&' and '||'
+		constructs ("shell scripts").
+
+		If undefined, you get the old, much simpler behaviour
+		with a somewhat smaller memory footprint.
+
+
+		CFG_PROMPT_HUSH_PS2
+
+		This defines the secondary prompt string, which is
+		printed when the command interpreter needs more input
+		to complete a command. Usually "> ".
+
+	Note:
+
+                In the current implementation, the local variables
+                space and global environment variables space are
+                separated. Local variables are those you define by
+                simply typing like `name=value'. To access a local
+                variable later on, you have write `$name' or
+                `${name}'; variable directly by typing say `$name' at
+                the command prompt.
+
+                Global environment variables are those you use
+                setenv/printenv to work with. To run a command stored
+                in such a variable, you need to use the run command,
+                and you must not use the '$' sign to access them.
+
+		To store commands and special characters in a
+		variable, please use double quotation marks
+		surrounding the whole text of the variable, instead
+		of the backslashes before semicolons and special
+		symbols.
+
+- Default Environment
+		CONFIG_EXTRA_ENV_SETTINGS
+
+                Define this to contain any number of null terminated
+                strings (variable = value pairs) that will be part of
+                the default enviroment compiled into the boot image.
+                For example, place something like this in your
+                board's config file:
+
+		#define CONFIG_EXTRA_ENV_SETTINGS \
+			"myvar1=value1\0" \
+			"myvar2=value2\0"
+
+                Warning: This method is based on knowledge about the
+                internal format how the environment is stored by the
+                U-Boot code. This is NOT an official, expoerted
+                interface! Although it is unlikely that this format
+                will change soon, there is no guarantee either.
+		You better know what you are doing here.
+
+                Note: overly (ab)use of the default environment is
+                discouraged. Make sure to check other ways to preset
+                the environment like the autoscript function or the
+                boot command first.
+
+- Show boot progress
+		CONFIG_SHOW_BOOT_PROGRESS
+
+                Defining this option allows to add some board-
+                specific code (calling a user-provided function
+                "show_boot_progress(int)") that enables you to show
+                the system's boot progress on some display (for
+                example, some LED's) on your board. At the moment,
+                the following checkpoints are implemented:
+
+  Arg	Where			When
+    1	common/cmd_bootm.c	before attempting to boot an image
+   -1	common/cmd_bootm.c	Image header has bad     magic number
+    2	common/cmd_bootm.c	Image header has correct magic number
+   -2	common/cmd_bootm.c	Image header has bad     checksum
+    3	common/cmd_bootm.c	Image header has correct checksum
+   -3	common/cmd_bootm.c	Image data   has bad     checksum
+    4	common/cmd_bootm.c	Image data   has correct checksum
+   -4	common/cmd_bootm.c	Image is for unsupported architecture
+    5	common/cmd_bootm.c	Architecture check OK
+   -5	common/cmd_bootm.c	Wrong Image Type (not kernel, multi, standalone)
+    6	common/cmd_bootm.c	Image Type check OK
+   -6	common/cmd_bootm.c	gunzip uncompression error
+   -7	common/cmd_bootm.c	Unimplemented compression type
+    7	common/cmd_bootm.c	Uncompression OK
+   -8	common/cmd_bootm.c	Wrong Image Type (not kernel, multi, standalone)
+    8	common/cmd_bootm.c	Image Type check OK
+   -9	common/cmd_bootm.c	Unsupported OS (not Linux, BSD, VxWorks, QNX)
+    9	common/cmd_bootm.c	Start initial ramdisk verification
+  -10	common/cmd_bootm.c	Ramdisk header has bad     magic number
+  -11	common/cmd_bootm.c	Ramdisk header has bad     checksum
+   10	common/cmd_bootm.c	Ramdisk header is OK
+  -12	common/cmd_bootm.c	Ramdisk data   has bad     checksum
+   11	common/cmd_bootm.c	Ramdisk data   has correct checksum
+   12	common/cmd_bootm.c	Ramdisk verification complete, start loading
+  -13	common/cmd_bootm.c	Wrong Image Type (not PPC Linux Ramdisk)
+   13	common/cmd_bootm.c	Start multifile image verification
+   14	common/cmd_bootm.c	No initial ramdisk, no multifile, continue.
+   15	common/cmd_bootm.c	All preparation done, transferring control to OS
+
+   -1	common/cmd_doc.c	Bad usage of "doc" command
+   -1	common/cmd_doc.c	No boot device
+   -1	common/cmd_doc.c	Unknown Chip ID on boot device
+   -1	common/cmd_doc.c	Read Error on boot device
+   -1	common/cmd_doc.c	Image header has bad magic number
+
+   -1	common/cmd_ide.c	Bad usage of "ide" command
+   -1	common/cmd_ide.c	No boot device
+   -1	common/cmd_ide.c	Unknown boot device
+   -1	common/cmd_ide.c	Unknown partition table
+   -1	common/cmd_ide.c	Invalid partition type
+   -1	common/cmd_ide.c	Read Error on boot device
+   -1	common/cmd_ide.c	Image header has bad magic number
+
+   -1	common/cmd_nvedit.c	Environment not changable, but has bad CRC
+
+
+Modem Support:
+--------------
+
+[so far only for SMDK2400 board]
+
+- Modem support endable:
+		CONFIG_MODEM_SUPPORT
+
+- RTS/CTS Flow control enable:
+		CONFIG_HWFLOW
+
+- Modem debug support:
+		CONFIG_MODEM_SUPPORT_DEBUG
+
+                Enables debugging stuff (char screen[1024], dbg())
+                for modem support. Useful only with BDI2000.
+
+- General:
+
+                In the target system modem support is enabled when a
+                specific key (key combination) is pressed during
+                power-on. Otherwise U-Boot will boot normally
+                (autoboot). The key_pressed() fuction is called from
+                board_init(). Currently key_pressed() is a dummy
+                function, returning 1 and thus enabling modem
+                initialization.
+
+                If there are no modem init strings in the
+                environment, U-Boot proceed to autoboot; the
+                previous output (banner, info printfs) will be
+                supressed, though.
+
+		See also: doc/README.Modem
+
+
+
+
+Configuration Settings:
+-----------------------
+
+- CFG_LONGHELP: Defined when you want long help messages included;
+		undefine this when you're short of memory.
+
+- CFG_PROMPT:	This is what U-Boot prints on the console to
+		prompt for user input.
+
+- CFG_CBSIZE:	Buffer size for input from the Console
+
+- CFG_PBSIZE:	Buffer size for Console output
+
+- CFG_MAXARGS:	max. Number of arguments accepted for monitor commands
+
+- CFG_BARGSIZE: Buffer size for Boot Arguments which are passed to
+		the application (usually a Linux kernel) when it is
+		booted
+
+- CFG_BAUDRATE_TABLE:
+		List of legal baudrate settings for this board.
+
+- CFG_CONSOLE_INFO_QUIET
+ 		Suppress display of console information at boot.
+
+- CFG_CONSOLE_IS_IN_ENV
+ 		If the board specific function
+ 			extern int overwrite_console (void);
+ 		returns 1, the stdin, stderr and stdout are switched to the
+		serial port, else the settings in the environment are used.
+
+- CFG_CONSOLE_OVERWRITE_ROUTINE
+ 		Enable the call to overwrite_console().
+
+- CFG_CONSOLE_ENV_OVERWRITE
+		Enable overwrite of previous console environment settings.
+
+- CFG_MEMTEST_START, CFG_MEMTEST_END:
+		Begin and End addresses of the area used by the
+		simple memory test.
+
+- CFG_ALT_MEMTEST:
+ 		Enable an alternate, more extensive memory test.
+
+- CFG_TFTP_LOADADDR:
+		Default load address for network file downloads
+
+- CFG_LOADS_BAUD_CHANGE:
+		Enable temporary baudrate change while serial download
+
+- CFG_SDRAM_BASE:
+		Physical start address of SDRAM. _Must_ be 0 here.
+
+- CFG_MBIO_BASE:
+		Physical start address of Motherboard I/O (if using a
+		Cogent motherboard)
+
+- CFG_FLASH_BASE:
+		Physical start address of Flash memory.
+
+- CFG_MONITOR_BASE:
+		Physical start address of boot monitor code (set by
+		make config files to be same as the text base address
+		(TEXT_BASE) used when linking) - same as
+		CFG_FLASH_BASE when booting from flash.
+
+- CFG_MONITOR_LEN:
+		Size of memory reserved for monitor code
+
+- CFG_MALLOC_LEN:
+		Size of DRAM reserved for malloc() use.
+
+- CFG_BOOTMAPSZ:
+		Maximum size of memory mapped by the startup code of
+		the Linux kernel; all data that must be processed by
+		the Linux kernel (bd_info, boot arguments, eventually
+		initrd image) must be put below this limit.
+
+- CFG_MAX_FLASH_BANKS:
+		Max number of Flash memory banks
+
+- CFG_MAX_FLASH_SECT:
+		Max number of sectors on a Flash chip
+
+- CFG_FLASH_ERASE_TOUT:
+		Timeout for Flash erase operations (in ms)
+
+- CFG_FLASH_WRITE_TOUT:
+		Timeout for Flash write operations (in ms)
+
+- CFG_DIRECT_FLASH_TFTP:
+
+		Enable TFTP transfers directly to flash memory;
+		without this option such a download has to be
+		performed in two steps: (1) download to RAM, and (2)
+		copy from RAM to flash.
+
+		The two-step approach is usually more reliable, since
+		you can check if the download worked before you erase
+		the flash, but in some situations (when sytem RAM is
+		too limited to allow for a tempory copy of the
+		downloaded image) this option may be very useful.
+
+- CFG_FLASH_CFI:
+                Define if the flash driver uses extra elements in the
+                common flash structure for storing flash geometry
+
+The following definitions that deal with the placement and management
+of environment data (variable area); in general, we support the
+following configurations:
+
+- CFG_ENV_IS_IN_FLASH:
+
+	Define this if the environment is in flash memory.
+
+	a) The environment occupies one whole flash sector, which is
+	   "embedded" in the text segment with the U-Boot code. This
+	   happens usually with "bottom boot sector" or "top boot
+	   sector" type flash chips, which have several smaller
+	   sectors at the start or the end. For instance, such a
+	   layout can have sector sizes of 8, 2x4, 16, Nx32 kB. In
+	   such a case you would place the environment in one of the
+	   4 kB sectors - with U-Boot code before and after it. With
+	   "top boot sector" type flash chips, you would put the
+	   environment in one of the last sectors, leaving a gap
+	   between U-Boot and the environment.
+
+	- CFG_ENV_OFFSET:
+
+	   Offset of environment data (variable area) to the
+	   beginning of flash memory; for instance, with bottom boot
+	   type flash chips the second sector can be used: the offset
+	   for this sector is given here.
+
+	   CFG_ENV_OFFSET is used relative to CFG_FLASH_BASE.
+
+	- CFG_ENV_ADDR:
+
+	   This is just another way to specify the start address of
+	   the flash sector containing the environment (instead of
+	   CFG_ENV_OFFSET).
+
+	- CFG_ENV_SECT_SIZE:
+
+	   Size of the sector containing the environment.
+
+
+	b) Sometimes flash chips have few, equal sized, BIG sectors.
+	   In such a case you don't want to spend a whole sector for
+	   the environment.
+
+	- CFG_ENV_SIZE:
+
+	   If you use this in combination with CFG_ENV_IS_IN_FLASH
+	   and CFG_ENV_SECT_SIZE, you can specify to use only a part
+	   of this flash sector for the environment. This saves
+	   memory for the RAM copy of the environment.
+
+	   It may also save flash memory if you decide to use this
+	   when your environment is "embedded" within U-Boot code,
+	   since then the remainder of the flash sector could be used
+	   for U-Boot code. It should be pointed out that this is
+	   STRONGLY DISCOURAGED from a robustness point of view:
+	   updating the environment in flash makes it always
+	   necessary to erase the WHOLE sector. If something goes
+	   wrong before the contents has been restored from a copy in
+	   RAM, your target system will be dead.
+
+	- CFG_ENV_ADDR_REDUND
+	  CFG_ENV_SIZE_REDUND
+
+           These settings describe a second storage area used to hold
+           a redundand copy of the environment data, so that there is
+           a valid backup copy in case there is a power failur during
+           a "saveenv" operation.
+
+BE CAREFUL! Any changes to the flash layout, and some changes to the
+source code will make it necessary to adapt <board>/u-boot.lds*
+accordingly!
+
+
+- CFG_ENV_IS_IN_NVRAM:
+
+	Define this if you have some non-volatile memory device
+	(NVRAM, battery buffered SRAM) which you want to use for the
+	environment.
+
+	- CFG_ENV_ADDR:
+	- CFG_ENV_SIZE:
+
+	  These two #defines are used to determin the memory area you
+	  want to use for environment. It is assumed that this memory
+	  can just be read and written to, without any special
+	  provision.
+
+BE CAREFUL! The first access to the environment happens quite early
+in U-Boot initalization (when we try to get the setting of for the
+console baudrate). You *MUST* have mappend your NVRAM area then, or
+U-Boot will hang.
+
+Please note that even with NVRAM we still use a copy of the
+environment in RAM: we could work on NVRAM directly, but we want to
+keep settings there always unmodified except somebody uses "saveenv"
+to save the current settings.
+
+
+- CFG_ENV_IS_IN_EEPROM:
+
+	Use this if you have an EEPROM or similar serial access
+	device and a driver for it.
+
+	- CFG_ENV_OFFSET:
+	- CFG_ENV_SIZE:
+
+	  These two #defines specify the offset and size of the
+	  environment area within the total memory of your EEPROM.
+
+	- CFG_I2C_EEPROM_ADDR:
+	  If defined, specified the chip address of the EEPROM device.
+	  The default address is zero.
+
+	- CFG_EEPROM_PAGE_WRITE_BITS:
+	  If defined, the number of bits used to address bytes in a
+	  single page in the EEPROM device.  A 64 byte page, for example
+	  would require six bits.
+
+	- CFG_EEPROM_PAGE_WRITE_DELAY_MS:
+	  If defined, the number of milliseconds to delay between
+	  page writes.  The default is zero milliseconds.
+
+	- CFG_I2C_EEPROM_ADDR_LEN:
+	  The length in bytes of the EEPROM memory array address.  Note
+	  that this is NOT the chip address length!
+
+	- CFG_EEPROM_SIZE:
+	  The size in bytes of the EEPROM device.
+
+	- CFG_I2C_EEPROM_ADDR:
+	  If defined, specified the chip address of the EEPROM device.
+	  The default address is zero.
+
+	- CFG_EEPROM_PAGE_WRITE_BITS:
+	  If defined, the number of bits used to address bytes in a
+	  single page in the EEPROM device.  A 64 byte page, for example
+	  would require six bits.
+
+	- CFG_EEPROM_PAGE_WRITE_DELAY_MS:
+	  If defined, the number of milliseconds to delay between
+	  page writes.  The default is zero milliseconds.
+
+	- CFG_I2C_EEPROM_ADDR_LEN:
+	  The length in bytes of the EEPROM memory array address.  Note
+	  that this is NOT the chip address length!
+
+	- CFG_EEPROM_SIZE:
+	  The size in bytes of the EEPROM device.
+
+- CFG_SPI_INIT_OFFSET
+
+	Defines offset to the initial SPI buffer area in DPRAM. The
+	area is used at an early stage (ROM part) if the environment
+	is configured to reside in the SPI EEPROM: We need a 520 byte
+	scratch DPRAM area. It is used between the two initialization
+	calls (spi_init_f() and spi_init_r()). A value of 0xB00 seems
+	to be a good choice since it makes it far enough from the
+	start of the data area as well as from the stack pointer.
+
+Please note that the environment is read-only as long as the monitor
+has been relocated to RAM and a RAM copy of the environment has been
+created; also, when using EEPROM you will have to use getenv_r()
+until then to read environment variables.
+
+The environment is now protected by a CRC32 checksum. Before the
+monitor is relocated into RAM, as a result of a bad CRC you will be
+working with the compiled-in default environment - *silently*!!!
+[This is necessary, because the first environment variable we need is
+the "baudrate" setting for the console - if we have a bad CRC, we
+don't have any device yet where we could complain.]
+
+Note: once the monitor has been relocated, then it will complain if
+the default environment is used; a new CRC is computed as soon as you
+use the "setenv" command to modify / delete / add any environment
+variable [even when you try to delete a non-existing variable!].
+
+Note2: you must edit your u-boot.lds file to reflect this
+configuration.
+
+
+Many of the options are named exactly as the corresponding Linux
+kernel configuration options. The intention is to make it easier to
+build a config tool - later.
+
+Low Level (hardware related) configuration options:
+
+- CFG_CACHELINE_SIZE:
+		Cache Line Size of the CPU.
+
+- CFG_DEFAULT_IMMR:
+		Default address of the IMMR after system reset.
+		Needed on some 8260 systems (MPC8260ADS and RPXsuper)
+		to be able to adjust the position of the IMMR
+		register after a reset.
+
+- CFG_IMMR:	Physical address of the Internal Memory Mapped
+		Register; DO NOT CHANGE! (11-4)
+		[MPC8xx systems only]
+
+- CFG_INIT_RAM_ADDR:
+
+		Start address of memory area tha can be used for
+		initial data and stack; please note that this must be
+		writable memory that is working WITHOUT special
+		initialization, i. e. you CANNOT use normal RAM which
+		will become available only after programming the
+		memory controller and running certain initialization
+		sequences.
+
+		U-Boot uses the following memory types:
+		- MPC8xx and MPC8260: IMMR (internal memory of the CPU)
+		- MPC824X: data cache
+		- PPC4xx:  data cache
+
+- CFG_INIT_DATA_OFFSET:
+
+		Offset of the initial data structure in the memory
+		area defined by CFG_INIT_RAM_ADDR. Usually
+		CFG_INIT_DATA_OFFSET is chosen such that the initial
+		data is located at the end of the available space
+		(sometimes written as (CFG_INIT_RAM_END -
+		CFG_INIT_DATA_SIZE), and the initial stack is just
+		below that area (growing from (CFG_INIT_RAM_ADDR +
+		CFG_INIT_DATA_OFFSET) downward.
+
+	Note:
+		On the MPC824X (or other systems that use the data
+		cache for initial memory) the address chosen for
+		CFG_INIT_RAM_ADDR is basically arbitrary - it must
+		point to an otherwise UNUSED address space between
+		the top of RAM and the start of the PCI space.
+
+- CFG_SIUMCR:	SIU Module Configuration (11-6)
+
+- CFG_SYPCR:	System Protection Control (11-9)
+
+- CFG_TBSCR:	Time Base Status and Control (11-26)
+
+- CFG_PISCR:	Periodic Interrupt Status and Control (11-31)
+
+- CFG_PLPRCR:	PLL, Low-Power, and Reset Control Register (15-30)
+
+- CFG_SCCR:	System Clock and reset Control Register (15-27)
+
+- CFG_OR_TIMING_SDRAM:
+		SDRAM timing
+
+- CFG_MAMR_PTA:
+		periodic timer for refresh
+
+- CFG_DER:	Debug Event Register (37-47)
+
+- FLASH_BASE0_PRELIM, FLASH_BASE1_PRELIM, CFG_REMAP_OR_AM,
+  CFG_PRELIM_OR_AM, CFG_OR_TIMING_FLASH, CFG_OR0_REMAP,
+  CFG_OR0_PRELIM, CFG_BR0_PRELIM, CFG_OR1_REMAP, CFG_OR1_PRELIM,
+  CFG_BR1_PRELIM:
+		Memory Controller Definitions: BR0/1 and OR0/1 (FLASH)
+
+- SDRAM_BASE2_PRELIM, SDRAM_BASE3_PRELIM, SDRAM_MAX_SIZE,
+  CFG_OR_TIMING_SDRAM, CFG_OR2_PRELIM, CFG_BR2_PRELIM,
+  CFG_OR3_PRELIM, CFG_BR3_PRELIM:
+		Memory Controller Definitions: BR2/3 and OR2/3 (SDRAM)
+
+- CFG_MAMR_PTA, CFG_MPTPR_2BK_4K, CFG_MPTPR_1BK_4K, CFG_MPTPR_2BK_8K,
+  CFG_MPTPR_1BK_8K, CFG_MAMR_8COL, CFG_MAMR_9COL:
+		Machine Mode Register and Memory Periodic Timer
+		Prescaler definitions (SDRAM timing)
+
+- CFG_I2C_UCODE_PATCH, CFG_I2C_DPMEM_OFFSET [0x1FC0]:
+		enable I2C microcode relocation patch (MPC8xx);
+		define relocation offset in DPRAM [DSP2]
+
+- CFG_SPI_UCODE_PATCH, CFG_SPI_DPMEM_OFFSET [0x1FC0]:
+		enable SPI microcode relocation patch (MPC8xx);
+		define relocation offset in DPRAM [SCC4]
+
+- CFG_USE_OSCCLK:
+		Use OSCM clock mode on MBX8xx board. Be careful,
+		wrong setting might damage your board. Read
+		doc/README.MBX before setting this variable!
+
+Building the Software:
+======================
+
+Building U-Boot has been tested in native PPC environments (on a
+PowerBook G3 running LinuxPPC 2000) and in cross environments
+(running RedHat 6.x and 7.x Linux on x86, Solaris 2.6 on a SPARC, and
+NetBSD 1.5 on x86).
+
+If you are not using a native PPC environment, it is assumed that you
+have the GNU cross compiling tools available in your path and named
+with a prefix of "powerpc-linux-". If this is not the case, (e.g. if
+you are using Monta Vista's Hard Hat Linux CDK 1.2) you must change
+the definition of CROSS_COMPILE in Makefile. For HHL on a 4xx CPU,
+change it to:
+
+	CROSS_COMPILE = ppc_4xx-
+
+
+U-Boot is intended to be  simple  to  build.  After  installing  the
+sources	 you must configure U-Boot for one specific board type. This
+is done by typing:
+
+	make NAME_config
+
+where "NAME_config" is the name of one of the existing
+configurations; the following names are supported:
+
+    ADCIOP_config	  GTH_config		TQM850L_config
+    ADS860_config	  IP860_config		TQM855L_config
+    AR405_config	  IVML24_config		TQM860L_config
+    CANBT_config	  IVMS8_config		WALNUT405_config
+    CPCI405_config	  LANTEC_config		cogent_common_config
+    CPCIISER4_config	  MBX_config		cogent_mpc8260_config
+    CU824_config	  MBX860T_config	cogent_mpc8xx_config
+    ESTEEM192E_config	  RPXlite_config	hermes_config
+    ETX094_config	  RPXsuper_config	hymod_config
+    FADS823_config	  SM850_config		lwmon_config
+    FADS850SAR_config	  SPD823TS_config	pcu_e_config
+    FADS860T_config	  SXNI855T_config	rsdproto_config
+    FPS850L_config	  Sandpoint8240_config	sbc8260_config
+    GENIETV_config	  TQM823L_config	PIP405_config
+    GEN860T_config	  EBONY_config
+
+Note: for some board special configuration names may exist; check  if
+      additional  information is available from the board vendor; for
+      instance, the TQM8xxL systems run normally at 50 MHz and use  a
+      SCC  for	10baseT	 ethernet; there are also systems with 80 MHz
+      CPU clock, and an optional Fast Ethernet	module	is  available
+      for  CPU's  with FEC. You can select such additional "features"
+      when chosing the configuration, i. e.
+
+      make TQM860L_config
+	- will configure for a plain TQM860L, i. e. 50MHz, no FEC
+
+      make TQM860L_FEC_config
+	- will configure for a TQM860L at 50MHz with FEC for ethernet
+
+      make TQM860L_80MHz_config
+	- will configure for a TQM860L at 80 MHz, with normal 10baseT
+	  interface
+
+      make TQM860L_FEC_80MHz_config
+	- will configure for a TQM860L at 80 MHz with FEC for ethernet
+
+      make TQM823L_LCD_config
+	- will configure for a TQM823L with U-Boot console on LCD
+
+      make TQM823L_LCD_80MHz_config
+	- will configure for a TQM823L at 80 MHz with U-Boot console on LCD
+
+      etc.
+
+
+
+Finally, type "make all", and you should  get  some  working  U-Boot
+images ready for downlod to / installation on your system:
+
+- "u-boot.bin" is a raw binary image
+- "u-boot" is an image in ELF binary format
+- "u-boot.srec" is in Motorola S-Record format
+
+
+Please be aware that the Makefiles assume you are using GNU make, so
+for instance on NetBSD you might need to use "gmake" instead of
+native "make".
+
+
+If the system board that you have is not listed, then you will need
+to port U-Boot to your hardware platform. To do this, follow these
+steps:
+
+1.  Add a new configuration option for your board to the toplevel
+    "Makefile", using the existing entries as examples.
+2.  Create a new directory to hold your board specific code. Add any
+    files you need.
+3.  If you're porting U-Boot to a new CPU, then also create a new
+    directory to hold your CPU specific code. Add any files you need.
+4.  Run "make config_name" with your new name.
+5.  Type "make", and you should get a working "u-boot.srec" file
+    to be installed on your target system.
+    [Of course, this last step is much harder than it sounds.]
+
+
+Testing of U-Boot Modifications, Ports to New Hardware, etc.:
+==============================================================
+
+If you have modified U-Boot sources (for instance added a new	board
+or  support  for  new  devices,	 a new CPU, etc.) you are expected to
+provide feedback to the other developers. The feedback normally takes
+the form of a "patch", i. e. a context diff against a certain (latest
+official or latest in CVS) version of U-Boot sources.
+
+But before you submit such a patch, please verify that	your  modifi-
+cation	did not break existing code. At least make sure that *ALL* of
+the supported boards compile WITHOUT ANY compiler warnings. To do so,
+just run the "MAKEALL" script, which will configure and build U-Boot
+for ALL supported system. Be warned, this will take a while. You  can
+select	which  (cross)	compiler  to use py passing a `CROSS_COMPILE'
+environment variable to the script, i. e. to use the cross tools from
+MontaVista's Hard Hat Linux you can type
+
+	CROSS_COMPILE=ppc_8xx- MAKEALL
+
+or to build on a native PowerPC system you can type
+
+	CROSS_COMPILE=' ' MAKEALL
+
+See also "U-Boot Porting Guide" below.
+
+
+
+Monitor Commands - Overview:
+============================
+
+go	- start application at address 'addr'
+run	- run commands in an environment variable
+bootm	- boot application image from memory
+bootp	- boot image via network using BootP/TFTP protocol
+tftpboot- boot image via network using TFTP protocol
+	       and env variables "ipaddr" and "serverip"
+	       (and eventually "gatewayip")
+rarpboot- boot image via network using RARP/TFTP protocol
+diskboot- boot from IDE devicebootd   - boot default, i.e., run 'bootcmd'
+loads	- load S-Record file over serial line
+loadb	- load binary file over serial line (kermit mode)
+md	- memory display
+mm	- memory modify (auto-incrementing)
+nm	- memory modify (constant address)
+mw	- memory write (fill)
+cp	- memory copy
+cmp	- memory compare
+crc32	- checksum calculation
+imd     - i2c memory display
+imm     - i2c memory modify (auto-incrementing)
+inm     - i2c memory modify (constant address)
+imw     - i2c memory write (fill)
+icrc32  - i2c checksum calculation
+iprobe  - probe to discover valid I2C chip addresses
+iloop   - infinite loop on address range
+isdram  - print SDRAM configuration information
+sspi    - SPI utility commands
+base	- print or set address offset
+printenv- print environment variables
+setenv	- set environment variables
+saveenv - save environment variables to persistent storage
+protect - enable or disable FLASH write protection
+erase	- erase FLASH memory
+flinfo	- print FLASH memory information
+bdinfo	- print Board Info structure
+iminfo	- print header information for application image
+coninfo - print console devices and informations
+ide	- IDE sub-system
+loop	- infinite loop on address range
+mtest	- simple RAM test
+icache	- enable or disable instruction cache
+dcache	- enable or disable data cache
+reset	- Perform RESET of the CPU
+echo	- echo args to console
+version - print monitor version
+help	- print online help
+?	- alias for 'help'
+
+
+Monitor Commands - Detailed Description:
+========================================
+
+TODO.
+
+For now: just type "help <command>".
+
+
+Environment Variables:
+======================
+
+U-Boot supports user configuration using Environment Variables which
+can be made persistent by saving to Flash memory.
+
+Environment Variables are set using "setenv", printed using
+"printenv", and saved to Flash using "saveenv". Using "setenv"
+without a value can be used to delete a variable from the
+environment. As long as you don't save the environment you are
+working with an in-memory copy. In case the Flash area containing the
+environment is erased by accident, a default environment is provided.
+
+Some configuration options can be set using Environment Variables:
+
+  baudrate	- see CONFIG_BAUDRATE
+
+  bootdelay	- see CONFIG_BOOTDELAY
+
+  bootcmd	- see CONFIG_BOOTCOMMAND
+
+  bootargs	- Boot arguments when booting an RTOS image
+
+  bootfile	- Name of the image to load with TFTP
+
+  autoload	- if set to "no" (any string beginning with 'n'),
+		  "bootp" will just load perform a lookup of the
+		  configuration from the BOOTP server, but not try to
+		  load any image using TFTP
+
+  autostart	- if set to "yes", an image loaded using the "bootp",
+		  "rarpboot", "tftpboot" or "diskboot" commands will
+		  be automatically started (by internally calling
+		  "bootm")
+
+  initrd_high	- restrict positioning of initrd images:
+		  If this variable is not set, initrd images will be
+		  copied to the highest possible address in RAM; this
+		  is usually what you want since it allows for
+		  maximum initrd size. If for some reason you want to
+		  make sure that the initrd image is loaded below the
+		  CFG_BOOTMAPSZ limit, you can set this environment
+		  variable to a value of "no" or "off" or "0".
+		  Alternatively, you can set it to a maximum upper
+		  address to use (U-Boot will still check that it
+		  does not overwrite the U-Boot stack and data).
+
+		  For instance, when you have a system with 16 MB
+		  RAM, and want to reseve 4 MB from use by Linux,
+		  you can do this by adding "mem=12M" to the value of
+		  the "bootargs" variable. However, now you must make
+		  sure, that the initrd image is placed in the first
+		  12 MB as well - this can be done with
+
+		  setenv initrd_high 00c00000
+
+  ipaddr	- IP address; needed for tftpboot command
+
+  loadaddr	- Default load address for commands like "bootp",
+		  "rarpboot", "tftpboot" or "diskboot"
+
+  loads_echo	- see CONFIG_LOADS_ECHO
+
+  serverip	- TFTP server IP address; needed for tftpboot command
+
+  bootretry	- see CONFIG_BOOT_RETRY_TIME
+
+  bootdelaykey	- see CONFIG_AUTOBOOT_DELAY_STR
+
+  bootstopkey	- see CONFIG_AUTOBOOT_STOP_STR
+
+
+The following environment variables may be used and automatically
+updated by the network boot commands ("bootp" and "rarpboot"),
+depending the information provided by your boot server:
+
+  bootfile	- see above
+  dnsip		- IP address of your Domain Name Server
+  gatewayip	- IP address of the Gateway (Router) to use
+  hostname	- Target hostname
+  ipaddr	- see above
+  netmask	- Subnet Mask
+  rootpath	- Pathname of the root filesystem on the NFS server
+  serverip	- see above
+
+
+There are two special Environment Variables:
+
+  serial#	- contains hardware identification information such
+		  as type string and/or serial number
+  ethaddr	- Ethernet address
+
+These variables can be set only once (usually during manufacturing of
+the board). U-Boot refuses to delete or overwrite these variables
+once they have been set once.
+
+
+Please note that changes to some configuration parameters may take
+only effect after the next boot (yes, that's just like Windoze :-).
+
+
+Note for Redundant Ethernet Interfaces:
+=======================================
+
+Some boards come with redundand ethernet interfaces; U-Boot supports
+such configurations and is capable of automatic selection of a
+"working" interface when needed. MAC assignemnt works as follows:
+
+Network interfaces are numbered eth0, eth1, eth2, ... Corresponding
+MAC addresses can be stored in the environment as "ethaddr" (=>eth0),
+"eth1addr" (=>eth1), "eth2addr", ...
+
+If the network interface stores some valid MAC address (for instance
+in SROM), this is used as default address if there is NO correspon-
+ding setting in the environment; if the corresponding environment
+variable is set, this overrides the settings in the card; that means:
+
+o If the SROM has a valid MAC address, and there is no address in the
+  environment, the SROM's address is used.
+
+o If there is no valid address in the SROM, and a definition in the
+  environment exists, then the value from the environment variable is
+  used.
+
+o If both the SROM and the environment contain a MAC address, and
+  both addresses are the same, this MAC address is used.
+
+o If both the SROM and the environment contain a MAC address, and the
+  addresses differ, the value from the environment is used and a
+  warning is printed.
+
+o If neither SROM nor the environment contain a MAC address, an error
+  is raised.
+
+
+
+Image Formats:
+==============
+
+The "boot" commands of this monitor operate on "image" files which
+can be basicly anything, preceeded by a special header; see the
+definitions in include/image.h for details; basicly, the header
+defines the following image properties:
+
+* Target Operating System (Provisions for OpenBSD, NetBSD, FreeBSD,
+  4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks,
+  LynxOS, pSOS, QNX;
+  Currently supported: Linux, NetBSD, VxWorks, QNX).
+* Target CPU Architecture (Provisions for Alpha, ARM, Intel x86,
+  IA64, MIPS, MIPS, PowerPC, IBM S390, SuperH, Sparc, Sparc 64 Bit;
+  Currently supported: PowerPC).
+* Compression Type (Provisions for uncompressed, gzip, bzip2;
+  Currently supported: uncompressed, gzip).
+* Load Address
+* Entry Point
+* Image Name
+* Image Timestamp
+
+The header is marked by a special Magic Number, and both the header
+and the data portions of the image are secured against corruption by
+CRC32 checksums.
+
+
+Linux Support:
+==============
+
+Although U-Boot should support any OS or standalone application
+easily, Linux has always been in the focus during the design of
+U-Boot.
+
+U-Boot includes many features that so far have been part of some
+special "boot loader" code within the Linux kernel. Also, any
+"initrd" images to be used are no longer part of one big Linux image;
+instead, kernel and "initrd" are separate images. This implementation
+serves serveral purposes:
+
+- the same features can be used for other OS or standalone
+  applications (for instance: using compressed images to reduce the
+  Flash memory footprint)
+
+- it becomes much easier to port new Linux kernel versions because
+  lots of low-level, hardware dependend stuff are done by U-Boot
+
+- the same Linux kernel image can now be used with different "initrd"
+  images; of course this also means that different kernel images can
+  be run with the same "initrd". This makes testing easier (you don't
+  have to build a new "zImage.initrd" Linux image when you just
+  change a file in your "initrd"). Also, a field-upgrade of the
+  software is easier now.
+
+
+Linux HOWTO:
+============
+
+Porting Linux to U-Boot based systems:
+---------------------------------------
+
+U-Boot cannot save you from doing all the necessary modifications to
+configure the Linux device drivers for use with your target hardware
+(no, we don't intend to provide a full virtual machine interface to
+Linux :-).
+
+But now you can ignore ALL boot loader code (in arch/ppc/mbxboot).
+
+Just make sure your machine specific header file (for instance
+include/asm-ppc/tqm8xx.h) includes the same definition of the Board
+Information structure as we define in include/u-boot.h, and make
+sure that your definition of IMAP_ADDR uses the same value as your
+U-Boot configuration in CFG_IMMR.
+
+
+Configuring the Linux kernel:
+-----------------------------
+
+No specific requirements for U-Boot. Make sure you have some root
+device (initial ramdisk, NFS) for your target system.
+
+
+Building a Linux Image:
+-----------------------
+
+No specific requirements for U-Boot. There is no need to add a
+"ramdisk.image.gz" file when building the kernel, even when you
+intend to run it with initial ramdisk.
+
+Example:
+
+	make TQM850L_config
+	make oldconfig
+	make dep
+	make zImage
+
+However, we don't use the 'zImage' (= 'arch/ppc/mbxboot/zvmlinux') we
+build this way. The 'zImage' includes the old boot loader code which
+we don't ned any more. Instead, we use the raw (compressed) Linux
+kernel image in 'arch/ppc/coffboot/vmlinux.gz'.
+
+There is a special tool (in 'tools/mkimage') to encapsulate this
+image with header information, CRC32 checksum etc. for use with
+U-Boot:
+
+In the first form (with "-l" option) mkimage  lists  the  information
+contained  in  the header of an existing U-Boot image; this includes
+checksum verification:
+
+	tools/mkimage -l image
+	  -l ==> list image header information
+
+The second form (with "-d" option) is used to build a U-Boot image
+from a "data file" which is used as image payload:
+
+	tools/mkimage -A arch -O os -T type -C comp -a addr -e ep \
+		      -n name -d data_file image
+	  -A ==> set architecture to 'arch'
+	  -O ==> set operating system to 'os'
+	  -T ==> set image type to 'type'
+	  -C ==> set compression type 'comp'
+	  -a ==> set load address to 'addr' (hex)
+	  -e ==> set entry point to 'ep' (hex)
+	  -n ==> set image name to 'name'
+	  -d ==> use image data from 'datafile'
+
+Right now, all Linux kernels use the same load address	(0x00000000),
+but the entry point address depends on the kernel version:
+
+- 2.2.x kernels have the entry point at 0x0000000C,
+- 2.3.x and 2.4.x kernels have the entry point at 0x00000000.
+
+So a typical call to build a U-Boot image would read:
+
+	-> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
+	> -A ppc -O linux -T kernel -C gzip -a 00000000 -e 0000000C \
+	> -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz \
+	> examples/image-2.2.13-initrd
+	Image Name:   2.2.13 for initrd on TQM850L
+	Created:      Wed Jul 19 02:34:59 2000
+	Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+	Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
+	Load Address: 0x00000000
+	Entry Point:  0x0000000c
+
+To verify the contents of the image (or check for corruption):
+
+	-> tools/mkimage -l examples/image-2.2.13-initrd
+	Image Name:   2.2.13 for initrd on TQM850L
+	Created:      Wed Jul 19 02:34:59 2000
+	Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+	Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
+	Load Address: 0x00000000
+	Entry Point:  0x0000000c
+
+NOTE: for embedded systems where boot time is critical you can trade
+speed for memory and install an UNCOMPRESSED image instead: this
+needs more space in Flash, but boots much faster since it does not
+need to be uncompressed:
+
+	-> gunzip /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz
+	-> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
+	> -A ppc -O linux -T kernel -C none -a 00000000 -e 0000000C \
+	> -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux \
+	> examples/image-2.2.13-initrd-uncompressed
+	Image Name:   2.2.13 for initrd on TQM850L
+	Created:      Wed Jul 19 02:34:59 2000
+	Image Type:   PowerPC Linux Kernel Image (uncompressed)
+	Data Size:    792160 Bytes = 773.59 kB = 0.76 MB
+	Load Address: 0x00000000
+	Entry Point:  0x0000000c
+
+
+Similar you can build U-Boot images from a 'ramdisk.image.gz' file
+when your kernel is intended to use an initial ramdisk:
+
+	-> tools/mkimage -n 'Simple Ramdisk Image' \
+	> -A ppc -O linux -T ramdisk -C gzip \
+	> -d /LinuxPPC/images/SIMPLE-ramdisk.image.gz examples/simple-initrd
+	Image Name:   Simple Ramdisk Image
+	Created:      Wed Jan 12 14:01:50 2000
+	Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
+	Data Size:    566530 Bytes = 553.25 kB = 0.54 MB
+	Load Address: 0x00000000
+	Entry Point:  0x00000000
+
+
+Installing a Linux Image:
+-------------------------
+
+To downloading a U-Boot image over the serial (console) interface,
+you must convert the image to S-Record format:
+
+	objcopy -I binary -O srec examples/image examples/image.srec
+
+The 'objcopy' does not understand the information in the U-Boot
+image header, so the resulting S-Record file will be relative to
+address 0x00000000. To load it to a given address, you need to
+specify the target address as 'offset' parameter with the 'loads'
+command.
+
+Example: install the image to address 0x40100000 (which on the
+TQM8xxL is in the first Flash bank):
+
+	=> erase 40100000 401FFFFF
+
+	.......... done
+	Erased 8 sectors
+
+	=> loads 40100000
+	## Ready for S-Record download ...
+	~>examples/image.srec
+	1 2 3 4 5 6 7 8 9 10 11 12 13 ...
+	...
+	15989 15990 15991 15992
+	[file transfer complete]
+	[connected]
+	## Start Addr = 0x00000000
+
+
+You can check the success of the download using the 'iminfo' command;
+this includes a checksum verification so you  can  be  sure  no	 data
+corruption happened:
+
+	=> imi 40100000
+
+	## Checking Image at 40100000 ...
+	   Image Name:	 2.2.13 for initrd on TQM850L
+	   Image Type:	 PowerPC Linux Kernel Image (gzip compressed)
+	   Data Size:	 335725 Bytes = 327 kB = 0 MB
+	   Load Address: 00000000
+	   Entry Point:	 0000000c
+	   Verifying Checksum ... OK
+
+
+
+Boot Linux:
+-----------
+
+The "bootm" command is used to boot an application that is stored in
+memory (RAM or Flash). In case of a Linux kernel image, the contents
+of the "bootargs" environment variable is passed to the kernel as
+parameters. You can check and modify this variable using the
+"printenv" and "setenv" commands:
+
+
+	=> printenv bootargs
+	bootargs=root=/dev/ram
+
+	=> setenv bootargs root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+
+	=> printenv bootargs
+	bootargs=root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+
+	=> bootm 40020000
+	## Booting Linux kernel at 40020000 ...
+	   Image Name:	 2.2.13 for NFS on TQM850L
+	   Image Type:	 PowerPC Linux Kernel Image (gzip compressed)
+	   Data Size:	 381681 Bytes = 372 kB = 0 MB
+	   Load Address: 00000000
+	   Entry Point:	 0000000c
+	   Verifying Checksum ... OK
+	   Uncompressing Kernel Image ... OK
+	Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:35:17 MEST 2000
+	Boot arguments: root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+	time_init: decrementer frequency = 187500000/60
+	Calibrating delay loop... 49.77 BogoMIPS
+	Memory: 15208k available (700k kernel code, 444k data, 32k init) [c0000000,c1000000]
+	...
+
+If you want to boot a Linux kernel with initial ram disk, you pass
+the memory addreses of both the kernel and the initrd image (PPBCOOT
+format!) to the "bootm" command:
+
+	=> imi 40100000 40200000
+
+	## Checking Image at 40100000 ...
+	   Image Name:	 2.2.13 for initrd on TQM850L
+	   Image Type:	 PowerPC Linux Kernel Image (gzip compressed)
+	   Data Size:	 335725 Bytes = 327 kB = 0 MB
+	   Load Address: 00000000
+	   Entry Point:	 0000000c
+	   Verifying Checksum ... OK
+
+	## Checking Image at 40200000 ...
+	   Image Name:	 Simple Ramdisk Image
+	   Image Type:	 PowerPC Linux RAMDisk Image (gzip compressed)
+	   Data Size:	 566530 Bytes = 553 kB = 0 MB
+	   Load Address: 00000000
+	   Entry Point:	 00000000
+	   Verifying Checksum ... OK
+
+	=> bootm 40100000 40200000
+	## Booting Linux kernel at 40100000 ...
+	   Image Name:	 2.2.13 for initrd on TQM850L
+	   Image Type:	 PowerPC Linux Kernel Image (gzip compressed)
+	   Data Size:	 335725 Bytes = 327 kB = 0 MB
+	   Load Address: 00000000
+	   Entry Point:	 0000000c
+	   Verifying Checksum ... OK
+	   Uncompressing Kernel Image ... OK
+	## Loading RAMDisk Image at 40200000 ...
+	   Image Name:	 Simple Ramdisk Image
+	   Image Type:	 PowerPC Linux RAMDisk Image (gzip compressed)
+	   Data Size:	 566530 Bytes = 553 kB = 0 MB
+	   Load Address: 00000000
+	   Entry Point:	 00000000
+	   Verifying Checksum ... OK
+	   Loading Ramdisk ... OK
+	Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:32:08 MEST 2000
+	Boot arguments: root=/dev/ram
+	time_init: decrementer frequency = 187500000/60
+	Calibrating delay loop... 49.77 BogoMIPS
+	...
+	RAMDISK: Compressed image found at block 0
+	VFS: Mounted root (ext2 filesystem).
+
+	bash#
+
+
+Standalone HOWTO:
+=================
+
+One of the features of U-Boot is that you can dynamically load and
+run "standalone" applications, which can use some resources of
+U-Boot like console I/O functions or interrupt services.
+
+Two simple examples are included with the sources:
+
+"Hello World" Demo:
+-------------------
+
+'examples/hello_world.c' contains a small "Hello World" Demo
+application; it is automatically compiled when you build U-Boot.
+It's configured to run at address 0x00040004, so you can play with it
+like that:
+
+	=> loads
+	## Ready for S-Record download ...
+	~>examples/hello_world.srec
+	1 2 3 4 5 6 7 8 9 10 11 ...
+	[file transfer complete]
+	[connected]
+	## Start Addr = 0x00040004
+
+	=> go 40004 Hello World! This is a test.
+	## Starting application at 0x00040004 ...
+	Hello World
+	argc = 7
+	argv[0] = "40004"
+	argv[1] = "Hello"
+	argv[2] = "World!"
+	argv[3] = "This"
+	argv[4] = "is"
+	argv[5] = "a"
+	argv[6] = "test."
+	argv[7] = "<NULL>"
+	Hit any key to exit ...
+
+	## Application terminated, rc = 0x0
+
+Another example, which demonstrates how to register a CPM interrupt
+handler with the U-Boot code, can be found in 'examples/timer.c'.
+Here, a CPM timer is set up to generate an interrupt every second.
+The interrupt service routine is trivial, just printing a '.'
+character, but this is just a demo program. The application can be
+controlled by the following keys:
+
+	? - print current values og the CPM Timer registers
+	b - enable interrupts and start timer
+	e - stop timer and disable interrupts
+	q - quit application
+
+	=> loads
+	## Ready for S-Record download ...
+	~>examples/timer.srec
+	1 2 3 4 5 6 7 8 9 10 11 ...
+	[file transfer complete]
+	[connected]
+	## Start Addr = 0x00040004
+
+	=> go 40004
+	## Starting application at 0x00040004 ...
+	TIMERS=0xfff00980
+	Using timer 1
+	  tgcr @ 0xfff00980, tmr @ 0xfff00990, trr @ 0xfff00994, tcr @ 0xfff00998, tcn @ 0xfff0099c, ter @ 0xfff009b0
+
+Hit 'b':
+	[q, b, e, ?] Set interval 1000000 us
+	Enabling timer
+Hit '?':
+	[q, b, e, ?] ........
+	tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0xef6, ter=0x0
+Hit '?':
+	[q, b, e, ?] .
+	tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x2ad4, ter=0x0
+Hit '?':
+	[q, b, e, ?] .
+	tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x1efc, ter=0x0
+Hit '?':
+	[q, b, e, ?] .
+	tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x169d, ter=0x0
+Hit 'e':
+	[q, b, e, ?] ...Stopping timer
+Hit 'q':
+	[q, b, e, ?] ## Application terminated, rc = 0x0
+
+
+NetBSD Notes:
+=============
+
+Starting at version 0.9.2, U-Boot supports NetBSD both as host
+(build U-Boot) and target system (boots NetBSD/mpc8xx).
+
+Building requires a cross environment; it is known to work on
+NetBSD/i386 with the cross-powerpc-netbsd-1.3 package (you will also
+need gmake since the Makefiles are not compatible with BSD make).
+Note that the cross-powerpc package does not install include files;
+attempting to build U-Boot will fail because <machine/ansi.h> is
+missing.  This file has to be installed and patched manually:
+
+	# cd /usr/pkg/cross/powerpc-netbsd/include
+	# mkdir powerpc
+	# ln -s powerpc machine
+	# cp /usr/src/sys/arch/powerpc/include/ansi.h powerpc/ansi.h
+	# ${EDIT} powerpc/ansi.h	## must remove __va_list, _BSD_VA_LIST
+
+Native builds *don't* work due to incompatibilities between native
+and U-Boot include files.
+
+Booting assumes that (the first part of) the image booted is a
+stage-2 loader which in turn loads and then invokes the kernel
+proper. Loader sources will eventually appear in the NetBSD source
+tree (probably in sys/arc/mpc8xx/stand/u-boot_stage2/); in the
+meantime, send mail to bruno@exet-ag.de and/or wd@denx.de for
+details.
+
+
+Implementation Internals:
+=========================
+
+The following is not intended to be a complete description of every
+implementation detail. However, it should help to understand the
+inner workings of U-Boot and make it easier to port it to custom
+hardware.
+
+
+Initial Stack, Global Data:
+---------------------------
+
+The implementation of U-Boot is complicated by the fact that U-Boot
+starts running out of ROM (flash memory), usually without access to
+system RAM (because the memory controller is not initialized yet).
+This means that we don't have writable Data or BSS segments, and BSS
+is not initialized as zero. To be able to get a C environment working
+at all, we have to allocate at least a minimal stack. Implementation
+options for this are defined and restricted by the CPU used: Some CPU
+models provide on-chip memory (like the IMMR area on MPC8xx and
+MPC826x processors), on others (parts of) the data cache can be
+locked as (mis-) used as memory, etc.
+
+It is essential to remember this, since it has some impact on the C
+code for the initialization procedures:
+
+* Initialized global data (data segment) is read-only. Do not attempt
+  to write it.
+
+* Do not use any unitialized global data (or implicitely initialized
+  as zero data - BSS segment) at all - this is undefined, initiali-
+  zation is performed later (when relocationg to RAM).
+
+* Stack space is very limited. Avoid big data buffers or things  like
+  that.
+
+Having only the stack as writable memory limits means we cannot use
+normal global data to share information beween the code. But it
+turned out that the implementation of U-Boot can be greatly
+simplified by making a global data structure (gd_t) available to all
+functions. We could pass a pointer to this data as argument to _all_
+functions, but this would bloat the code. Instead we use a feature of
+the GCC compiler (Global Register Variables) to share the data: we
+place a pointer (gd) to the global data into a register which we
+reserve for this purpose.
+
+When chosing a register for such a purpose we are restricted  by  the
+relevant  (E)ABI  specifications for the current architecture, and by
+GCC's implementation.
+
+For PowerPC, the following registers have specific use:
+	R1:	stack pointer
+	R2:	TOC pointer
+	R3-R4:	parameter passing and return values
+	R5-R10:	parameter passing
+	R13:	small data area pointer
+	R30:	GOT pointer
+	R31:	frame pointer
+
+	(U-Boot also uses R14 as internal GOT pointer.)
+
+    ==> U-Boot will use R29 to hold a pointer to the global data
+
+    Note: on PPC, we could use a static initializer (since the
+    address of the global data structure is known at compile time),
+    but it turned out that reserving a register results in somewhat
+    smaller code - although the code savings are not that big (on
+    average for all boards 752 bytes for the whole U-Boot image,
+    624 text + 127 data).
+
+On ARM, the following registers are used:
+
+	R0:	function argument word/integer result
+	R1-R3:	function argument word
+	R9:	GOT pointer
+	R10:	stack limit (used only if stack checking if enabled)
+	R11:	argument (frame) pointer
+	R12:	temporary workspace
+	R13:	stack pointer
+	R14:	link register
+	R15:	program counter
+
+    ==> U-Boot will use R8 to hold a pointer to the global data
+
+
+
+Memory Management:
+------------------
+
+U-Boot runs in system state and uses physical addresses, i.e. the
+MMU is not used either for address mapping nor for memory protection.
+
+The available memory is mapped to fixed addresses using the memory
+controller. In this process, a contiguous block is formed for each
+memory type (Flash, SDRAM, SRAM), even when it consists of several
+physical memory banks.
+
+U-Boot is installed in the first 128 kB of the first Flash bank (on
+TQM8xxL modules this is the range 0x40000000 ... 0x4001FFFF). After
+booting and sizing and initializing DRAM, the code relocates itself
+to the upper end of DRAM. Immediately below the U-Boot code some
+memory is reserved for use by malloc() [see CFG_MALLOC_LEN
+configuration setting]. Below that, a structure with global Board
+Info data is placed, followed by the stack (growing downward).
+
+Additionally, some exception handler code is copied to the low 8 kB
+of DRAM (0x00000000 ... 0x00001FFF).
+
+So a typical memory configuration with 16 MB of DRAM could look like
+this:
+
+	0x0000 0000	Exception Vector code
+	      :
+	0x0000 1FFF
+	0x0000 2000	Free for Application Use
+	      :
+	      :
+
+	      :
+	      :
+	0x00FB FF20	Monitor Stack (Growing downward)
+	0x00FB FFAC	Board Info Data and permanent copy of global data
+	0x00FC 0000	Malloc Arena
+	      :
+	0x00FD FFFF
+	0x00FE 0000	RAM Copy of Monitor Code
+	...		eventually: LCD or video framebuffer
+	...		eventually: pRAM (Protected RAM - unchanged by reset)
+	0x00FF FFFF	[End of RAM]
+
+
+System Initialization:
+----------------------
+
+In the reset configuration, U-Boot starts at the reset entry point
+(on most PowerPC systens at address 0x00000100). Because of the reset
+configuration for CS0# this is a mirror of the onboard Flash memory.
+To be able to re-map memory U-Boot then jumps to it's link address.
+To be able to implement the initialization code in C, a (small!)
+initial stack is set up in the internal Dual Ported RAM (in case CPUs
+which provide such a feature like MPC8xx or MPC8260), or in a locked
+part of the data cache. After that, U-Boot initializes the CPU core,
+the caches and the SIU.
+
+Next, all (potentially) available memory banks are mapped using a
+preliminary mapping. For example, we put them on 512 MB boundaries
+(multiples of 0x20000000: SDRAM on 0x00000000 and 0x20000000, Flash
+on 0x40000000 and 0x60000000, SRAM on 0x80000000). Then UPM A is
+programmed for SDRAM access. Using the temporary configuration, a
+simple memory test is run that determines the size of the SDRAM
+banks.
+
+When there is more than one SDRAM bank, and the banks are of
+different size, the larger is mapped first. For equal size, the first
+bank (CS2#) is mapped first. The first mapping is always for address
+0x00000000, with any additional banks following immediately to create
+contiguous memory starting from 0.
+
+Then, the monitor installs itself at the upper end of the SDRAM area
+and allocates memory for use by malloc() and for the global Board
+Info data; also, the exception vector code is copied to the low RAM
+pages, and the final stack is set up.
+
+Only after this relocation will you have a "normal" C environment;
+until that you are restricted in several ways, mostly because you are
+running from ROM, and because the code will have to be relocated to a
+new address in RAM.
+
+
+U-Boot Porting Guide:
+----------------------
+
+[Based on messages by Jerry Van Baren in the U-Boot-Users mailing
+list, Octover 2002]
+
+
+int main (int argc, char *argv[])
+{
+	sighandler_t no_more_time;
+
+	signal (SIGALRM, no_more_time);
+	alarm (PROJECT_DEADLINE - toSec (3 * WEEK));
+
+	if (available_money > available_manpower) {
+		pay consultant to port U-Boot;
+		return 0;
+	}
+
+	Download latest U-Boot source;
+
+	if (clueless) {
+		email ("Hi, I am new to U-Boot, how do I get started?");
+	}
+
+	while (learning) {
+		Read the README file in the top level directory;
+		Read http://www.denx.de/re/DPLG.html
+		Read the source, Luke;
+	}
+
+	if (available_money > toLocalCurrency ($2500)) {
+		Buy a BDI2000;
+	} else {
+		Add a lot of aggravation and time;
+	}
+
+	Create your own board support subdirectory;
+
+	while (!running) {
+		do {
+			Add / modify source code;
+		} until (compiles);
+		Debug;
+		if (clueless)
+			email ("Hi, I am having problems...");
+	}
+	Send patch file to Wolfgang;
+
+	return 0;
+}
+
+void no_more_time (int sig)
+{
+      hire_a_guru();
+}
+
+
+
+Coding Standards:
+-----------------
+
+All contributions to U-Boot should conform to the Linux kernel
+coding style; see the file "Documentation/CodingStyle" in your Linux
+kernel source directory.
+
+Please note that U-Boot is implemented in C (and to some small parts
+in Assembler); no C++ is used, so please do not use C++ style
+comments (//) in your code.
+
+Submissions which do not conform to the standards may be returned
+with a request to reformat the changes.
+
+
+Submitting Patches:
+-------------------
+
+Since the number of patches for U-Boot is growing, we need to
+establish some rules. Submissions which do not conform to these rules
+may be rejected, even when they contain important and valuable stuff.
+
+
+When you send a patch, please include the following information with
+it:
+
+* For bug fixes: a description of the bug and how your patch fixes
+  this bug. Please try to include a way of demonstrating that the
+  patch actually fixes something.
+
+* For new features: a description of the feature and your
+  implementation.
+
+* A CHANGELOG entry as plaintext (separate from the patch)
+
+* For major contributions, your entry to the CREDITS file
+
+* When you add support for a new board, don't forget to add this
+  board to the MAKEALL script, too.
+
+* If your patch adds new configuration options, don't forget to
+  document these in the README file.
+
+* The patch itself. If you are accessing the CVS repository use "cvs
+  update; cvs diff -puRN"; else, use "diff -purN OLD NEW". If your
+  version of diff does not support these options, then get the latest
+  version of GNU diff.
+
+  We accept patches as plain text, MIME attachments or as uuencoded
+  gzipped text.
+
+Notes:
+
+* Before sending the patch, run the MAKEALL script on your patched
+  source tree and make sure that no errors or warnings are reported
+  for any of the boards.
+
+* Keep your modifications to the necessary minimum: A patch
+  containing several unrelated changes or arbitrary reformats will be
+  returned with a request to re-formatting / split it.
+
+* If you modify existing code, make sure that your new code does not
+  add to the memory footprint of the code ;-) Small is beautiful!
+  When adding new features, these should compile conditionally only
+  (using #ifdef), and the resulting code with the new feature
+  disabled must not need more memory than the old code without your
+  modification.

+ 190 - 0
board/cogent/serial.c

@@ -0,0 +1,190 @@
+/*
+ * Simple serial driver for Cogent motherboard serial ports
+ * for use during boot
+ */
+
+#include <common.h>
+#include <board/cogent/serial.h>
+
+#if (CMA_MB_CAPS & CMA_MB_CAP_SERPAR)
+
+#if (defined(CONFIG_8xx) && defined(CONFIG_8xx_CONS_NONE)) || \
+     (defined(CONFIG_8260) && defined(CONFIG_CONS_NONE))
+
+#if CONFIG_CONS_INDEX == 1
+#define CMA_MB_SERIAL_BASE	CMA_MB_SERIALA_BASE
+#elif CONFIG_CONS_INDEX == 2
+#define CMA_MB_SERIAL_BASE	CMA_MB_SERIALB_BASE
+#elif CONFIG_CONS_INDEX == 3 && (CMA_MB_CAPS & CMA_MB_CAP_SER2)
+#define CMA_MB_SERIAL_BASE	CMA_MB_SER2A_BASE
+#elif CONFIG_CONS_INDEX == 4 && (CMA_MB_CAPS & CMA_MB_CAP_SER2)
+#define CMA_MB_SERIAL_BASE	CMA_MB_SER2B_BASE
+#else
+#error CONFIG_CONS_INDEX must be configured for Cogent motherboard serial
+#endif
+
+int serial_init (void)
+{
+/*  DECLARE_GLOBAL_DATA_PTR; */
+
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_SERIAL_BASE;
+
+    cma_mb_reg_write(&mbsp->ser_ier, 0x00);	/* turn off interrupts */
+    serial_setbrg ();
+    cma_mb_reg_write(&mbsp->ser_lcr, 0x03);	/* 8 data, 1 stop, no parity */
+    cma_mb_reg_write(&mbsp->ser_mcr, 0x03);	/* RTS/DTR */
+    cma_mb_reg_write(&mbsp->ser_fcr, 0x07);	/* Clear & enable FIFOs */
+
+    return (0);
+}
+
+void
+serial_setbrg (void)
+{
+    DECLARE_GLOBAL_DATA_PTR;
+
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_SERIAL_BASE;
+    unsigned int divisor;
+    unsigned char lcr;
+
+    if ((divisor = br_to_div(gd->baudrate)) == 0)
+	divisor = DEFDIV;
+
+    lcr = cma_mb_reg_read(&mbsp->ser_lcr);
+    cma_mb_reg_write(&mbsp->ser_lcr, lcr|0x80);/* Access baud rate(set DLAB)*/
+    cma_mb_reg_write(&mbsp->ser_brl, divisor & 0xff);
+    cma_mb_reg_write(&mbsp->ser_brh, (divisor >> 8) & 0xff);
+    cma_mb_reg_write(&mbsp->ser_lcr, lcr);	/* unset DLAB */
+}
+
+void
+serial_putc(const char c)
+{
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_SERIAL_BASE;
+
+    if (c == '\n')
+	serial_putc('\r');
+
+    while ((cma_mb_reg_read(&mbsp->ser_lsr) & LSR_THRE) == 0)
+	;
+
+    cma_mb_reg_write(&mbsp->ser_thr, c);
+}
+
+void
+serial_puts(const char *s)
+{
+    while (*s != '\0')
+	serial_putc(*s++);
+}
+
+int
+serial_getc(void)
+{
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_SERIAL_BASE;
+
+    while ((cma_mb_reg_read(&mbsp->ser_lsr) & LSR_DR) == 0)
+	;
+
+    return ((int)cma_mb_reg_read(&mbsp->ser_rhr) & 0x7f);
+}
+
+int
+serial_tstc(void)
+{
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_SERIAL_BASE;
+
+    return ((cma_mb_reg_read(&mbsp->ser_lsr) & LSR_DR) != 0);
+}
+
+#endif /* CONS_NONE */
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB) && \
+    defined(CONFIG_KGDB_NONE)
+
+#if CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX
+#error Console and kgdb are on the same serial port - this is not supported
+#endif
+
+#if CONFIG_KGDB_INDEX == 1
+#define CMA_MB_KGDB_SER_BASE	CMA_MB_SERIALA_BASE
+#elif CONFIG_KGDB_INDEX == 2
+#define CMA_MB_KGDB_SER_BASE	CMA_MB_SERIALB_BASE
+#elif CONFIG_KGDB_INDEX == 3 && (CMA_MB_CAPS & CMA_MB_CAP_SER2)
+#define CMA_MB_KGDB_SER_BASE	CMA_MB_SER2A_BASE
+#elif CONFIG_KGDB_INDEX == 4 && (CMA_MB_CAPS & CMA_MB_CAP_SER2)
+#define CMA_MB_KGDB_SER_BASE	CMA_MB_SER2B_BASE
+#else
+#error CONFIG_KGDB_INDEX must be configured for Cogent motherboard serial
+#endif
+
+void
+kgdb_serial_init(void)
+{
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_KGDB_SER_BASE;
+    unsigned int divisor;
+
+    if ((divisor = br_to_div(CONFIG_KGDB_BAUDRATE)) == 0)
+	divisor = DEFDIV;
+
+    cma_mb_reg_write(&mbsp->ser_ier, 0x00);	/* turn off interrupts */
+    cma_mb_reg_write(&mbsp->ser_lcr, 0x80);	/* Access baud rate(set DLAB)*/
+    cma_mb_reg_write(&mbsp->ser_brl, divisor & 0xff);
+    cma_mb_reg_write(&mbsp->ser_brh, (divisor >> 8) & 0xff);
+    cma_mb_reg_write(&mbsp->ser_lcr, 0x03);	/* 8 data, 1 stop, no parity */
+    cma_mb_reg_write(&mbsp->ser_mcr, 0x03);	/* RTS/DTR */
+    cma_mb_reg_write(&mbsp->ser_fcr, 0x07);	/* Clear & enable FIFOs */
+
+    printf("[on cma10x serial port B] ");
+}
+
+void
+putDebugChar(int c)
+{
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_KGDB_SER_BASE;
+
+    while ((cma_mb_reg_read(&mbsp->ser_lsr) & LSR_THRE) == 0)
+	;
+
+    cma_mb_reg_write(&mbsp->ser_thr, c & 0xff);
+}
+
+void
+putDebugStr(const char *str)
+{
+    while (*str != '\0') {
+	if (*str == '\n')
+	    putDebugChar('\r');
+	putDebugChar(*str++);
+    }
+}
+
+int
+getDebugChar(void)
+{
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_KGDB_SER_BASE;
+
+    while ((cma_mb_reg_read(&mbsp->ser_lsr) & LSR_DR) == 0)
+	;
+
+    return ((int)cma_mb_reg_read(&mbsp->ser_rhr) & 0x7f);
+}
+
+void
+kgdb_interruptible(int yes)
+{
+    cma_mb_serial *mbsp = (cma_mb_serial *)CMA_MB_KGDB_SER_BASE;
+
+    if (yes == 1) {
+	printf("kgdb: turning serial ints on\n");
+	cma_mb_reg_write(&mbsp->ser_ier, 0xf);
+    }
+    else {
+	printf("kgdb: turning serial ints off\n");
+	cma_mb_reg_write(&mbsp->ser_ier, 0x0);
+    }
+}
+
+#endif /* KGDB && KGDB_NONE */
+
+#endif /* CAPS & SERPAR */

+ 119 - 0
board/cu824/cu824.c

@@ -0,0 +1,119 @@
+/*
+ * (C) Copyright 2001
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
+ *
+ * (C) Copyright 2001, 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 <common.h>
+#include <mpc824x.h>
+#include <asm/processor.h>
+#include <pci.h>
+
+#define BOARD_REV_REG 0xFE80002B
+
+int checkboard (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	char  revision = *(volatile char *)(BOARD_REV_REG);
+	char  buf[32];
+
+	puts ("Board: CU824 ");
+	printf("Revision %d ", revision);
+	printf("Local Bus at %s MHz\n", strmhz(buf, gd->bus_clk));
+
+	return 0;
+}
+
+long int initdram(int board_type)
+{
+	int              i, cnt;
+	volatile uchar * base      = CFG_SDRAM_BASE;
+	volatile ulong * addr;
+	ulong            save[32];
+	ulong            val, ret  = 0;
+
+	for (i=0, cnt=(CFG_MAX_RAM_SIZE / sizeof(long)) >> 1; cnt > 0; cnt >>= 1) {
+		addr = (volatile ulong *)base + cnt;
+		save[i++] = *addr;
+		*addr = ~cnt;
+	}
+
+	addr = (volatile ulong *)base;
+	save[i] = *addr;
+	*addr = 0;
+
+	if (*addr != 0) {
+		*addr = save[i];
+		goto Done;
+	}
+
+	for (cnt = 1; cnt <= CFG_MAX_RAM_SIZE / sizeof(long); cnt <<= 1) {
+		addr = (volatile ulong *)base + cnt;
+		val = *addr;
+		*addr = save[--i];
+		if (val != ~cnt) {
+			ulong new_bank0_end = cnt * sizeof(long) - 1;
+			ulong mear1  = mpc824x_mpc107_getreg(MEAR1);
+			ulong emear1 = mpc824x_mpc107_getreg(EMEAR1);
+			mear1 =  (mear1  & 0xFFFFFF00) |
+			  ((new_bank0_end & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT);
+			emear1 = (emear1 & 0xFFFFFF00) |
+			  ((new_bank0_end & MICR_ADDR_MASK) >> MICR_EADDR_SHIFT);
+			mpc824x_mpc107_setreg(MEAR1,  mear1);
+			mpc824x_mpc107_setreg(EMEAR1, emear1);
+
+			ret = cnt * sizeof(long);
+			goto Done;
+		}
+	}
+
+	ret = CFG_MAX_RAM_SIZE;
+Done:
+	return ret;
+}
+
+/*
+ * Initialize PCI Devices, report devices found.
+ */
+#ifndef CONFIG_PCI_PNP
+static struct pci_config_table pci_sandpoint_config_table[] = {
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  PCI_BUS(CFG_ETH_DEV_FN), PCI_DEV(CFG_ETH_DEV_FN), PCI_FUNC(CFG_ETH_DEV_FN),
+	  pci_cfgfunc_config_device, { CFG_ETH_IOBASE,
+				       0,
+				       PCI_COMMAND_IO | PCI_COMMAND_MASTER }},
+	{ }
+};
+#endif
+
+struct pci_controller hose = {
+#ifndef CONFIG_PCI_PNP
+	config_table: pci_sandpoint_config_table,
+#endif
+};
+
+void pci_init(void)
+{
+	pci_mpc824x_init(&hose);
+}

+ 53 - 0
board/dnp1110/u-boot.lds

@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+        . = 0x00000000;
+
+        . = ALIGN(4);
+	.text      :
+	{
+	  cpu/sa1100/start.o	(.text)
+	  *(.text)
+	}
+
+        . = ALIGN(4);
+        .rodata : { *(.rodata) }
+
+        . = ALIGN(4);
+        .data : { *(.data) }
+
+        . = ALIGN(4);
+        .got : { *(.got) }
+
+	armboot_end_data = .;
+
+        . = ALIGN(4);
+        .bss : { *(.bss) }
+
+	armboot_end = .;
+}

+ 301 - 0
board/ebony/ebony.c

@@ -0,0 +1,301 @@
+/*
+ *  Copyright (C) 2002 Scott McNutt <smcnutt@artesyncp.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+extern long int spd_sdram (void);
+
+#include <common.h>
+#include "ebony.h"
+#include <asm/processor.h>
+
+#define BOOT_SMALL_FLASH	32	/* 00100000 */
+#define FLASH_ONBD_N		2	/* 00000010 */
+#define FLASH_SRAM_SEL		1	/* 00000001 */
+
+long int fixed_sdram (void);
+
+int board_pre_init (void)
+{
+	uint reg;
+	unsigned char *fpga_base = (unsigned char *) CFG_FPGA_BASE;
+	unsigned char status;
+
+
+	/*--------------------------------------------------------------------
+	 * Setup the external bus controller/chip selects
+	 *-------------------------------------------------------------------*/
+	mtdcr (ebccfga, xbcfg);
+	reg = mfdcr (ebccfgd);
+	mtdcr (ebccfgd, reg | 0x04000000);	/* Set ATC */
+
+	mtebc (pb1ap, 0x02815480);	/* NVRAM/RTC */
+	mtebc (pb1cr, 0x48018000);	/* BA=0x480 1MB R/W 8-bit */
+	mtebc (pb7ap, 0x01015280);	/* FPGA registers */
+	mtebc (pb7cr, 0x48318000);	/* BA=0x483 1MB R/W 8-bit */
+
+	/* read FPGA_REG0  and set the bus controller */
+	status = *fpga_base;
+	if ((status & BOOT_SMALL_FLASH) && !(status & FLASH_ONBD_N)) {
+		mtebc (pb0ap, 0x9b015480);	/* FLASH/SRAM */
+		mtebc (pb0cr, 0xfff18000);	/* BAS=0xfff 1MB R/W 8-bit */
+		mtebc (pb2ap, 0x9b015480);	/* 4MB FLASH */
+		mtebc (pb2cr, 0xff858000);	/* BAS=0xff8 4MB R/W 8-bit */
+	} else {
+		mtebc (pb0ap, 0x9b015480);	/* 4MB FLASH */
+		mtebc (pb0cr, 0xffc58000);	/* BAS=0xffc 4MB R/W 8-bit */
+
+		/* set CS2 if FLASH_ONBD_N == 0 */
+		if (!(status & FLASH_ONBD_N)) {
+			mtebc (pb2ap, 0x9b015480);	/* FLASH/SRAM */
+			mtebc (pb2cr, 0xff818000);	/* BAS=0xff8 4MB R/W 8-bit */
+		}
+	}
+
+	/*--------------------------------------------------------------------
+	 * Setup the interrupt controller polarities, triggers, etc.
+	 *-------------------------------------------------------------------*/
+	mtdcr (uic0sr, 0xffffffff);	/* clear all */
+	mtdcr (uic0er, 0x00000000);	/* disable all */
+	mtdcr (uic0cr, 0x00000009);	/* SMI & UIC1 crit are critical */
+	mtdcr (uic0pr, 0xfffffe13);	/* per ref-board manual */
+	mtdcr (uic0tr, 0x01c00008);	/* per ref-board manual */
+	mtdcr (uic0vr, 0x00000001);	/* int31 highest, base=0x000 */
+	mtdcr (uic0sr, 0xffffffff);	/* clear all */
+
+	mtdcr (uic1sr, 0xffffffff);	/* clear all */
+	mtdcr (uic1er, 0x00000000);	/* disable all */
+	mtdcr (uic1cr, 0x00000000);	/* all non-critical */
+	mtdcr (uic1pr, 0xffffe0ff);	/* per ref-board manual */
+	mtdcr (uic1tr, 0x00ffc000);	/* per ref-board manual */
+	mtdcr (uic1vr, 0x00000001);	/* int31 highest, base=0x000 */
+	mtdcr (uic1sr, 0xffffffff);	/* clear all */
+
+	return 0;
+}
+
+
+
+int checkboard (void)
+{
+	sys_info_t sysinfo;
+
+	get_sys_info (&sysinfo);
+
+	printf ("Board: IBM 440GP Evaluation Board (Ebony)\n");
+	printf ("\tVCO: %lu MHz\n", sysinfo.freqVCOMhz / 1000000);
+	printf ("\tCPU: %lu MHz\n", sysinfo.freqProcessor / 1000000);
+	printf ("\tPLB: %lu MHz\n", sysinfo.freqPLB / 1000000);
+	printf ("\tOPB: %lu MHz\n", sysinfo.freqOPB / 1000000);
+	printf ("\tEPB: %lu MHz\n", sysinfo.freqEPB / 1000000);
+	return (0);
+}
+
+
+long int initdram (int board_type)
+{
+	long dram_size = 0;
+	extern long spd_sdram (void);
+
+#if defined(CONFIG_SPD_EEPROM)
+	dram_size = spd_sdram ();
+#else
+	dram_size = fixed_sdram ();
+#endif
+	return dram_size;
+}
+
+
+#if defined(CFG_DRAM_TEST)
+int testdram (void)
+{
+	uint *pstart = (uint *) 0x00000000;
+	uint *pend = (uint *) 0x08000000;
+	uint *p;
+
+	for (p = pstart; p < pend; p++)
+		*p = 0xaaaaaaaa;
+
+	for (p = pstart; p < pend; p++) {
+		if (*p != 0xaaaaaaaa) {
+			printf ("SDRAM test fails at: %08x\n", (uint) p);
+			return 1;
+		}
+	}
+
+	for (p = pstart; p < pend; p++)
+		*p = 0x55555555;
+
+	for (p = pstart; p < pend; p++) {
+		if (*p != 0x55555555) {
+			printf ("SDRAM test fails at: %08x\n", (uint) p);
+			return 1;
+		}
+	}
+	return 0;
+}
+#endif
+
+#if !defined(CONFIG_SPD_EEPROM)
+/*************************************************************************
+ *  fixed sdram init -- doesn't use serial presence detect.
+ *
+ *  Assumes:    128 MB, non-ECC, non-registered
+ *              PLB @ 133 MHz
+ *
+ ************************************************************************/
+long int fixed_sdram (void)
+{
+	uint reg;
+
+	/*--------------------------------------------------------------------
+	 * Setup some default
+	 *------------------------------------------------------------------*/
+	mtsdram (mem_uabba, 0x00000000);	/* ubba=0 (default)             */
+	mtsdram (mem_slio, 0x00000000);		/* rdre=0 wrre=0 rarw=0         */
+	mtsdram (mem_devopt, 0x00000000);	/* dll=0 ds=0 (normal)          */
+	mtsdram (mem_wddctr, 0x00000000);	/* wrcp=0 dcd=0                 */
+	mtsdram (mem_clktr, 0x40000000);	/* clkp=1 (90 deg wr) dcdt=0    */
+
+	/*--------------------------------------------------------------------
+	 * Setup for board-specific specific mem
+	 *------------------------------------------------------------------*/
+	/*
+	 * Following for CAS Latency = 2.5 @ 133 MHz PLB
+	 */
+	mtsdram (mem_b0cr, 0x000a4001);	/* SDBA=0x000 128MB, Mode 3, enabled */
+	mtsdram (mem_tr0, 0x410a4012);	/* WR=2  WD=1 CL=2.5 PA=3 CP=4 LD=2 */
+	/* RA=10 RD=3                       */
+	mtsdram (mem_tr1, 0x8080082f);	/* SS=T2 SL=STAGE 3 CD=1 CT=0x02f   */
+	mtsdram (mem_rtr, 0x08200000);	/* Rate 15.625 ns @ 133 MHz PLB     */
+	mtsdram (mem_cfg1, 0x00000000);	/* Self-refresh exit, disable PM    */
+	udelay (400);			/* Delay 200 usecs (min)            */
+
+	/*--------------------------------------------------------------------
+	 * Enable the controller, then wait for DCEN to complete
+	 *------------------------------------------------------------------*/
+	mtsdram (mem_cfg0, 0x86000000);	/* DCEN=1, PMUD=1, 64-bit           */
+	for (;;) {
+		mfsdram (mem_mcsts, reg);
+		if (reg & 0x80000000)
+			break;
+	}
+
+	return (128 * 1024 * 1024);	/* 128 MB                           */
+}
+#endif	/* !defined(CONFIG_SPD_EEPROM) */
+
+
+/*************************************************************************
+ *  pci_pre_init
+ *
+ *  This routine is called just prior to registering the hose and gives
+ *  the board the opportunity to check things. Returning a value of zero
+ *  indicates that things are bad & PCI initialization should be aborted.
+ *
+ *	Different boards may wish to customize the pci controller structure
+ *	(add regions, override default access routines, etc) or perform
+ *	certain pre-initialization actions.
+ *
+ ************************************************************************/
+#if defined(CONFIG_PCI) && defined(CFG_PCI_PRE_INIT)
+int pci_pre_init(struct pci_controller * hose )
+{
+    unsigned long strap;
+
+	/*--------------------------------------------------------------------------+
+     *	The ebony board is always configured as the host & requires the
+     *	PCI arbiter to be enabled.
+	 *--------------------------------------------------------------------------*/
+    strap = mfdcr(cpc0_strp1);
+    if( (strap & 0x00100000) == 0 ){
+        printf("PCI: CPC0_STRP1[PAE] not set.\n");
+        return 0;
+    }
+
+    return 1;
+}
+#endif /* defined(CONFIG_PCI) && defined(CFG_PCI_PRE_INIT) */
+
+/*************************************************************************
+ *  pci_target_init
+ *
+ *	The bootstrap configuration provides default settings for the pci
+ *	inbound map (PIM). But the bootstrap config choices are limited and
+ *	may not be sufficient for a given board.
+ *
+ ************************************************************************/
+#if defined(CONFIG_PCI) && defined(CFG_PCI_TARGET_INIT)
+void pci_target_init(struct pci_controller * hose )
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	/*--------------------------------------------------------------------------+
+	 * Disable everything
+	 *--------------------------------------------------------------------------*/
+	out32r( PCIX0_PIM0SA, 0 ); /* disable */
+	out32r( PCIX0_PIM1SA, 0 ); /* disable */
+	out32r( PCIX0_PIM2SA, 0 ); /* disable */
+	out32r( PCIX0_EROMBA, 0 ); /* disable expansion rom */
+
+	/*--------------------------------------------------------------------------+
+	 * Map all of SDRAM to PCI address 0x0000_0000. Note that the 440 strapping
+     * options to not support sizes such as 128/256 MB.
+	 *--------------------------------------------------------------------------*/
+	out32r( PCIX0_PIM0LAL, CFG_SDRAM_BASE );
+	out32r( PCIX0_PIM0LAH, 0 );
+	out32r( PCIX0_PIM0SA, ~(gd->ram_size - 1) | 1 );
+
+	out32r( PCIX0_BAR0, 0 );
+
+	/*--------------------------------------------------------------------------+
+	 * Program the board's subsystem id/vendor id
+	 *--------------------------------------------------------------------------*/
+    out16r( PCIX0_SBSYSVID, CFG_PCI_SUBSYS_VENDORID );
+    out16r( PCIX0_SBSYSID, CFG_PCI_SUBSYS_DEVICEID );
+
+	out16r( PCIX0_CMD, in16r(PCIX0_CMD) | PCI_COMMAND_MEMORY );
+}
+#endif /* defined(CONFIG_PCI) && defined(CFG_PCI_TARGET_INIT) */
+
+
+/*************************************************************************
+ *  is_pci_host
+ *
+ *	This routine is called to determine if a pci scan should be
+ *	performed. With various hardware environments (especially cPCI and
+ *	PPMC) it's insufficient to depend on the state of the arbiter enable
+ *	bit in the strap register, or generic host/adapter assumptions.
+ *
+ *	Rather than hard-code a bad assumption in the general 440 code, the
+ *	440 pci code requires the board to decide at runtime.
+ *
+ *	Return 0 for adapter mode, non-zero for host (monarch) mode.
+ *
+ *
+ ************************************************************************/
+#if defined(CONFIG_PCI)
+int is_pci_host(struct pci_controller *hose)
+{
+    /* The ebony board is always configured as host. */
+    return(1);
+}
+#endif /* defined(CONFIG_PCI) */

+ 98 - 0
board/ebony/init.S

@@ -0,0 +1,98 @@
+/*
+*  Copyright (C) 2002 Scott McNutt <smcnutt@artesyncp.com>
+*
+* See file CREDITS for list of people who contributed to this
+* project.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+* MA 02111-1307 USA
+*/
+
+#include <ppc_asm.tmpl>
+#include <config.h>
+
+/* General */
+#define TLB_VALID   0x00000200
+
+/* Supported page sizes */
+
+#define SZ_1K	    0x00000000
+#define SZ_4K	    0x00000010
+#define SZ_16K	    0x00000020
+#define SZ_64K	    0x00000030
+#define SZ_256K	    0x00000040
+#define SZ_1M	    0x00000050
+#define SZ_16M	    0x00000070
+#define SZ_256M	    0x00000090
+
+/* Storage attributes */
+#define SA_W	    0x00000800	    /* Write-through */
+#define SA_I	    0x00000400	    /* Caching inhibited */
+#define SA_M	    0x00000200	    /* Memory coherence */
+#define SA_G	    0x00000100	    /* Guarded */
+#define SA_E	    0x00000080	    /* Endian */
+
+/* Access control */
+#define AC_X	    0x00000024	    /* Execute */
+#define AC_W	    0x00000012	    /* Write */
+#define AC_R	    0x00000009	    /* Read */
+
+/* Some handy macros */
+
+#define EPN(e)		((e) & 0xfffffc00)
+#define TLB0(epn,sz)	( (EPN((epn)) | (sz) | TLB_VALID ) )
+#define TLB1(rpn,erpn)	( ((rpn)&0xfffffc00) | (erpn) )
+#define TLB2(a)		( (a)&0x00000fbf )
+
+#define tlbtab_start\
+	mflr    r1  ;\
+	bl 0f	    ;
+
+#define tlbtab_end\
+	.long 0, 0, 0	;   \
+0:	mflr    r0	;   \
+	mtlr    r1	;   \
+	blr		;
+
+#define tlbentry(epn,sz,rpn,erpn,attr)\
+	.long TLB0(epn,sz),TLB1(rpn,erpn),TLB2(attr)
+
+
+/**************************************************************************
+ * TLB TABLE
+ *
+ * This table is used by the cpu boot code to setup the initial tlb
+ * entries. Rather than make broad assumptions in the cpu source tree,
+ * this table lets each board set things up however they like.
+ *
+ *  Pointer to the table is returned in r1
+ *
+ *************************************************************************/
+
+    .section .bootpg,"ax"
+    .globl tlbtab
+
+tlbtab:
+    tlbtab_start
+    tlbentry( 0xf0000000, SZ_256M, 0xf0000000, 1, AC_R|AC_W|AC_X|SA_G|SA_I)
+    tlbentry( CFG_PERIPHERAL_BASE, SZ_256M, 0x40000000, 1, AC_R|AC_W|SA_G|SA_I)
+    tlbentry( CFG_ISRAM_BASE, SZ_4K, 0x80000000, 0, AC_R|AC_W|AC_X )
+    tlbentry( CFG_ISRAM_BASE + 0x1000, SZ_4K, 0x80001000, 0, AC_R|AC_W|AC_X )
+    tlbentry( CFG_SDRAM_BASE, SZ_256M, 0x00000000, 0, AC_R|AC_W|AC_X|SA_G|SA_I )
+    tlbentry( CFG_PCI_BASE, SZ_256M, 0x00000000, 2, AC_R|AC_W|SA_G|SA_I )
+    tlbentry( CFG_PCI_MEMBASE, SZ_256M, 0x00000000, 3, AC_R|AC_W|SA_G|SA_I )
+    tlbtab_end
+
+

+ 1487 - 0
board/eltec/bab7xx/asm_init.S

@@ -0,0 +1,1487 @@
+/*
+ * (C) Copyright 2001 ELTEC Elektronik AG
+ * Frank Gottschling <fgottschling@eltec.de>
+ *
+ * ELTEC BAB PPC RAM initialization
+ *
+ * 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 <mpc75x.h>
+#include <mpc106.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+/*
+ * This following contains the entry code for the initialization code
+ * for the MPC 106, a PCI Bridge/Memory Controller.
+ * Register usage:
+ * r0  = ramtest scratch register, toggleError loop counter
+ * r1  = 0xfec0 0cf8 CONFIG_ADDRESS
+ * r2  = 0xfee0 0cfc CONFIG_DATA
+ * r3  = scratch register, subroutine argument and return value, ramtest size
+ * r4  = scratch register, spdRead clock mask, OutHex loop count
+ * r5  = ramtest scratch register
+ * r6  = toggleError 1st value, spdRead port mask
+ * r7  = toggleError 2nd value, ramtest scratch register,
+ *       spdRead scratch register (0x00)
+ * r8  = ramtest scratch register, spdRead scratch register (0x80)
+ * r9  = ramtest scratch register, toggleError loop end, OutHex digit
+ * r10 = ramtest scratch register, spdWriteByte parameter,
+ *        spdReadByte return value, printf pointer to COM1
+ * r11 = startType
+ * r12 = ramtest scratch register, spdRead data mask
+ * r13 = pointer to message block
+ * r14 = pointer to GOT
+ * r15 = scratch register, SPD save
+ * r16 = bank0 size, total memory size
+ * r17 = bank1 size
+ * r18 = bank2 size
+ * r19 = bank3 size
+ * r20 = MCCR1, MSAR1
+ * r21 = MCCR3, MEAR1
+ * r22 = MCCR4, MBER
+ * r23 = EMSAR1
+ * r24 = EMEAR1
+ * r25 = save link register 1st level
+ * r26 = save link register 2nd level
+ * r27 = save link register 3rd level
+ * r30 = pointer to GPIO for spdRead
+ */
+
+
+.globl board_asm_init
+board_asm_init:
+/*
+ * setup pointer to message block
+ */
+    mflr    r25             /* save away link register */
+    bl      get_lnk_reg     /* r3=addr of next instruction */
+    subi    r4, r3, 8       /* r4=board_asm_init addr */
+    addi    r13, r4, (MessageBlock-board_asm_init)
+/*
+ * dcache_disable
+ */
+    mfspr   r3, HID0
+    li      r4, HID0_DCE
+    andc    r3, r3, r4
+    mr      r2, r3
+    ori     r3, r3, HID0_DCI
+    sync
+    mtspr   HID0, r3
+    mtspr   HID0, r2
+    isync
+    sync
+/*
+ * icache_disable
+ */
+    mfspr   r3, HID0
+    li      r4, 0
+    ori     r4, r4, HID0_ICE
+    andc    r3, r3, r4
+    sync
+    mtspr   HID0, r3
+/*
+ * invalidate caches
+ */
+    ori     r3, r3, (HID0_ICE | HID0_ICFI | HID0_DCI | HID0_DCE)
+    or      r4, r4, r3
+    isync
+    mtspr   HID0, r4
+    andc    r4, r4, r3
+    isync
+    mtspr   HID0, r4
+    isync
+/*
+ * icache_enable
+ */
+    mfspr   r3, HID0
+    ori     r3, r3, (HID0_ICE | HID0_ICFI)
+    sync
+    mtspr   HID0, r3
+
+    lis     r1, 0xfec0
+    ori     r1, r1, 0x0cf8
+    lis     r2, 0xfee0
+    ori     r2, r2, 0xcfc
+
+#ifdef CFG_ADDRESS_MAP_A
+/*
+ * Switch to address map A if necessary.
+ */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, PCI_PICR1
+    stwbrx  r3, 0, r1
+    sync
+    lwbrx   r4, 0, r2
+    sync
+    lis     r0, PICR1_XIO_MODE@h
+    ori     r0, r0, PICR1_XIO_MODE@l
+    andc    r4, r4, r0
+    lis     r0, PICR1_ADDRESS_MAP@h
+    ori     r0, r0, PICR1_ADDRESS_MAP@l
+    or      r4, r4, r0
+    stwbrx  r4, 0, r2
+    sync
+#endif
+
+/*
+ * Do the init for the SIO.
+ */
+    bl      .sioInit
+
+    addi    r3, r13, (MinitLogo-MessageBlock)
+    bl      Printf
+
+    addi    r3, r13, (Mspd01-MessageBlock)
+    bl      Printf
+/*
+ * Memory cofiguration using SPD information stored on the SODIMMs
+ */
+    li      r17, 0
+    li      r18, 0
+    li      r19, 0
+
+    li      r3, 0x0002          /* get RAM type from spd for bank0/1 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, -1        /* error ? */
+    bne     noSpdError
+
+    addi    r3, r13, (Mfail-MessageBlock)
+    bl      Printf
+
+    li      r6, 0xe0            /* error codes in r6 and r7  */
+    li      r7, 0x00
+    b       toggleError         /* fail - loop forever */
+
+noSpdError:
+    mr      r15, r3             /* save r3 */
+
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+
+    cmpli   0, 0, r15, 0x0001   /* FPM ? */
+    beq     configFPM
+    cmpli   0, 0, r15, 0x0002   /* EDO ? */
+    beq     configEDO
+    cmpli   0, 0, r15, 0x0004   /* SDRAM ? */
+    beq     configSDRAM
+
+    li      r6, 0xe0            /* error codes in r6 and r7  */
+    li      r7, 0x01
+    b       toggleError         /* fail - loop forever */
+
+configSDRAM:
+    addi    r3, r13, (MsdRam-MessageBlock)
+    bl      Printf
+/*
+ * set the Memory Configuration Reg. 1
+ */
+    li      r3, 0x001f          /* get bank size from spd bank0/1 */
+    bl      spdRead
+
+    andi.   r3, r3, 0x0038
+    beq     SD16MB2B
+
+    li      r3, 0x0011          /* get number of internal banks */
+                                /* from spd for bank0/1 */
+    bl      spdRead
+
+    cmpli   0, 0, r3, 0x02
+    beq     SD64MB2B
+
+    cmpli   0, 0, r3, 0x04
+    beq     SD64MB4B
+
+    li      r6, 0xe0            /* error codes in r6 and r7  */
+    li      r7, 0x02
+    b       toggleError         /* fail - loop forever */
+
+SD64MB2B:
+    li      r20, 0x0005         /* 64-Mbit SDRAM 2 banks */
+    b       SDRow2nd
+
+SD64MB4B:
+    li      r20, 0x0000         /* 64-Mbit SDRAM 4 banks */
+    b       SDRow2nd
+
+SD16MB2B:
+    li      r20, 0x000f         /* 16-Mbit SDRAM 2 banks */
+
+SDRow2nd:
+    li      r3, 0x0102          /* get RAM type spd for bank2/3 */
+    bl      spdRead
+
+    cmpli   0, 0, r3, 0x0004
+    bne     S2D64MB4B           /* bank2/3 isn't present or no SDRAM */
+
+    li      r3, 0x011f          /* get bank size from spd bank2/3 */
+    bl      spdRead
+
+    andi.   r3, r3, 0x0038
+    beq     S2D16MB2B
+/*
+ * set the Memory Configuration Reg. 2
+ */
+    li      r3, 0x0111          /* get number of internal banks */
+                                /* from spd for bank2/3 */
+    bl      spdRead
+
+    cmpli   0, 0, r3, 0x02
+    beq     S2D64MB2B
+
+    cmpli   0, 0, r3, 0x04
+    beq     S2D64MB4B
+
+    li      r6, 0xe0            /* error codes in r6 and r7 */
+    li      r7, 0x03
+    b       toggleError         /* fail - loop forever */
+
+S2D64MB2B:
+    ori     r20, r20, 0x0050    /* 64-Mbit SDRAM 2 banks */
+    b       S2D64MB4B
+
+S2D16MB2B:
+    ori     r20, r20, 0x00f0    /* 16-Mbit SDRAM 2 banks */
+
+/*
+ * set the Memory Configuration Reg. 3
+ */
+S2D64MB4B:
+    lis     r21, 0x8630         /* BSTOPRE = 0x80, REFREC = 6, */
+                                /* RDLAT = 3 */
+
+/*
+ * set the Memory Configuration Reg. 4
+ */
+    lis     r22, 0x2430         /* PRETOACT = 2, ACTOPRE = 4, */
+                                /* WCBUF = 1, RCBUF = 1 */
+    ori     r22, r22, 0x2220    /* SDMODE = 0x022, ACTORW = 2 */
+
+/*
+ * get the size of bank 0-3
+ */
+    li      r3, 0x001f          /* get bank size from spd bank0/1 */
+    bl      spdRead
+
+    rlwinm  r16, r3, 2, 24, 29  /* calculate size in MByte */
+                                /* (128 MB max.) */
+
+    li      r3, 0x0005          /* get number of banks from spd */
+                                /* for bank0/1 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, 2         /* 2 banks ? */
+    bne     SDRAMnobank1
+
+    mr      r17, r16
+
+SDRAMnobank1:
+    addi    r3, r13, (Mspd23-MessageBlock)
+    bl      Printf
+
+    li      r3, 0x0102          /* get RAM type spd for bank2/3 */
+    bl      spdRead
+
+    cmpli   0, 0, r3, 0x0001    /* FPM ? */
+    bne     noFPM23             /* handle as EDO */
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+    addi    r3, r13, (MfpmRam-MessageBlock)
+    bl      Printf
+    b       configRAMcommon
+noFPM23:
+    cmpli   0, 0, r3, 0x0002    /* EDO ? */
+    bne     noEDO23
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+    addi    r3, r13, (MedoRam-MessageBlock)
+    bl      Printf
+    b       configRAMcommon
+noEDO23:
+    cmpli   0, 0, r3, 0x0004    /* SDRAM ? */
+    bne    noSDRAM23
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+    addi    r3, r13, (MsdRam-MessageBlock)
+    bl      Printf
+    b       configSDRAM23
+noSDRAM23:
+    addi    r3, r13, (Mna-MessageBlock)
+    bl      Printf
+    b       configRAMcommon     /* bank2/3 isn't present or no SDRAM */
+
+configSDRAM23:
+    li      r3, 0x011f          /* get bank size from spd bank2/3 */
+    bl      spdRead
+
+    rlwinm  r18, r3, 2, 24, 29  /* calculate size in MByte */
+                                /* (128 MB max.) */
+
+    li      r3, 0x0105          /* get number of banks from */
+                                /* spd bank0/1 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, 2         /* 2 banks ? */
+    bne     SDRAMnobank3
+
+    mr    r19, r18
+
+SDRAMnobank3:
+    b       configRAMcommon
+
+configFPM:
+    addi    r3, r13, (MfpmRam-MessageBlock)
+    bl      Printf
+    b       configEDO0
+/*
+ * set the Memory Configuration Reg. 1
+ */
+configEDO:
+    addi    r3, r13, (MedoRam-MessageBlock)
+    bl      Printf
+configEDO0:
+    lis     r20, MCCR1_TYPE_EDO@h
+
+getSpdRowBank01:
+    li      r3, 0x0003          /* get number of row bits from */
+                                /* spd from bank0/1 */
+    bl      spdRead
+    ori     r20, r20, (MCCR1_BK0_9BITS | MCCR1_BK1_9BITS)
+    cmpli   0, 0, r3, 0x0009    /* bank0 -  9 row bits */
+    beq     getSpdRowBank23
+
+    ori     r20, r20, (MCCR1_BK0_10BITS | MCCR1_BK1_10BITS)
+    cmpli   0, 0, r3, 0x000a    /* bank0 -  10 row bits */
+    beq     getSpdRowBank23
+
+    ori     r20, r20, (MCCR1_BK0_11BITS | MCCR1_BK1_11BITS)
+    cmpli   0, 0, r3, 0x000b    /* bank0 -  11 row bits */
+    beq     getSpdRowBank23
+
+    ori     r20, r20, (MCCR1_BK0_12BITS | MCCR1_BK1_12BITS)
+    cmpli   0, 0, r3, 0x000c    /* bank0 -  12 row bits */
+    beq     getSpdRowBank23
+
+    cmpli   0, 0, r3, 0x000d    /* bank0 -  13 row bits */
+    beq     getSpdRowBank23
+
+    li      r6, 0xe0            /* error codes in r6 and r7 */
+    li      r7, 0x10
+    b       toggleError         /* fail - loop forever */
+
+getSpdRowBank23:
+    li     r3, 0x0103           /* get number of row bits from */
+                                /* spd for bank2/3 */
+    bl      spdRead
+
+    ori     r20, r20, (MCCR1_BK2_9BITS | MCCR1_BK3_9BITS)
+    cmpli   0, 0, r3, 0x0009    /* bank0 -  9 row bits */
+    beq     writeRowBits
+
+    ori     r20, r20, (MCCR1_BK2_10BITS | MCCR1_BK3_10BITS)
+    cmpli   0, 0, r3, 0x000a    /* bank0 -  10 row bits */
+    beq     writeRowBits
+
+    ori     r20, r20, (MCCR1_BK2_11BITS | MCCR1_BK3_11BITS)
+    cmpli   0, 0, r3, 0x000b    /* bank0 -  11 row bits */
+    beq     writeRowBits
+
+    ori     r20, r20, (MCCR1_BK2_12BITS | MCCR1_BK3_12BITS)
+
+/*
+ * set the Memory Configuration Reg. 3
+ */
+writeRowBits:
+    lis     r21, 0x000a         /* CPX = 1, RAS6P = 4 */
+    ori     r21, r21, 0x2293    /* CAS5 = 2, CP4 = 1, */
+                                /* CAS3 = 2, RCD2 = 2, RP = 3 */
+/*
+ * set the Memory Configuration Reg. 4
+ */
+    lis     r22, 0x0010         /* all SDRAM parameter 0, */
+                                /* WCBUF flow through, */
+                                /* RCBUF registered */
+/*
+ * get the size of bank 0-3
+ */
+    li      r3, 0x0003          /* get row bits from spd  bank0/1 */
+    bl      spdRead
+
+    li      r16, 0              /* bank size is: */
+                                /* (8*2^row*2^column)/0x100000 MB */
+    ori     r16, r16, 0x8000
+    rlwnm   r16, r16, r3, 0, 31
+
+    li      r3, 0x0004          /* get column bits from spd bank0/1 */
+    bl      spdRead
+
+    rlwnm   r16, r16, r3, 0, 31
+
+    li      r3, 0x0005          /* get number of banks from */
+                                /* spd for bank0/1 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, 2         /* 2 banks ? */
+    bne     EDOnobank1
+
+    mr      r17, r16
+
+EDOnobank1:
+    addi    r3, r13, (Mspd23-MessageBlock)
+    bl      Printf
+
+    li      r3, 0x0102          /* get RAM type spd for bank2/3 */
+    bl      spdRead
+
+    cmpli   0, 0, r3, 0x0001    /* FPM ? */
+    bne     noFPM231            /* handle as EDO */
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+    addi    r3, r13, (MfpmRam-MessageBlock)
+    bl      Printf
+    b       EDObank2
+noFPM231:
+    cmpli   0, 0, r3, 0x0002    /* EDO ? */
+    bne     noEDO231
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+    addi    r3, r13, (MedoRam-MessageBlock)
+    bl      Printf
+    b       EDObank2
+noEDO231:
+    cmpli   0, 0, r3, 0x0004    /* SDRAM ? */
+    bne     noSDRAM231
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+    addi    r3, r13, (MsdRam-MessageBlock)
+    bl      Printf
+    b       configRAMcommon
+noSDRAM231:
+    addi    r3, r13, (Mfail-MessageBlock)
+    bl      Printf
+    b       configRAMcommon     /* bank2/3 isn't present or no SDRAM */
+
+EDObank2:
+    li      r3, 0x0103          /* get row bits from spd for bank2/3 */
+    bl      spdRead
+
+    li      r18, 0              /* bank size is: */
+                                /* (8*2^row*2^column)/0x100000 MB */
+    ori     r18, r18, 0x8000
+    rlwnm   r18, r18, r3, 0, 31
+
+    li      r3, 0x0104          /* get column bits from spd bank2/3 */
+    bl      spdRead
+
+    rlwnm   r18, r18, r3, 0, 31
+
+    li      r3, 0x0105          /* get number of banks from */
+                                /* spd for bank2/3 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, 2         /* 2 banks ? */
+    bne     configRAMcommon
+
+    mr      r19, r18
+
+configRAMcommon:
+    lis     r1, MPC106_REG_ADDR@h
+    ori     r1, r1, MPC106_REG_ADDR@l
+    lis     r2, MPC106_REG_DATA@h
+    ori     r2, r2, MPC106_REG_DATA@l
+
+    li      r0, 0
+
+/*
+ * If we are already running in RAM (debug mode), we should
+ * NOT reset the MEMGO flag. Otherwise we will stop all memory
+ * accesses.
+ */
+#ifdef IN_RAM
+    lis     r4, MCCR1_MEMGO@h
+    ori     r4, r4, MCCR1_MEMGO@l
+    or      r20, r20, r4
+#endif
+
+/*
+ * set the Memory Configuration Reg. 1
+ */
+    lis     r3, MPC106_REG@h        /* start building new reg number */
+    ori     r3, r3, MPC106_MCCR1    /* register number 0xf0 */
+    stwbrx  r3, r0, r1              /* write this value to CONFIG_ADDR */
+    eieio                           /* make sure mem. access is complete */
+    stwbrx  r20, r0, r2             /* write data to CONFIG_DATA */
+/*
+ * set the Memory Configuration Reg. 3
+ */
+    lis     r3, MPC106_REG@h        /* start building new reg number */
+    ori     r3, r3, MPC106_MCCR3    /* register number 0xf8 */
+    stwbrx  r3, r0, r1              /* write this value to CONFIG_ADDR */
+    eieio                           /* make sure mem. access is complete */
+    stwbrx    r21, r0, r2           /* write data to CONFIG_DATA */
+/*
+ * set the Memory Configuration Reg. 4
+ */
+    lis     r3, MPC106_REG@h        /* start building new reg number */
+    ori     r3, r3, MPC106_MCCR4    /* register number 0xfc */
+    stwbrx  r3, r0, r1              /* write this value to CONFIG_ADDR */
+    eieio                           /* make sure mem. access is complete */
+    stwbrx  r22, r0, r2             /* write data to CONFIG_DATA */
+/*
+ * set the memory boundary registers for bank 0-3
+ */
+    li      r20, 0
+    li      r23, 0
+    li      r24, 0
+    subi    r21, r16, 1         /* calculate end address bank0 */
+    li      r22, (MBER_BANK0)
+
+    cmpi    0, 0, r17, 0        /* bank1 present ? */
+    beq     nobank1
+
+    rlwinm  r3, r16, 8, 16, 23  /* calculate start address of bank1 */
+    or      r20, r20, r3
+    add     r16, r16, r17       /* add to total memory size */
+    subi    r3, r16, 1          /* calculate end address of bank1 */
+    rlwinm  r3, r3, 8, 16, 23
+    or      r21, r21, r3
+    ori     r22, r22, (MBER_BANK1)      /* enable bank1 */
+    b       bank2
+
+nobank1:
+    ori     r23, r23, 0x0300    /* set bank1 start to unused area */
+    ori     r24, r24, 0x0300    /* set bank1 end to unused area */
+
+bank2:
+    cmpi    0, 0, r18, 0        /* bank2 present ? */
+    beq     nobank2
+
+    andi.   r3, r16, 0x00ff     /* calculate start address of bank2 */
+    andi.   r4, r16, 0x0300
+    rlwinm  r3, r3, 16, 8, 15
+    or      r20, r20, r3
+    rlwinm  r3, r4, 8, 8, 15
+    or      r23, r23, r3
+    add     r16, r16, r18       /* add to total memory size */
+    subi    r3, r16, 1          /* calculate end address of bank2 */
+    andi.   r4, r3, 0x0300
+    andi.   r3, r3, 0x00ff
+    rlwinm  r3, r3, 16, 8, 15
+    or      r21, r21, r3
+    rlwinm  r3, r4, 8, 8, 15
+    or      r24, r24, r3
+    ori     r22, r22, (MBER_BANK2)    /* enable bank2 */
+    b       bank3
+
+nobank2:
+    lis     r3, 0x0003
+    or      r23, r23, r3        /* set bank2 start to unused area */
+    or      r24, r24, r3        /* set bank2 end to unused area */
+
+bank3:
+    cmpi    0, 0, r19, 0        /* bank3 present ? */
+    beq     nobank3
+
+    andi.   r3, r16, 0x00ff     /* calculate start address of bank3 */
+    andi.   r4, r16, 0x0300
+    rlwinm  r3, r3, 24, 0, 7
+    or      r20, r20, r3
+    rlwinm  r3, r4, 16, 0, 7
+    or      r23, r23, r3
+    add     r16, r16, r19       /* add to total memory size */
+    subi    r3, r16, 1          /* calculate end address of bank3 */
+    andi.   r4, r3, 0x0300
+    andi.   r3, r3, 0x00ff
+    rlwinm  r3, r3, 24, 0, 7
+    or      r21, r21, r3
+    rlwinm  r3, r4, 16, 0, 7
+    or      r24, r24, r3
+    ori     r22, r22, (MBER_BANK3)    /* enable bank3 */
+    b       writebound
+
+nobank3:
+    lis     r3, 0x0300
+    or      r23, r23, r3        /* set bank3 start to unused area */
+    or      r24, r24, r3        /* set bank3 end to unused area */
+
+writebound:
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_MSAR1    /* register number 0x80 */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+    stwbrx  r20, r0, r2         /* write data to CONFIG_DATA */
+
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_MEAR1    /* register number 0x90 */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+    stwbrx  r21, r0, r2         /* write data to CONFIG_DATA */
+
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_EMSAR1    /* register number 0x88 */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+    stwbrx  r23, r0, r2         /* write data to CONFIG_DATA */
+
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_EMEAR1    /* register number 0x98 */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+    stwbrx  r24, r0, r2         /* write data to CONFIG_DATA */
+
+/*
+ * set boundaries of unused banks to unused address space
+ */
+    lis     r4, 0x0303
+    ori     r4, r4, 0x0303      /* bank 4-7 start and end adresses */
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_EMSAR2    /* register number 0x8C */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+    stwbrx  r4, r0, r2          /* write data to CONFIG_DATA */
+
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_EMEAR2    /* register number 0x9C */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+    stwbrx  r4, r0, r2          /* write data to CONFIG_DATA */
+
+/*
+ * set the Memory Configuration Reg. 2
+ */
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_MCCR2    /* register number 0xf4 */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+
+    li      r3, 0x000c          /* get refresh from spd for bank0/1 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, -1        /* error ? */
+    bne     common1
+
+    li      r6, 0xe0            /* error codes in r6 and r7  */
+    li      r7, 0x20
+    b       toggleError         /* fail - loop forever */
+
+common1:
+    andi.   r15, r3, 0x007f     /* mask selfrefresh bit */
+    li      r3, 0x010c          /* get refresh from spd for bank2/3 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, -1        /* error ? */
+    beq     common2
+    andi.   r3, r3, 0x007f      /* mask selfrefresh bit */
+    cmp     0, 0, r3, r15       /* find the lower */
+    blt     common3
+
+common2:
+    mr      r3, r15
+
+common3:
+    li      r4, 0x1010          /* refesh cycle 1028 clocks */
+                                /*  left shifted 2 */
+    cmpli   0, 0, r3, 0x0000    /* 15.6 us ? */
+    beq     writeRefresh
+
+    li      r4, 0x0808          /* refesh cycle 514 clocks */
+                                /* left shifted 2 */
+    cmpli   0, 0, r3, 0x0002    /* 7.8 us ? */
+    beq     writeRefresh
+
+    li      r4, 0x2020          /* refesh cycle 2056 clocks */
+                                /* left shifted 2 */
+    cmpli   0, 0, r3, 0x0003    /* 31.3 us ? */
+    beq     writeRefresh
+
+    li      r4, 0x4040          /* refesh cycle 4112 clocks */
+                                /* left shifted 2 */
+    cmpli   0, 0, r3, 0x0004    /* 62.5 us ? */
+    beq     writeRefresh
+
+    li      r4, 0
+    ori     r4, r4, 0x8080      /* refesh cycle 8224 clocks */
+                                /* left shifted 2 */
+    cmpli   0, 0, r3, 0x0005    /* 125 us ? */
+    beq     writeRefresh
+
+    li      r6, 0xe0            /* error codes in r6 and r7 */
+    li      r7, 0x21
+    b       toggleError         /* fail - loop forever */
+
+writeRefresh:
+    stwbrx  r4, r0, r2          /* write data to CONFIG_DATA */
+
+/*
+ * DRAM BANKS SHOULD BE ENABLED
+ */
+    addi    r3, r13, (Mactivate-MessageBlock)
+    bl      Printf
+    mr      r3, r16
+    bl      OutDec
+    addi    r3, r13, (Mmbyte-MessageBlock)
+    bl      Printf
+
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_MBER /* register number 0xa0 */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+    stb     r22, 0(r2)          /* write data to CONFIG_DATA */
+    li      r8, 0x63            /* PGMAX = 99 */
+    stb     r8, 3(r2)           /* write data to CONFIG_DATA */
+
+/*
+ *  DRAM SHOULD NOW BE CONFIGURED AND ENABLED
+ *  MUST WAIT 200us BEFORE ACCESSING
+ */
+    li      r0, 0x7800
+    mtctr   r0
+
+wait200us:
+    bdnz    wait200us
+
+    lis     r3, MPC106_REG@h    /* start building new reg number */
+    ori     r3, r3, MPC106_MCCR1    /* register number 0xf0 */
+    stwbrx  r3, r0, r1          /* write this value to CONFIG_ADDR */
+    eieio                       /* make sure mem. access is complete */
+
+    lwbrx   r4, r0, r2          /* load r4 from CONFIG_DATA */
+
+    lis     r0, MCCR1_MEMGO@h   /* MEMGO=1 */
+    ori     r0, r0, MCCR1_MEMGO@l
+    or      r4, r4, r0          /* set the MEMGO bit */
+    stwbrx  r4, r0, r2          /* write mdfd data to CONFIG_DATA */
+
+    li      r0, 0x7000
+    mtctr   r0
+
+wait8ref:
+    bdnz    wait8ref
+
+    addi    r3, r13, (Mok-MessageBlock)
+    bl      Printf
+
+    mtlr    r25
+    blr
+
+/*
+ * Infinite loop called in case of an error during RAM initialisation.
+ * error codes in r6 and r7.
+ */
+toggleError:
+    li      r0, 0
+    lis     r9, 127
+    ori     r9, r9, 65535
+toggleError1:
+    addic   r0, r0, 1
+    cmpw    cr1, r0, r9
+    ble     cr1, toggleError1
+    li      r0, 0
+    lis     r9, 127
+    ori     r9, r9, 65535
+toggleError2:
+    addic   r0, r0, 1
+    cmpw    cr1, r0, r9
+    ble     cr1, toggleError2
+    b       toggleError
+
+
+/******************************************************************************
+ * This function performs a basic initialisation of the superio chip
+ * to enable basic console output and SPD access during RAM initialisation.
+ *
+ * Upon completion, SIO resource registers are mapped as follows:
+ * Resource     Enabled         Address
+ * UART1        Yes             3F8-3FF COM1
+ * UART2        Yes             2F8-2FF COM2
+ * GPIO         Yes             220-227
+ */
+.set    SIO_LUNINDEX, 0x07      /* SIO LUN index register */
+.set    SIO_CNFG1, 0x21         /* SIO configuration #1 register */
+.set    SIO_PCSCI, 0x23         /* SIO PCS configuration index reg */
+.set    SIO_PCSCD, 0x24         /* SIO PCS configuration data reg */
+.set    SIO_ACTIVATE, 0x30      /* SIO activate register */
+.set    SIO_IOBASEHI, 0x60      /* SIO I/O port base address, 15:8 */
+.set    SIO_IOBASELO, 0x61      /* SIO I/O port base address, 7:0 */
+.set    SIO_LUNENABLE, 0x01     /* SIO LUN enable */
+
+.sioInit:
+    mfspr   r7, 8               /* save link register */
+
+.sioInit_87308:
+
+/*
+ * Get base addr of ISA I/O space
+ */
+    lis     r6, CFG_ISA_IO@h
+    ori     r6, r6, CFG_ISA_IO@l
+
+/*
+ * Set offset to base address for config registers.
+ */
+#if defined(CFG_NS87308_BADDR_0x)
+    addi    r4, r0, 0x0279
+#elif defined(CFG_NS87308_BADDR_10)
+    addi    r4, r0, 0x015C
+#elif defined(CFG_NS87308_BADDR_11)
+    addi    r4, r0, 0x002E
+#endif
+    add     r6, r6, r4          /* add offset to base */
+    or      r3, r6, r6          /* make a copy */
+
+/*
+ * PMC (LUN 8)
+ */
+    addi    r4, r0, SIO_LUNINDEX    /* select PMC LUN */
+    addi    r5, r0, 0x8
+    bl      .sio_bw
+    addi    r4, r0, SIO_IOBASEHI    /* initialize PMC address to 0x460 */
+    addi    r5, r0, 0x04
+    bl      .sio_bw
+    addi    r4, r0, SIO_IOBASELO
+    addi    r5, r0, 0x60
+    bl      .sio_bw
+    addi    r4, r0, SIO_ACTIVATE    /* enable PMC */
+    addi    r5, r0, SIO_LUNENABLE
+    bl      .sio_bw
+
+    lis     r8, CFG_ISA_IO@h
+    ori     r8, r8, 0x0460
+    li      r9, 0x03
+    stb     r9, 0(r8)               /* select PMC2 register */
+    eieio
+    li      r9, 0x00
+    stb     r9, 1(r8)               /* SuperI/O clock src: 24MHz via X1 */
+    eieio
+
+/*
+ * map UART1 (LUN 6) or UART2 (LUN 5) to COM1 (0x3F8)
+ */
+    addi    r4, r0, SIO_LUNINDEX    /* select COM1 LUN */
+    addi    r5, r0, 0x6
+    bl      .sio_bw
+
+    addi    r4, r0, SIO_IOBASEHI    /* initialize COM1 address to 0x3F8 */
+    addi    r5, r0, 0x03
+    bl      .sio_bw
+
+    addi    r4, r0, SIO_IOBASELO
+    addi    r5, r0, 0xF8
+    bl      .sio_bw
+
+    addi    r4, r0, SIO_ACTIVATE    /* enable COM1 */
+    addi    r5, r0, SIO_LUNENABLE
+    bl      .sio_bw
+
+/*
+ * Init COM1 for polled output
+ */
+    lis     r8, CFG_ISA_IO@h
+    ori     r8, r8, 0x03f8
+    li      r9, 0x00
+    stb     r9, 1(r8)           /* int disabled */
+    eieio
+    li      r9, 0x00
+    stb     r9, 4(r8)           /* modem ctrl */
+    eieio
+    li      r9, 0x80
+    stb     r9, 3(r8)           /* link ctrl, bank select */
+    eieio
+    li      r9, 115200/CONFIG_BAUDRATE
+    stb     r9, 0(r8)           /* baud rate (LSB)*/
+    eieio
+    rotrwi  r9, r9, 8
+    stb     r9, 1(r8)           /* baud rate (MSB) */
+    eieio
+    li      r9, 0x03
+    stb     r9, 3(r8)           /* 8 data bits, 1 stop bit, */
+                                /* no parity */
+    eieio
+    li      r9, 0x0b
+    stb     r9, 4(r8)           /* enable the receiver and transmitter */
+    eieio
+
+waitEmpty:
+    lbz     r9, 5(r8)           /* transmit empty */
+    andi.   r9, r9, 0x40
+    beq     waitEmpty
+    li      r9, 0x47
+    stb     r9, 3(r8)           /* send break, 8 data bits, */
+                                /* 2 stop bits, no parity */
+    eieio
+
+    lis     r0, 0x0001
+    mtctr   r0
+
+waitCOM1:
+    lwz     r0, 5(r8)           /* load from port for delay */
+    bdnz    waitCOM1
+
+waitEmpty1:
+    lbz     r9, 5(r8)           /* transmit empty */
+    andi.   r9, r9, 0x40
+    beq     waitEmpty1
+    li      r9, 0x07
+    stb     r9, 3(r8)           /* 8 data bits, 2 stop bits, */
+                                /* no parity */
+    eieio
+
+/*
+ * GPIO (LUN 7)
+ */
+    addi    r4, r0, SIO_LUNINDEX    /* select GPIO LUN */
+    addi    r5, r0, 0x7
+    bl      .sio_bw
+
+    addi    r4, r0, SIO_IOBASEHI    /* initialize GPIO address to 0x220 */
+    addi    r5, r0, 0x02
+    bl      .sio_bw
+
+    addi    r4, r0, SIO_IOBASELO
+    addi    r5, r0, 0x20
+    bl      .sio_bw
+
+    addi    r4, r0, SIO_ACTIVATE    /* enable GPIO */
+    addi    r5, r0, SIO_LUNENABLE
+    bl      .sio_bw
+
+.sioInit_done:
+
+/*
+ * Get base addr of ISA I/O space
+ */
+    lis     r3, CFG_ISA_IO@h
+    ori     r3, r3, CFG_ISA_IO@l
+
+    addi    r3, r3, 0x015C      /* adjust to superI/O 87308 base */
+    or      r6, r3, r3          /* make a copy */
+/*
+ * CS0
+ */
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x00
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x00
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x01
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x76
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x02
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x40
+    bl      .sio_bw
+/*
+ * CS1
+ */
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x05
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x00
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x05
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x70
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x06
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x1C
+    bl      .sio_bw
+/*
+ * CS2
+ */
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x08
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x00
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x09
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x71
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCI   /* select PCSCIR */
+    addi    r5, r0, 0x0A
+    bl      .sio_bw
+    addi    r4, r0, SIO_PCSCD   /* select PCSCDR */
+    addi    r5, r0, 0x1C
+    bl      .sio_bw
+
+    mtspr   8, r7               /* restore link register */
+    bclr    20, 0               /* return to caller */
+
+/*
+ * this function writes a register to the SIO chip
+ */
+.sio_bw:
+    stb     r4, 0(r3)           /* write index register with register offset */
+    eieio
+    sync
+    stb     r5, 1(r3)           /* 1st write */
+    eieio
+    sync
+    stb     r5, 1(r3)           /* 2nd write */
+    eieio
+    sync
+    bclr    20, 0               /* return to caller */
+/*
+ * this function reads a register from the SIO chip
+ */
+.sio_br:
+    stb     r4, 0(r3)           /* write index register with register offset */
+    eieio
+    sync
+    lbz     r3, 1(r3)           /* retrieve specified reg offset contents */
+    eieio
+    sync
+    bclr    20, 0               /* return to caller */
+
+/*
+ * Print a message to COM1 in polling mode
+ * r10=COM1 port, r3=(char*)string
+ */
+.globl Printf
+Printf:
+    lis     r10, CFG_ISA_IO@h   /* COM1 port */
+    ori     r10, r10, 0x03f8
+
+WaitChr:
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, WaitChr        /* wait till empty */
+    lbzx    r0, r0, r3          /* get char */
+    stb     r0, 0(r10)          /* write to transmit reg */
+    eieio
+    addi    r3, r3, 1           /* next char */
+    lbzx    r0, r0, r3          /* get char */
+    cmpwi   cr1, r0, 0          /* end of string ? */
+    bne     cr1, WaitChr
+    blr
+
+/*
+ * Print 8/4/2 digits hex value to COM1 in polling mode
+ * r10=COM1 port, r3=val
+ */
+OutHex2:
+    li      r9, 4               /* shift reg for 2 digits */
+    b       OHstart
+OutHex4:
+    li      r9, 12              /* shift reg for 4 digits */
+    b       OHstart
+    .globl OutHex
+OutHex:
+    li      r9, 28              /* shift reg for 8 digits */
+OHstart:
+    lis     r10, CFG_ISA_IO@h   /* COM1 port */
+    ori     r10, r10, 0x03f8
+OutDig:
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDig
+    sraw    r0, r3, r9
+    clrlwi  r0, r0, 28
+    cmpwi   cr1, r0, 9
+    ble     cr1, digIsNum
+    addic   r0, r0, 55
+    b       nextDig
+digIsNum:
+    addic   r0, r0, 48
+nextDig:
+    stb     r0, 0(r10)          /* write to transmit reg */
+    eieio
+    addic.  r9, r9, -4
+    bge     OutDig
+    blr
+/*
+ * Print 3 digits hdec value to COM1 in polling mode
+ * r10=COM1 port, r3=val, r7=x00, r8=x0, r9=x, r0, r6=scratch
+ */
+.globl OutDec
+OutDec:
+    li      r6, 10
+    divwu   r0, r3, r6          /* r0 = r3 / 10, r9 = r3 mod 10 */
+    mullw   r10, r0, r6
+    subf    r9, r10, r3
+
+    mr      r3, r0
+    divwu   r0, r3, r6          /* r0 = r3 / 10, r8 = r3 mod 10 */
+    mullw   r10, r0, r6
+    subf    r8, r10, r3
+
+    mr      r3, r0
+    divwu   r0, r3, r6          /* r0 = r3 / 10, r7 = r3 mod 10 */
+    mullw   r10, r0, r6
+    subf    r7, r10, r3
+
+    lis     r10, CFG_ISA_IO@h   /* COM1 port */
+    ori     r10, r10, 0x03f8
+
+    or.     r7, r7, r7
+    bne     noblank1
+    li      r3, 0x20
+    b       OutDec4
+
+noblank1:
+    addi    r3, r7, 48          /* convert to ASCII */
+
+OutDec4:
+    lbz     r0, 0(r13)          /* slow down dummy read */
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDec4
+    stb     r3, 0(r10)          /* x00 to transmit */
+    eieio
+
+    or.     r7, r7, r8
+    beq     OutDec5
+
+    addi    r3, r8, 48          /* convert to ASCII */
+OutDec5:
+    lbz     r0, 0(r13)          /* slow down dummy read */
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDec5
+    stb     r3, 0(r10)          /* x0  to transmit */
+    eieio
+
+    addi    r3, r9, 48          /* convert to ASCII */
+OutDec6:
+    lbz     r0, 0(r13)          /* slow down dummy read */
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDec6
+    stb     r3, 0(r10)          /* x   to transmit */
+    eieio
+    blr
+/*
+ * Print a char to COM1 in polling mode
+ * r10=COM1 port, r3=char
+ */
+.globl    OutChr
+OutChr:
+    lis     r10, CFG_ISA_IO@h   /* COM1 port */
+    ori     r10, r10, 0x03f8
+
+OutChr1:
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutChr1        /* wait till empty */
+    stb     r3, 0(r10)          /* write to transmit reg */
+    eieio
+    blr
+/*
+ * Input:  r3 adr to read
+ * Output: r3 val or -1 for error
+ */
+spdRead:
+    mfspr   r26, 8              /* save link register */
+
+    lis     r30, CFG_ISA_IO@h
+    ori     r30, r30, 0x220     /* GPIO Port 1 */
+    li      r7, 0x00
+    li      r8, 0x100
+    and.    r5, r3, r8
+    beq     spdbank0
+    li      r12, 0x08
+    li      r4, 0x10
+    li      r6, 0x18
+    b       spdRead1
+
+spdbank0:
+    li      r12, 0x20           /* set I2C data */
+    li      r4, 0x40            /* set I2C clock */
+    li      r6, 0x60            /* set I2C clock and data */
+
+spdRead1:
+    li      r8, 0x80
+
+    bl      spdStart            /* access I2C bus as master */
+    li      r10, 0xa0           /* write to SPD */
+    bl      spdWriteByte
+    bl      spdReadAck          /* ACK returns in r10 */
+    cmpw    cr0, r10, r7
+    bne     AckErr              /* r10 must be 0, if ACK received */
+    mr      r10, r3             /* adr to read */
+    bl      spdWriteByte
+    bl      spdReadAck
+    cmpw    cr0, r10, r7
+    bne     AckErr
+    bl      spdStart
+    li      r10, 0xa1           /* read from SPD */
+    bl      spdWriteByte
+    bl      spdReadAck
+    cmpw    cr0, r10, r7
+    bne     AckErr
+    bl      spdReadByte         /* return val in r10 */
+    bl      spdWriteAck
+    bl      spdStop             /* release I2C bus */
+    mr      r3, r10
+    mtspr   8, r26              /* restore link register */
+    blr
+/*
+ * ACK error occurred
+ */
+AckErr:
+    bl      spdStop
+    orc     r3, r0, r0          /* return -1 */
+    mtspr   8, r26              /* restore link register */
+    blr
+
+/*
+ * Routines to read from RAM spd.
+ * r30 - GPIO Port1 address in all cases.
+ * r4 - clock mask for SPD
+ * r6 - port mask for SPD
+ * r12 - data mask for SPD
+ */
+waitSpd:
+    li      r0, 0x1000
+    mtctr   r0
+wSpd:
+    bdnz    wSpd
+    bclr    20, 0               /* return to caller */
+
+/*
+ * establish START condition on I2C bus
+ */
+spdStart:
+    mfspr   r27, 8              /* save link register */
+    stb     r6, 0(r30)          /* set SDA and SCL */
+    eieio
+    stb     r6, 1(r30)          /* switch GPIO to output */
+    eieio
+    bl      waitSpd
+    stb     r4, 0(r30)          /* reset SDA */
+    eieio
+    bl      waitSpd
+    stb     r7, 0(r30)          /* reset SCL */
+    eieio
+    bl      waitSpd
+    mtspr   8, r27
+    bclr    20, 0               /* return to caller */
+
+/*
+ * establish STOP condition on I2C bus
+ */
+spdStop:
+    mfspr   r27, 8              /* save link register */
+    stb     r7, 0(r30)          /* reset SCL and SDA */
+    eieio
+    stb     r6, 1(r30)          /* switch GPIO to output */
+    eieio
+    bl      waitSpd
+    stb     r4, 0(r30)          /* set SCL */
+    eieio
+    bl      waitSpd
+    stb     r6, 0(r30)          /* set SDA and SCL */
+    eieio
+    bl      waitSpd
+    stb     r7, 1(r30)          /* switch GPIO to input */
+    eieio
+    mtspr   8, r27
+    bclr    20, 0               /* return to caller */
+
+spdReadByte:
+    mfspr   r27, 8
+    stb     r4, 1(r30)          /* set GPIO for SCL output */
+    eieio
+    li      r9, 0x08
+    li      r10, 0x00
+loopRB:
+    stb     r7, 0(r30)          /* reset SDA and SCL */
+    eieio
+    bl      waitSpd
+    stb     r4, 0(r30)          /* set SCL */
+    eieio
+    bl      waitSpd
+    lbz     r5, 0(r30)          /* read from GPIO Port1 */
+    rlwinm  r10, r10, 1, 0, 31
+    and.    r5, r5, r12
+    beq     clearBit
+    ori     r10, r10, 0x01      /* append _1_ */
+clearBit:
+    stb     r7, 0(r30)          /* reset SCL */
+    eieio
+    bl      waitSpd
+    addic.  r9, r9, -1
+    bne     loopRB
+    mtspr   8, r27
+    bclr    20, 0               /* return (r10) to caller */
+
+/*
+ * spdWriteByte writes bits 24 - 31 of r10 to I2C.
+ * r8 contains bit mask 0x80
+ */
+spdWriteByte:
+    mfspr   r27, 8              /* save link register */
+    li      r9, 0x08            /* write octet */
+    and.    r5, r10, r8
+    bne     sWB1
+    stb     r7, 0(r30)          /* set SDA to _0_ */
+    eieio
+    b       sWB2
+sWB1:
+    stb     r12, 0(r30)         /* set SDA to _1_ */
+    eieio
+sWB2:
+    stb     r6, 1(r30)          /* set GPIO to output */
+    eieio
+loopWB:
+    and.    r5, r10, r8
+    bne     sWB3
+    stb     r7, 0(r30)          /* set SDA to _0_ */
+    eieio
+    b       sWB4
+sWB3:
+    stb     r12, 0(r30)         /* set SDA to _1_ */
+    eieio
+sWB4:
+    bl      waitSpd
+    and.    r5, r10, r8
+    bne     sWB5
+    stb     r4, 0(r30)          /* set SDA to _0_ and SCL */
+    eieio
+    b       sWB6
+sWB5:
+    stb     r6, 0(r30)          /* set SDA to _1_ and SCL */
+    eieio
+sWB6:
+    bl      waitSpd
+    and.    r5, r10, r8
+    bne     sWB7
+    stb     r7, 0(r30)          /* set SDA to _0_ and reset SCL */
+    eieio
+    b       sWB8
+sWB7:
+    stb     r12, 0(r30)         /* set SDA to _1_ and reset SCL */
+    eieio
+sWB8:
+    bl      waitSpd
+    rlwinm  r10, r10, 1, 0, 31  /* next bit */
+    addic.  r9, r9, -1
+    bne     loopWB
+    mtspr   8, r27
+    bclr    20, 0               /* return to caller */
+
+/*
+ * Read ACK from SPD, return value in r10
+ */
+spdReadAck:
+    mfspr   r27, 8              /* save link register */
+    stb     r4, 1(r30)          /* set GPIO to output */
+    eieio
+    stb     r7, 0(r30)          /* reset SDA and SCL */
+    eieio
+    bl      waitSpd
+    stb     r4, 0(r30)          /* set SCL */
+    eieio
+    bl      waitSpd
+    lbz     r10, 0(r30)         /* read GPIO Port 1 and mask SDA */
+    and     r10, r10, r12
+    bl      waitSpd
+    stb     r7, 0(r30)          /* reset SDA and SCL */
+    eieio
+    bl      waitSpd
+    mtspr   8, r27
+    bclr    20, 0               /* return (r10) to caller */
+
+spdWriteAck:
+    mfspr   r27, 8
+    stb     r12, 0(r30)         /* set SCL */
+    eieio
+    stb     r6, 1(r30)          /* set GPIO to output */
+    eieio
+    bl      waitSpd
+    stb     r6, 0(r30)          /* SDA and SCL */
+    eieio
+    bl      waitSpd
+    stb     r12, 0(r30)         /* reset SCL */
+    eieio
+    bl      waitSpd
+    mtspr   8, r27
+    bclr    20, 0               /* return to caller */
+
+get_lnk_reg:
+    mflr    r3                  /* return link reg */
+    blr
+
+/*
+ * Messages for console output
+ */
+.globl MessageBlock
+MessageBlock:
+Mok:
+    .ascii  "OK\015\012\000"
+Mfail:
+    .ascii  "FAILED\015\012\000"
+Mna:
+    .ascii  "NA\015\012\000"
+MinitLogo:
+    .ascii  "\015\012*** ELTEC Elektronik, Mainz ***\015\012"
+    .ascii  "\015\012Initialising RAM\015\012\000"
+Mspd01:
+    .ascii  "       Reading SPD of bank0/1 ..... \000"
+Mspd23:
+    .ascii  "       Reading SPD of bank2/3 ..... \000"
+MfpmRam:
+    .ascii  "       RAM-Type: FPM \015\012\000"
+MedoRam:
+    .ascii  "       RAM-Type: EDO \015\012\000"
+MsdRam:
+    .ascii  "       RAM-Type: SDRAM \015\012\000"
+Mactivate:
+    .ascii  "       Activating \000"
+Mmbyte:
+    .ascii  " MB .......... \000"
+    .align  4
+
+
+
+
+
+
+
+
+
+
+
+

+ 292 - 0
board/eltec/bab7xx/el_srom.c

@@ -0,0 +1,292 @@
+/*
+ * (C) Copyright 2002 ELTEC Elektronik AG
+ * Frank Gottschling <fgottschling@eltec.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include "srom.h"
+
+/*----------------------------------------------------------------------------*/
+/*
+ *  START sequence
+ *        _ _________
+ *  SCLK  _>         \____
+ *        _ ____
+ *  SDIO  _>    \_________
+ *         :    :    :
+ */
+static void eepStart (void)
+{
+    out8(I2C_BUS_DAT, 0x60);     /* SCLK = high  SDIO = high */
+    out8(I2C_BUS_DIR, 0x60);     /* set output direction for SCLK/SDIO */
+    udelay(10);
+    out8(I2C_BUS_DAT, 0x40);     /* SCLK = high  SDIO = low */
+    udelay(10);
+    out8(I2C_BUS_DAT, 0x00);     /* SCLK = low   SDIO = low */
+    udelay(10);
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ *  STOP sequence
+ *              _______
+ *  SCLK  _____/
+ *        _         ___
+ *  SDIO  _>_______/
+ *         :   :   :
+ */
+static void eepStop (void)
+{
+    out8(I2C_BUS_DAT, 0x00);      /* SCLK = low   SDIO = low */
+    out8(I2C_BUS_DIR, 0x60);      /* set output direction for SCLK/SDIO */
+    udelay(10);
+    out8(I2C_BUS_DAT, 0x40);      /* SCLK = high  SDIO = low */
+    udelay(10);
+    out8(I2C_BUS_DAT, 0x60);      /* SCLK = high  SDIO = high */
+    udelay(10);
+    out8(I2C_BUS_DIR, 0x00);      /* reset to input direction */
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ *  Read one byte from EEPROM
+ *            ___     ___     ___     ___     ___     ___     ___     ___
+ *  SCLK  ___/   \___/   \___/   \___/   \___/   \___/   \___/   \___/   \
+ *        _________________________________________________________________
+ *  SDIO  >     ^       ^       ^       ^       ^       ^       ^       ^
+ *        :  :   :   :   :   :   :   :   :   :   :   :   :   :   :   :   :
+ */
+static unsigned char eepReadByte (void)
+{
+    register unsigned char buf = 0x00;
+    register int i;
+
+    out8(I2C_BUS_DIR, 0x40);
+
+    for (i = 0; i < 8; i++)
+    {
+        out8(I2C_BUS_DAT, 0x00);    /* SCLK = low   SDIO = high */
+        udelay(10);
+        out8(I2C_BUS_DAT, 0x40);    /* SCLK = high  SDIO = high */
+        udelay(15);
+        buf <<= 1;
+        buf = (in8(I2C_BUS_DAT) & 0x20) ? (buf | 0x01) : (buf & 0xFE);
+        out8(I2C_BUS_DAT, 0x00);    /* SCLK = low   SDIO = high */
+        udelay(10);
+    }
+    return(buf);
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ *  Write one byte to EEPROM
+ *           ___     ___     ___     ___     ___     ___     ___     ___
+ *  SCLK  __/   \___/   \___/   \___/   \___/   \___/   \___/   \___/   \__
+ *         _______ _______ _______ _______ _______ _______ _______ ________
+ *  SDIO  X_______X_______X_______X_______X_______X_______X_______X________
+ *      :   7   :   6   :   5   :   4   :   3   :   2   :   1   :   0
+ */
+static void eepWriteByte (register unsigned char buf)
+{
+    register int    i;
+
+    (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00);     /* SCLK = low   SDIO = data */
+    out8(I2C_BUS_DIR, 0x60);
+
+    for (i = 7; i >= 0; i--)
+    {
+        (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK=low  SDIO=data */
+        udelay(10);
+        (buf & 0x80) ? out8(I2C_BUS_DAT, 0x60) : out8(I2C_BUS_DAT, 0x40); /* SCLK=high SDIO=data */
+        udelay(15);
+        (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK=low  SDIO=data */
+        udelay(10);
+        buf <<= 1;
+    }
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ *  Read data acknowledge of EEPROM
+ *             _______
+ *  SCLK  ____/       \___
+ *         _______________
+ *  SDIO  >
+ *        :   :   ^   :
+ */
+static int eepReadAck (void)
+{
+    int retval;
+
+    out8(I2C_BUS_DIR, 0x40);
+    out8(I2C_BUS_DAT, 0x00);            /* SCLK = low   SDIO = high */
+    udelay(10);
+    out8(I2C_BUS_DAT, 0x40);            /* SCLK = high  SDIO = high */
+    udelay(10);
+    retval = (in8(I2C_BUS_DAT) & 0x20) ? ERROR : 0;
+    udelay(10);
+    out8(I2C_BUS_DAT, 0x00);            /* SCLK = low   SDIO = high */
+    udelay(10);
+
+    return(retval);
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ *  Write data acknowledge to EEPROM
+ *             _______
+ *  SCLK  ____/       \___
+ *
+ *  SDIO  >_______________
+ *        :   :       :
+ */
+static void eepWriteAck (unsigned char ack)
+{
+    ack ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low   SDIO = ack */
+    out8(I2C_BUS_DIR, 0x60);
+    udelay(10);
+    ack ? out8(I2C_BUS_DAT, 0x60) : out8(I2C_BUS_DAT, 0x40); /* SCLK = high  SDIO = ack */
+    udelay(15);
+    ack ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low   SDIO = ack */
+    udelay(10);
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Read bytes from EEPROM
+ */
+int el_srom_load (addr, buf, cnt, device, block)
+unsigned char addr;
+unsigned char *buf;
+int cnt;
+unsigned char device;
+unsigned char block;
+{
+    register int i;
+
+    for (i=0;i<cnt;i++)
+    {
+        eepStart();
+        eepWriteByte(0xA0 | device | block);
+        if (eepReadAck() == ERROR)
+        {
+           eepStop();
+            return(ERROR);
+        }
+        eepWriteByte(addr++);
+        if (eepReadAck() == ERROR)
+        {
+            eepStop();
+            return(ERROR);
+        }
+        eepStart();
+
+        eepWriteByte(0xA1 | device | block);
+        if (eepReadAck() == ERROR)
+        {
+            eepStop();
+            return(ERROR);
+        }
+
+        *buf++ = eepReadByte();
+        eepWriteAck(1);
+        eepStop();
+
+        if ((addr == 0) && (i != (cnt-1)))    /* is it the same block ? */
+        {
+            if (block == FIRST_BLOCK)
+                block = SECOND_BLOCK;
+            else
+                return(ERROR);
+        }
+    }
+    return(cnt);
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ *
+ * Write bytes to EEPROM
+ *
+ */
+int el_srom_store (addr, buf, cnt, device, block)
+unsigned char    addr, *buf, device, block;
+int        cnt;
+{
+    register int i, retVal;
+
+    for (i=0;i<cnt;i++)
+    {
+        retVal = ERROR;
+        do
+        {
+            eepStart();
+            eepWriteByte(0xA0 | device | block);
+            if ((retVal = eepReadAck()) == ERROR)
+                eepStop();
+        } while (retVal == ERROR);
+
+        eepWriteByte(addr++);
+        if (eepReadAck() == ERROR)  return(ERROR);
+
+        if ((addr == 0) && (i != (cnt-1)))    /* is it the same block ? */
+        {
+            if (block == FIRST_BLOCK)
+                block = SECOND_BLOCK;
+            else
+            return(ERROR);
+        }
+
+        eepWriteByte(*buf++);
+        if (eepReadAck() == ERROR)
+            return(ERROR);
+
+        eepStop();
+    }
+    return(cnt);
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ * calculate checksum for ELTEC revision srom
+ */
+unsigned long el_srom_checksum (ptr, size)
+register unsigned char *ptr;
+unsigned long size;
+{
+    u_long f, accu = 0;
+    u_int  i;
+    u_char byte;
+
+    for (; size; size--)
+    {
+        byte = *ptr++;
+        for (i = 8; i; i--)
+        {
+            f =  ((byte & 1) ^ (accu & 1)) ? 0x84083001 : 0;
+            accu >>= 1; accu ^= f;
+            byte >>= 1;
+        }
+    }
+    return(accu);
+}
+
+/*----------------------------------------------------------------------------*/

+ 129 - 0
board/eltec/bab7xx/u-boot.lds

@@ -0,0 +1,129 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * 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
+ */
+
+/*
+ * u-boot.lds - linker script for U-Boot 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 = .);
+}

+ 877 - 0
board/eltec/elppc/asm_init.S

@@ -0,0 +1,877 @@
+/*
+ * (C) Copyright 2001 ELTEC Elektronik AG
+ * Frank Gottschling <fgottschling@eltec.de>
+ *
+ * ELTEC ELPPC RAM initialization
+ *
+ * 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 <version.h>
+#include <mpc106.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+.globl board_asm_init
+board_asm_init:
+
+/*
+ * setup pointer to message block
+ */
+    mflr    r13                 /* save away link register */
+    bl      get_lnk_reg         /* r3=addr of next instruction */
+    subi    r4, r3, 8           /* r4=board_asm_init addr */
+    addi    r29, r4, (MessageBlock-board_asm_init)
+
+/*
+ * dcache_disable
+ */
+    mfspr   r3, HID0
+    li      r4, HID0_DCE
+    andc    r3, r3, r4
+    mr      r2, r3
+    ori     r3, r3, HID0_DCI
+    sync
+    mtspr   HID0, r3
+    mtspr   HID0, r2
+    isync
+    sync
+/*
+ * icache_disable
+ */
+    mfspr   r3, HID0
+    li      r4, 0
+    ori     r4, r4, HID0_ICE
+    andc    r3, r3, r4
+    sync
+    mtspr   HID0, r3
+/*
+ * invalidate caches
+ */
+    ori     r3, r3, (HID0_ICE | HID0_ICFI | HID0_DCI | HID0_DCE)
+    or      r4, r4, r3
+    isync
+    mtspr   HID0, r4
+    andc    r4, r4, r3
+    isync
+    mtspr   HID0, r4
+    isync
+/*
+ * icache_enable
+ */
+    mfspr   r3, HID0
+    ori     r3, r3, (HID0_ICE | HID0_ICFI)
+    sync
+    mtspr   HID0, r3
+
+
+/*
+ * setup memory controller
+ */
+    lis     r1, MPC106_REG_ADDR@h
+    ori     r1, r1, MPC106_REG_ADDR@l
+    lis     r2, MPC106_REG_DATA@h
+    ori     r2, r2, MPC106_REG_DATA@l
+
+    /* Configure PICR1 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, PCI_PICR1
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0xFF14
+    ori     r3, r3, 0x1CC8
+    eieio
+    stwbrx  r3, 0, r2
+
+    /* Configure PICR2 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, PCI_PICR2
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0000
+    ori     r3, r3, 0x0000
+    eieio
+    stwbrx  r3, 0, r2
+
+    /* Configure EUMBAR */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, 0x0078      /* offest of EUMBAR in PCI config space */
+    stwbrx  r3, 0, r1
+    lis     r3, MPC107_EUMB_ADDR@h
+    eieio
+    stwbrx  r3, 0, r2
+
+    /* Configure Address Map B Option Reg */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, 0x00e0      /* offest of AMBOR in PCI config space */
+    stwbrx  r3, 0, r1
+    lis     r3, 0
+    eieio
+    stwbrx  r3, 0, r2
+
+    /* Configure I2C Controller */
+    lis     r14, MPC107_I2C_ADDR@h  /* base of I2C controller */
+    ori     r14, r14, MPC107_I2C_ADDR@l
+    lis     r3, 0x2b10          /* I2C clock = 100MHz/1024 */
+    stw     r3, 4(r14)
+    li      r3, 0               /* clear arbitration */
+    eieio
+    stw     r3, 12(r14)
+
+    /* Configure MCCR1 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, MPC106_MCCR1
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0660      /* don't set MEMGO now ! */
+    ori     r3, r3, 0x0000
+    eieio
+    stwbrx  r3, 0, r2
+
+    /* Configure MCCR2 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, MPC106_MCCR2
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0400
+    ori     r3, r3, 0x1800
+    eieio
+    stwbrx  r3, 0, r2
+
+
+    /* Configure MCCR3 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, MPC106_MCCR3
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0230
+    ori     r3, r3, 0x0000
+    eieio
+    stwbrx  r3, 0, r2
+
+    /* Configure MCCR4 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, MPC106_MCCR4
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x2532
+    ori     r3, r3, 0x2220
+    eieio
+    stwbrx  r3, 0, r2
+
+/*
+ * configure memory interface (MICRs)
+ */
+    addis   r3, r0, 0x8000      /* ADDR_80 */
+    ori     r3, r3, 0x0080      /* SMEMADD1 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0xFFFF
+    ori     r3, r3, 0x4000
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_84 */
+    ori     r3, r3, 0x0084      /* SMEMADD2 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0xFFFF
+    ori     r3, r3, 0xFFFF
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_88 */
+    ori     r3, r3, 0x0088      /* EXTSMEM1 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0303
+    ori     r3, r3, 0x0000
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_8C */
+    ori     r3, r3, 0x008c      /* EXTSMEM2 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0303
+    ori     r3, r3, 0x0303
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_90 */
+    ori     r3, r3, 0x0090      /* EMEMADD1 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0xFFFF
+    ori     r3, r3, 0x7F3F
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_94 */
+    ori     r3, r3, 0x0094      /* EMEMADD2 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0xFFFF
+    ori     r3, r3, 0xFFFF
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_98 */
+    ori     r3, r3, 0x0098      /* EXTEMEM1 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0303
+    ori     r3, r3, 0x0000
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_9C */
+    ori     r3, r3, 0x009c      /* EXTEMEM2 */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0303
+    ori     r3, r3, 0x0303
+    eieio
+    stwbrx  r3, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_A0 */
+    ori     r3, r3, 0x00a0      /* MEMBNKEN */
+    stwbrx  r3, 0, r1
+    addis   r3, r0, 0x0000
+    ori     r3, r3, 0x0003
+    eieio
+    stwbrx  r3, 0, r2
+
+/*
+ * must wait at least 100us after HRESET to issue a MEMGO
+ */
+    lis     r0, 1
+    mtctr   r0
+memStartWait:
+    bdnz    memStartWait
+
+/*
+ * enable RAM Operations through MCCR1 (MEMGO)
+ */
+    lis     r3, 0x8000
+    ori     r3, r3, 0x00f0
+    stwbrx  r3, r0, r1
+    sync
+    lwbrx   r3, 0, r2
+    lis     r0, 0x0008
+    or      r3, r0, r3
+    stwbrx  r3, 0, r2
+    sync
+
+/*
+ * set LEDs first time
+ */
+    li      r3, 0x1
+    lis     r30, CFG_USR_LED_BASE@h
+    stb     r3, 2(r30)
+    sync
+
+/*
+ * init COM1 for polled output
+ */
+    lis     r8, CFG_NS16550_COM1@h  /* COM1 base address*/
+    ori     r8, r8, CFG_NS16550_COM1@l
+    li      r9, 0x00
+    stb     r9, 1(r8)           /* int disabled */
+    eieio
+    li      r9, 0x00
+    stb     r9, 4(r8)           /* modem ctrl */
+    eieio
+    li      r9, 0x80
+    stb     r9, 3(r8)           /* link ctrl */
+    eieio
+    li      r9, (CFG_NS16550_CLK / 16 / CONFIG_BAUDRATE)
+    stb     r9, 0(r8)           /* baud rate (LSB)*/
+    eieio
+    li      r9, ((CFG_NS16550_CLK / 16 / CONFIG_BAUDRATE) >> 8)
+    stb     r9, 1(r8)           /* baud rate (MSB) */
+    eieio
+    li      r9, 0x07
+    stb     r9, 3(r8)           /* 8 data bits, 2 stop bit, no parity */
+    eieio
+    li      r9, 0x0b
+    stb     r9, 4(r8)           /* enable the receiver and transmitter (modem ctrl) */
+    eieio
+waitEmpty:
+    lbz     r9, 5(r8)           /* transmit empty */
+    andi.   r9, r9, 0x40
+    beq     waitEmpty
+    li      r9, 0x47
+    stb     r9, 3(r8)           /* send break, 8 data bits, 2 stop bit, no parity */
+    eieio
+
+    lis     r0, 0x0001
+    mtctr   r0
+waitCOM1:
+    lwz     r0, 5(r8)           /* load from port for delay */
+    bdnz    waitCOM1
+
+waitEmpty1:
+    lbz     r9, 5(r8)           /* transmit empty */
+    andi.   r9, r9, 0x40
+    beq     waitEmpty1
+    li      r9, 0x07
+    stb     r9, 3(r8)           /* 8 data bits, 2 stop bit, no parity */
+    eieio
+
+/*
+ * intro message from message block
+ */
+    addi    r3, r29, (MnewLine-MessageBlock)
+    bl      Printf
+    addi    r3, r29, (MinitLogo-MessageBlock)
+    bl      Printf
+
+/*
+ * memory cofiguration using SPD information stored on the SODIMMs
+ */
+    addi    r3, r29, (Mspd01-MessageBlock)
+    bl      Printf
+
+    li      r17, 0
+
+    li      r3, 0x0002          /* get RAM type from spd for bank0/1 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, -1        /* error ? */
+    bne     noSpdError
+
+    addi    r3, r29, (Mfail-MessageBlock)
+    bl      Printf
+
+    li      r6, 0xe             /* error codes in r6 and r7  */
+    li      r7, 0x0
+    b       toggleError         /* fail - loop forever */
+
+noSpdError:
+    mr      r15, r3             /* save r3 */
+
+    addi    r3, r29, (Mok-MessageBlock)
+    bl      Printf
+
+    cmpli   0, 0, r15, 0x0004   /* SDRAM ? */
+    beq     isSDRAM
+
+    addi    r3, r29, (MramTyp-MessageBlock)
+    bl      Printf
+
+    li      r6, 0xd             /* error codes in r6 and r7  */
+    li      r7, 0x0
+    b       toggleError         /* fail - loop forever */
+
+isSDRAM:
+    li      r3, 0x0012          /* get supported CAS latencies from byte 18 */
+    bl      spdRead
+    mr      r15, r3
+    li      r3, 0x09
+    andi.   r0, r15, 0x04
+    bne     maxCLis3
+    li      r3, 0x17
+maxCLis3:
+    andi.   r0, r15, 0x02
+    bne     CL2
+
+    addi    r3, r29, (MramTyp-MessageBlock)
+    bl      Printf
+
+    li      r6, 0xc             /* error codes in r6 and r7  */
+    li      r7, 0x0
+    b       toggleError         /* fail - loop forever */
+CL2:
+    bl      spdRead
+    cmpli   0, 0, r3, 0xa1      /* cycle time must be 10ns max. */
+    blt     speedOk
+
+    addi    r3, r29, (MramTyp-MessageBlock)
+    bl      Printf
+
+    li      r6, 0xb             /* error codes in r6 and r7  */
+    li      r7, 0x0
+    b       toggleError         /* fail - loop forever */
+speedOk:
+    lis     r20, 0x06e8         /* preset MCR1 value */
+
+    li      r3, 0x0011          /* get number of internal banks from spd for bank0/1 */
+    bl      spdRead
+
+    cmpli   0, 0, r3, 0x02
+    beq     SD_2B
+    cmpli   0, 0, r3, 0x04
+    beq     SD_4B
+memConfErr:
+    addi    r3, r29, (MramConfErr-MessageBlock)
+    bl      Printf
+
+    li      r6, 0xa             /* error codes in r6 and r7  */
+    li      r7, 0x0
+    b       toggleError         /* fail - loop forever */
+
+SD_2B:
+    li      r3, 0x0003          /* get number of row bits from spd for bank0/1 */
+    bl      spdRead
+    cmpli   0, 0, r3, 0x0b
+    beq     row11x2
+    cmpli   0, 0, r3, 0x0c
+    beq     row12x2or13x2
+    cmpli   0, 0, r3, 0x0d
+    beq     row12x2or13x2
+    b       memConfErr
+SD_4B:
+    li      r3, 0x0003          /* get number of row bits from spd for bank0/1 */
+    bl      spdRead
+    cmpli   0, 0, r3, 0x0b
+    beq     row11x4or12x4
+    cmpli   0, 0, r3, 0x0c
+    beq     row11x4or12x4
+    cmpli   0, 0, r3, 0x0d
+    beq     row13x4
+    b       memConfErr
+row12x2or13x2:
+    ori     r20, r20, 0x05
+    b       row11x4or12x4
+row13x4:
+    ori     r20, r20, 0x0a
+    b       row11x4or12x4
+row11x2:
+    ori     r20, r20, 0x0f
+row11x4or12x4:
+    /* get the size of bank 0-1 */
+
+    li      r3, 0x001f          /* get bank size from spd for bank0/1 */
+    bl      spdRead
+
+    rlwinm  r16, r3, 2, 24, 29  /* calculate size in MByte (128 MB max.) */
+
+    li      r3, 0x0005          /* get number of banks from spd for bank0/1 */
+    bl      spdRead
+
+    cmpi    0, 0, r3, 2         /* 2 banks ? */
+    bne     SDRAMnobank1
+
+    mr      r17, r16
+
+SDRAMnobank1:
+    li      r3, 0x000c          /* get refresh from spd for bank0/1 */
+    bl      spdRead
+    andi.   r3, r3, 0x007f      /* mask selfrefresh bit */
+    li      r4, 0x1800          /* refesh cycle 1536 clocks left shifted 2 */
+    cmpli   0, 0, r3, 0x0000    /* 15.6 us ? */
+    beq     writeRefresh
+
+    li      r4, 0x0c00          /* refesh cycle 768 clocks left shifted 2 */
+    cmpli   0, 0, r3, 0x0002    /* 7.8 us ? */
+    beq     writeRefresh
+
+    li      r4, 0x3000          /* refesh cycle 3072 clocks left shifted 2 */
+    cmpli   0, 0, r3, 0x0003    /* 31.3 us ? */
+    beq     writeRefresh
+
+    li      r4, 0x6000          /* refesh cycle 6144 clocks left shifted 2 */
+    cmpli   0, 0, r3, 0x0004    /* 62.5 us ? */
+    beq     writeRefresh
+
+    li      r4, 0
+    ori     r4, r4, 0xc000      /* refesh cycle 8224 clocks left shifted 2 */
+    cmpli   0, 0, r3, 0x0005    /* 125 us ? */
+    beq     writeRefresh
+
+    b       memConfErr
+
+writeRefresh:
+    lis     r21, 0x0400         /* preset MCCR2 value */
+    or      r21, r21, r4
+
+    /* Overwrite MCCR1 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, MPC106_MCCR1
+    stwbrx  r3, 0, r1
+    eieio
+    stwbrx  r20, 0, r2
+
+    /* Overwrite MCCR2 */
+    lis     r3, MPC106_REG@h
+    ori     r3, r3, MPC106_MCCR2
+    stwbrx  r3, 0, r1
+    eieio
+    stwbrx  r21, 0, r2
+
+    /* set the memory boundary registers for bank 0-3 */
+    li      r20, 0
+    lis     r23, 0x0303
+    lis     r24, 0x0303
+    subi    r21, r16, 1         /* calculate end address bank0 */
+    li      r22, 1
+
+    cmpi    0, 0, r17, 0        /* bank1 present ? */
+    beq     nobank1
+
+    andi.   r3, r16, 0x00ff     /* calculate start address of bank1 */
+    andi.   r4, r16, 0x0300
+    rlwinm  r3, r3, 8, 16, 23
+    or      r20, r20, r3
+    or      r23, r23, r4
+
+    add     r16, r16, r17       /* add to total memory size */
+
+    subi    r3, r16, 1          /* calculate end address of bank1 */
+    andi.   r4, r3, 0x0300
+    andi.   r3, r3, 0x00ff
+    rlwinm  r3, r3, 8, 16, 23
+    or      r21, r21, r3
+    or      r24, r24, r4
+
+    ori     r22, r22, 2         /* enable bank1 */
+    b       bankOk
+nobank1:
+    ori     r23, r23, 0x0300    /* set bank1 start to unused area */
+    ori     r24, r24, 0x0300    /* set bank1 end to unused area */
+bankOk:
+    addi    r3, r29, (Mactivate-MessageBlock)
+    bl      Printf
+    mr      r3, r16
+    bl      OutDec
+    addi    r3, r29, (Mact0123e-MessageBlock)
+    bl      Printf
+
+/*
+ * overwrite MSAR1, MEAR1, EMSAR1, and EMEAR1
+ */
+    addis   r3, r0, 0x8000      /* ADDR_80 */
+    ori     r3, r3, 0x0080      /* MSAR1 */
+    stwbrx  r3, 0, r1
+    eieio
+    stwbrx  r20, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_88 */
+    ori     r3, r3, 0x0088      /* EMSAR1 */
+    stwbrx  r3, 0, r1
+    eieio
+    stwbrx  r23, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_90 */
+    ori     r3, r3, 0x0090      /* MEAR1 */
+    stwbrx  r3, 0, r1
+    eieio
+    stwbrx  r21, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_98 */
+    ori     r3, r3, 0x0098      /* EMEAR1 */
+    stwbrx  r3, 0, r1
+    eieio
+    stwbrx  r24, 0, r2
+
+    addis   r3, r0, 0x8000      /* ADDR_A0 */
+    ori     r3, r3, 0x00a0      /* MBER */
+    stwbrx  r3, 0, r1
+    eieio
+    stwbrx  r22, 0, r2
+
+/*
+ * delay to let SDRAM go through several initialization/refresh cycles
+ */
+    lis     r3, 3
+    mtctr   r3
+memStartWait_1:
+    bdnz    memStartWait_1
+    eieio
+
+/*
+ * set LEDs end
+ */
+    li      r3, 0xf
+    lis     r30, CFG_USR_LED_BASE@h
+    stb     r3, 2(r30)
+    sync
+
+    mtlr    r13
+    blr                         /* EXIT board_asm_init ... */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * print a message to COM1 in polling mode (r10=COM1 port, r3=(char*)string)
+ */
+
+Printf:
+    lis     r10, CFG_NS16550_COM1@h /* COM1 base address*/
+    ori     r10, r10, CFG_NS16550_COM1@l
+WaitChr:
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, WaitChr        /* wait till empty */
+    lbzx    r0, r0, r3          /* get char */
+    stb     r0, 0(r10)          /* write to transmit reg */
+    eieio
+    addi    r3, r3, 1           /* next char */
+    lbzx    r0, r0, r3          /* get char */
+    cmpwi   cr1, r0, 0          /* end of string ? */
+    bne     cr1, WaitChr
+    blr
+
+/*
+ * print a char to COM1 in polling mode (r10=COM1 port, r3=char)
+ */
+OutChr:
+    lis     r10, CFG_NS16550_COM1@h /* COM1 base address*/
+    ori     r10, r10, CFG_NS16550_COM1@l
+OutChr1:
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutChr1        /* wait till empty */
+    stb     r3, 0(r10)          /* write to transmit reg */
+    eieio
+    blr
+
+/*
+ * print 8/4/2 digits hex value to COM1 in polling mode (r10=COM1 port, r3=val)
+ */
+OutHex2:
+    li      r9, 4               /* shift reg for 2 digits */
+    b       OHstart
+OutHex4:
+    li      r9, 12              /* shift reg for 4 digits */
+    b       OHstart
+OutHex:
+    li      r9, 28              /* shift reg for 8 digits */
+OHstart:
+    lis     r10, CFG_NS16550_COM1@h /* COM1 base address*/
+    ori     r10, r10, CFG_NS16550_COM1@l
+OutDig:
+    lbz     r0, 0(r29)          /* slow down dummy read */
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDig
+    sraw    r0, r3, r9
+    clrlwi  r0, r0, 28
+    cmpwi   cr1, r0, 9
+    ble     cr1, digIsNum
+    addic   r0, r0, 55
+    b       nextDig
+digIsNum:
+    addic   r0, r0, 48
+nextDig:
+    stb     r0, 0(r10)          /* write to transmit reg */
+    eieio
+    addic.  r9, r9, -4
+    bge     OutDig
+    blr
+
+/*
+ * print 3 digits hdec value to COM1 in polling mode
+ * (r10=COM1 port, r3=val, r7=x00, r8=x0, r9=x, r0, r6=scratch)
+ */
+OutDec:
+    li      r6, 10
+    divwu   r0, r3, r6          /* r0 = r3 / 10, r9 = r3 mod 10 */
+    mullw   r10, r0, r6
+    subf    r9, r10, r3
+    mr      r3, r0
+    divwu   r0, r3, r6          /* r0 = r3 / 10, r8 = r3 mod 10 */
+    mullw   r10, r0, r6
+    subf    r8, r10, r3
+    mr      r3, r0
+    divwu   r0, r3, r6          /* r0 = r3 / 10, r7 = r3 mod 10 */
+    mullw   r10, r0, r6
+    subf    r7, r10, r3
+    lis     r10, CFG_NS16550_COM1@h /* COM1 base address*/
+    ori     r10, r10, CFG_NS16550_COM1@l
+    or.     r7, r7, r7
+    bne     noblank1
+    li      r3, 0x20
+    b       OutDec4
+noblank1:
+    addi    r3, r7, 48          /* convert to ASCII */
+OutDec4:
+    lbz     r0, 0(r29)          /* slow down dummy read */
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDec4
+    stb     r3, 0(r10)          /* x00 to transmit */
+    eieio
+    or.     r7, r7, r8
+    beq     OutDec5
+    addi    r3, r8, 48          /* convert to ASCII */
+OutDec5:
+    lbz     r0, 0(r29)          /* slow down dummy read */
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDec5
+    stb     r3, 0(r10)          /* x0  to transmit */
+    eieio
+    addi    r3, r9, 48          /* convert to ASCII */
+OutDec6:
+    lbz     r0, 0(r29)          /* slow down dummy read */
+    lbz     r0, 5(r10)          /* read link status */
+    eieio
+    andi.   r0, r0, 0x40        /* mask transmitter empty bit */
+    beq     cr0, OutDec6
+    stb     r3, 0(r10)          /* x   to transmit */
+    eieio
+    blr
+
+/*
+ * hang endless loop
+ */
+toggleError:                    /* fail type in r6, r7=0xff, toggle LEDs */
+    stb     r7, 2(r30)          /* r7 to LED */
+    li      r0, 0
+    lis     r9, 127
+    ori     r9, r9, 65535
+toggleError1:
+    addic   r0, r0, 1
+    cmpw    cr1, r0, r9
+    ble     cr1, toggleError1
+    stb     r6, 2(r30)          /* r6 to LED */
+    li      r0, 0
+    lis     r9, 127
+    ori     r9, r9, 65535
+toggleError2:
+    addic   r0, r0, 1
+    cmpw    cr1, r0, r9
+    ble     cr1, toggleError2
+    b       toggleError
+
+/*
+ * routines to read from ram spd
+ */
+spdWaitIdle:
+    lis     r0, 0x1             /* timeout for about 100us */
+    mtctr   r0
+iSpd:
+    lbz     r10, 12(r14)
+    andi.   r10, r10, 0x20      /* mask and test MBB */
+    beq     idle
+    bdnz    iSpd
+    orc.    r10, r0, r0         /* return -1 to caller */
+idle:
+    bclr    20, 0               /* return to caller */
+
+waitSpd:
+    lis     r0, 0x10            /* timeout for about 1.5ms */
+    mtctr   r0
+wSpd:
+    lbz     r10, 12(r14)
+    andi.   r10, r10, 0x82
+    cmpli   0, 0, r10, 0x82     /* test MCF and MIF set */
+    beq     wend
+    bdnz    wSpd
+    orc.    r10, r0, r0         /* return -1 to caller */
+    bclr    20, 0               /* return to caller */
+
+wend:
+    li      r10, 0
+    stb     r10, 12(r14)        /* clear status */
+    bclr    20, 0               /* return to caller */
+
+/*
+ * spdread
+ * in:  r3 adr to read
+ * out: r3 val or -1 for error
+ * uses r10, assumes that r14 points to I2C controller
+ */
+spdRead:
+    mfspr   r25, 8              /* save link register */
+
+    bl      spdWaitIdle
+    bne     spdErr
+
+    li      r10, 0x80           /* start with MEN */
+    stb     r10, 8(r14)
+    eieio
+
+    li      r10, 0xb0           /* start as master */
+    stb     r10, 8(r14)
+    eieio
+
+    li      r10, 0xa0           /* write device 0xA0 */
+    stb     r10, 16(r14)
+    eieio
+    bl      waitSpd
+    bne     spdErr
+
+    lbz     r10, 12(r14)        /* test ACK */
+    andi.   r10, r10, 0x01
+    bne     gotNoAck
+
+    stb     r3, 16(r14)         /* data address */
+    eieio
+    bl      waitSpd
+    bne     spdErr
+
+
+    li      r10, 0xb4           /* switch to read - restart */
+    stb     r10, 8(r14)
+    eieio
+
+    li      r10, 0xa1           /* read device 0xA0 */
+    stb     r10, 16(r14)
+    eieio
+    bl      waitSpd
+    bne     spdErr
+
+    li      r10, 0xa8           /* no ACK */
+    stb     r10, 8(r14)
+    eieio
+
+    lbz     r10, 16(r14)        /* trigger read next byte */
+    eieio
+    bl      waitSpd
+    bne     spdErr
+
+    li      r10, 0x88           /* generate STOP condition */
+    stb     r10, 8(r14)
+    eieio
+
+    lbz     r3, 16(r14)         /* return read byte */
+
+    mtspr   8, r25              /* restore link register */
+    blr
+
+gotNoAck:
+    li      r10, 0x80           /* generate STOP condition */
+    stb     r10, 8(r14)
+    eieio
+spdErr:
+    orc     r3, r0, r0          /* return -1 */
+    mtspr   8, r25              /* restore link register */
+    blr
+
+get_lnk_reg:
+    mflr    r3                  /* return link reg */
+    blr
+
+MessageBlock:
+
+MinitLogo:
+    .ascii  "\015\012*** ELTEC Elektronik, Mainz ***\015\012"
+    .ascii  "\015\012Initialising RAM\015\012\000"
+Mspd01:
+    .ascii  "       Reading SPD of SODIMM ...... \000"
+MramTyp:
+    .ascii  "\015\012\SDRAM with CL=2 at 100 MHz required!\015\012\000"
+MramConfErr:
+    .ascii  "\015\012\Unsupported SODIMM Configuration!\015\012\000"
+Mactivate:
+    .ascii  "       Activating \000"
+Mact0123e:
+    .ascii  " MByte.\015\012\000"
+Mok:
+    .ascii  "OK \015\012\000"
+Mfail:
+    .ascii  "FAILED \015\012\000"
+MnewLine:
+    .ascii  "\015\012\000"
+    .align 4

+ 129 - 0
board/eltec/elppc/u-boot.lds

@@ -0,0 +1,129 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * 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
+ */
+
+/*
+ * u-boot.lds - linker script for U-Boot 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 = .);
+}

+ 341 - 0
board/ep7312/flash.c

@@ -0,0 +1,341 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#define FLASH_BANK_SIZE 0x1000000
+#define MAIN_SECT_SIZE  0x20000
+
+flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+
+ulong flash_init (void)
+{
+	int i, j;
+	ulong size = 0;
+
+	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+		ulong flashbase = 0;
+
+		flash_info[i].flash_id =
+				(INTEL_MANUFACT & FLASH_VENDMASK) |
+				(INTEL_ID_28F128J3 & FLASH_TYPEMASK);
+		flash_info[i].size = FLASH_BANK_SIZE;
+		flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
+		memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
+		if (i == 0)
+			flashbase = PHYS_FLASH_1;
+		else
+			panic ("configured to many flash banks!\n");
+		for (j = 0; j < flash_info[i].sector_count; j++) {
+			flash_info[i].start[j] = flashbase + j * MAIN_SECT_SIZE;
+		}
+		size += flash_info[i].size;
+	}
+
+	/* Protect monitor and environment sectors
+	 */
+	flash_protect ( FLAG_PROTECT_SET,
+			CFG_FLASH_BASE,
+			CFG_FLASH_BASE + _armboot_end_data - _armboot_start,
+			&flash_info[0]);
+
+	flash_protect ( FLAG_PROTECT_SET,
+			CFG_ENV_ADDR,
+			CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
+
+	return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+	int i;
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case (INTEL_MANUFACT & FLASH_VENDMASK):
+		printf ("Intel: ");
+		break;
+	default:
+		printf ("Unknown Vendor ");
+		break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case (INTEL_ID_28F128J3 & FLASH_TYPEMASK):
+		printf ("28F128J3 (128Mbit)\n");
+		break;
+	default:
+		printf ("Unknown Chip Type\n");
+		goto Done;
+		break;
+	}
+
+	printf ("  Size: %ld MB in %d Sectors\n",
+			info->size >> 20, 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");
+
+  Done:
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+	int flag, prot, sect;
+	int rc = ERR_OK;
+
+	if (info->flash_id == FLASH_UNKNOWN)
+		return ERR_UNKNOWN_FLASH_TYPE;
+
+	if ((s_first < 0) || (s_first > s_last)) {
+		return ERR_INVAL;
+	}
+
+	if ((info->flash_id & FLASH_VENDMASK) !=
+		(INTEL_MANUFACT & FLASH_VENDMASK)) {
+		return ERR_UNKNOWN_FLASH_VENDOR;
+	}
+
+	prot = 0;
+	for (sect = s_first; sect <= s_last; ++sect) {
+		if (info->protect[sect]) {
+			prot++;
+		}
+	}
+	if (prot)
+		return ERR_PROTECTED;
+
+	/*
+	 * Disable interrupts which might cause a timeout
+	 * here. Remember that our exception vectors are
+	 * at address 0 in the flash, and we don't want a
+	 * (ticker) exception to happen while the flash
+	 * chip is in programming mode.
+	 */
+	flag = disable_interrupts ();
+
+	/* Start erase on unprotected sectors */
+	for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
+
+		printf ("Erasing sector %2d ... ", sect);
+
+		/* arm simple, non interrupt dependent timer */
+		reset_timer_masked ();
+
+		if (info->protect[sect] == 0) {	/* not protected */
+			vu_short *addr = (vu_short *) (info->start[sect]);
+
+			*addr = 0x20;		/* erase setup */
+			*addr = 0xD0;		/* erase confirm */
+
+			while ((*addr & 0x80) != 0x80) {
+				if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
+					*addr = 0xB0;	/* suspend erase */
+					*addr = 0xFF;	/* reset to read mode */
+					rc = ERR_TIMOUT;
+					goto outahere;
+				}
+			}
+
+			/* clear status register command */
+			*addr = 0x50;
+			/* reset to read mode */
+			*addr = 0xFF;
+		}
+		printf ("ok.\n");
+	}
+	if (ctrlc ())
+		printf ("User Interrupt!\n");
+
+  outahere:
+
+	/* allow flash to settle - wait 10 ms */
+	udelay_masked (10000);
+
+	if (flag)
+		enable_interrupts ();
+
+	return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash
+ */
+
+static int write_word (flash_info_t * info, ulong dest, ushort data)
+{
+	vu_short *addr = (vu_short *) dest, val;
+	int rc = ERR_OK;
+	int flag;
+
+	/* Check if Flash is (sufficiently) erased
+	 */
+	if ((*addr & data) != data)
+		return ERR_NOT_ERASED;
+
+	/*
+	 * Disable interrupts which might cause a timeout
+	 * here. Remember that our exception vectors are
+	 * at address 0 in the flash, and we don't want a
+	 * (ticker) exception to happen while the flash
+	 * chip is in programming mode.
+	 */
+	flag = disable_interrupts ();
+
+	/* clear status register command */
+	*addr = 0x50;
+
+	/* program set-up command */
+	*addr = 0x40;
+
+	/* latch address/data */
+	*addr = data;
+
+	/* arm simple, non interrupt dependent timer */
+	reset_timer_masked ();
+
+	/* wait while polling the status register */
+	while (((val = *addr) & 0x80) != 0x80) {
+		if (get_timer_masked () > CFG_FLASH_WRITE_TOUT) {
+			rc = ERR_TIMOUT;
+			/* suspend program command */
+			*addr = 0xB0;
+			goto outahere;
+		}
+	}
+
+	if (val & 0x1A) {			/* check for error */
+		printf ("\nFlash write error %02x at address %08lx\n",
+				(int) val, (unsigned long) dest);
+		if (val & (1 << 3)) {
+			printf ("Voltage range error.\n");
+			rc = ERR_PROG_ERROR;
+			goto outahere;
+		}
+		if (val & (1 << 1)) {
+			printf ("Device protect error.\n");
+			rc = ERR_PROTECTED;
+			goto outahere;
+		}
+		if (val & (1 << 4)) {
+			printf ("Programming error.\n");
+			rc = ERR_PROG_ERROR;
+			goto outahere;
+		}
+		rc = ERR_PROG_ERROR;
+		goto outahere;
+	}
+
+  outahere:
+	/* read array command */
+	*addr = 0xFF;
+
+	if (flag)
+		enable_interrupts ();
+
+	return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ */
+
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+	ulong cp, wp;
+	ushort data;
+	int l;
+	int i, rc;
+
+	wp = (addr & ~1);			/* 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 << 8);
+		}
+		for (; i < 2 && cnt > 0; ++i) {
+			data = (data >> 8) | (*src++ << 8);
+			--cnt;
+			++cp;
+		}
+		for (; cnt == 0 && i < 2; ++i, ++cp) {
+			data = (data >> 8) | (*(uchar *) cp << 8);
+		}
+
+		if ((rc = write_word (info, wp, data)) != 0) {
+			return (rc);
+		}
+		wp += 2;
+	}
+
+	/*
+	 * handle word aligned part
+	 */
+	while (cnt >= 2) {
+		data = *((vu_short *) src);
+		if ((rc = write_word (info, wp, data)) != 0) {
+			return (rc);
+		}
+		src += 2;
+		wp += 2;
+		cnt -= 2;
+	}
+
+	if (cnt == 0) {
+		return ERR_OK;
+	}
+
+	/*
+	 * handle unaligned tail bytes
+	 */
+	data = 0;
+	for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) {
+		data = (data >> 8) | (*src++ << 8);
+		--cnt;
+	}
+	for (; i < 2; ++i, ++cp) {
+		data = (data >> 8) | (*(uchar *) cp << 8);
+	}
+
+	return write_word (info, wp, data);
+}

+ 53 - 0
board/ep7312/u-boot.lds

@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+        . = 0x00000000;
+
+        . = ALIGN(4);
+	.text      :
+	{
+	  cpu/arm720t/start.o	(.text)
+	  *(.text)
+	}
+
+        . = ALIGN(4);
+        .rodata : { *(.rodata) }
+
+        . = ALIGN(4);
+        .data : { *(.data) }
+
+        . = ALIGN(4);
+        .got : { *(.got) }
+
+	armboot_end_data = .;
+
+        . = ALIGN(4);
+        .bss : { *(.bss) }
+
+	armboot_end = .;
+}

+ 262 - 0
board/esd/common/fpga.c

@@ -0,0 +1,262 @@
+/*
+ * (C) Copyright 2001
+ * Matthias Fuchs, esd gmbh germany, matthias.fuchs@esd-electronics.com
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <command.h>
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef FPGA_DEBUG
+#define DBG(x...) printf(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG */
+
+#define MAX_ONES               226
+
+#define IBM405GP_GPIO0_OR      0xef600700  /* GPIO Output */
+#define IBM405GP_GPIO0_TCR     0xef600704  /* GPIO Three-State Control */
+#define IBM405GP_GPIO0_ODR     0xef600718  /* GPIO Open Drain */
+#define IBM405GP_GPIO0_IR      0xef60071c  /* GPIO Input */
+
+#ifdef CFG_FPGA_PRG
+# define FPGA_PRG              CFG_FPGA_PRG /* FPGA program pin (ppc output)*/
+# define FPGA_CLK              CFG_FPGA_CLK /* FPGA clk pin (ppc output)    */
+# define FPGA_DATA             CFG_FPGA_DATA /* FPGA data pin (ppc output)  */
+# define FPGA_DONE             CFG_FPGA_DONE /* FPGA done pin (ppc input)   */
+# define FPGA_INIT             CFG_FPGA_INIT /* FPGA init pin (ppc input)   */
+#else
+# define FPGA_PRG              0x04000000  /* FPGA program pin (ppc output) */
+# define FPGA_CLK              0x02000000  /* FPGA clk pin (ppc output)     */
+# define FPGA_DATA             0x01000000  /* FPGA data pin (ppc output)    */
+# define FPGA_DONE             0x00800000  /* FPGA done pin (ppc input)     */
+# define FPGA_INIT             0x00400000  /* FPGA init pin (ppc input)     */
+#endif
+
+#define ERROR_FPGA_PRG_INIT_LOW  -1        /* Timeout after PRG* asserted   */
+#define ERROR_FPGA_PRG_INIT_HIGH -2        /* Timeout after PRG* deasserted */
+#define ERROR_FPGA_PRG_DONE      -3        /* Timeout after programming     */
+
+#define SET_FPGA(data)         out32(IBM405GP_GPIO0_OR, data)
+
+#define FPGA_WRITE_1 {                                                    \
+        SET_FPGA(FPGA_PRG |            FPGA_DATA);  /* set clock to 0 */  \
+        SET_FPGA(FPGA_PRG |            FPGA_DATA);  /* set data to 1  */  \
+        SET_FPGA(FPGA_PRG | FPGA_CLK | FPGA_DATA);  /* set clock to 1 */  \
+        SET_FPGA(FPGA_PRG | FPGA_CLK | FPGA_DATA);} /* set data to 1  */
+
+#define FPGA_WRITE_0 {                                                    \
+        SET_FPGA(FPGA_PRG |            FPGA_DATA);  /* set clock to 0 */  \
+        SET_FPGA(FPGA_PRG);                         /* set data to 0  */  \
+        SET_FPGA(FPGA_PRG | FPGA_CLK);              /* set clock to 1 */  \
+        SET_FPGA(FPGA_PRG | FPGA_CLK | FPGA_DATA);} /* set data to 1  */
+
+
+static int fpga_boot(unsigned char *fpgadata, int size)
+{
+  int i,index,len;
+  int count;
+#ifdef CFG_FPGA_SPARTAN2
+  int j;
+#else
+  unsigned char b;
+  int bit;
+#endif
+
+  /* display infos on fpgaimage */
+  index = 15;
+  for (i=0; i<4; i++)
+    {
+      len = fpgadata[index];
+      DBG("FPGA: %s\n", &(fpgadata[index+1]));
+      index += len+3;
+    }
+
+#ifdef CFG_FPGA_SPARTAN2
+  /* search for preamble 0xFFFFFFFF */
+  while (1)
+    {
+      if ((fpgadata[index] == 0xff) && (fpgadata[index+1] == 0xff) &&
+          (fpgadata[index+2] == 0xff) && (fpgadata[index+3] == 0xff))
+        break; /* preamble found */
+      else
+        index++;
+    }
+#else
+  /* search for preamble 0xFF2X */
+  for (index = 0; index < size-1 ; index++)
+    {
+      if ((fpgadata[index] == 0xff) && ((fpgadata[index+1] & 0xf0) == 0x30))
+	break;
+    }
+  index += 2;
+#endif
+
+  DBG("FPGA: configdata starts at position 0x%x\n",index);
+  DBG("FPGA: length of fpga-data %d\n", size-index);
+
+  /*
+   * Setup port pins for fpga programming
+   */
+  out32(IBM405GP_GPIO0_ODR, 0x00000000);                       /* no open drain pins      */
+  out32(IBM405GP_GPIO0_TCR, FPGA_PRG | FPGA_CLK | FPGA_DATA);  /* setup for output        */
+  out32(IBM405GP_GPIO0_OR,  FPGA_PRG | FPGA_CLK | FPGA_DATA);  /* set output pins to high */
+
+  DBG("%s, ",((in32(IBM405GP_GPIO0_IR) & FPGA_DONE) == 0) ? "NOT DONE" : "DONE" );
+  DBG("%s\n",((in32(IBM405GP_GPIO0_IR) & FPGA_INIT) == 0) ? "NOT INIT" : "INIT" );
+
+  /*
+   * Init fpga by asserting and deasserting PROGRAM*
+   */
+  SET_FPGA(FPGA_CLK | FPGA_DATA);
+
+  /* Wait for FPGA init line low */
+  count = 0;
+  while (in32(IBM405GP_GPIO0_IR) & FPGA_INIT)
+    {
+      udelay(1000); /* wait 1ms */
+      /* Check for timeout - 100us max, so use 3ms */
+      if (count++ > 3)
+        {
+          DBG("FPGA: Booting failed!\n");
+          return ERROR_FPGA_PRG_INIT_LOW;
+        }
+    }
+
+  DBG("%s, ",((in32(IBM405GP_GPIO0_IR) & FPGA_DONE) == 0) ? "NOT DONE" : "DONE" );
+  DBG("%s\n",((in32(IBM405GP_GPIO0_IR) & FPGA_INIT) == 0) ? "NOT INIT" : "INIT" );
+
+  /* deassert PROGRAM* */
+  SET_FPGA(FPGA_PRG | FPGA_CLK | FPGA_DATA);
+
+  /* Wait for FPGA end of init period .  */
+  count = 0;
+  while (!(in32(IBM405GP_GPIO0_IR) & FPGA_INIT))
+    {
+      udelay(1000); /* wait 1ms */
+      /* Check for timeout */
+      if (count++ > 3)
+        {
+          DBG("FPGA: Booting failed!\n");
+          return ERROR_FPGA_PRG_INIT_HIGH;
+        }
+    }
+
+  DBG("%s, ",((in32(IBM405GP_GPIO0_IR) & FPGA_DONE) == 0) ? "NOT DONE" : "DONE" );
+  DBG("%s\n",((in32(IBM405GP_GPIO0_IR) & FPGA_INIT) == 0) ? "NOT INIT" : "INIT" );
+
+  DBG("write configuration data into fpga\n");
+  /* write configuration-data into fpga... */
+
+#ifdef CFG_FPGA_SPARTAN2
+  /*
+   * Load uncompressed image into fpga
+   */
+  for (i=index; i<size; i++)
+    {
+      for (j=0; j<8; j++)
+        {
+          if ((fpgadata[i] & 0x80) == 0x80)
+	    {
+              FPGA_WRITE_1;
+	    }
+          else
+	    {
+              FPGA_WRITE_0;
+	    }
+          fpgadata[i] <<= 1;
+        }
+    }
+#else
+  /* send 0xff 0x20 */
+  FPGA_WRITE_1; FPGA_WRITE_1; FPGA_WRITE_1; FPGA_WRITE_1;
+  FPGA_WRITE_1; FPGA_WRITE_1; FPGA_WRITE_1; FPGA_WRITE_1;
+  FPGA_WRITE_0; FPGA_WRITE_0; FPGA_WRITE_1; FPGA_WRITE_0;
+  FPGA_WRITE_0; FPGA_WRITE_0; FPGA_WRITE_0; FPGA_WRITE_0;
+
+  /*
+  ** Bit_DeCompression
+  **   Code 1           .. maxOnes     : n                 '1's followed by '0'
+  **        maxOnes + 1 .. maxOnes + 1 : n - 1             '1's no '0'
+  **        maxOnes + 2 .. 254         : n - (maxOnes + 2) '0's followed by '1'
+  **        255                        :                   '1'
+  */
+
+  for (i=index; i<size; i++)
+    {
+      b = fpgadata[i];
+      if ((b >= 1) && (b <= MAX_ONES))
+	{
+	  for(bit=0; bit<b; bit++)
+            {
+              FPGA_WRITE_1;
+            }
+	  FPGA_WRITE_0;
+	}
+      else if (b == (MAX_ONES+1))
+	{
+	  for(bit=1; bit<b; bit++)
+            {
+              FPGA_WRITE_1;
+            }
+	}
+      else if ((b >= (MAX_ONES+2)) && (b <= 254))
+	{
+	  for(bit=0; bit<(b-(MAX_ONES+2)); bit++)
+            {
+              FPGA_WRITE_0;
+            }
+          FPGA_WRITE_1;
+	}
+      else if (b == 255)
+        {
+          FPGA_WRITE_1;
+        }
+    }
+#endif
+
+  DBG("%s, ",((in32(IBM405GP_GPIO0_IR) & FPGA_DONE) == 0) ? "NOT DONE" : "DONE" );
+  DBG("%s\n",((in32(IBM405GP_GPIO0_IR) & FPGA_INIT) == 0) ? "NOT INIT" : "INIT" );
+
+  /*
+   * Check if fpga's DONE signal - correctly booted ?
+   */
+
+  /* Wait for FPGA end of programming period .  */
+  count = 0;
+  while (!(in32(IBM405GP_GPIO0_IR) & FPGA_DONE))
+    {
+      udelay(1000); /* wait 1ms */
+      /* Check for timeout */
+      if (count++ > 3)
+        {
+          DBG("FPGA: Booting failed!\n");
+          return ERROR_FPGA_PRG_DONE;
+        }
+    }
+
+  DBG("FPGA: Booting successful!\n");
+  return 0;
+}

+ 202 - 0
board/esd/common/pci.c

@@ -0,0 +1,202 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+#include <pci.h>
+
+
+u_long pci9054_iobase;
+
+
+#define PCI_PRIMARY_CAR	(0x500000dc) /* PCI config address reg */
+#define PCI_PRIMARY_CDR	(0x80000000) /* PCI config data    reg */
+
+
+/*-----------------------------------------------------------------------------+
+|  Subroutine:  pci9054_read_config_dword
+|  Description: Read a PCI configuration register
+|  Inputs:
+|               hose            PCI Controller
+|               dev             PCI Bus+Device+Function number
+|               offset          Configuration register number
+|               value           Address of the configuration register value
+|  Return value:
+|               0               Successful
++-----------------------------------------------------------------------------*/
+int pci9054_read_config_dword(struct pci_controller *hose,
+			      pci_dev_t dev, int offset, u32* value)
+{
+  unsigned long      conAdrVal;
+  unsigned long      val;
+
+  /* generate coded value for CON_ADR register */
+  conAdrVal = dev | (offset & 0xfc) | 0x80000000;
+
+  /* Load the CON_ADR (CAR) value first, then read from CON_DATA (CDR) */
+  *(unsigned long *)PCI_PRIMARY_CAR = conAdrVal;
+
+  /* Note: *pResult comes back as -1 if machine check happened */
+  val = in32r(PCI_PRIMARY_CDR);
+
+  *value = (unsigned long) val;
+
+  out32r(PCI_PRIMARY_CAR, 0);
+
+  if ((*(unsigned long *)0x50000304) & 0x60000000)
+    {
+      /* clear pci master/target abort bits */
+      *(unsigned long *)0x50000304 = *(unsigned long *)0x50000304;
+    }
+
+  return 0;
+}
+
+/*-----------------------------------------------------------------------------+
+|  Subroutine:  pci9054_write_config_dword
+|  Description: Write a PCI configuration register.
+|  Inputs:
+|               hose            PCI Controller
+|               dev             PCI Bus+Device+Function number
+|               offset          Configuration register number
+|               Value           Configuration register value
+|  Return value:
+|               0               Successful
+| Updated for pass2 errata #6. Need to disable interrupts and clear the
+| PCICFGADR reg after writing the PCICFGDATA reg.
++-----------------------------------------------------------------------------*/
+int pci9054_write_config_dword(struct pci_controller *hose,
+			       pci_dev_t dev, int offset, u32 value)
+{
+  unsigned long      conAdrVal;
+
+  conAdrVal = dev | (offset & 0xfc) | 0x80000000;
+
+  *(unsigned long *)PCI_PRIMARY_CAR = conAdrVal;
+
+  out32r(PCI_PRIMARY_CDR, value);
+
+  out32r(PCI_PRIMARY_CAR, 0);
+
+  /* clear pci master/target abort bits */
+  *(unsigned long *)0x50000304 = *(unsigned long *)0x50000304;
+
+  return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+#ifdef CONFIG_DASA_SIM
+static void pci_dasa_sim_config_pci9054(struct pci_controller *hose, pci_dev_t dev,
+					struct pci_config_table *_)
+{
+  unsigned int iobase;
+  unsigned short status = 0;
+  unsigned char timer;
+
+  /*
+   * Configure PLX PCI9054
+   */
+  pci_read_config_word(CFG_PCI9054_DEV_FN, PCI_COMMAND, &status);
+  status |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+  pci_write_config_word(CFG_PCI9054_DEV_FN, PCI_COMMAND, status);
+
+  /* Check the latency timer for values >= 0x60.
+   */
+  pci_read_config_byte(CFG_PCI9054_DEV_FN, PCI_LATENCY_TIMER, &timer);
+  if (timer < 0x60)
+    {
+      pci_write_config_byte(CFG_PCI9054_DEV_FN, PCI_LATENCY_TIMER, 0x60);
+    }
+
+  /* Set I/O base register.
+   */
+  pci_write_config_dword(CFG_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, CFG_PCI9054_IOBASE);
+  pci_read_config_dword(CFG_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, &iobase);
+
+  pci9054_iobase = pci_mem_to_phys(CFG_PCI9054_DEV_FN, iobase & PCI_BASE_ADDRESS_MEM_MASK);
+
+  if (pci9054_iobase == 0xffffffff)
+    {
+      printf("Error: Can not set I/O base register.\n");
+      return;
+    }
+}
+#endif
+
+static struct pci_config_table pci9054_config_table[] = {
+#ifndef CONFIG_PCI_PNP
+  { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+    PCI_BUS(CFG_ETH_DEV_FN), PCI_DEV(CFG_ETH_DEV_FN), PCI_FUNC(CFG_ETH_DEV_FN),
+    pci_cfgfunc_config_device, { CFG_ETH_IOBASE,
+				 CFG_ETH_IOBASE,
+				 PCI_COMMAND_IO | PCI_COMMAND_MASTER }},
+#ifdef CONFIG_DASA_SIM
+  { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+    PCI_BUS(CFG_PCI9054_DEV_FN), PCI_DEV(CFG_PCI9054_DEV_FN), PCI_FUNC(CFG_PCI9054_DEV_FN),
+    pci_dasa_sim_config_pci9054 },
+#endif
+#endif
+  { }
+};
+
+static struct pci_controller pci9054_hose = {
+  config_table: pci9054_config_table,
+};
+
+void pci_init(void)
+{
+  struct pci_controller *hose = &pci9054_hose;
+
+  /*
+   * Register the hose
+   */
+  hose->first_busno = 0;
+  hose->last_busno = 0xff;
+
+  /* System memory space */
+  pci_set_region(hose->regions + 0,
+		 0x00000000, 0x00000000, 0x01000000,
+		 PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+  /* PCI Memory space */
+  pci_set_region(hose->regions + 1,
+		 0x00000000, 0xc0000000, 0x10000000,
+		 PCI_REGION_MEM);
+
+  pci_set_ops(hose,
+	      pci_hose_read_config_byte_via_dword,
+	      pci_hose_read_config_word_via_dword,
+	      pci9054_read_config_dword,
+	      pci_hose_write_config_byte_via_dword,
+	      pci_hose_write_config_word_via_dword,
+	      pci9054_write_config_dword);
+
+  hose->region_count = 2;
+
+  pci_register_hose(hose);
+
+  hose->last_busno = pci_hose_scan(hose);
+}

+ 451 - 0
board/esd/cpci405/cpci405.c

@@ -0,0 +1,451 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <malloc.h>
+
+/* ------------------------------------------------------------------------- */
+
+#if 0
+#define FPGA_DEBUG
+#endif
+
+/* fpga configuration data - generated by bin2cc */
+const unsigned char fpgadata[] =
+{
+#ifdef CONFIG_CPCI405_VER2
+# include "fpgadata_cpci4052.c"
+#else
+# include "fpgadata_cpci405.c"
+#endif
+};
+
+/*
+ * include common fpga code (for esd boards)
+ */
+#include "../common/fpga.c"
+
+
+/* Prototypes */
+int version2(void);
+int gunzip(void *, int, unsigned char *, int *);
+
+
+int board_pre_init (void)
+{
+#ifndef CONFIG_CPCI405_VER2
+	int index, len, i;
+	int status;
+#endif
+
+#ifdef FPGA_DEBUG
+	DECLARE_GLOBAL_DATA_PTR;
+
+	/* set up serial port with default baudrate */
+	(void) get_clocks ();
+	gd->baudrate = CONFIG_BAUDRATE;
+	serial_init ();
+	console_init_f();
+#endif
+
+	/*
+	 * First pull fpga-prg pin low, to disable fpga logic (on version 2 board)
+	 */
+	out32(IBM405GP_GPIO0_ODR, 0x00000000);        /* no open drain pins      */
+	out32(IBM405GP_GPIO0_TCR, CFG_FPGA_PRG);      /* setup for output        */
+	out32(IBM405GP_GPIO0_OR,  CFG_FPGA_PRG);      /* set output pins to high */
+	out32(IBM405GP_GPIO0_OR, 0);                  /* pull prg low            */
+
+	/*
+	 * Boot onboard FPGA
+	 */
+#ifndef CONFIG_CPCI405_VER2
+	if (!version2()) {
+		status = fpga_boot((unsigned char *)fpgadata, sizeof(fpgadata));
+		if (status != 0) {
+			/* booting FPGA failed */
+#ifndef FPGA_DEBUG
+			DECLARE_GLOBAL_DATA_PTR;
+
+			/* set up serial port with default baudrate */
+			(void) get_clocks ();
+			gd->baudrate = CONFIG_BAUDRATE;
+			serial_init ();
+			console_init_f();
+#endif
+			printf("\nFPGA: Booting failed ");
+			switch (status) {
+			case ERROR_FPGA_PRG_INIT_LOW:
+				printf("(Timeout: INIT not low after asserting PROGRAM*)\n ");
+				break;
+			case ERROR_FPGA_PRG_INIT_HIGH:
+				printf("(Timeout: INIT not high after deasserting PROGRAM*)\n ");
+				break;
+			case ERROR_FPGA_PRG_DONE:
+				printf("(Timeout: DONE not high after programming FPGA)\n ");
+				break;
+			}
+
+			/* display infos on fpgaimage */
+			index = 15;
+			for (i=0; i<4; i++) {
+				len = fpgadata[index];
+				printf("FPGA: %s\n", &(fpgadata[index+1]));
+				index += len+3;
+			}
+			putc ('\n');
+			/* delayed reboot */
+			for (i=20; i>0; i--) {
+				printf("Rebooting in %2d seconds \r",i);
+				for (index=0;index<1000;index++)
+					udelay(1000);
+			}
+			putc ('\n');
+			do_reset(NULL, 0, 0, NULL);
+		}
+	}
+#endif /* !CONFIG_CPCI405_VER2 */
+
+	/*
+	 * IRQ 0-15  405GP internally generated; active high; level sensitive
+	 * IRQ 16    405GP internally generated; active low; level sensitive
+	 * IRQ 17-24 RESERVED
+	 * IRQ 25 (EXT IRQ 0) CAN0; active low; level sensitive
+	 * IRQ 26 (EXT IRQ 1) CAN1 (+FPGA on CPCI4052) ; active low; level sensitive
+	 * IRQ 27 (EXT IRQ 2) PCI SLOT 0; active low; level sensitive
+	 * IRQ 28 (EXT IRQ 3) PCI SLOT 1; active low; level sensitive
+	 * IRQ 29 (EXT IRQ 4) PCI SLOT 2; active low; level sensitive
+	 * IRQ 30 (EXT IRQ 5) PCI SLOT 3; active low; level sensitive
+	 * IRQ 31 (EXT IRQ 6) COMPACT FLASH; active high; level sensitive
+	 */
+	mtdcr(uicsr, 0xFFFFFFFF);       /* clear all ints */
+	mtdcr(uicer, 0x00000000);       /* disable all ints */
+	mtdcr(uiccr, 0x00000000);       /* set all to be non-critical*/
+	mtdcr(uicpr, 0xFFFFFF81);       /* set int polarities */
+	mtdcr(uictr, 0x10000000);       /* set int trigger levels */
+	mtdcr(uicvcr, 0x00000001);      /* set vect base=0,INT0 highest priority*/
+	mtdcr(uicsr, 0xFFFFFFFF);       /* clear all ints */
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+int ctermm2(void)
+{
+#ifdef CONFIG_CPCI405_VER2
+	return 0;                       /* no, board is cpci405 */
+#else
+	if ((*(unsigned char *)0xf0000400 == 0x00) &&
+	    (*(unsigned char *)0xf0000401 == 0x01))
+		return 0;               /* no, board is cpci405 */
+	else
+		return -1;              /* yes, board is cterm-m2 */
+#endif
+}
+
+
+int cpci405_host(void)
+{
+	if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+		return -1;              /* yes, board is cpci405 host */
+	else
+		return 0;               /* no, board is cpci405 adapter */
+}
+
+
+int version2(void)
+{
+	unsigned long cntrl0Reg;
+	unsigned long value;
+
+	/*
+	 * Setup GPIO pins (CS2/GPIO11 as GPIO)
+	 */
+	cntrl0Reg = mfdcr(cntrl0);
+	mtdcr(cntrl0, cntrl0Reg | 0x02000000);
+
+	udelay(1000);                   /* wait some time before reading input */
+	value = in32(IBM405GP_GPIO0_IR) & 0x00100000; /* test GPIO11 */
+
+	/*
+	 * Setup GPIO pins (CS2/GPIO11 as CS again)
+	 */
+	mtdcr(cntrl0, cntrl0Reg);
+
+	if (value)
+		return 0;               /* no, board is version 1.x */
+	else
+		return -1;              /* yes, board is version 2.x */
+}
+
+
+int misc_init_f (void)
+{
+	return 0;  /* dummy implementation */
+}
+
+
+int misc_init_r (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	bd_t *bd = gd->bd;
+	char *	tmp;                    /* Temporary char pointer      */
+
+#ifdef CONFIG_CPCI405_VER2
+	unsigned char *dst;
+	ulong len = sizeof(fpgadata);
+	int status;
+	int index;
+	int i;
+	unsigned long cntrl0Reg;
+
+	/*
+	 * On CPCI-405 version 2 the environment is saved in eeprom!
+	 * FPGA can be gzip compressed (malloc) and booted this late.
+	 */
+
+	if (version2()) {
+		/*
+		 * Setup GPIO pins (CS6+CS7 as GPIO)
+		 */
+		cntrl0Reg = mfdcr(cntrl0);
+		mtdcr(cntrl0, cntrl0Reg | 0x00300000);
+
+		dst = malloc(CFG_FPGA_MAX_SIZE);
+		if (gunzip (dst, CFG_FPGA_MAX_SIZE, (uchar *)fpgadata, (int *)&len) != 0) {
+			printf ("GUNZIP ERROR - must RESET board to recover\n");
+			do_reset (NULL, 0, 0, NULL);
+		}
+
+		status = fpga_boot(dst, len);
+		if (status != 0) {
+			printf("\nFPGA: Booting failed ");
+			switch (status) {
+			case ERROR_FPGA_PRG_INIT_LOW:
+				printf("(Timeout: INIT not low after asserting PROGRAM*)\n ");
+				break;
+			case ERROR_FPGA_PRG_INIT_HIGH:
+				printf("(Timeout: INIT not high after deasserting PROGRAM*)\n ");
+				break;
+			case ERROR_FPGA_PRG_DONE:
+				printf("(Timeout: DONE not high after programming FPGA)\n ");
+				break;
+			}
+
+			/* display infos on fpgaimage */
+			index = 15;
+			for (i=0; i<4; i++) {
+				len = dst[index];
+				printf("FPGA: %s\n", &(dst[index+1]));
+				index += len+3;
+			}
+			putc ('\n');
+			/* delayed reboot */
+			for (i=20; i>0; i--) {
+				printf("Rebooting in %2d seconds \r",i);
+				for (index=0;index<1000;index++)
+					udelay(1000);
+			}
+			putc ('\n');
+			do_reset(NULL, 0, 0, NULL);
+		}
+
+		/* restore gpio/cs settings */
+		mtdcr(cntrl0, cntrl0Reg);
+
+		puts("FPGA:  ");
+
+		/* display infos on fpgaimage */
+		index = 15;
+		for (i=0; i<4; i++) {
+			len = dst[index];
+			printf("%s ", &(dst[index+1]));
+			index += len+3;
+		}
+		putc ('\n');
+
+		free(dst);
+	}
+	else {
+		printf("\n*** U-Boot Version does not match Board Version!\n");
+		printf("*** CPCI-405 Version 2.x detected!\n");
+		printf("*** Please use correct U-Boot version (CPCI4052)!\n\n");
+	}
+
+#else /* CONFIG_CPCI405_VER2 */
+
+	/*
+	 * Generate last byte of ip-addr from code-plug @ 0xf0000400
+	 */
+	if (ctermm2()) {
+		char str[32];
+		unsigned char ipbyte = *(unsigned char *)0xf0000400;
+
+		/*
+		 * Only overwrite ip-addr with allowed values
+		 */
+		if ((ipbyte != 0x00) && (ipbyte != 0xff)) {
+			bd->bi_ip_addr = (bd->bi_ip_addr & 0xffffff00) | ipbyte;
+			sprintf(str, "%ld.%ld.%ld.%ld",
+				(bd->bi_ip_addr & 0xff000000) >> 24,
+				(bd->bi_ip_addr & 0x00ff0000) >> 16,
+				(bd->bi_ip_addr & 0x0000ff00) >> 8,
+				(bd->bi_ip_addr & 0x000000ff));
+			setenv("ipaddr", str);
+		}
+	}
+
+	if (version2()) {
+		printf("\n*** U-Boot Version does not match Board Version!\n");
+		printf("*** CPCI-405 Board Version 1.x detected!\n");
+		printf("*** Please use correct U-Boot version (CPCI405)!\n\n");
+	}
+
+#endif /* CONFIG_CPCI405_VER2 */
+
+	/*
+	 * Write ethernet addr in NVRAM for VxWorks
+	 */
+	tmp = (char *)CFG_NVRAM_BASE_ADDR + CFG_NVRAM_VXWORKS_OFFS;
+	memcpy( (char *)tmp, (char *)&bd->bi_enetaddr[0], 6 );
+	return (0);
+}
+
+
+/*
+ * Check Board Identity:
+ */
+
+int checkboard (void)
+{
+#ifndef CONFIG_CPCI405_VER2
+	int index;
+	int len;
+#endif
+	unsigned char str[64];
+	int i = getenv_r ("serial#", str, sizeof(str));
+
+	puts ("Board: ");
+
+	if (i == -1) {
+		puts ("### No HW ID - assuming CPCI405");
+	} else {
+		puts(str);
+	}
+
+	if (version2())
+		puts (" (Ver 2.x, ");
+	else
+		puts (" (Ver 1.x, ");
+
+#if 0
+	if ((*(unsigned short *)((unsigned long)CFG_FPGA_BASE_ADDR) + CFG_FPGA_STATUS)
+	    & CFG_FPGA_STATUS_FLASH)
+		puts ("FLASH Bank A, ");
+	else
+		puts ("FLASH Bank B, ");
+#endif
+
+	if (ctermm2()) {
+		printf("CTERM-M2 - Id=0x%02x)", *(unsigned char *)0xf0000400);
+	} else {
+		if (cpci405_host()) {
+			puts ("PCI Host Version)");
+		} else {
+			puts ("PCI Adapter Version)");
+		}
+	}
+
+#ifndef CONFIG_CPCI405_VER2
+	puts ("\nFPGA:  ");
+
+	/* display infos on fpgaimage */
+	index = 15;
+	for (i=0; i<4; i++) {
+		len = fpgadata[index];
+		printf("%s ", &(fpgadata[index+1]));
+		index += len+3;
+	}
+#endif
+
+	putc ('\n');
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+long int initdram (int board_type)
+{
+	unsigned long val;
+
+	mtdcr(memcfga, mem_mb0cf);
+	val = mfdcr(memcfgd);
+
+#if 0
+	printf("\nmb0cf=%x\n", val); /* test-only */
+	printf("strap=%x\n", mfdcr(strap)); /* test-only */
+#endif
+
+	return (4*1024*1024 << ((val & 0x000e0000) >> 17));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int testdram (void)
+{
+	/* TODO: XXX XXX XXX */
+	printf ("test: 16 MB - ok\n");
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_CPCI405_VER2
+#ifdef CONFIG_IDE_RESET
+
+void ide_set_reset(int on)
+{
+	volatile unsigned short *fpga_mode = (unsigned short *)CFG_FPGA_BASE_ADDR;
+
+	/*
+	 * Assert or deassert CompactFlash Reset Pin
+	 */
+	if (on) {		/* assert RESET */
+		*fpga_mode &= ~(CFG_FPGA_MODE_CF_RESET);
+	} else {		/* release RESET */
+		*fpga_mode |= CFG_FPGA_MODE_CF_RESET;
+	}
+}
+
+#endif /* CONFIG_IDE_RESET */
+#endif /* CONFIG_CPCI405_VER2 */
+
+/* ------------------------------------------------------------------------- */

+ 140 - 0
board/esd/cpci440/cpci440.c

@@ -0,0 +1,140 @@
+/*
+ * (C) Copyright 2002
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <common.h>
+#include <asm/processor.h>
+
+
+long int fixed_sdram( void );
+
+int board_pre_init (void)
+{
+	uint reg;
+
+	/*--------------------------------------------------------------------
+	 * Setup the external bus controller/chip selects
+	 *-------------------------------------------------------------------*/
+	mtdcr( ebccfga, xbcfg );
+	reg = mfdcr( ebccfgd );
+	mtdcr( ebccfgd, reg | 0x04000000 );	/* Set ATC */
+
+	mtebc( pb0ap, 0x92015480 );	/* FLASH/SRAM */
+	mtebc( pb0cr, 0xFF87A000 ); /* BAS=0xff8 8MB R/W 16-bit */
+	/* test-only: other regs still missing... */
+
+	/*--------------------------------------------------------------------
+	 * Setup the interrupt controller polarities, triggers, etc.
+	 *-------------------------------------------------------------------*/
+	mtdcr( uic0sr, 0xffffffff );    /* clear all */
+	mtdcr( uic0er, 0x00000000 );    /* disable all */
+	mtdcr( uic0cr, 0x00000009 );    /* SMI & UIC1 crit are critical */
+	mtdcr( uic0pr, 0xfffffe13 );    /* per ref-board manual */
+	mtdcr( uic0tr, 0x01c00008 );    /* per ref-board manual */
+	mtdcr( uic0vr, 0x00000001 );    /* int31 highest, base=0x000 */
+	mtdcr( uic0sr, 0xffffffff );    /* clear all */
+
+	mtdcr( uic1sr, 0xffffffff );    /* clear all */
+	mtdcr( uic1er, 0x00000000 );    /* disable all */
+	mtdcr( uic1cr, 0x00000000 );    /* all non-critical */
+	mtdcr( uic1pr, 0xffffe0ff );    /* per ref-board manual */
+	mtdcr( uic1tr, 0x00ffc000 );    /* per ref-board manual */
+	mtdcr( uic1vr, 0x00000001 );    /* int31 highest, base=0x000 */
+	mtdcr( uic1sr, 0xffffffff );    /* clear all */
+
+	return 0;
+}
+
+
+
+int checkboard (void)
+{
+	sys_info_t sysinfo;
+	get_sys_info(&sysinfo);
+
+	printf("Board: esd CPCI-440\n");
+	printf("\tVCO: %lu MHz\n", sysinfo.freqVCOMhz/1000000);
+	printf("\tCPU: %lu MHz\n", sysinfo.freqProcessor/1000000);
+	printf("\tPLB: %lu MHz\n", sysinfo.freqPLB/1000000);
+	printf("\tOPB: %lu MHz\n", sysinfo.freqOPB/1000000);
+	printf("\tEPB: %lu MHz\n", sysinfo.freqEPB/1000000);
+	return (0);
+}
+
+
+long int initdram (int board_type)
+{
+	long    dram_size = 0;
+
+	dram_size = fixed_sdram();
+	return dram_size;
+}
+
+
+/*************************************************************************
+ *  fixed sdram init -- doesn't use serial presence detect.
+ *
+ *  Assumes:    64 MB, non-ECC, non-registered
+ *              PLB @ 133 MHz
+ *
+ ************************************************************************/
+long int fixed_sdram( void )
+{
+	uint    reg;
+
+	/*--------------------------------------------------------------------
+	 * Setup some default
+	 *------------------------------------------------------------------*/
+	mtsdram( mem_uabba, 0x00000000 );   /* ubba=0 (default)             */
+	mtsdram( mem_slio,  0x00000000 );   /* rdre=0 wrre=0 rarw=0         */
+	mtsdram( mem_devopt,0x00000000 );   /* dll=0 ds=0 (normal)          */
+	mtsdram( mem_wddctr,0x40000000 );   /* wrcp=0 dcd=0                 */
+	mtsdram( mem_clktr, 0x40000000 );   /* clkp=1 (90 deg wr) dcdt=0    */
+
+	/*--------------------------------------------------------------------
+	 * Setup for board-specific specific mem
+	 *------------------------------------------------------------------*/
+	/*
+	 * Following for CAS Latency = 2.5 @ 133 MHz PLB
+	 */
+	mtsdram( mem_b0cr, 0x00082001 );/* SDBA=0x000, 64MB, Mode 2, enabled*/
+	mtsdram( mem_tr0,  0x410a4012 );/* WR=2  WD=1 CL=2.5 PA=3 CP=4 LD=2 */
+	/* RA=10 RD=3                       */
+	mtsdram( mem_tr1,  0x8080082f );/* SS=T2 SL=STAGE 3 CD=1 CT=0x02f   */
+	mtsdram( mem_rtr,  0x08200000 );/* Rate 15.625 ns @ 133 MHz PLB     */
+	mtsdram( mem_cfg1, 0x00000000 );/* Self-refresh exit, disable PM    */
+	udelay( 400 );                  /* Delay 200 usecs (min)            */
+
+	/*--------------------------------------------------------------------
+	 * Enable the controller, then wait for DCEN to complete
+	 *------------------------------------------------------------------*/
+	mtsdram( mem_cfg0, 0x86000000 );/* DCEN=1, PMUD=1, 64-bit           */
+	for(;;)
+	{
+		mfsdram( mem_mcsts, reg );
+		if( reg & 0x80000000 )
+			break;
+	}
+
+	return( 64 * 1024 * 1024 );      /* 64 MB                           */
+}

+ 96 - 0
board/esd/cpci440/init.S

@@ -0,0 +1,96 @@
+/*
+*  Copyright (C) 2002 Scott McNutt <smcnutt@artesyncp.com>
+*
+* See file CREDITS for list of people who contributed to this
+* project.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+* MA 02111-1307 USA
+*/
+
+#include <ppc_asm.tmpl>
+#include <config.h>
+
+/* General */
+#define TLB_VALID   0x00000200
+
+/* Supported page sizes */
+
+#define SZ_1K	    0x00000000
+#define SZ_4K	    0x00000010
+#define SZ_16K	    0x00000020
+#define SZ_64K	    0x00000030
+#define SZ_256K	    0x00000040
+#define SZ_1M	    0x00000050
+#define SZ_16M	    0x00000070
+#define SZ_256M	    0x00000090
+
+/* Storage attributes */
+#define SA_W	    0x00000800	    /* Write-through */
+#define SA_I	    0x00000400	    /* Caching inhibited */
+#define SA_M	    0x00000200	    /* Memory coherence */
+#define SA_G	    0x00000100	    /* Guarded */
+#define SA_E	    0x00000080	    /* Endian */
+
+/* Access control */
+#define AC_X	    0x00000024	    /* Execute */
+#define AC_W	    0x00000012	    /* Write */
+#define AC_R	    0x00000009	    /* Read */
+
+/* Some handy macros */
+
+#define EPN(e)		((e) & 0xfffffc00)
+#define TLB0(epn,sz)	( (EPN((epn)) | (sz) | TLB_VALID ) )
+#define TLB1(rpn,erpn)	( ((rpn)&0xfffffc00) | (erpn) )
+#define TLB2(a)		( (a)&0x00000fbf )
+
+#define tlbtab_start\
+	mflr    r1  ;\
+	bl 0f	    ;
+
+#define tlbtab_end\
+	.long 0, 0, 0	;   \
+0:	mflr    r0	;   \
+	mtlr    r1	;   \
+	blr		;
+
+#define tlbentry(epn,sz,rpn,erpn,attr)\
+	.long TLB0(epn,sz),TLB1(rpn,erpn),TLB2(attr)
+
+
+/**************************************************************************
+ * TLB TABLE
+ *
+ * This table is used by the cpu boot code to setup the initial tlb
+ * entries. Rather than make broad assumptions in the cpu source tree,
+ * this table lets each board set things up however they like.
+ *
+ *  Pointer to the table is returned in r1
+ *
+ *************************************************************************/
+
+    .section .bootpg,"ax"
+    .globl tlbtab
+
+tlbtab:
+    tlbtab_start
+    tlbentry( 0xf0000000, SZ_256M, 0xf0000000, 1, AC_R|AC_W|AC_X|SA_G|SA_I)
+    tlbentry( CFG_PERIPHERAL_BASE, SZ_256M, 0x40000000, 1, AC_R|AC_W|SA_G|SA_I)
+    tlbentry( CFG_ISRAM_BASE, SZ_4K, 0x80000000, 0, AC_R|AC_W|AC_X )
+    tlbentry( CFG_ISRAM_BASE + 0x1000, SZ_4K, 0x80001000, 0, AC_R|AC_W|AC_X )
+    tlbentry( CFG_SDRAM_BASE, SZ_256M, 0x00000000, 0, AC_R|AC_W|AC_X )
+    tlbtab_end
+
+

+ 254 - 0
board/esd/pci405/pci405.c

@@ -0,0 +1,254 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <malloc.h>
+#include <pci.h>
+#include <405gp_pci.h>
+
+/* ------------------------------------------------------------------------- */
+
+#if 0
+#define FPGA_DEBUG
+#endif
+
+#define PCI_RECONFIG_MAGIC       0x07081967
+
+
+struct pci_config_regs {
+	unsigned short  command;
+	unsigned char   latency_timer;
+	unsigned char   int_line;
+	unsigned long   bar1;
+	unsigned long   bar2;
+	unsigned long   magic;
+};
+
+
+/* fpga configuration data - generated by bin2cc */
+const unsigned char fpgadata[] =
+{
+#include "fpgadata.c"
+};
+
+/*
+ * include common fpga code (for esd boards)
+ */
+#include "../common/fpga.c"
+
+
+/* Prototypes */
+int gunzip(void *, int, unsigned char *, int *);
+
+
+int board_pre_init (void)
+{
+	unsigned long cntrl0Reg;
+
+	/*
+	 * IRQ 0-15  405GP internally generated; active high; level sensitive
+	 * IRQ 16    405GP internally generated; active low; level sensitive
+	 * IRQ 17-24 RESERVED
+	 * IRQ 25 (EXT IRQ 0) CAN0; active low; level sensitive
+	 * IRQ 26 (EXT IRQ 1) CAN1; active low; level sensitive
+	 * IRQ 27 (EXT IRQ 2) CAN2; active low; level sensitive
+	 * IRQ 28 (EXT IRQ 3) CAN3; active low; level sensitive
+	 * IRQ 29 (EXT IRQ 4) unused; active low; level sensitive
+	 * IRQ 30 (EXT IRQ 5) FPGA Timestamp; active low; level sensitive
+	 * IRQ 31 (EXT IRQ 6) PCI Reset; active low; level sensitive
+	 */
+	mtdcr(uicsr, 0xFFFFFFFF);        /* clear all ints */
+	mtdcr(uicer, 0x00000000);        /* disable all ints */
+	mtdcr(uiccr, 0x00000000);        /* set all to be non-critical*/
+	mtdcr(uicpr, 0xFFFFFF80);        /* set int polarities */
+	mtdcr(uictr, 0x10000000);        /* set int trigger levels */
+	mtdcr(uicvcr, 0x00000001);       /* set vect base=0,INT0 highest priority*/
+	mtdcr(uicsr, 0xFFFFFFFF);        /* clear all ints */
+
+	/*
+	 * Setup GPIO pins (IRQ4/GPIO21 as GPIO)
+	 */
+	cntrl0Reg = mfdcr(cntrl0);
+	mtdcr(cntrl0, cntrl0Reg | 0x00008000);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+int misc_init_f (void)
+{
+	return 0;  /* dummy implementation */
+}
+
+
+int misc_init_r (void)
+{
+	unsigned char *dst;
+	ulong len = sizeof(fpgadata);
+	int status;
+	int index;
+	int i;
+	struct pci_config_regs *pci_regs;
+
+	/*
+	 * On PCI-405 the environment is saved in eeprom!
+	 * FPGA can be gzip compressed (malloc) and booted this late.
+	 */
+
+	dst = malloc(CFG_FPGA_MAX_SIZE);
+	if (gunzip (dst, CFG_FPGA_MAX_SIZE, (uchar *)fpgadata, (int *)&len) != 0) {
+		printf ("GUNZIP ERROR - must RESET board to recover\n");
+		do_reset (NULL, 0, 0, NULL);
+	}
+
+	status = fpga_boot(dst, len);
+	if (status != 0) {
+		printf("\nFPGA: Booting failed ");
+		switch (status) {
+		case ERROR_FPGA_PRG_INIT_LOW:
+			printf("(Timeout: INIT not low after asserting PROGRAM*)\n ");
+			break;
+		case ERROR_FPGA_PRG_INIT_HIGH:
+			printf("(Timeout: INIT not high after deasserting PROGRAM*)\n ");
+			break;
+		case ERROR_FPGA_PRG_DONE:
+			printf("(Timeout: DONE not high after programming FPGA)\n ");
+			break;
+		}
+
+		/* display infos on fpgaimage */
+		index = 15;
+		for (i=0; i<4; i++) {
+			len = dst[index];
+			printf("FPGA: %s\n", &(dst[index+1]));
+			index += len+3;
+		}
+		putc ('\n');
+		/* delayed reboot */
+		for (i=20; i>0; i--) {
+			printf("Rebooting in %2d seconds \r",i);
+			for (index=0;index<1000;index++)
+				udelay(1000);
+		}
+		putc ('\n');
+		do_reset(NULL, 0, 0, NULL);
+	}
+
+	puts("FPGA:  ");
+
+	/* display infos on fpgaimage */
+	index = 15;
+	for (i=0; i<4; i++) {
+		len = dst[index];
+		printf("%s ", &(dst[index+1]));
+		index += len+3;
+	}
+	putc ('\n');
+
+	/*
+	 * Rewrite pci config regs (only after soft-reset with magic set)
+	 */
+	pci_regs = (struct pci_config_regs *)0x10;
+	if (pci_regs->magic == PCI_RECONFIG_MAGIC) {
+		puts("PCI:   Found magic, rewriting config regs...\n");
+		pci_write_config_word(PCIDEVID_405GP, PCI_COMMAND,
+				      pci_regs->command);
+		pci_write_config_byte(PCIDEVID_405GP, PCI_LATENCY_TIMER,
+				      pci_regs->latency_timer);
+		pci_write_config_byte(PCIDEVID_405GP, PCI_INTERRUPT_LINE,
+				      pci_regs->int_line);
+		pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_1,
+				       pci_regs->bar1);
+		pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2,
+				       pci_regs->bar2);
+	}
+	pci_regs->magic = 0; /* clear magic again */
+
+#if 0 /* test-only */
+	pci_read_config_word(PCIDEVID_405GP, PCI_COMMAND, &(pci_regs->command));
+	pci_read_config_byte(PCIDEVID_405GP, PCI_LATENCY_TIMER, &(pci_regs->latency_timer));
+	pci_read_config_byte(PCIDEVID_405GP, PCI_INTERRUPT_LINE, &(pci_regs->int_line));
+	pci_read_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_1, &(pci_regs->bar1));
+	pci_read_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, &(pci_regs->bar2));
+	pci_regs->magic = PCI_RECONFIG_MAGIC; /* set magic */
+#endif
+
+	free(dst);
+	return (0);
+}
+
+
+/*
+ * Check Board Identity:
+ */
+
+int checkboard (void)
+{
+	unsigned char str[64];
+	int i = getenv_r ("serial#", str, sizeof(str));
+
+	puts ("Board: ");
+
+	if (i == -1) {
+		puts ("### No HW ID - assuming CPCI405");
+	} else {
+		puts (str);
+	}
+	putc ('\n');
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+long int initdram (int board_type)
+{
+	unsigned long val;
+
+	mtdcr(memcfga, mem_mb0cf);
+	val = mfdcr(memcfgd);
+
+#if 0
+	printf("\nmb0cf=%x\n", val); /* test-only */
+	printf("strap=%x\n", mfdcr(strap)); /* test-only */
+#endif
+
+	return (4*1024*1024 << ((val & 0x000e0000) >> 17));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int testdram (void)
+{
+	/* TODO: XXX XXX XXX */
+	printf ("test: 16 MB - ok\n");
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */

+ 225 - 0
board/evb64260/eth_addrtbl.c

@@ -0,0 +1,225 @@
+#include <common.h>
+#include <malloc.h>
+#include <galileo/gt64260R.h>
+#include <galileo/core.h>
+#include <asm/cache.h>
+#include "eth.h"
+#include "eth_addrtbl.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define PRINTF printf
+
+#ifdef CONFIG_GT_USE_MAC_HASH_TABLE
+
+static u32           addressTableHashMode[ GAL_ETH_DEVS ] = { 0, };
+static u32           addressTableHashSize[ GAL_ETH_DEVS ] = { 0, };
+static addrTblEntry *addressTableBase[     GAL_ETH_DEVS ] = { 0, };
+static void         *realAddrTableBase[    GAL_ETH_DEVS ] = { 0, };
+
+static const u32 hashLength[ 2 ] = {
+    (0x8000),             /* 8K * 4 entries */
+    (0x8000/16),          /* 512 * 4 entries */
+};
+
+/* Initialize the address table for a port, if needed */
+unsigned int initAddressTable( u32 port, u32 hashMode, u32 hashSizeSelector)
+{
+    unsigned int tableBase;
+
+    if( port < 0 || port >= GAL_ETH_DEVS ) {
+		printf("%s: Invalid port number %d\n", __FUNCTION__, port );
+		return 0;
+	}
+
+	if (hashMode > 1) {
+		printf("%s: Invalid Hash Mode %d\n", __FUNCTION__, port );
+		return 0;
+	}
+
+	if ( realAddrTableBase[port] &&
+		( addressTableHashSize[port] != hashSizeSelector )) {
+		/* we have been here before,
+		 * but now we want a different sized table
+		 */
+		free( realAddrTableBase[port] );
+		realAddrTableBase[port] = 0;
+		addressTableBase[port] = 0;
+
+	}
+
+	tableBase = (unsigned int)addressTableBase[port];
+	/* we get called for every probe, so only do this once */
+	if ( !tableBase ) {
+    	int bytes = hashLength[hashSizeSelector] * sizeof(addrTblEntry);
+
+		tableBase = (unsigned int)realAddrTableBase[port] = malloc(bytes+64);
+
+	    if(!tableBase)
+		{
+			printf("%s: alloc memory failed \n", __FUNCTION__);
+			return 0;
+		}
+
+    	/* align to octal byte */
+	    if(tableBase&63) tableBase=(tableBase+63) & ~63;
+
+    	addressTableHashMode[port] = hashMode;
+	    addressTableHashSize[port] = hashSizeSelector;
+    	addressTableBase[port] = (addrTblEntry *)tableBase;
+
+	    memset((void *)tableBase,0,bytes);
+	}
+
+    return tableBase;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * This function will calculate the hash function of the address.
+ * depends on the hash mode and hash size.
+ * Inputs
+ * macH             - the 2 most significant bytes of the MAC address.
+ * macL             - the 4 least significant bytes of the MAC address.
+ * hashMode         - hash mode 0 or hash mode 1.
+ * hashSizeSelector - indicates number of hash table entries (0=0x8000,1=0x800)
+ * Outputs
+ * return the calculated entry.
+ */
+u32
+hashTableFunction( u32 macH, u32 macL, u32 HashSize, u32 hash_mode)
+{
+    u32 hashResult;
+    u32 addrH;
+    u32 addrL;
+    u32 addr0;
+    u32 addr1;
+    u32 addr2;
+    u32 addr3;
+    u32 addrHSwapped;
+    u32 addrLSwapped;
+
+
+    addrH = NIBBLE_SWAPPING_16_BIT( macH );
+    addrL = NIBBLE_SWAPPING_32_BIT( macL );
+
+    addrHSwapped =   FLIP_4_BITS(  addrH        & 0xf )
+                 + ((FLIP_4_BITS( (addrH >>  4) & 0xf)) <<  4)
+                 + ((FLIP_4_BITS( (addrH >>  8) & 0xf)) <<  8)
+                 + ((FLIP_4_BITS( (addrH >> 12) & 0xf)) << 12);
+
+    addrLSwapped =   FLIP_4_BITS(  addrL        & 0xf )
+                 + ((FLIP_4_BITS( (addrL >>  4) & 0xf)) <<  4)
+                 + ((FLIP_4_BITS( (addrL >>  8) & 0xf)) <<  8)
+                 + ((FLIP_4_BITS( (addrL >> 12) & 0xf)) << 12)
+                 + ((FLIP_4_BITS( (addrL >> 16) & 0xf)) << 16)
+                 + ((FLIP_4_BITS( (addrL >> 20) & 0xf)) << 20)
+                 + ((FLIP_4_BITS( (addrL >> 24) & 0xf)) << 24)
+                 + ((FLIP_4_BITS( (addrL >> 28) & 0xf)) << 28);
+
+    addrH = addrHSwapped;
+    addrL = addrLSwapped;
+
+    if( hash_mode == 0 )  {
+        addr0 =  (addrL >>  2) & 0x03f;
+        addr1 =  (addrL        & 0x003) | ((addrL >> 8) & 0x7f) << 2;
+        addr2 =  (addrL >> 15) & 0x1ff;
+        addr3 = ((addrL >> 24) & 0x0ff) | ((addrH &  1)         << 8);
+    } else  {
+        addr0 = FLIP_6_BITS(    addrL        & 0x03f );
+        addr1 = FLIP_9_BITS(  ((addrL >>  6) & 0x1ff));
+        addr2 = FLIP_9_BITS(   (addrL >> 15) & 0x1ff);
+        addr3 = FLIP_9_BITS( (((addrL >> 24) & 0x0ff) | ((addrH & 0x1) << 8)));
+    }
+
+    hashResult = (addr0 << 9) | (addr1 ^ addr2 ^ addr3);
+
+    if( HashSize == _8K_TABLE )  {
+        hashResult = hashResult & 0xffff;
+    } else  {
+        hashResult = hashResult & 0x07ff;
+    }
+
+    return( hashResult );
+}
+
+
+/*
+ * ----------------------------------------------------------------------------
+ * This function will add an entry to the address table.
+ * depends on the hash mode and hash size that was initialized.
+ * Inputs
+ * port - ETHERNET port number.
+ * macH - the 2 most significant bytes of the MAC address.
+ * macL - the 4 least significant bytes of the MAC address.
+ * skip - if 1, skip this address.
+ * rd   - the RD field in the address table.
+ * Outputs
+ * address table entry is added.
+ * TRUE if success.
+ * FALSE if table full
+ */
+int
+addAddressTableEntry(
+    u32           port,
+    u32           macH,
+    u32           macL,
+    u32           rd,
+    u32           skip         )
+{
+    addrTblEntry *entry;
+    u32           newHi;
+    u32           newLo;
+    u32           i;
+
+    newLo = (((macH >>  4) & 0xf) << 15)
+          | (((macH >>  0) & 0xf) << 11)
+          | (((macH >> 12) & 0xf) <<  7)
+          | (((macH >>  8) & 0xf) <<  3)
+          | (((macL >> 20) & 0x1) << 31)
+          | (((macL >> 16) & 0xf) << 27)
+          | (((macL >> 28) & 0xf) << 23)
+          | (((macL >> 24) & 0xf) << 19)
+          |   (skip << SKIP_BIT)  |  (rd << 2) | VALID;
+
+    newHi = (((macL >>  4) & 0xf) << 15)
+          | (((macL >>  0) & 0xf) << 11)
+          | (((macL >> 12) & 0xf) <<  7)
+          | (((macL >>  8) & 0xf) <<  3)
+          | (((macL >> 21) & 0x7) <<  0);
+
+    /*
+     * Pick the appropriate table, start scanning for free/reusable
+     * entries at the index obtained by hashing the specified MAC address
+     */
+    entry  = addressTableBase[port];
+    entry += hashTableFunction( macH, macL, addressTableHashSize[port],
+                                            addressTableHashMode[port]  );
+    for( i = 0;  i < HOP_NUMBER;  i++, entry++ )  {
+        if( !(entry->lo & VALID)   /*|| (entry->lo & SKIP)*/   )  {
+            break;
+        } else  {                    /* if same address put in same position */
+            if(   ((entry->lo & 0xfffffff8) == (newLo & 0xfffffff8))
+                && (entry->hi               ==  newHi) )
+            {
+                    break;
+            }
+        }
+    }
+
+    if( i == HOP_NUMBER )  {
+        PRINTF( "addGT64260addressTableEntry: table section is full\n" );
+        return( FALSE );
+    }
+
+    /*
+     * Update the selected entry
+     */
+    entry->hi = newHi;
+    entry->lo = newLo;
+    DCACHE_FLUSH_N_SYNC( (u32)entry, MAC_ENTRY_SIZE );
+    return( TRUE );
+}
+
+#endif /* CONFIG_GT_USE_MAC_HASH_TABLE */

+ 691 - 0
board/evb64260/pci.c

@@ -0,0 +1,691 @@
+/* PCI.c - PCI functions */
+
+/* Copyright - Galileo technology. */
+
+#include <common.h>
+#include <pci.h>
+
+#include <galileo/pci.h>
+
+static const unsigned char pci_irq_swizzle[2][PCI_MAX_DEVICES] = {
+#ifdef CONFIG_ZUMA_V2
+    {0,0,0,0,0,0,0,29, [8 ... PCI_MAX_DEVICES-1]=0},
+    {0,0,0,0,0,0,0,28, [8 ... PCI_MAX_DEVICES-1]=0}
+#else	/* EVB??? This is a guess */
+    {0,0,0,0,0,0,0,27,27, [9 ... PCI_MAX_DEVICES-1]=0},
+    {0,0,0,0,0,0,0,29,29, [9 ... PCI_MAX_DEVICES-1]=0}
+#endif
+};
+
+static const unsigned int pci_p2p_configuration_reg[]={
+    PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION};
+
+static const unsigned int pci_configuration_address[]={
+    PCI_0CONFIGURATION_ADDRESS, PCI_1CONFIGURATION_ADDRESS};
+
+static const unsigned int pci_configuration_data[]={
+    PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER,
+    PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER};
+
+static const unsigned int pci_error_cause_reg[]={
+    PCI_0ERROR_CAUSE, PCI_1ERROR_CAUSE};
+
+static const unsigned int pci_arbiter_control[]={
+    PCI_0ARBITER_CONTROL, PCI_1ARBITER_CONTROL};
+
+static const unsigned int pci_snoop_control_base_0_low[]={
+    PCI_0SNOOP_CONTROL_BASE_0_LOW, PCI_1SNOOP_CONTROL_BASE_0_LOW};
+static const unsigned int pci_snoop_control_top_0[]={
+    PCI_0SNOOP_CONTROL_TOP_0, PCI_1SNOOP_CONTROL_TOP_0};
+
+static const unsigned int pci_access_control_base_0_low[]={
+    PCI_0ACCESS_CONTROL_BASE_0_LOW, PCI_1ACCESS_CONTROL_BASE_0_LOW};
+static const unsigned int pci_access_control_top_0[]={
+    PCI_0ACCESS_CONTROL_TOP_0, PCI_1ACCESS_CONTROL_TOP_0};
+
+static const unsigned int pci_scs_bank_size[2][4] = {
+    {PCI_0SCS_0_BANK_SIZE, PCI_0SCS_1_BANK_SIZE,
+     PCI_0SCS_2_BANK_SIZE, PCI_0SCS_3_BANK_SIZE},
+    {PCI_1SCS_0_BANK_SIZE, PCI_1SCS_1_BANK_SIZE,
+     PCI_1SCS_2_BANK_SIZE, PCI_1SCS_3_BANK_SIZE}};
+
+static const unsigned int pci_p2p_configuration[] = {
+    PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION};
+
+/********************************************************************
+* pciWriteConfigReg - Write to a PCI configuration register
+*                    - Make sure the GT is configured as a master before writing
+*                      to another device on the PCI.
+*                    - The function takes care of Big/Little endian conversion.
+*
+*
+* Inputs:   unsigned int regOffset: The register offset as it apears in the GT spec
+*                   (or any other PCI device spec)
+*           pciDevNum: The device number needs to be addressed.
+*
+*  Configuration Address 0xCF8:
+*
+*       31 30    24 23  16 15  11 10     8 7      2  0     <=bit Number
+*  |congif|Reserved|  Bus |Device|Function|Register|00|
+*  |Enable|        |Number|Number| Number | Number |  |    <=field Name
+*
+*********************************************************************/
+void pciWriteConfigReg(PCI_HOST host, unsigned int regOffset,unsigned int pciDevNum,unsigned int data)
+{
+    volatile unsigned int DataForAddrReg;
+    unsigned int functionNum;
+    unsigned int busNum = 0;
+    unsigned int addr;
+
+    if(pciDevNum > 32) /* illegal device Number */
+        return;
+    if(pciDevNum == SELF) /* configure our configuration space. */
+    {
+        pciDevNum = (GTREGREAD(pci_p2p_configuration_reg[host]) >> 24) & 0x1f;
+        busNum = GTREGREAD(pci_p2p_configuration_reg[host]) & 0xff0000;
+    }
+    functionNum =  regOffset & 0x00000700;
+    pciDevNum = pciDevNum << 11;
+    regOffset = regOffset & 0xfc;
+    DataForAddrReg = ( regOffset | pciDevNum | functionNum | busNum) | BIT31;
+    GT_REG_WRITE(pci_configuration_address[host],DataForAddrReg);
+    GT_REG_READ(pci_configuration_address[host], &addr);
+    if (addr != DataForAddrReg) return;
+    GT_REG_WRITE(pci_configuration_data[host],data);
+}
+
+/********************************************************************
+* pciReadConfigReg  - Read from a PCI0 configuration register
+*                    - Make sure the GT is configured as a master before reading
+*                     from another device on the PCI.
+*                   - The function takes care of Big/Little endian conversion.
+* INPUTS:   regOffset: The register offset as it apears in the GT spec (or PCI
+*                        spec)
+*           pciDevNum: The device number needs to be addressed.
+* RETURNS: data , if the data == 0xffffffff check the master abort bit in the
+*                 cause register to make sure the data is valid
+*
+*  Configuration Address 0xCF8:
+*
+*       31 30    24 23  16 15  11 10     8 7      2  0     <=bit Number
+*  |congif|Reserved|  Bus |Device|Function|Register|00|
+*  |Enable|        |Number|Number| Number | Number |  |    <=field Name
+*
+*********************************************************************/
+unsigned int pciReadConfigReg (PCI_HOST host, unsigned int regOffset,unsigned int pciDevNum)
+{
+    volatile unsigned int DataForAddrReg;
+   	unsigned int data;
+    unsigned int functionNum;
+    unsigned int busNum = 0;
+
+    if(pciDevNum > 32) /* illegal device Number */
+        return 0xffffffff;
+    if(pciDevNum == SELF) /* configure our configuration space. */
+    {
+        pciDevNum = (GTREGREAD(pci_p2p_configuration_reg[host]) >> 24) & 0x1f;
+        busNum = GTREGREAD(pci_p2p_configuration_reg[host]) & 0xff0000;
+    }
+    functionNum = regOffset & 0x00000700;
+    pciDevNum = pciDevNum << 11;
+    regOffset = regOffset & 0xfc;
+    DataForAddrReg = (regOffset | pciDevNum | functionNum | busNum) | BIT31 ;
+    GT_REG_WRITE(pci_configuration_address[host],DataForAddrReg);
+    GT_REG_READ(pci_configuration_address[host], &data);
+    if (data != DataForAddrReg)
+        return 0xffffffff;
+    GT_REG_READ(pci_configuration_data[host], &data);
+    return data;
+}
+
+/********************************************************************
+* pciOverBridgeWriteConfigReg - Write to a PCI configuration register where
+*                               the agent is placed on another Bus. For more
+*                               information read P2P in the PCI spec.
+*
+* Inputs:   unsigned int regOffset - The register offset as it apears in the
+*           GT spec (or any other PCI device spec).
+*           unsigned int pciDevNum - The device number needs to be addressed.
+*           unsigned int busNum - On which bus does the Target agent connect
+*                                 to.
+*           unsigned int data - data to be written.
+*
+*  Configuration Address 0xCF8:
+*
+*       31 30    24 23  16 15  11 10     8 7      2  0     <=bit Number
+*  |congif|Reserved|  Bus |Device|Function|Register|01|
+*  |Enable|        |Number|Number| Number | Number |  |    <=field Name
+*
+*  The configuration Address is configure as type-I (bits[1:0] = '01') due to
+*   PCI spec referring to P2P.
+*
+*********************************************************************/
+void pciOverBridgeWriteConfigReg(PCI_HOST host,
+				 unsigned int regOffset,
+                                 unsigned int pciDevNum,
+                                 unsigned int busNum,unsigned int data)
+{
+   	unsigned int   DataForReg;
+    unsigned int   functionNum;
+
+   	functionNum =  regOffset & 0x00000700;
+    pciDevNum = pciDevNum << 11;
+    regOffset = regOffset & 0xff;
+    busNum = busNum << 16;
+    if(pciDevNum == SELF) /* This board */
+    {
+        DataForReg = ( regOffset | pciDevNum | functionNum) | BIT0;
+    }
+    else
+    {
+        DataForReg = ( regOffset | pciDevNum | functionNum | busNum) |
+            BIT31 | BIT0;
+    }
+    GT_REG_WRITE(pci_configuration_address[host],DataForReg);
+    if(pciDevNum == SELF) /* This board */
+    {
+        GT_REG_WRITE(pci_configuration_data[host],data);
+    }
+    else /* configuration Transaction over the pci. */
+    {
+        /* The PCI is working in LE Mode So it swap the Data. */
+        GT_REG_WRITE(pci_configuration_data[host],WORD_SWAP(data));
+    }
+}
+
+
+/********************************************************************
+* pciOverBridgeReadConfigReg  - Read from a PCIn configuration register where
+*                               the agent target locate on another PCI bus.
+*                             - Make sure the GT is configured as a master
+*                               before reading from another device on the PCI.
+*                             - The function takes care of Big/Little endian
+*                               conversion.
+* INPUTS:   regOffset: The register offset as it apears in the GT spec (or PCI
+*                        spec). (configuration register offset.)
+*           pciDevNum: The device number needs to be addressed.
+*           busNum: the Bus number where the agent is place.
+* RETURNS: data , if the data == 0xffffffff check the master abort bit in the
+*                 cause register to make sure the data is valid
+*
+*  Configuration Address 0xCF8:
+*
+*       31 30    24 23  16 15  11 10     8 7      2  0     <=bit Number
+*  |congif|Reserved|  Bus |Device|Function|Register|01|
+*  |Enable|        |Number|Number| Number | Number |  |    <=field Name
+*
+*********************************************************************/
+unsigned int pciOverBridgeReadConfigReg(PCI_HOST host,
+					unsigned int regOffset,
+                                        unsigned int pciDevNum,
+                                        unsigned int busNum)
+{
+    unsigned int DataForReg;
+    unsigned int data;
+    unsigned int functionNum;
+
+    functionNum = regOffset & 0x00000700;
+    pciDevNum = pciDevNum << 11;
+    regOffset = regOffset & 0xff;
+    busNum = busNum << 16;
+    if (pciDevNum == SELF) /* This board */
+    {
+        DataForReg = (regOffset | pciDevNum | functionNum) | BIT31 ;
+    }
+    else /* agent on another bus */
+    {
+        DataForReg = (regOffset | pciDevNum | functionNum | busNum) |
+        BIT0 | BIT31 ;
+    }
+    GT_REG_WRITE(pci_configuration_address[host],DataForReg);
+    if (pciDevNum == SELF) /* This board */
+   	{
+        GT_REG_READ(pci_configuration_data[host], &data);
+    	return data;
+    }
+    else /* The PCI is working in LE Mode So it swap the Data. */
+    {
+        GT_REG_READ(pci_configuration_data[host], &data);
+    	return WORD_SWAP(data);
+    }
+}
+
+/********************************************************************
+* pciGetRegOffset - Gets the register offset for this region config.
+*
+* INPUT:   Bus, Region - The bus and region we ask for its base address.
+* OUTPUT:   N/A
+* RETURNS: PCI register base address
+*********************************************************************/
+static unsigned int pciGetRegOffset(PCI_HOST host, PCI_REGION region)
+{
+    switch (host)
+    {
+	case PCI_HOST0:
+	    switch(region) {
+		case PCI_IO:		return PCI_0I_O_LOW_DECODE_ADDRESS;
+		case PCI_REGION0:	return PCI_0MEMORY0_LOW_DECODE_ADDRESS;
+		case PCI_REGION1:	return PCI_0MEMORY1_LOW_DECODE_ADDRESS;
+		case PCI_REGION2:	return PCI_0MEMORY2_LOW_DECODE_ADDRESS;
+		case PCI_REGION3:	return PCI_0MEMORY3_LOW_DECODE_ADDRESS;
+	    }
+	case PCI_HOST1:
+	    switch(region) {
+		case PCI_IO:		return PCI_1I_O_LOW_DECODE_ADDRESS;
+		case PCI_REGION0:	return PCI_1MEMORY0_LOW_DECODE_ADDRESS;
+		case PCI_REGION1:	return PCI_1MEMORY1_LOW_DECODE_ADDRESS;
+		case PCI_REGION2:	return PCI_1MEMORY2_LOW_DECODE_ADDRESS;
+		case PCI_REGION3:	return PCI_1MEMORY3_LOW_DECODE_ADDRESS;
+	    }
+    }
+    return PCI_0MEMORY0_LOW_DECODE_ADDRESS;
+}
+
+static unsigned int pciGetRemapOffset(PCI_HOST host, PCI_REGION region)
+{
+    switch (host)
+    {
+	case PCI_HOST0:
+	    switch(region) {
+		case PCI_IO:		return PCI_0I_O_ADDRESS_REMAP;
+		case PCI_REGION0:	return PCI_0MEMORY0_ADDRESS_REMAP;
+		case PCI_REGION1:	return PCI_0MEMORY1_ADDRESS_REMAP;
+		case PCI_REGION2:	return PCI_0MEMORY2_ADDRESS_REMAP;
+		case PCI_REGION3:	return PCI_0MEMORY3_ADDRESS_REMAP;
+	    }
+	case PCI_HOST1:
+	    switch(region) {
+		case PCI_IO:		return PCI_1I_O_ADDRESS_REMAP;
+		case PCI_REGION0:	return PCI_1MEMORY0_ADDRESS_REMAP;
+		case PCI_REGION1:	return PCI_1MEMORY1_ADDRESS_REMAP;
+		case PCI_REGION2:	return PCI_1MEMORY2_ADDRESS_REMAP;
+		case PCI_REGION3:	return PCI_1MEMORY3_ADDRESS_REMAP;
+	    }
+    }
+    return PCI_0MEMORY0_ADDRESS_REMAP;
+}
+
+bool pciMapSpace(PCI_HOST host, PCI_REGION region, unsigned int remapBase, unsigned int bankBase,unsigned int bankLength)
+{
+    unsigned int low=0xfff;
+    unsigned int high=0x0;
+    unsigned int regOffset=pciGetRegOffset(host, region);
+    unsigned int remapOffset=pciGetRemapOffset(host, region);
+
+    if(bankLength!=0) {
+	low = (bankBase >> 20) & 0xfff;
+	high=((bankBase+bankLength)>>20)-1;
+    }
+
+    GT_REG_WRITE(regOffset, low | (1<<24));	/* no swapping */
+    GT_REG_WRITE(regOffset+8, high);
+
+    if(bankLength!=0) {	/* must do AFTER writing maps */
+	GT_REG_WRITE(remapOffset, remapBase>>20);	/* sorry, 32 bits only.
+							   dont support upper 32
+							   in this driver */
+    }
+    return true;
+}
+
+unsigned int pciGetSpaceBase(PCI_HOST host, PCI_REGION region)
+{
+    unsigned int low;
+    unsigned int regOffset=pciGetRegOffset(host, region);
+    GT_REG_READ(regOffset,&low);
+    return (low&0xfff)<<20;
+}
+
+unsigned int pciGetSpaceSize(PCI_HOST host, PCI_REGION region)
+{
+    unsigned int low,high;
+    unsigned int regOffset=pciGetRegOffset(host, region);
+    GT_REG_READ(regOffset,&low);
+    GT_REG_READ(regOffset+8,&high);
+    high&=0xfff;
+    low&=0xfff;
+    if(high<=low) return 0;
+    return (high+1-low)<<20;
+}
+
+/********************************************************************
+* pciMapMemoryBank - Maps PCI_host memory bank "bank" for the slave.
+*
+* Inputs: base and size of PCI SCS
+*********************************************************************/
+void pciMapMemoryBank(PCI_HOST host, MEMORY_BANK bank, unsigned int pciDramBase,unsigned int pciDramSize)
+{
+  	pciDramBase = pciDramBase & 0xfffff000;
+    pciDramBase = pciDramBase | (pciReadConfigReg(host,
+        PCI_SCS_0_BASE_ADDRESS + 4*bank,SELF) & 0x00000fff);
+    pciWriteConfigReg(host,PCI_SCS_0_BASE_ADDRESS + 4*bank,SELF,pciDramBase);
+    if(pciDramSize == 0)
+        pciDramSize ++;
+    GT_REG_WRITE(pci_scs_bank_size[host][bank], pciDramSize-1);
+}
+
+
+/********************************************************************
+* pciSetRegionFeatures - This function modifys one of the 8 regions with
+*                         feature bits given as an input.
+*                       - Be advised to check the spec before modifying them.
+* Inputs: PCI_PROTECT_REGION region - one of the eight regions.
+*         unsigned int features - See file: pci.h there are defintion for those
+*                                 region features.
+*         unsigned int baseAddress - The region base Address.
+*         unsigned int topAddress - The region top Address.
+* Returns: false if one of the parameters is erroneous true otherwise.
+*********************************************************************/
+bool pciSetRegionFeatures(PCI_HOST host, PCI_ACCESS_REGIONS region,unsigned int features,
+                           unsigned int baseAddress,unsigned int regionLength)
+{
+    unsigned int accessLow;
+    unsigned int accessHigh;
+    unsigned int accessTop = baseAddress + regionLength;
+
+    if(regionLength == 0) /* close the region. */
+    {
+        pciDisableAccessRegion(host, region);
+        return true;
+    }
+    /* base Address is store is bits [11:0] */
+    accessLow = (baseAddress & 0xfff00000) >> 20;
+    /* All the features are update according to the defines in pci.h (to be on
+       the safe side we disable bits: [11:0] */
+    accessLow = accessLow | (features & 0xfffff000);
+    /* write to the Low Access Region register */
+    GT_REG_WRITE( pci_access_control_base_0_low[host] + 0x10*region,accessLow);
+
+    accessHigh = (accessTop & 0xfff00000) >> 20;
+
+    /* write to the High Access Region register */
+    GT_REG_WRITE(pci_access_control_top_0[host] + 0x10*region,accessHigh - 1);
+    return true;
+}
+
+/********************************************************************
+* pciDisableAccessRegion - Disable The given Region by writing MAX size
+*                           to its low Address and MIN size to its high Address.
+*
+* Inputs:   PCI_ACCESS_REGIONS region - The region we to be Disabled.
+* Returns:  N/A.
+*********************************************************************/
+void pciDisableAccessRegion(PCI_HOST host, PCI_ACCESS_REGIONS region)
+{
+    /* writing back the registers default values. */
+    GT_REG_WRITE(pci_access_control_base_0_low[host] + 0x10*region,0x01001fff);
+    GT_REG_WRITE(pci_access_control_top_0[host] + 0x10*region,0);
+}
+
+/********************************************************************
+* pciArbiterEnable - Enables PCI-0`s Arbitration mechanism.
+*
+* Inputs:   N/A
+* Returns:  true.
+*********************************************************************/
+bool pciArbiterEnable(PCI_HOST host)
+{
+    unsigned int regData;
+
+    GT_REG_READ(pci_arbiter_control[host],&regData);
+    GT_REG_WRITE(pci_arbiter_control[host],regData | BIT31);
+    return true;
+}
+
+/********************************************************************
+* pciArbiterDisable - Disable PCI-0`s Arbitration mechanism.
+*
+* Inputs:   N/A
+* Returns:  true
+*********************************************************************/
+bool pciArbiterDisable(PCI_HOST host)
+{
+    unsigned int regData;
+
+    GT_REG_READ(pci_arbiter_control[host],&regData);
+    GT_REG_WRITE(pci_arbiter_control[host],regData & 0x7fffffff);
+    return true;
+}
+
+/********************************************************************
+* pciParkingDisable - Park on last option disable, with this function you can
+*                      disable the park on last mechanism for each agent.
+*                      disabling this option for all agents results parking
+*                      on the internal master.
+*
+* Inputs: PCI_AGENT_PARK internalAgent -  parking Disable for internal agent.
+*         PCI_AGENT_PARK externalAgent0 - parking Disable for external#0 agent.
+*         PCI_AGENT_PARK externalAgent1 - parking Disable for external#1 agent.
+*         PCI_AGENT_PARK externalAgent2 - parking Disable for external#2 agent.
+*         PCI_AGENT_PARK externalAgent3 - parking Disable for external#3 agent.
+*         PCI_AGENT_PARK externalAgent4 - parking Disable for external#4 agent.
+*         PCI_AGENT_PARK externalAgent5 - parking Disable for external#5 agent.
+* Returns:  true
+*********************************************************************/
+bool pciParkingDisable(PCI_HOST host, PCI_AGENT_PARK internalAgent,
+                        PCI_AGENT_PARK externalAgent0,
+                        PCI_AGENT_PARK externalAgent1,
+                        PCI_AGENT_PARK externalAgent2,
+                        PCI_AGENT_PARK externalAgent3,
+                        PCI_AGENT_PARK externalAgent4,
+                        PCI_AGENT_PARK externalAgent5)
+{
+    unsigned int regData;
+    unsigned int writeData;
+
+    GT_REG_READ(pci_arbiter_control[host],&regData);
+    writeData = (internalAgent << 14) + (externalAgent0 << 15) +     \
+                (externalAgent1 << 16) + (externalAgent2 << 17) +    \
+                (externalAgent3 << 18) + (externalAgent4 << 19) +    \
+                (externalAgent5 << 20);
+    regData = (regData & ~(0x7f<<14)) | writeData;
+    GT_REG_WRITE(pci_arbiter_control[host],regData);
+    return true;
+}
+
+/********************************************************************
+* pciSetRegionSnoopMode - This function modifys one of the 4 regions which
+*                          supports Cache Coherency in the PCI_n interface.
+* Inputs: region - One of the four regions.
+*         snoopType - There is four optional Types:
+*                        1. No Snoop.
+*                        2. Snoop to WT region.
+*                        3. Snoop to WB region.
+*                        4. Snoop & Invalidate to WB region.
+*         baseAddress - Base Address of this region.
+*         regionLength - Region length.
+* Returns: false if one of the parameters is wrong otherwise return true.
+*********************************************************************/
+bool pciSetRegionSnoopMode(PCI_HOST host, PCI_SNOOP_REGION region,PCI_SNOOP_TYPE snoopType,
+                            unsigned int baseAddress,
+                            unsigned int regionLength)
+{
+    unsigned int snoopXbaseAddress;
+    unsigned int snoopXtopAddress;
+    unsigned int data;
+    unsigned int snoopHigh = baseAddress + regionLength;
+
+    if( (region > PCI_SNOOP_REGION3) || (snoopType > PCI_SNOOP_WB) )
+        return false;
+    snoopXbaseAddress = pci_snoop_control_base_0_low[host] + 0x10 * region;
+    snoopXtopAddress = pci_snoop_control_top_0[host] + 0x10 * region;
+    if(regionLength == 0) /* closing the region */
+    {
+        GT_REG_WRITE(snoopXbaseAddress,0x0000ffff);
+        GT_REG_WRITE(snoopXtopAddress,0);
+        return true;
+    }
+    baseAddress = baseAddress & 0xfff00000; /* Granularity of 1MByte */
+    data = (baseAddress >> 20) | snoopType << 12;
+    GT_REG_WRITE(snoopXbaseAddress,data);
+    snoopHigh = (snoopHigh & 0xfff00000) >> 20;
+    GT_REG_WRITE(snoopXtopAddress,snoopHigh - 1);
+    return true;
+}
+
+/*
+ *
+ */
+
+static int gt_read_config_dword(struct pci_controller *hose,
+				pci_dev_t dev,
+				int offset, u32* value)
+{
+    *value = pciReadConfigReg((PCI_HOST) hose->cfg_addr, offset, PCI_DEV(dev));
+    return 0;
+}
+
+static int gt_write_config_dword(struct pci_controller *hose,
+				 pci_dev_t dev,
+				 int offset, u32 value)
+{
+    pciWriteConfigReg((PCI_HOST)hose->cfg_addr, offset, PCI_DEV(dev), value);
+    return 0;
+}
+
+/*
+ *
+ */
+
+static void gt_setup_ide(struct pci_controller *hose,
+			 pci_dev_t dev, struct pci_config_table *entry)
+{
+    static const int ide_bar[]={8,4,8,4,0,0};
+    u32 bar_response, bar_value;
+    int bar;
+
+    for (bar=0; bar<6; bar++)
+    {
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar*4, 0x0);
+	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar*4, &bar_response);
+
+	pciauto_region_allocate(bar_response & PCI_BASE_ADDRESS_SPACE_IO ?
+				hose->pci_io : hose->pci_mem, ide_bar[bar], &bar_value);
+
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar*4, bar_value);
+    }
+}
+
+static void gt_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+    unsigned char pin, irq;
+
+    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
+    if(pin == 1) {	/* only allow INT A */
+	irq = pci_irq_swizzle[(PCI_HOST)hose->cfg_addr][PCI_DEV(dev)];
+	if(irq)
+	    pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+    }
+}
+
+struct pci_config_table gt_config_table[] = {
+    { PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
+      PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, gt_setup_ide},
+
+    { }
+};
+
+struct pci_controller pci0_hose = {
+    fixup_irq: gt_fixup_irq,
+    config_table: gt_config_table,
+};
+
+struct pci_controller pci1_hose = {
+    fixup_irq: gt_fixup_irq,
+    config_table: gt_config_table,
+};
+
+void
+pci_init(void)
+{
+    unsigned int command;
+
+    pci0_hose.first_busno = 0;
+    pci0_hose.last_busno = 0xff;
+
+    /* PCI memory space */
+    pci_set_region(pci0_hose.regions + 0,
+		   CFG_PCI0_0_MEM_SPACE,
+		   CFG_PCI0_0_MEM_SPACE,
+		   CFG_PCI0_MEM_SIZE,
+		   PCI_REGION_MEM);
+
+    /* PCI I/O space */
+    pci_set_region(pci0_hose.regions + 1,
+		   CFG_PCI0_IO_SPACE_PCI,
+		   CFG_PCI0_IO_SPACE,
+		   CFG_PCI0_IO_SIZE,
+		   PCI_REGION_IO);
+
+    pci_set_ops(&pci0_hose,
+		pci_hose_read_config_byte_via_dword,
+		pci_hose_read_config_word_via_dword,
+		gt_read_config_dword,
+		pci_hose_write_config_byte_via_dword,
+		pci_hose_write_config_word_via_dword,
+		gt_write_config_dword);
+
+    pci0_hose.region_count = 2;
+
+    pci0_hose.cfg_addr = (unsigned int*) PCI_HOST0;
+
+    pci_register_hose(&pci0_hose);
+
+    pciArbiterEnable(PCI_HOST0);
+    pciParkingDisable(PCI_HOST0,1,1,1,1,1,1,1);
+
+    command = pciReadConfigReg(PCI_HOST0, PCI_COMMAND, SELF);
+    command |= PCI_COMMAND_MASTER;
+    pciWriteConfigReg(PCI_HOST0, PCI_COMMAND, SELF, command);
+
+    pci0_hose.last_busno = pci_hose_scan(&pci0_hose);
+
+    command = pciReadConfigReg(PCI_HOST0, PCI_COMMAND, SELF);
+    command |= PCI_COMMAND_MEMORY;
+    pciWriteConfigReg(PCI_HOST0, PCI_COMMAND, SELF, command);
+
+    pci1_hose.first_busno = pci0_hose.last_busno + 1;
+    pci1_hose.last_busno = 0xff;
+
+    /* PCI memory space */
+    pci_set_region(pci1_hose.regions + 0,
+		   CFG_PCI1_0_MEM_SPACE,
+		   CFG_PCI1_0_MEM_SPACE,
+		   CFG_PCI1_MEM_SIZE,
+		   PCI_REGION_MEM);
+
+    /* PCI I/O space */
+    pci_set_region(pci1_hose.regions + 1,
+		   CFG_PCI1_IO_SPACE_PCI,
+		   CFG_PCI1_IO_SPACE,
+		   CFG_PCI1_IO_SIZE,
+		   PCI_REGION_IO);
+
+    pci_set_ops(&pci1_hose,
+		pci_hose_read_config_byte_via_dword,
+		pci_hose_read_config_word_via_dword,
+		gt_read_config_dword,
+		pci_hose_write_config_byte_via_dword,
+		pci_hose_write_config_word_via_dword,
+		gt_write_config_dword);
+
+    pci1_hose.region_count = 2;
+
+    pci1_hose.cfg_addr = (unsigned int*) PCI_HOST1;
+
+    pci_register_hose(&pci1_hose);
+
+    pciArbiterEnable(PCI_HOST1);
+    pciParkingDisable(PCI_HOST1,1,1,1,1,1,1,1);
+
+    command = pciReadConfigReg(PCI_HOST1, PCI_COMMAND, SELF);
+    command |= PCI_COMMAND_MASTER;
+    pciWriteConfigReg(PCI_HOST1, PCI_COMMAND, SELF, command);
+
+    pci1_hose.last_busno = pci_hose_scan(&pci1_hose);
+
+    command = pciReadConfigReg(PCI_HOST1, PCI_COMMAND, SELF);
+    command |= PCI_COMMAND_MEMORY;
+    pciWriteConfigReg(PCI_HOST1, PCI_COMMAND, SELF, command);
+}

+ 629 - 0
board/evb64260/sdram_init.c

@@ -0,0 +1,629 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * 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
+ */
+
+/* sdram_init.c - automatic memory sizing */
+
+#include <common.h>
+#include <74xx_7xx.h>
+#include <galileo/memory.h>
+#include <galileo/pci.h>
+#include <galileo/gt64260R.h>
+#include <net.h>
+
+#include "eth.h"
+#include "mpsc.h"
+#include "i2c.h"
+#include "64260.h"
+
+/* #define	DEBUG */
+#define	MAP_PCI
+
+#ifdef DEBUG
+#define DP(x) x
+#else
+#define DP(x)
+#endif
+
+#define GB         (1 << 30)
+
+/* structure to store the relevant information about an sdram bank */
+typedef struct sdram_info {
+	uchar drb_size;
+	uchar registered, ecc;
+	uchar tpar;
+	uchar tras_clocks;
+	uchar burst_len;
+	uchar banks, slot;
+	int size;	/* detected size, not from I2C but from dram_size() */
+} sdram_info_t;
+
+#ifdef DEBUG
+void dump_dimm_info(struct sdram_info *d)
+{
+    static const char *ecc_legend[]={""," Parity"," ECC"};
+    printf("dimm%s %sDRAM: %dMibytes:\n",
+	    ecc_legend[d->ecc],
+	    d->registered?"R":"",
+	    (d->size>>20));
+    printf("  drb=%d tpar=%d tras=%d burstlen=%d banks=%d slot=%d\n",
+	    d->drb_size, d->tpar, d->tras_clocks, d->burst_len,
+	    d->banks, d->slot);
+}
+#endif
+
+static int
+memory_map_bank(unsigned int bankNo,
+		unsigned int bankBase,
+		unsigned int bankLength)
+{
+#ifdef DEBUG
+	if (bankLength > 0) {
+		printf("mapping bank %d at %08x - %08x\n",
+		       bankNo, bankBase, bankBase + bankLength - 1);
+	} else {
+		printf("unmapping bank %d\n", bankNo);
+	}
+#endif
+
+	memoryMapBank(bankNo, bankBase, bankLength);
+
+	return 0;
+}
+
+#ifdef MAP_PCI
+static int
+memory_map_bank_pci(unsigned int bankNo,
+		unsigned int bankBase,
+		unsigned int bankLength)
+{
+	PCI_HOST host;
+	for (host=PCI_HOST0;host<=PCI_HOST1;host++) {
+		const int features=
+			PREFETCH_ENABLE |
+			DELAYED_READ_ENABLE |
+			AGGRESSIVE_PREFETCH |
+			READ_LINE_AGGRESSIVE_PREFETCH |
+			READ_MULTI_AGGRESSIVE_PREFETCH |
+			MAX_BURST_4 |
+			PCI_NO_SWAP;
+
+		pciMapMemoryBank(host, bankNo, bankBase, bankLength);
+
+		pciSetRegionSnoopMode(host, bankNo, PCI_SNOOP_WB, bankBase,
+				bankLength);
+
+		pciSetRegionFeatures(host, bankNo, features, bankBase, bankLength);
+	}
+	return 0;
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/* much of this code is based on (or is) the code in the pip405 port */
+/* thanks go to the authors of said port - Josh */
+
+
+/*
+ * translate ns.ns/10 coding of SPD timing values
+ * into 10 ps unit values
+ */
+static inline unsigned short
+NS10to10PS(unsigned char spd_byte)
+{
+	unsigned short ns, ns10;
+
+	/* isolate upper nibble */
+	ns = (spd_byte >> 4) & 0x0F;
+	/* isolate lower nibble */
+	ns10 = (spd_byte & 0x0F);
+
+	return(ns*100 + ns10*10);
+}
+
+/*
+ * translate ns coding of SPD timing values
+ * into 10 ps unit values
+ */
+static inline unsigned short
+NSto10PS(unsigned char spd_byte)
+{
+	return(spd_byte*100);
+}
+
+#ifdef CONFIG_ZUMA_V2
+static int
+check_dimm(uchar slot, sdram_info_t *info)
+{
+        /* assume 2 dimms, 2 banks each 256M - we dont have an
+	 * dimm i2c so rely on the detection routines later */
+
+	memset(info, 0, sizeof(*info));
+
+	info->slot = slot;
+	info->banks = 2;	/* Detect later */
+	    info->registered = 0;
+	info->drb_size = 32;	/* 16 - 256MBit, 32 - 512MBit
+				   but doesn't matter, both do same
+				   thing in setup_sdram() */
+	    info->tpar = 3;
+	    info->tras_clocks = 5;
+	    info->burst_len = 4;
+#ifdef CONFIG_ECC
+	info->ecc = 0;		/* Detect later */
+#endif /* CONFIG_ECC */
+	return 0;
+}
+
+#else /* ! CONFIG_ZUMA_V2 */
+
+/* This code reads the SPD chip on the sdram and populates
+ * the array which is passed in with the relevant information */
+static int
+check_dimm(uchar slot, sdram_info_t *info)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	uchar addr = slot == 0 ? DIMM0_I2C_ADDR : DIMM1_I2C_ADDR;
+	int ret;
+	uchar rows, cols, sdram_banks, supp_cal, width, cal_val;
+	ulong tmemclk;
+	uchar trp_clocks, trcd_clocks;
+	uchar data[128];
+
+	get_clocks ();
+
+ 	tmemclk = 1000000000 / (gd->bus_clk / 100);  /* in 10 ps units */
+
+#ifdef CONFIG_EVB64260_750CX
+	if (0 != slot) {
+		printf("check_dimm: The EVB-64260-750CX only has 1 DIMM,");
+		printf("            called with slot=%d insetad!\n", slot);
+		return 0;
+	}
+#endif
+	DP(puts("before i2c read\n"));
+
+	ret = i2c_read(addr, 0, 128, data, 0);
+
+	DP(puts("after i2c read\n"));
+
+	/* zero all the values */
+	memset(info, 0, sizeof(*info));
+
+	if (ret) {
+		DP(printf("No DIMM in slot %d [err = %x]\n", slot, ret));
+		return 0;
+	}
+
+	/* first, do some sanity checks */
+	if (data[2] != 0x4) {
+		printf("Not SDRAM in slot %d\n", slot);
+		return 0;
+	}
+
+	/* get various information */
+	rows = data[3];
+	cols = data[4];
+	info->banks = data[5];
+	sdram_banks = data[17];
+	width = data[13] & 0x7f;
+
+	DP(printf("sdram_banks: %d, banks: %d\n", sdram_banks, info->banks));
+
+	/* check if the memory is registered */
+	if (data[21] & (BIT1 | BIT4))
+		info->registered = 1;
+
+#ifdef CONFIG_ECC
+	/* check for ECC/parity [0 = none, 1 = parity, 2 = ecc] */
+	info->ecc = (data[11] & 2) >> 1;
+#endif
+
+	/* bit 1 is CL2, bit 2 is CL3 */
+	supp_cal = (data[18] & 0x6) >> 1;
+
+	/* compute the relevant clock values */
+	trp_clocks = (NSto10PS(data[27])+(tmemclk-1)) / tmemclk;
+	trcd_clocks = (NSto10PS(data[29])+(tmemclk-1)) / tmemclk;
+	info->tras_clocks = (NSto10PS(data[30])+(tmemclk-1)) / tmemclk;
+
+	DP(printf("trp = %d\ntrcd_clocks = %d\ntras_clocks = %d\n",
+		  trp_clocks, trcd_clocks, info->tras_clocks));
+
+	/* try a CAS latency of 3 first... */
+	cal_val = 0;
+	if (supp_cal & 3) {
+		if (NS10to10PS(data[9]) <= tmemclk)
+			cal_val = 3;
+	}
+
+	/* then 2... */
+	if (supp_cal & 2) {
+		if (NS10to10PS(data[23]) <= tmemclk)
+			cal_val = 2;
+	}
+
+	DP(printf("cal_val = %d\n", cal_val));
+
+	/* bummer, did't work... */
+	if (cal_val == 0) {
+		DP(printf("Couldn't find a good CAS latency\n"));
+		return 0;
+	}
+
+	/* get the largest delay -- these values need to all be the same
+	 * see Res#6 */
+	info->tpar = cal_val;
+	if (trp_clocks > info->tpar)
+		info->tpar = trp_clocks;
+	if (trcd_clocks > info->tpar)
+		info->tpar = trcd_clocks;
+
+	DP(printf("tpar set to: %d\n", info->tpar));
+
+#ifdef CFG_BROKEN_CL2
+	if (info->tpar == 2){
+		info->tpar = 3;
+	        DP(printf("tpar fixed-up to: %d\n", info->tpar));
+	}
+#endif
+	/* compute the module DRB size */
+	info->drb_size = (((1 << (rows + cols)) * sdram_banks) * width) / _16M;
+
+	DP(printf("drb_size set to: %d\n", info->drb_size));
+
+	/* find the burst len */
+	info->burst_len = data[16] & 0xf;
+	if ((info->burst_len & 8) == 8) {
+		info->burst_len = 1;
+	} else if ((info->burst_len & 4) == 4) {
+		info->burst_len = 0;
+	} else {
+		return 0;
+	}
+
+	info->slot = slot;
+	return 0;
+}
+#endif /* ! CONFIG_ZUMA_V2 */
+
+static int
+setup_sdram_common(sdram_info_t info[2])
+{
+    	ulong tmp;
+	int tpar=2, tras_clocks=5, registered=1, ecc=2;
+
+	if(!info[0].banks && !info[1].banks) return 0;
+
+	if(info[0].banks) {
+	    if(info[0].tpar>tpar) tpar=info[0].tpar;
+	    if(info[0].tras_clocks>tras_clocks) tras_clocks=info[0].tras_clocks;
+	    if(!info[0].registered) registered=0;
+	    if(info[0].ecc!=2) ecc=0;
+	}
+
+	if(info[1].banks) {
+	    if(info[1].tpar>tpar) tpar=info[1].tpar;
+	    if(info[1].tras_clocks>tras_clocks) tras_clocks=info[1].tras_clocks;
+	    if(!info[1].registered) registered=0;
+	    if(info[1].ecc!=2) ecc=0;
+	}
+
+	/* SDRAM configuration */
+	tmp = GTREGREAD(SDRAM_CONFIGURATION);
+
+	/* Turn on physical interleave if both DIMMs
+	 * have even numbers of banks. */
+	if( (info[0].banks == 0 || info[0].banks == 2) &&
+	    (info[1].banks == 0 || info[1].banks == 2) ) {
+	    /* physical interleave on */
+	    tmp &= ~(1 << 15);
+	} else {
+	    /* physical interleave off */
+	    tmp |= (1 << 15);
+	}
+
+	tmp |= (registered << 17);
+
+	/* Use buffer 1 to return read data to the CPU
+	 * See Res #12 */
+	tmp |= (1 << 26);
+
+	GT_REG_WRITE(SDRAM_CONFIGURATION, tmp);
+	DP(printf("SDRAM config: %08x\n",
+		GTREGREAD(SDRAM_CONFIGURATION)));
+
+	/* SDRAM timing */
+	tmp = (((tpar == 3) ? 2 : 1) |
+	       (((tpar == 3) ? 2 : 1) << 2) |
+	       (((tpar == 3) ? 2 : 1) << 4) |
+	       (tras_clocks << 8));
+
+#ifdef CONFIG_ECC
+	/* Setup ECC */
+	if (ecc == 2) tmp |= 1<<13;
+#endif /* CONFIG_ECC */
+
+	GT_REG_WRITE(SDRAM_TIMING, tmp);
+	DP(printf("SDRAM timing: %08x (%d,%d,%d,%d)\n",
+		GTREGREAD(SDRAM_TIMING), tpar,tpar,tpar,tras_clocks));
+
+	/* SDRAM address decode register */
+	/* program this with the default value */
+	GT_REG_WRITE(SDRAM_ADDRESS_DECODE, 0x2);
+	DP(printf("SDRAM decode: %08x\n",
+		GTREGREAD(SDRAM_ADDRESS_DECODE)));
+
+	return 0;
+}
+
+/* sets up the GT properly with information passed in */
+static int
+setup_sdram(sdram_info_t *info)
+{
+	ulong tmp, check;
+	ulong *addr = 0;
+	int i;
+
+	/* sanity checking */
+	if (! info->banks) return 0;
+
+	/* ---------------------------- */
+	/* Program the GT with the discovered data */
+
+	/* bank parameters */
+	tmp = (0xf<<16);	/* leave all virt bank pages open */
+
+	DP(printf("drb_size: %d\n", info->drb_size));
+	switch (info->drb_size) {
+	case 1:
+		tmp |= (1 << 14);
+		break;
+	case 4:
+	case 8:
+		tmp |= (2 << 14);
+		break;
+	case 16:
+	case 32:
+		tmp |= (3 << 14);
+		break;
+	default:
+		printf("Error in dram size calculation\n");
+		return 1;
+	}
+
+	/* SDRAM bank parameters */
+	/* the param registers for slot 1 (banks 2+3) are offset by 0x8 */
+	GT_REG_WRITE(SDRAM_BANK0PARAMETERS + (info->slot * 0x8), tmp);
+	GT_REG_WRITE(SDRAM_BANK1PARAMETERS + (info->slot * 0x8), tmp);
+	DP(printf("SDRAM bankparam slot %d (bank %d+%d): %08lx\n", info->slot, info->slot*2, (info->slot*2)+1, tmp));
+
+	/* set the SDRAM configuration for each bank */
+	for (i = info->slot * 2; i < ((info->slot * 2) + info->banks); i++) {
+		DP(printf("*** Running a MRS cycle for bank %d ***\n", i));
+
+		/* map the bank */
+		memory_map_bank(i, 0, GB/4);
+
+		/* set SDRAM mode */
+		GT_REG_WRITE(SDRAM_OPERATION_MODE, 0x3);
+		check = GTREGREAD(SDRAM_OPERATION_MODE);
+
+		/* dummy write */
+		*addr = 0;
+
+		/* wait for the command to complete */
+		while ((GTREGREAD(SDRAM_OPERATION_MODE) & (1 << 31)) == 0)
+			;
+
+		/* switch back to normal operation mode */
+		GT_REG_WRITE(SDRAM_OPERATION_MODE, 0);
+		check = GTREGREAD(SDRAM_OPERATION_MODE);
+
+		/* unmap the bank */
+		memory_map_bank(i, 0, 0);
+		DP(printf("*** MRS cycle for bank %d done ***\n", i));
+	}
+
+	return 0;
+}
+
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'. Some (not all) hardware errors are detected:
+ * - short between address lines
+ * - short between data lines
+ */
+static long int
+dram_size(long int *base, long int maxsize)
+{
+    volatile long int	 *addr, *b=base;
+    long int	 cnt, val, save1, save2;
+
+#define STARTVAL (1<<20)	/* start test at 1M */
+    for (cnt = STARTVAL/sizeof(long); cnt < maxsize/sizeof(long); cnt <<= 1) {
+	    addr = base + cnt;	/* pointer arith! */
+
+	    save1=*addr;	/* save contents of addr */
+	    save2=*b;		/* save contents of base */
+
+	    *addr=cnt;		/* write cnt to addr */
+	    *b=0;		/* put null at base */
+
+	    /* check at base address */
+	    if ((*b) != 0) {
+		*addr=save1;	/* restore *addr */
+		*b=save2;	/* restore *b */
+		return (0);
+	    }
+	    val = *addr;	/* read *addr */
+
+	    *addr=save1;
+	    *b=save2;
+
+	    if (val != cnt) {
+		    /* fix boundary condition.. STARTVAL means zero */
+		    if(cnt==STARTVAL/sizeof(long)) cnt=0;
+		    return (cnt * sizeof(long));
+	    }
+    }
+    return maxsize;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* U-Boot interface function to SDRAM init - this is where all the
+ * controlling logic happens */
+long int
+initdram(int board_type)
+{
+	ulong checkbank[4] = { [0 ... 3] = 0 };
+	int bank_no;
+        ulong total;
+	int nhr;
+	sdram_info_t dimm_info[2];
+
+
+	/* first, use the SPD to get info about the SDRAM */
+
+	/* check the NHR bit and skip mem init if it's already done */
+	nhr = get_hid0() & (1 << 16);
+
+	if (nhr) {
+		printf("Skipping SDRAM setup due to NHR bit being set\n");
+	} else {
+		/* DIMM0 */
+		check_dimm(0, &dimm_info[0]);
+
+		/* DIMM1 */
+#ifndef CONFIG_EVB64260_750CX /* EVB64260_750CX has only 1 DIMM */
+		check_dimm(1, &dimm_info[1]);
+#else /* CONFIG_EVB64260_750CX */
+		memset(&dimm_info[1], 0, sizeof(sdram_info_t));
+#endif
+
+		/* unmap all banks */
+		memory_map_bank(0, 0, 0);
+		memory_map_bank(1, 0, 0);
+		memory_map_bank(2, 0, 0);
+		memory_map_bank(3, 0, 0);
+
+		/* Now, program the GT with the correct values */
+		if (setup_sdram_common(dimm_info)) {
+			printf("Setup common failed.\n");
+		}
+
+		if (setup_sdram(&dimm_info[0])) {
+			printf("Setup for DIMM1 failed.\n");
+		}
+
+		if (setup_sdram(&dimm_info[1])) {
+			printf("Setup for DIMM2 failed.\n");
+		}
+
+		/* set the NHR bit */
+		set_hid0(get_hid0() | (1 << 16));
+	}
+	/* next, size the SDRAM banks */
+
+	total = 0;
+	if (dimm_info[0].banks > 0) checkbank[0] = 1;
+	if (dimm_info[0].banks > 1) checkbank[1] = 1;
+	if (dimm_info[0].banks > 2)
+		printf("Error, SPD claims DIMM1 has >2 banks\n");
+
+	if (dimm_info[1].banks > 0) checkbank[2] = 1;
+	if (dimm_info[1].banks > 1) checkbank[3] = 1;
+	if (dimm_info[1].banks > 2)
+		printf("Error, SPD claims DIMM2 has >2 banks\n");
+
+	/* Generic dram sizer: works even if we don't have i2c DIMMs,
+	 * as long as the timing settings are more or less correct */
+
+	/*
+	 * pass 1: size all the banks, using first bat (0-256M)
+	 * 	   limitation: we only support 256M per bank due to
+	 *  	   us only having 1 BAT for all DRAM
+	 */
+	for (bank_no = 0; bank_no < CFG_DRAM_BANKS; bank_no++) {
+		/* skip over banks that are not populated */
+		if (! checkbank[bank_no])
+			continue;
+
+		DP(printf("checking bank %d\n", bank_no));
+
+		memory_map_bank(bank_no, 0, GB/4);
+		checkbank[bank_no] = dram_size(NULL, GB/4);
+		memory_map_bank(bank_no, 0, 0);
+
+		DP(printf("bank %d %08lx\n", bank_no, checkbank[bank_no]));
+	}
+
+	/*
+	 * pass 2: contiguously map each bank into physical address
+	 * 	   space.
+	 */
+	dimm_info[0].banks=dimm_info[1].banks=0;
+	for (bank_no = 0; bank_no < CFG_DRAM_BANKS; bank_no++) {
+		if(!checkbank[bank_no]) continue;
+
+		dimm_info[bank_no/2].banks++;
+		dimm_info[bank_no/2].size+=checkbank[bank_no];
+
+		memory_map_bank(bank_no, total, checkbank[bank_no]);
+#ifdef MAP_PCI
+		memory_map_bank_pci(bank_no, total, checkbank[bank_no]);
+#endif
+		total += checkbank[bank_no];
+	}
+
+#ifdef CONFIG_ECC
+#ifdef CONFIG_ZUMA_V2
+	/*
+	 * We always enable ECC when bank 2 and 3 are unpopulated
+	 * If we 2 or 3 are populated, we CAN'T support ECC.
+	 * (Zuma boards only support ECC in banks 0 and 1; assume that
+	 * in that configuration, ECC chips are mounted, even for stacked
+	 * chips)
+	 */
+	if (checkbank[2]==0 && checkbank[3]==0) {
+	    	dimm_info[0].ecc=2;
+		GT_REG_WRITE(SDRAM_TIMING, GTREGREAD(SDRAM_TIMING) | (1 << 13));
+		/* TODO: do we have to run MRS cycles again? */
+	}
+#endif /* CONFIG_ZUMA_V2 */
+
+	if (GTREGREAD(SDRAM_TIMING) & (1 << 13)) {
+		puts("[ECC] ");
+	}
+#endif /* CONFIG_ECC */
+
+#ifdef DEBUG
+	dump_dimm_info(&dimm_info[0]);
+	dump_dimm_info(&dimm_info[1]);
+#endif
+	/* TODO: return at MOST 256M? */
+        /* return total > GB/4 ? GB/4 : total; */
+	return total;
+}

+ 191 - 0
board/evb64260/serial.c

@@ -0,0 +1,191 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * 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
+ */
+
+/*
+ * serial.c - serial support for the gal ev board
+ */
+
+/* supports both the 16650 duart and the MPSC */
+
+#include <common.h>
+#include <command.h>
+#include <galileo/memory.h>
+
+#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2)
+#include <ns16550.h>
+#endif
+
+#include "serial.h"
+
+#include "mpsc.h"
+
+#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2)
+const NS16550_t COM_PORTS[] = { (NS16550_t) CFG_NS16550_COM1,
+				(NS16550_t) CFG_NS16550_COM2 };
+#endif
+
+#ifdef CONFIG_MPSC
+
+int serial_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2)
+	int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate;
+#endif
+
+	mpsc_init(gd->baudrate);
+
+	/* init the DUART chans so that KGDB in the kernel can use them */
+#ifdef CFG_INIT_CHAN1
+	NS16550_reinit(COM_PORTS[0], clock_divisor);
+#endif
+#ifdef CFG_INIT_CHAN2
+	NS16550_reinit(COM_PORTS[1], clock_divisor);
+#endif
+	return (0);
+}
+
+void
+serial_putc(const char c)
+{
+	if (c == '\n')
+		mpsc_putchar('\r');
+
+	mpsc_putchar(c);
+}
+
+int
+serial_getc(void)
+{
+	return mpsc_getchar();
+}
+
+int
+serial_tstc(void)
+{
+	return mpsc_test_char();
+}
+
+void
+serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	galbrg_set_baudrate(CONFIG_MPSC_PORT, gd->baudrate);
+}
+
+#else /* ! CONFIG_MPSC */
+
+int serial_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate;
+
+#ifdef CFG_INIT_CHAN1
+	(void)NS16550_init(COM_PORTS[0], clock_divisor);
+#endif
+#ifdef CFG_INIT_CHAN2
+	(void)NS16550_init(COM_PORTS[1], clock_divisor);
+#endif
+
+	return (0);
+}
+
+void
+serial_putc(const char c)
+{
+	if (c == '\n')
+		NS16550_putc(COM_PORTS[CFG_DUART_CHAN], '\r');
+
+	NS16550_putc(COM_PORTS[CFG_DUART_CHAN], c);
+}
+
+int
+serial_getc(void)
+{
+	return NS16550_getc(COM_PORTS[CFG_DUART_CHAN]);
+}
+
+int
+serial_tstc(void)
+{
+	return NS16550_tstc(COM_PORTS[CFG_DUART_CHAN]);
+}
+
+void
+serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate;
+
+#ifdef CFG_INIT_CHAN1
+	NS16550_reinit(COM_PORTS[0], clock_divisor);
+#endif
+#ifdef CFG_INIT_CHAN2
+	NS16550_reinit(COM_PORTS[1], clock_divisor);
+#endif
+}
+
+#endif /* CONFIG_MPSC */
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+void
+kgdb_serial_init(void)
+{
+}
+
+void
+putDebugChar (int c)
+{
+	serial_putc (c);
+}
+
+void
+putDebugStr (const char *str)
+{
+	serial_puts (str);
+}
+
+int
+getDebugChar (void)
+{
+	return serial_getc();
+}
+
+void
+kgdb_interruptible (int yes)
+{
+	return;
+}
+#endif	/* CFG_CMD_KGDB	*/

+ 142 - 0
board/gen860t/README

@@ -0,0 +1,142 @@
+
+This directory contains board specific code for a generic MPC860T based
+embedded computer, called 'GEN860T'.  The design is generic in the sense that
+common, readily available components are used and that the architecture of the
+system is i(relatively) straightforward:
+
+	One eight bit wide boot (FLASH) memory
+	32 bit main memory using SDRAM
+	DOC 2000+
+	Ethernet PHY
+	Some I2C peripheral devices: Atmel AT24C256 EEPROM, Maxim DS1337 RTC.
+	Some other miscellaneous peripherals
+
+NOTE: There are references to a XIlinx FPGA and Mil-Std 1553 databus in this
+port.  I guess the computer is not as generic as I first said 8)  However,
+these extras can be safely ignored.
+
+Given the GEN860T files, it should be pretty easy to reverse engineer the
+hardware configuration, if that's useful to you.  Hopefully, this code will
+be useful to someone as a basis for a port to a new system or as a head start
+on a custom design.  If you end up using any of this, I would appreciate
+hearing from you, especially if you discover bugs or find ways to improve the
+quality of this U-Boot port.
+
+Here are the salient features of the system:
+Clock						:	33 Mhz oscillator
+Processor core frequency	:	66 Mhz  if in 1:2:1 mode; can also run 1:1
+Bus frequency				:	33 Mhz
+
+Main memory:
+	Type	: SDRAM
+	Width	: 32 bits
+	Size	: 64 megabytes
+	Chip	: Two Micron MT48LC16M16A2TG-7E
+	CS		: MPC860T CS1*/UPMA
+	UPMA CONNECTIONS:
+		SDRAM A10	: GPLA0*
+		SDRAM CAS*	: GPLA2*
+		SDRAM WE*	: GPLA3*
+		SDRAM RAS*	: GPLA4*
+
+Boot memory:
+	Type	: FLASH
+	Width	: 8 bits
+	Size	: 16 megabytes
+	Chip	: One Intel 28F128J3A (StrataFlash)
+	CS		: MPC860T CS0*/GPCM (this is the "boot" chip select)
+
+EEPROM memory:
+	Type	: Serial I2C EEPROM
+	Width	: 8 bits
+	Size	: 32 kibibytes
+	Chip	: One Atmel AT25C256
+	CS		: 0x50 (external I2C address pins on device are tied to GND)
+
+Filesystem memory:
+	Type	: NAND FLASH (Toshiba)
+	Width	: 8 bits (i.e. interface to DOC is 8 bits)
+	Size	: 32 megabytes
+	Chip	: One DiskOnCHip Millenium Plus (DOC 2000+)
+	CS		: MPC860T CS2*/GPCM
+
+Network support:
+	MAC		: MPC86OT FEC (Fast Ethernet Controller)
+	PHY		: Intel LXT971A
+	MII Addr: 0x0 (hardwired on the board)
+	MII IRQ	:
+
+Console:
+	RS-232 on SMC1 (Maxim MAX3232 LVCMOS-RS232 level shifter)
+
+Real Time Clock:
+	Type	: Low power, I2C interface
+	Chip	: Maxim DS1337
+	CS		: Address 0x68 on I2C bus
+
+	The MPC860T's internal RTC has a defect in Mask rev D that increases
+	the current drain on the KAPWR line to 10 mA.  Since this is an
+	unreasonable amount of current draw for a RTC, and Motorola does not
+	plan to fix this in future mask revisions, a serial (I2C) RTC that
+	works has been included instead.  NOTE that the DS1337 can be
+	configured to output a 32768 Hz clock while the main power is on.
+	This clock output has been routed to the MPC860T's EXTAL pin to allow
+	the internal RTC to be used.  NOTE also that due to yet another
+	defect in the rev D mask, the RTC does not operate reliably when the
+	internal RTC divisor is set to use a 32768 Hz reference.  So just use
+	the I2C RTC.
+
+Miscellaneous:
+	Xilinx Virtex FPGA on CS3*/GPCM.
+	Virtex FPGA slave SelectMap interface on cs4*/UPMB.
+	Mil-Std 1553 databus interface on CS5*/GPCM.
+	Audio sounder (beeper) with digital volume control connected to SPKROUT.
+
+Issues:
+	The DOC 2000+ returns 0x40 as its device ID when probed using the method
+	desxribed in the DOC datasheet.  Unfortunately, the U-Boot DOC driver
+	does not recognize this device.  As of this writing, it seems that MTD
+	does not support the DOC 2000+ either.
+
+Status:
+	Everything appears to work except DOC support. As of this writing,
+	David Woodhouse has stated on the MTD mailing list that he has no
+	knowledge of the DOC Millineum Plus and therfore there is no support
+	in MTD for this device.  I wish I had known this sooner :(
+
+The GEN860T board specific files and configuration is based on the work
+of others who have contributed to U-Boot. The copright and license notices
+of these authors have been retained wherever their code has been reused.
+All new code to support the GEN860T board is:
+
+	(C) Copyright 2001-2002
+	Keith Outwater (keith_outwater@mvis.com)
+
+and the following license applies:
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+
+Thanks to Wolfgang Denk for a great software package and to everyone
+who contributed to its development.
+
+Keith Outwater
+Sr. Staff Engineer
+Microvision, Inc.
+<keith_outwater@mvis.com>
+<outwater@eskimo.com>
+
+vim: set ts=4 sw=4 tw=78:
+

+ 213 - 0
board/gen860t/beeper.c

@@ -0,0 +1,213 @@
+/*
+ * (C) Copyright 2002
+ * Keith Outwater, keith_outwater@mvis.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <linux/ctype.h>
+
+/*
+ * Basic beeper support for the GEN860T board.  The GEN860T includes
+ * an audio sounder driven by a Phillips TDA8551 amplifier.  The
+ * TDA8551 features a digital volume control which uses a "trinary"
+ * input (high/high-Z/low) to set volume.  The 860's SPKROUT pin
+ * drives the amplifier input.
+ */
+
+
+/*
+ * Initialize beeper-related hardware. Initialize timer 1 for use with
+ * the beeper. Use 66 Mhz internal clock with prescale of 33 to get
+ * 1 uS period per count.
+ * FIXME: we should really compute the prescale based on the reported
+ * core clock frequency.
+ */
+void
+init_beeper(void)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	immap->im_cpmtimer.cpmt_tgcr &= ~TGCR_RST1 | TGCR_STP1;
+	immap->im_cpmtimer.cpmt_tmr1 = ((33 << TMR_PS_SHIFT) & TMR_PS_MSK)
+								 | TMR_OM | TMR_FRR | TMR_ICLK_IN_GEN;
+	immap->im_cpmtimer.cpmt_tcn1 = 0;
+	immap->im_cpmtimer.cpmt_ter1 = 0xffff;
+	immap->im_cpmtimer.cpmt_tgcr |= TGCR_RST1;
+}
+
+
+/*
+ * Set beeper frequency.  Max allowed frequency is 2.5 KHz.  This limit
+ * is mostly arbitrary, but the beeper isn't really much good beyond this
+ * frequency.
+ */
+void
+set_beeper_frequency(uint frequency)
+{
+#define FREQ_LIMIT	2500
+
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	/*
+	 * Compute timer ticks given desired frequency.  The timer is set up
+	 * to count 0.5 uS per tick and it takes two ticks per cycle (Hz).
+	 */
+	if (frequency > FREQ_LIMIT) frequency = FREQ_LIMIT;
+	frequency = 1000000/frequency;
+	immap->im_cpmtimer.cpmt_trr1 = (ushort)frequency;
+}
+
+
+/*
+ * Turn the beeper on
+ */
+void
+beeper_on(void)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	immap->im_cpmtimer.cpmt_tgcr &= ~TGCR_STP1;
+}
+
+
+/*
+ * Turn the beeper off
+ */
+void
+beeper_off(void)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	immap->im_cpmtimer.cpmt_tgcr |= TGCR_STP1;
+}
+
+
+/*
+ * Increase or decrease the beeper volume.  Volume can be set
+ * from off to full in 64 steps.  To increase volume, the output
+ * pin is actively driven high, then returned to tristate.
+ * To decrease volume, output a low on the port pin (no need to
+ * change pin mode to tristate) then output a high to go back to
+ * tristate.
+ */
+void
+set_beeper_volume(int steps)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+	int i;
+
+	if (steps >= 0) {
+		for (i = 0; i < (steps >= 64 ? 64 : steps); i++) {
+			immap->im_cpm.cp_pbodr &= ~(0x80000000 >> 19);
+			udelay(1);
+			immap->im_cpm.cp_pbodr |= (0x80000000 >> 19);
+			udelay(1);
+		}
+	}
+	else {
+		for (i = 0; i > (steps <= -64 ? -64 : steps); i--) {
+			immap->im_cpm.cp_pbdat &= ~(0x80000000 >> 19);
+			udelay(1);
+			immap->im_cpm.cp_pbdat |= (0x80000000 >> 19);
+			udelay(1);
+		}
+	}
+}
+
+
+/*
+ * Check the environment to see if the beeper needs beeping.
+ * Controlled by a sequence of the form:
+ * freq/delta volume/on time/off time;... where:
+ * freq 		= frequency in Hz (0 - 2500)
+ * delta volume = volume steps up or down (-64 <= vol <= 64)
+ * on time		= time in mS
+ * off time		= time in mS
+ *
+ * Return 1 on success, 0 on failure
+ */
+int
+do_beeper(char *sequence)
+{
+#define DELIMITER	';'
+
+int args[4];
+int i;
+int val;
+char *p = sequence;
+char *tp;
+
+	/*
+	 * Parse the control sequence.  This is a really simple parser
+	 * without any real error checking.  You can probably blow it
+	 * up really easily.
+	 */
+	if (*p == '\0' || !isdigit(*p)) {
+		printf("%s:%d: null or invalid string (%s)\n",
+				__FILE__, __LINE__, p);
+		return 0;
+	}
+
+	i = 0;
+	while (*p != '\0') {
+		while (*p != DELIMITER) {
+			if (i > 3) i = 0;
+			val = (int) simple_strtol(p, &tp, 0);
+			if (tp == p) {
+				printf("%s:%d: no digits or bad format\n",
+								__FILE__,__LINE__);
+				return 0;
+			}
+			else {
+				args[i] = val;
+			}
+
+			i++;
+			if (*tp == DELIMITER)
+				p = tp;
+			else
+				p = ++tp;
+		}
+		p++;
+
+		/*
+		 * Well, we got something that has a chance of being correct
+		 */
+#if 0
+		for (i = 0; i < 4; i++) {
+			printf("%s:%d:arg %d = %d\n", __FILE__, __LINE__, i, args[i]);
+		}
+		printf("\n");
+#endif
+
+		set_beeper_frequency(args[0]);
+		set_beeper_volume(args[1]);
+		beeper_on();
+		udelay(1000 * args[2]);
+		beeper_off();
+		udelay(1000 * args[3]);
+	}
+	return 1;
+}
+
+/* vim: set ts=4 sw=4 tw=78: */

+ 644 - 0
board/gen860t/flash.c

@@ -0,0 +1,644 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Keith Outwater, keith_outwater@mvsi.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR	(CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE	CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*
+ * Use buffered writes to flash by default - they are about 32x faster than
+ * single byte writes.
+ */
+#ifndef  CFG_GEN860T_FLASH_USE_WRITE_BUFFER
+#define CFG_GEN860T_FLASH_USE_WRITE_BUFFER
+#endif
+
+/*
+ * Max time to wait (in mS) for flash device to allocate a write buffer.
+ */
+#ifndef CFG_FLASH_ALLOC_BUFFER_TOUT
+#define CFG_FLASH_ALLOC_BUFFER_TOUT		100
+#endif
+
+/*
+ * These functions support a single Intel StrataFlash device (28F128J3A)
+ * in byte mode only!.  The flash routines are very basic and simple
+ * since there isn't really any remapping necessary.
+ */
+
+/*
+ * Intel SCS (Scalable Command Set) command definitions
+ * (taken from 28F128J3A datasheet)
+ */
+#define SCS_READ_CMD				0xff
+#define SCS_READ_ID_CMD				0x90
+#define SCS_QUERY_CMD				0x98
+#define SCS_READ_STATUS_CMD			0x70
+#define SCS_CLEAR_STATUS_CMD		0x50
+#define SCS_WRITE_BUF_CMD			0xe8
+#define SCS_PROGRAM_CMD				0x40
+#define SCS_BLOCK_ERASE_CMD			0x20
+#define SCS_BLOCK_ERASE_RESUME_CMD	0xd0
+#define SCS_PROGRAM_RESUME_CMD		0xd0
+#define SCS_BLOCK_ERASE_SUSPEND_CMD	0xb0
+#define SCS_SET_BLOCK_LOCK_CMD		0x60
+#define SCS_CLR_BLOCK_LOCK_CMD		0x60
+
+/*
+ * SCS status/extended status register bit definitions
+ */
+#define  SCS_SR7					0x80
+#define  SCS_XSR7					0x80
+
+/*---------------------------------------------------------------------*/
+#if 0
+#define DEBUG_FLASH
+#endif
+
+#ifdef DEBUG_FLASH
+#define PRINTF(fmt,args...) printf(fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t	flash_info[CFG_MAX_FLASH_BANKS];
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_char *addr, flash_info_t *info);
+static int write_data8 (flash_info_t *info, ulong dest, uchar data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ * Initialize the flash memory.
+ */
+unsigned long
+flash_init (void)
+{
+	volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	unsigned long size_b0;
+	int i;
+
+	for (i= 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+		flash_info[i].flash_id = FLASH_UNKNOWN;
+	}
+
+	/*
+	 * The gen860t board only has one FLASH memory device, so the
+	 * FLASH Bank configuration is done statically.
+	 */
+	PRINTF("\n## Get flash bank 1 size @ 0x%08x\n", FLASH_BASE0_PRELIM);
+	size_b0 = flash_get_size((vu_char *)FLASH_BASE0_PRELIM, &flash_info[0]);
+	if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+		printf ("## Unknown FLASH on Bank 0: "
+				"ID 0x%lx, Size = 0x%08lx = %ld MB\n",
+				flash_info[0].flash_id,size_b0, size_b0 << 20);
+	}
+
+	PRINTF("## Before remap:\n"
+		   "  BR0: 0x%08x    OR0: 0x%08x\n  BR1: 0x%08x    OR1: 0x%08x\n",
+		   memctl->memc_br0, memctl->memc_or0,
+		   memctl->memc_br1, memctl->memc_or1);
+
+	/*
+	 * Remap FLASH according to real size
+	 */
+	memctl->memc_or0 |= (-size_b0 & 0xFFFF8000);
+	memctl->memc_br0 |= (CFG_FLASH_BASE & BR_BA_MSK);
+
+	PRINTF("## After remap:\n"
+		   "  BR0: 0x%08x    OR0: 0x%08x\n", memctl->memc_br0, memctl->memc_or0);
+
+	/*
+	 * Re-do sizing to get full correct info
+	 */
+	size_b0 = flash_get_size ((vu_char *)CFG_FLASH_BASE, &flash_info[0]);
+	flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+	flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+	/*
+	 * Monitor protection is ON by default
+	 */
+	flash_protect(FLAG_PROTECT_SET,
+		      	  CFG_MONITOR_BASE,
+		      	  CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+		      	  &flash_info[0]);
+#endif
+
+#ifdef	CFG_ENV_IS_IN_FLASH
+	/*
+	 * Environment protection ON by default
+	 */
+	flash_protect(FLAG_PROTECT_SET,
+		      	  CFG_ENV_ADDR,
+		      	  CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+		      	  &flash_info[0]);
+#endif
+
+	PRINTF("## Final Flash bank size: 0x%08lx\n",size_b0);
+	return (size_b0);
+}
+
+
+/*-----------------------------------------------------------------------
+ * Fill in the FLASH offset table
+ */
+static void
+flash_get_offsets (ulong base, flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+		case FLASH_MAN_INTEL:
+	    	for (i = 0; i < info->sector_count; i++) {
+				info->start[i] = base;
+				base += 1024 * 128;
+	    	}
+	    	return;
+
+		default:
+	   		printf ("Don't know sector offsets for FLASH"
+			        " type 0x%lx\n", info->flash_id);
+	    return;
+	}
+}
+
+
+/*-----------------------------------------------------------------------
+ * Display FLASH device info
+ */
+void
+flash_print_info (flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf ("Missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_INTEL:
+			printf ("Intel ");
+			break;
+	default:
+			printf ("Unknown Vendor ");
+			break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_28F128J3A:
+			printf ("28F128J3A (128Mbit = 128K x 128)\n");
+			break;
+	default:
+			printf ("Unknown Chip Type\n");
+			break;
+	}
+
+	if (info->size >= (1024 * 1024)) {
+		i = 20;
+	} else {
+		i = 10;
+	}
+	printf ("  Size: %ld %cB in %d Sectors\n",
+			info->size >> i,
+			(i == 20) ? 'M' : 'k',
+			info->sector_count);
+
+	printf ("  Sector Start Addresses:");
+	for (i=0; i<info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			printf ("\n   ");
+			printf (" %08lX%s",
+			info->start[i],
+			info->protect[i] ? " (RO)" : "     "
+		);
+	}
+	printf ("\n");
+	return;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Get size and other information for a FLASH device.
+ * NOTE: The following code cannot be run from FLASH!
+ */
+static
+ulong flash_get_size (vu_char *addr, flash_info_t *info)
+{
+#define NO_FLASH	0
+
+	vu_char value[2];
+
+	/*
+	 * Try to read the manufacturer ID
+	 */
+	addr[0] = SCS_READ_CMD;
+	addr[0] = SCS_READ_ID_CMD;
+	value[0] = addr[0];
+	value[1] = addr[2];
+	addr[0] = SCS_READ_CMD;
+
+	PRINTF("Manuf. ID @ 0x%08lx: 0x%02x\n", (ulong)addr, value[0]);
+	switch (value[0]) {
+		case (INTEL_MANUFACT & 0xff):
+			info->flash_id = FLASH_MAN_INTEL;
+			break;
+		default:
+			info->flash_id = FLASH_UNKNOWN;
+			info->sector_count = 0;
+			info->size = 0;
+			return (NO_FLASH);
+	}
+
+	/*
+	 * Read the device ID
+	 */
+	PRINTF("Device ID @ 0x%08lx: 0x%02x\n", (ulong)(&addr[2]), value[1]);
+	switch (value[1]) {
+		case (INTEL_ID_28F128J3A & 0xff):
+			info->flash_id += FLASH_28F128J3A;
+			info->sector_count = 128;
+			info->size = 16 * 1024 * 1024;
+			break;
+
+		default:
+			info->flash_id = FLASH_UNKNOWN;
+			return (NO_FLASH);
+	}
+
+	if (info->sector_count > CFG_MAX_FLASH_SECT) {
+		printf ("** ERROR: sector count %d > max (%d) **\n",
+				info->sector_count, CFG_MAX_FLASH_SECT);
+				info->sector_count = CFG_MAX_FLASH_SECT;
+	}
+	return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ * Erase the specified sectors in the specified FLASH device
+ */
+int
+flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+	int flag, prot, sect;
+	ulong start, now, last;
+
+	if ((s_first < 0) || (s_first > s_last)) {
+		if (info->flash_id == FLASH_UNKNOWN) {
+			printf ("- missing\n");
+		} else {
+			printf ("- no sectors to erase\n");
+		}
+		return 1;
+	}
+
+	if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
+		printf ("Can erase only Intel flash types - aborted\n");
+		return 1;
+	}
+
+	prot = 0;
+	for (sect=s_first; sect<=s_last; ++sect) {
+		if (info->protect[sect]) {
+			prot++;
+		}
+	}
+
+	if (prot) {
+		printf ("- Warning: %d protected sectors will not be erased!\n",
+				prot);
+	} else {
+		printf ("\n");
+	}
+
+	start = get_timer (0);
+	last  = start;
+
+	/*
+	 * Start erase on unprotected sectors
+	 */
+	for (sect = s_first; sect<=s_last; sect++) {
+		if (info->protect[sect] == 0) {	/* not protected */
+			vu_char *addr = (uchar *)(info->start[sect]);
+			vu_char status;
+
+			/*
+			 * Disable interrupts which might cause a timeout
+			 */
+			flag = disable_interrupts();
+
+			*addr = SCS_CLEAR_STATUS_CMD;
+			*addr = SCS_BLOCK_ERASE_CMD;
+			*addr = SCS_BLOCK_ERASE_RESUME_CMD;
+
+			/*
+			 * Re-enable interrupts if necessary
+			 */
+			if (flag)
+				enable_interrupts();
+
+			/*
+			 * Wait at least 80us - let's wait 1 ms
+			 */
+			udelay (1000);
+
+			while (((status = *addr) & SCS_SR7) != SCS_SR7) {
+				if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+					printf ("Timeout\n");
+					*addr = SCS_BLOCK_ERASE_SUSPEND_CMD;
+					*addr = SCS_READ_CMD;
+					return 1;
+				}
+
+				/*
+				 * Show that we're waiting
+				 */
+				if ((now - last) > 1000) {	/* 1 second */
+					putc ('.');
+					last = now;
+				}
+			}
+			*addr = SCS_READ_CMD;
+		}
+	}
+	printf (" done\n");
+	return 0;
+}
+
+
+#ifdef CFG_GEN860T_FLASH_USE_WRITE_BUFFER
+/*
+ * Allocate a flash buffer, fill it with data and write it to the flash.
+ * 0 - OK
+ * 1 - Timeout on buffer request
+ *
+ * NOTE: After the last call to this function, WSM status needs to be checked!
+ */
+static int
+write_flash_buffer8(flash_info_t *info_p, vu_char *src_p, vu_char *dest_p,
+				    uint count)
+{
+	vu_char *block_addr_p = NULL;
+	vu_char *start_addr_p = NULL;
+	ulong blocksize = info_p->size / (ulong)info_p->sector_count;
+
+	int i;
+	uint time = get_timer(0);
+
+	PRINTF("%s:%d: src: 0x%p dest: 0x%p  count: %d\n",
+		   __FUNCTION__, __LINE__, src_p, dest_p, count);
+
+	/*
+	 * What block are we in? We already know that the source address is
+	 * in the flash address range, but we also can't cross a block boundary.
+	 * We assume that the block does not cross a boundary (we'll check before
+	 * calling this function).
+	 */
+ 	for (i = 0; i < info_p->sector_count; ++i) {
+		if ( ((ulong)dest_p >= info_p->start[i]) &&
+		    ((ulong)dest_p < (info_p->start[i] + blocksize)) ) {
+			PRINTF("%s:%d: Dest addr 0x%p is in block %d @ 0x%.8lx\n",
+				   __FUNCTION__, __LINE__, dest_p, i, info_p->start[i]);
+			block_addr_p = (vu_char *)info_p->start[i];
+			break;
+		}
+	}
+
+	/*
+	 * Request a buffer
+	 */
+	*block_addr_p = SCS_WRITE_BUF_CMD;
+	while ((*block_addr_p & SCS_XSR7) != SCS_XSR7) {
+		if (get_timer(time) >  CFG_FLASH_ALLOC_BUFFER_TOUT) {
+			PRINTF("%s:%d: Buffer allocation timeout @ 0x%p (waited %d mS)\n",
+				   __FUNCTION__, __LINE__, block_addr_p,
+				   CFG_FLASH_ALLOC_BUFFER_TOUT);
+			return 1;
+		}
+		*block_addr_p = SCS_WRITE_BUF_CMD;
+	}
+
+	/*
+	 * Fill the buffer with data
+	 */
+	start_addr_p = dest_p;
+	*block_addr_p = count - 1; /* flash device wants count - 1 */
+	PRINTF("%s:%d: Fill buffer at block addr 0x%p\n",
+		   __FUNCTION__, __LINE__, block_addr_p);
+	for (i = 0; i < count; i++) {
+		*start_addr_p++ = *src_p++;
+	}
+
+	/*
+	 * Flush buffer to flash
+	 */
+	*block_addr_p = SCS_PROGRAM_RESUME_CMD;
+#if 1
+	time = get_timer(0);
+	while ((*block_addr_p & SCS_SR7) != SCS_SR7) {
+		if (get_timer(time) >  CFG_FLASH_WRITE_TOUT) {
+			PRINTF("%s:%d: Write timeout @ 0x%p (waited %d mS)\n",
+				   __FUNCTION__, __LINE__, block_addr_p, CFG_FLASH_WRITE_TOUT);
+			return 1;
+		}
+	}
+
+#endif
+	return 0;
+}
+#endif
+
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+int
+write_buff(flash_info_t *info_p, uchar *src_p, ulong addr, ulong count)
+{
+	int rc = 0;
+#ifdef CFG_GEN860T_FLASH_USE_WRITE_BUFFER
+#define FLASH_WRITE_BUF_SIZE	0x00000020	/* 32 bytes */
+	int i;
+	uint bufs;
+	ulong buf_count;
+	vu_char *sp;
+	vu_char *dp;
+#else
+	ulong wp;
+#endif
+
+	PRINTF("\n%s:%d: src: 0x%.8lx dest: 0x%.8lx size: %d (0x%.8lx)\n",
+		   __FUNCTION__, __LINE__, (ulong)src_p, addr, (uint)count, count);
+
+	if (info_p->flash_id == FLASH_UNKNOWN) {
+		return 4;
+	}
+
+#ifdef CFG_GEN860T_FLASH_USE_WRITE_BUFFER
+	sp = src_p;
+	dp = (uchar *)addr;
+
+	/*
+	 * For maximum performance, we want to align the start address to
+	 * the beginning of a write buffer boundary (i.e. A4-A0 of the
+	 * start address = 0). See how many bytes are required to get to a
+	 * write-buffer-aligned address.  If that number is non-zero, do
+	 * non buffered writes of the non-aligned data.  By doing non-buffered
+	 * writes, we avoid the problem of crossing a block (sector) boundary
+	 * with buffered writes.
+	 */
+	buf_count = FLASH_WRITE_BUF_SIZE - (addr & (FLASH_WRITE_BUF_SIZE - 1));
+	if (buf_count == FLASH_WRITE_BUF_SIZE) { /* already on a boundary */
+		buf_count = 0;
+	}
+	if (buf_count > count) { /* not a full buffers worth of data to write */
+		buf_count = count;
+	}
+	count -= buf_count;
+
+	PRINTF("%s:%d: Write buffer alignment count = %ld\n",
+		   __FUNCTION__, __LINE__, buf_count);
+	while (buf_count-- >= 1) {
+		if ((rc = write_data8(info_p, (ulong)dp++, *sp++)) != 0)  {
+			return (rc);
+		}
+	}
+
+	PRINTF("%s:%d: count = %ld\n", __FUNCTION__, __LINE__, count);
+	if (count == 0) { /* all done */
+		PRINTF("%s:%d: Less than 1 buffer (%d) worth of bytes\n",
+			   __FUNCTION__, __LINE__, FLASH_WRITE_BUF_SIZE);
+		return (rc);
+	}
+
+	/*
+	 * Now that we are write buffer aligned, write full or partial buffers.
+	 * The fact that we are write buffer aligned automatically avoids
+	 * crossing a block address during a write buffer operation.
+	 */
+	bufs = count / FLASH_WRITE_BUF_SIZE;
+	PRINTF("%s:%d: %d (0x%x) buffers to write\n", __FUNCTION__, __LINE__,
+		   bufs, bufs);
+	while (bufs >= 1) {
+		rc = write_flash_buffer8(info_p, sp, dp, FLASH_WRITE_BUF_SIZE);
+		if (rc != 0) {
+			PRINTF("%s:%d: ** Error writing buf %d\n",
+				   __FUNCTION__, __LINE__, bufs);
+			return (rc);
+		}
+		bufs--;
+		sp += FLASH_WRITE_BUF_SIZE;
+		dp += FLASH_WRITE_BUF_SIZE;
+	}
+
+	/*
+	 * Do the leftovers
+	 */
+	i = count % FLASH_WRITE_BUF_SIZE;
+	PRINTF("%s:%d: %d (0x%x) leftover bytes\n", __FUNCTION__, __LINE__, i, i);
+	if (i > 0) {
+		rc = write_flash_buffer8(info_p, sp, dp, i);
+	}
+
+	sp = (vu_char*)info_p->start[0];
+	*sp = SCS_READ_CMD;
+	return (rc);
+
+#else
+	wp = addr;
+	while (count-- >= 1) {
+		if((rc = write_data8(info_p, wp++, *src_p++)) != 0)
+			return (rc);
+	}
+	return 0;
+#endif
+}
+
+
+/*-----------------------------------------------------------------------
+ * Write a byte to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int
+write_data8 (flash_info_t *info, ulong dest, uchar data)
+{
+	vu_char *addr = (vu_char *)dest;
+	vu_char status;
+	ulong start;
+	int flag;
+
+	/* Check if Flash is (sufficiently) erased */
+	if ((*addr & data) != data) {
+		return (2);
+	}
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts();
+
+	*addr = SCS_PROGRAM_CMD;
+	*addr = data;
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts();
+
+	start = get_timer (0);
+
+	while (((status = *addr) & SCS_SR7) != SCS_SR7) {
+		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+			*addr = SCS_READ_CMD;
+			return (1);
+		}
+	}
+	*addr = SCS_READ_CMD;
+	return (0);
+}
+
+/* vim: set ts=4 sw=4 tw=78: */

+ 401 - 0
board/gen860t/fpga.c

@@ -0,0 +1,401 @@
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ * Keith Outwater, keith_outwater@mvis.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Virtex2 FPGA configuration support for the GEN860T computer
+ */
+
+#include <common.h>
+#include <virtex2.h>
+#include <command.h>
+#include "fpga.h"
+
+#if (CONFIG_FPGA)
+
+#if 0
+#define GEN860T_FPGA_DEBUG
+#endif
+
+#ifdef GEN860T_FPGA_DEBUG
+#define	PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define	PRINTF(fmt,args...)
+#endif
+
+/*
+ * Port bit numbers for the Selectmap controls
+ */
+#define FPGA_INIT_BIT_NUM		22	/* PB22 */
+#define FPGA_RESET_BIT_NUM		11	/* PC11 */
+#define FPGA_DONE_BIT_NUM		16	/* PB16 */
+#define FPGA_PROGRAM_BIT_NUM	7	/* PA7  */
+
+/* Note that these are pointers to code that is in Flash.  They will be
+ * relocated at runtime.
+ */
+Xilinx_Virtex2_Slave_SelectMap_fns fpga_fns = {
+	fpga_pre_config_fn,
+	fpga_pgm_fn,
+	fpga_init_fn,
+	fpga_err_fn,
+	fpga_done_fn,
+	fpga_clk_fn,
+	fpga_cs_fn,
+	fpga_wr_fn,
+	fpga_read_data_fn,
+	fpga_write_data_fn,
+	fpga_busy_fn,
+	fpga_abort_fn,
+	fpga_post_config_fn
+};
+
+Xilinx_desc fpga[CONFIG_FPGA_COUNT] = {
+	{ Xilinx_Virtex2,
+	  slave_selectmap,
+	  XILINX_XC2V3000_SIZE,
+	  (void *)&fpga_fns,
+	  0
+	}
+};
+
+/*
+ * Display FPGA revision information
+ */
+void
+print_fpga_revision(void)
+{
+	vu_long *rev_p = (vu_long *)0x60000008;
+
+	printf("FPGA Revision 0x%.8lx"
+		   " (Date %.2lx/%.2lx/%.2lx, Status \"%.1lx\", Version %.3lu)\n",
+		   *rev_p,
+		   ((*rev_p >> 28) & 0xf),
+		   ((*rev_p >> 20) & 0xff),
+		   ((*rev_p >> 12) & 0xff),
+		   ((*rev_p >> 8) & 0xf),
+		   (*rev_p & 0xff));
+}
+
+
+/*
+ * Perform a simple test of the FPGA to processor interface using the FPGA's
+ * inverting bus test register.  The great thing about doing a read/write
+ * test on a register that inverts it's contents is that you avoid any
+ * problems with bus charging.
+ * Return 0 on failure, 1 on success.
+ */
+int
+test_fpga_ibtr(void)
+{
+	vu_long *ibtr_p = (vu_long *)0x60000010;
+	vu_long readback;
+	vu_long compare;
+	int i;
+	int j;
+	int k;
+	int pass = 1;
+
+	static const ulong bitpattern[] = {
+		0xdeadbeef,	/* magic ID pattern for debug	*/
+		0x00000001,	/* single bit					*/
+		0x00000003,	/* two adjacent bits			*/
+		0x00000007,	/* three adjacent bits			*/
+		0x0000000F,	/* four adjacent bits			*/
+		0x00000005,	/* two non-adjacent bits		*/
+		0x00000015,	/* three non-adjacent bits		*/
+		0x00000055,	/* four non-adjacent bits		*/
+		0xaaaaaaaa,	/* alternating 1/0				*/
+	};
+
+	for (i = 0; i < 1024; i++) {
+		for (j = 0; j < 31; j++) {
+			for (k = 0; k < sizeof(bitpattern)/sizeof(bitpattern[0]); k++) {
+				*ibtr_p = compare = (bitpattern[k] << j);
+				readback = *ibtr_p;
+				if (readback != ~compare) {
+					printf("%s:%d: FPGA test fail: expected 0x%.8lx"
+						   " actual 0x%.8lx\n",
+						   __FUNCTION__, __LINE__, ~compare, readback);
+					pass = 0;
+					break;
+				}
+			}
+			if (!pass) break;
+		}
+		if (!pass) break;
+	}
+	if (pass) {
+		printf("FPGA inverting bus test passed\n");
+		print_fpga_revision();
+	}
+	else {
+		printf("** FPGA inverting bus test failed\n");
+	}
+	return pass;
+}
+
+
+/*
+ * Set the active-low FPGA reset signal.
+ */
+void
+fpga_reset(int assert)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	PRINTF("%s:%d: RESET ", __FUNCTION__, __LINE__);
+	if (assert) {
+		immap->im_ioport.iop_pcdat &= ~(0x8000 >> FPGA_RESET_BIT_NUM);
+		PRINTF("asserted\n");
+	}
+	else {
+		immap->im_ioport.iop_pcdat |= (0x8000 >> FPGA_RESET_BIT_NUM);
+		PRINTF("deasserted\n");
+	}
+}
+
+
+/*
+ * Initialize the SelectMap interface.  We assume that the mode and the
+ * initial state of all of the port pins have already been set!
+ */
+void
+fpga_selectmap_init(void)
+{
+	PRINTF("%s:%d: Initialize SelectMap interface\n", __FUNCTION__, __LINE__);
+	fpga_pgm_fn(FALSE, FALSE, 0);   /* make sure program pin is inactive */
+}
+
+
+/*
+ * Initialize the fpga.  Return 1 on success, 0 on failure.
+ */
+int
+gen860t_init_fpga(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int i;
+
+	PRINTF("%s:%d: Initialize FPGA interface (relocation offset = 0x%.8lx)\n",
+			__FUNCTION__, __LINE__, gd->reloc_off);
+	fpga_init(gd->reloc_off);
+	fpga_selectmap_init();
+
+	for(i=0; i < CONFIG_FPGA_COUNT; i++) {
+		PRINTF("%s:%d: Adding fpga %d\n", __FUNCTION__, __LINE__, i);
+		fpga_add(fpga_xilinx, &fpga[i]);
+	}
+ 	return 1;
+}
+
+
+/*
+ * Set the FPGA's active-low SelectMap program line to the specified level
+ */
+int
+fpga_pgm_fn(int assert, int flush, int cookie)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	PRINTF("%s:%d: FPGA PROGRAM ", __FUNCTION__, __LINE__);
+
+	if (assert) {
+		immap->im_ioport.iop_padat &= ~(0x8000 >> FPGA_PROGRAM_BIT_NUM);
+		PRINTF("asserted\n");
+	}
+	else {
+		immap->im_ioport.iop_padat |= (0x8000 >> FPGA_PROGRAM_BIT_NUM);
+		PRINTF("deasserted\n");
+	}
+	return assert;
+}
+
+
+/*
+ * Test the state of the active-low FPGA INIT line.  Return 1 on INIT
+ * asserted (low).
+ */
+int
+fpga_init_fn(int cookie)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	PRINTF("%s:%d: INIT check... ", __FUNCTION__, __LINE__);
+	if(immap->im_cpm.cp_pbdat & (0x80000000 >> FPGA_INIT_BIT_NUM)) {
+		PRINTF("high\n");
+		return 0;
+	}
+	else {
+		PRINTF("low\n");
+		return 1;
+	}
+}
+
+
+/*
+ * Test the state of the active-high FPGA DONE pin
+ */
+int
+fpga_done_fn(int cookie)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+	PRINTF("%s:%d: DONE check... ", __FUNCTION__, __LINE__);
+	if (immap->im_cpm.cp_pbdat & (0x80000000 >> FPGA_DONE_BIT_NUM)) {
+		PRINTF("high\n");
+		return FPGA_SUCCESS;
+	}
+	else {
+		PRINTF("low\n");
+		return FPGA_FAIL;
+	}
+}
+
+
+/*
+ * Read FPGA SelectMap data.
+ */
+int
+fpga_read_data_fn(unsigned char *data, int cookie)
+{
+	vu_char *p = (vu_char *)SELECTMAP_BASE;
+
+	*data = *p;
+#if 0
+	PRINTF("%s: Read 0x%x into 0x%p\n", __FUNCTION__, (int)data, data);
+#endif
+	return (int)data;
+}
+
+
+/*
+ * Write data to the FPGA SelectMap port
+ */
+int
+fpga_write_data_fn(unsigned char data, int flush, int cookie)
+{
+	vu_char *p = (vu_char *)SELECTMAP_BASE;
+
+#if 0
+	PRINTF("%s: Write Data 0x%x\n", __FUNCTION__, (int)data);
+#endif
+	*p = data;
+	return (int)data;
+}
+
+
+/*
+ * Abort and FPGA operation
+ */
+int
+fpga_abort_fn(int cookie)
+{
+	PRINTF("%s:%d: FPGA program sequence aborted\n",
+		   __FUNCTION__, __LINE__);
+	return FPGA_FAIL;
+}
+
+
+/*
+ * FPGA pre-configuration function. Just make sure that
+ * FPGA reset is asserted to keep the FPGA from starting up after
+ * configuration.
+ */
+int
+fpga_pre_config_fn(int cookie)
+{
+	PRINTF("%s:%d: FPGA pre-configuration\n", __FUNCTION__, __LINE__);
+	fpga_reset(TRUE);
+	return 0;
+}
+
+
+/*
+ * FPGA post configuration function. Blip the FPGA reset line and then see if
+ * the FPGA appears to be running.
+ */
+int
+fpga_post_config_fn(int cookie)
+{
+	int rc;
+
+	PRINTF("%s:%d: FPGA post configuration\n", __FUNCTION__, __LINE__);
+	fpga_reset(TRUE);
+	udelay(1000);
+	fpga_reset(FALSE);
+	udelay (1000);
+
+	/*
+	 * Use the FPGA,s inverting bus test register to do a simple test of the
+	 * processor interface.
+	 */
+	rc = test_fpga_ibtr();
+	return rc;
+}
+
+
+/*
+ * Clock, chip select and write signal assert functions and error check
+ * and busy functions.  These are only stubs because the GEN860T selectmap
+ * interface handles sequencing of control signals automatically (it uses
+ * a memory-mapped interface to the FPGA SelectMap port).  The design of
+ * the interface guarantees that the SelectMap port cannot be overrun so
+ * no busy check is needed.  A configuration error is signalled by INIT
+ * going low during configuration, so there is no need for a separate error
+ * function.
+ */
+int
+fpga_clk_fn(int assert_clk, int flush, int cookie)
+{
+	return assert_clk;
+}
+
+int
+fpga_cs_fn(int assert_cs, int flush, int cookie)
+{
+	return assert_cs;
+}
+
+int
+fpga_wr_fn(int assert_write, int flush, int cookie)
+{
+	return assert_write;
+}
+
+int
+fpga_err_fn(int cookie)
+{
+	return 0;
+}
+
+int
+fpga_busy_fn(int cookie)
+{
+	return 0;
+}
+#endif
+
+/* vim: set ts=4 tw=78 sw=4: */

+ 299 - 0
board/gen860t/gen860t.c

@@ -0,0 +1,299 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Keith Outwater, keith_outwater@mvis.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <virtex2.h>
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include "beeper.h"
+#include "fpga.h"
+#include "ioport.h"
+
+#ifdef CONFIG_STATUS_LED
+#include <status_led.h>
+#endif
+
+#if defined(CFG_CMD_MII) && defined(CONFIG_MII)
+#include <net.h>
+#endif
+
+#if 0
+#define GEN860T_DEBUG
+#endif
+
+#ifdef GEN860T_DEBUG
+#define	PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define	PRINTF(fmt,args...)
+#endif
+
+/*
+ * The following UPM init tables were generated automatically by
+ * Motorola's MCUINIT program. See the README file for UPM to
+ * SDRAM pin assignments if you want to type this data into
+ * MCUINIT in order to reverse engineer the waveforms.
+ */
+
+/*
+ * UPM initialization tables for MICRON MT48LC16M16A2TG SDRAM devices
+ * (UPMA) and Virtex FPGA SelectMap interface (UPMB).
+ * NOTE that unused areas of the table are used to hold NOP, precharge
+ * and mode register set sequences.
+ *
+ */
+#define	UPMA_NOP_ADDR			0x5
+#define	UPMA_PRECHARGE_ADDR		0x6
+#define UPMA_MRS_ADDR			0x12
+
+#define UPM_SINGLE_READ_ADDR	0x00
+#define UPM_BURST_READ_ADDR		0x08
+#define UPM_SINGLE_WRITE_ADDR	0x18
+#define UPM_BURST_WRITE_ADDR	0x20
+#define	UPM_REFRESH_ADDR		0x30
+
+const uint sdram_upm_table[] = {
+	/* single read   (offset 0x00 in upm ram) */
+	0x0e0fdc04, 0x01adfc04, 0x0fbffc00, 0x1fff5c05,
+	0xffffffff, 0x0fffffcd, 0x0fff0fce, 0xefcfffff,
+	/* burst read    (offset 0x08 in upm ram) */
+	0x0f0fdc04, 0x00fdfc04, 0xf0fffc00, 0xf0fffc00,
+	0xf1fffc00, 0xfffffc00, 0xfffffc05, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x0ffffff4, 0x1f3d5ff4,
+	0xfffffff4, 0xfffffff5, 0xffffffff, 0xffffffff,
+	/* single write  (offset 0x18 in upm ram) */
+	0x0f0fdc04, 0x00ad3c00, 0x1fff5c05, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* burst write   (offset 0x20 in upm ram) */
+	0x0f0fdc00, 0x10fd7c00, 0xf0fffc00, 0xf0fffc00,
+	0xf1fffc04, 0xfffffc05, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xfffff7ff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* refresh       (offset 0x30 in upm ram) */
+	0x1ffddc84, 0xfffffc04, 0xfffffc04, 0xfffffc84,
+	0xfffffc05, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* exception     (offset 0x3C in upm ram) */
+   };
+
+const uint selectmap_upm_table[] = {
+	/* single read   (offset 0x00 in upm ram) */
+	0x88fffc06, 0x00fff404, 0x00fffc04, 0x33fffc00,
+	0xfffffc05, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* burst read    (offset 0x08 in upm ram) */
+	0xfffffc04, 0xfffffc05, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* single write  (offset 0x18 in upm ram) */
+	0x88fffc04, 0x00fff400, 0x77fffc05, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* burst write   (offset 0x20 in upm ram) */
+	0xfffffc04, 0xfffffc05, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* refresh       (offset 0x30 in upm ram) */
+	0xfffffc04, 0xfffffc05, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	/* exception     (offset 0x3C in upm ram) */
+	0xfffffc05, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+/*
+ * Check board identity.  Always successful (gives information only)
+ */
+int
+checkboard(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+    unsigned char *s;
+    unsigned char buf[64];
+    int i;
+
+    i = getenv_r("board_id", buf, sizeof(buf));
+    s = (i>0) ? buf : NULL;
+
+	if (s) {
+		printf("%s ", s);
+	} else {
+		printf("<unknown> ");
+	}
+
+    i = getenv_r("serial#", buf, sizeof(buf));
+    s = (i>0) ? buf : NULL;
+
+	if (s) {
+		printf("S/N %s\n", s);
+	} else {
+		printf("S/N <unknown>\n");
+	}
+
+    printf("CPU at %s MHz, ",strmhz(buf, gd->cpu_clk));
+	printf("local bus at %s MHz\n", strmhz(buf, gd->bus_clk));
+    return (0);
+}
+
+/*
+ * Initialize SDRAM
+ */
+long int
+initdram(int board_type)
+{
+    volatile immap_t     *immr  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immr->im_memctl;
+
+    upmconfig(UPMA,
+			  (uint *)sdram_upm_table,
+			  sizeof(sdram_upm_table) / sizeof(uint)
+			 );
+
+    /*
+     * Setup MAMR register
+     */
+    memctl->memc_mptpr = CFG_MPTPR_1BK_8K;
+    memctl->memc_mamr = CFG_MAMR_8COL & (~(MAMR_PTAE)); /* no refresh yet */
+
+    /*
+     * Map CS1* to SDRAM bank
+     */
+    memctl->memc_or1 = CFG_OR1;
+    memctl->memc_br1 = CFG_BR1;
+
+	/*
+	 * Perform SDRAM initialization sequence:
+	 * 1. Apply at least one NOP command
+	 * 2. 100 uS delay (JEDEC standard says 200 uS)
+	 * 3. Issue 4 precharge commands
+	 * 4. Perform two refresh cycles
+	 * 5. Program mode register
+	 *
+	 * Program SDRAM for standard operation, sequential burst, burst length
+	 * of 4, CAS latency of 2.
+	 */
+    memctl->memc_mar = 0x00000000;
+	memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 |
+					   MCR_MLCF(0) | UPMA_NOP_ADDR;
+	udelay(200);
+    memctl->memc_mar = 0x00000000;
+	memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 |
+					   MCR_MLCF(4) | UPMA_PRECHARGE_ADDR;
+
+    memctl->memc_mar = 0x00000000;
+	memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 |
+					   MCR_MLCF(2) | UPM_REFRESH_ADDR;
+
+    memctl->memc_mar = 0x00000088;
+	memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 |
+					   MCR_MLCF(1) | UPMA_MRS_ADDR;
+
+    memctl->memc_mar = 0x00000000;
+	memctl->memc_mcr = MCR_UPM_A | MCR_OP_RUN | MCR_MB_CS1 |
+					   MCR_MLCF(0) | UPMA_NOP_ADDR;
+	/*
+	 * Enable refresh
+	 */
+    memctl->memc_mamr |= MAMR_PTAE;
+
+    return (SDRAM_SIZE);
+}
+
+/*
+ * Disk On Chip (DOC) Millenium initialization.
+ * The DOC lives in the CS2* space
+ */
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+extern void
+doc_probe(ulong physadr);
+
+void
+doc_init(void)
+{
+	printf("Probing at 0x%.8x: ", DOC_BASE);
+	doc_probe(DOC_BASE);
+}
+#endif
+
+/*
+ * Miscellaneous intialization
+ */
+int
+misc_init_r (void)
+{
+    volatile immap_t     *immr  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immr->im_memctl;
+
+	/*
+	 * Set up UPMB to handle the Virtex FPGA SelectMap interface
+	 */
+	upmconfig(UPMB, (uint *)selectmap_upm_table,
+			  sizeof(selectmap_upm_table) / sizeof(uint));
+
+    memctl->memc_mbmr = 0x0;
+
+	config_mpc8xx_ioports(immr);
+
+#if (CONFIG_COMMANDS & CFG_CMD_MII)
+	mii_init();
+#endif
+
+#if (CONFIG_FPGA)
+	gen860t_init_fpga();
+#endif
+	return 0;
+}
+
+/*
+ * Final init hook before entering command loop.
+ */
+int
+last_stage_init(void)
+{
+	unsigned char buf[256];
+	int i;
+
+	/*
+	 * Set LEDs here since status LED init code has already run
+	 */
+	status_led_set(STATUS_LED_BIT1, STATUS_LED_ON);
+	status_led_set(STATUS_LED_BIT3, STATUS_LED_ON);
+
+	/*
+	 * Turn the beeper volume all the way down in case this is a warm
+	 * boot.
+	 */
+	set_beeper_volume(-64);
+	init_beeper();
+
+	/*
+	 * Read the environment to see what to do with the beeper
+	 */
+    i = getenv_r("beeper", buf, sizeof(buf));
+	if (i > 0) {
+		do_beeper(buf);
+	}
+	return 0;
+}
+/* vim: set ts=4 sw=4 tw=78 : */

+ 276 - 0
board/gen860t/ioport.c

@@ -0,0 +1,276 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include "ioport.h"
+
+#if 0
+#define IOPORT_DEBUG
+#endif
+
+#ifdef  IOPORT_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/*
+ * The ioport configuration table.
+ */
+const mpc8xx_iop_conf_t iop_conf_tab[NUM_PORTS][PORT_BITS] = {
+    /*
+	 * Port A configuration
+	 * Pin		Signal				Type	Active		Initial state
+	 * PA7 		fpgaProgramLowOut	Out		Low			High
+	 */
+    {	/*	    conf ppar psor pdir podr pdat pint	   function 		*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /* No pin			*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /* No pin			*/
+	/* PA15 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA14 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA13 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA12 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA11 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA10 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA9  */ { 1,   0,   0,   1,   0,   0,   0 }, /* grn bicolor LED 1*/
+	/* PA8  */ { 1,   0,   0,   1,   0,   0,   0 }, /* red bicolor LED 1*/
+	/* PA7  */ { 1,   0,   0,   1,   0,   1,   0 }, /* fpgaProgramLow	*/
+	/* PA6  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA5  */ { 1,   0,   0,   1,   0,   0,   0 }, /* grn bicolor LED 0*/
+	/* PA4  */ { 1,   0,   0,   1,   0,   0,   0 }, /* red bicolor LED 0*/
+	/* PA3  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA2  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA1  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PA0  */ { 0,   0,   0,   0,   0,   0,   0 }  /*	*/
+    },
+
+	/*
+	 * Pin		Signal			Type		Active		Initial state
+	 * PB14		docBusyLowIn	In			Low			X
+	 * PB15		gpio1Sig		Out			High		Low
+	 * PB16		fpgaDoneBi		In			High		X
+	 * PB17		swBitOkLowOut	Out			Low			Low
+	 * PB19		speakerVolSig	Out/Hi-Z	High/Low	High (Hi-Z)
+	 * PB22		fpgaInitLowBi	In			Low			X
+	 * PB23		batteryOkSig	In			High		X
+     */
+    {	/*	    conf ppar psor pdir podr pdat pint 	  function			*/
+	/* PB31 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB30 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB29 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB28 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB27 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB26 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB25 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB24 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB23 */ { 1,   0,   0,   0,   0,   0,   0 }, /* batteryOk		*/
+	/* PB22 */ { 1,   0,   0,   0,   0,   0,   0 }, /* fpgaInitLowBi	*/
+	/* PB21 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB20 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB19 */ { 1,   0,   0,   1,   1,   1,   0 }, /* speakerVol		*/
+	/* PB18 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PB17 */ { 1,   0,   0,   1,   0,   0,   0 }, /* swBitOkLow		*/
+	/* PB16 */ { 1,   0,   0,   0,   0,   0,   0 }, /* fpgaDone			*/
+	/* PB15 */ { 1,   0,   0,   1,   0,   0,   0 }, /* gpio1			*/
+	/* PB14 */ { 1,   0,   0,   0,   0,   0,   0 }  /* docBusyLow		*/
+    },
+
+	/*
+	 * Pin		Signal				Type	Active		Initial state
+	 * PC4		i2cBus1EnSig		Out		High		High
+	 * PC5		i2cBus2EnSig		Out		High		High
+	 * PC6		gpio0Sig			Out		High		Low
+	 * PC8		i2cBus3EnSig		Out		High		High
+	 * PC10		i2cBus4EnSig		Out		High		High
+	 * PC11		fpgaResetLowOut		Out		Low			High
+	 * PC12		systemBitOkIn		In		High		X
+	 * PC15		selfDreqLow			In		Low			X
+	 */
+    {	/*	    conf ppar psor pdir podr pdat pint 	  function			*/
+	/* N/A	*/ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A	*/ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PC15 */ { 1,   0,   0,   0,   0,   0,   0 }, /* selfDreqLowIn	*/
+	/* PC14 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PC13 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PC12 */ { 1,   0,   0,   0,   0,   0,   0 }, /* systemBitOkIn	*/
+	/* PC11 */ { 1,   0,   0,   1,   0,   1,   0 }, /* fpgaResetLowOut	*/
+	/* PC10 */ { 1,   0,   0,   1,   0,   1,   0 }, /* i2cBus4EnSig		*/
+	/* PC9  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PC8  */ { 1,   0,   0,   1,   0,   1,   0 }, /* i2cBus3EnSig		*/
+	/* PC7  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PC6  */ { 1,   0,   0,   1,   0,   1,   0 }, /* gpio0			*/
+	/* PC5  */ { 1,   0,   0,   1,   0,   1,   0 }, /* i2cBus2EnSig		*/
+	/* PC4  */ { 1,   0,   0,   1,   0,   1,   0 }, /* i2cBus1EnSig		*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }  /*	*/
+    },
+
+    /* Port D configuration */
+    {	/*	    conf ppar psor pdir podr pdat pint 	   function			*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD15 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD14 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD13 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD12 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD11 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD10 */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD9  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD8  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD7  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD6  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD5  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD4  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* PD3  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }, /*	*/
+	/* N/A  */ { 0,   0,   0,   0,   0,   0,   0 }  /*	*/
+    }
+};
+
+/*
+ * Configure the MPC8XX I/O ports per the ioport configuration table
+ * (taken from ./cpu/mpc8260/cpu_init.c)
+ */
+void
+config_mpc8xx_ioports(volatile immap_t *immr)
+{
+    int portnum;
+
+    for (portnum = 0; portnum < NUM_PORTS; portnum++) {
+		uint pmsk = 0, ppar = 0, psor = 0, pdir = 0;
+		uint podr = 0, pdat = 0, pint = 0;
+		uint msk = 1;
+		mpc8xx_iop_conf_t *iopc = (mpc8xx_iop_conf_t *)&iop_conf_tab[portnum][0];
+		mpc8xx_iop_conf_t *eiopc = iopc + PORT_BITS;
+
+		/*
+		 * For all ports except port B, ignore the two don't care entries
+		 * in the configuration tables.
+		 */
+		if (portnum != 1) {
+			iopc = (mpc8xx_iop_conf_t *)&iop_conf_tab[portnum][2];
+		}
+
+		/*
+		 * NOTE: index 0 refers to pin 17, index 17 refers to pin 0
+		 */
+		while (iopc < eiopc) {
+	    	if (iopc->conf) {
+				pmsk |= msk;
+				if (iopc->ppar) ppar |= msk;
+				if (iopc->psor) psor |= msk;
+				if (iopc->pdir) pdir |= msk;
+				if (iopc->podr) podr |= msk;
+				if (iopc->pdat) pdat |= msk;
+				if (iopc->pint) pint |= msk;
+		    }
+		    msk <<= 1;
+	  	  iopc++;
+		}
+
+		PRINTF("%s:%d:\n  portnum=%d ", __FUNCTION__, __LINE__, portnum);
+#ifdef IOPORT_DEBUG
+		switch(portnum) {
+			case 0: printf("(A)\n"); break;
+			case 1: printf("(B)\n"); break;
+			case 2: printf("(C)\n"); break;
+			case 3: printf("(D)\n"); break;
+			default: printf("(?)\n"); break;
+		}
+#endif
+		PRINTF("  ppar=0x%.8x  pdir=0x%.8x  podr=0x%.8x\n"
+			   "  pdat=0x%.8x  psor=0x%.8x  pint=0x%.8x  pmsk=0x%.8x\n",
+			   ppar, pdir, podr, pdat, psor, pint, pmsk);
+
+		/*
+		 * Have to handle the ioports on a port-by-port basis since there
+		 * are three different flavors.
+		 */
+		if (pmsk != 0) {
+		    uint tpmsk = ~pmsk;
+
+			if (0 == portnum) { /* port A */
+		    	immr->im_ioport.iop_papar &= tpmsk;
+		    	immr->im_ioport.iop_padat =
+					(immr->im_ioport.iop_padat & tpmsk) | pdat;
+		    	immr->im_ioport.iop_padir =
+					(immr->im_ioport.iop_padir & tpmsk) | pdir;
+		    	immr->im_ioport.iop_paodr =
+					(immr->im_ioport.iop_paodr & tpmsk) | podr;
+		    	immr->im_ioport.iop_papar |= ppar;
+			}
+			else if (1 == portnum) { /* port B */
+		    	immr->im_cpm.cp_pbpar &= tpmsk;
+		    	immr->im_cpm.cp_pbdat = (immr->im_cpm.cp_pbdat & tpmsk) | pdat;
+		    	immr->im_cpm.cp_pbdir = (immr->im_cpm.cp_pbdir & tpmsk) | pdir;
+		    	immr->im_cpm.cp_pbodr = (immr->im_cpm.cp_pbodr & tpmsk) | podr;
+		    	immr->im_cpm.cp_pbpar |= ppar;
+			}
+			else if (2 == portnum) { /* port C */
+		    	immr->im_ioport.iop_pcpar &= tpmsk;
+		    	immr->im_ioport.iop_pcdat =
+					(immr->im_ioport.iop_pcdat & tpmsk) | pdat;
+		    	immr->im_ioport.iop_pcdir =
+					(immr->im_ioport.iop_pcdir & tpmsk) | pdir;
+		    	immr->im_ioport.iop_pcint =
+					(immr->im_ioport.iop_pcint & tpmsk) | pint;
+		    	immr->im_ioport.iop_pcso =
+					(immr->im_ioport.iop_pcso & tpmsk) | psor;
+		    	immr->im_ioport.iop_pcpar |= ppar;
+			}
+			else if (3 == portnum) { /* port D */
+		    	immr->im_ioport.iop_pdpar &= tpmsk;
+		    	immr->im_ioport.iop_pddat =
+					(immr->im_ioport.iop_pddat & tpmsk) | pdat;
+		    	immr->im_ioport.iop_pddir =
+					(immr->im_ioport.iop_pddir & tpmsk) | pdir;
+		    	immr->im_ioport.iop_pdpar |= ppar;
+			}
+		}
+    }
+
+	PRINTF("%s:%d: Port A:\n  papar=0x%.4x  padir=0x%.4x"
+		   "  paodr=0x%.4x\n  padat=0x%.4x\n", __FUNCTION__, __LINE__,
+		   immr->im_ioport.iop_papar, immr->im_ioport.iop_padir,
+		   immr->im_ioport.iop_paodr, immr->im_ioport.iop_padat);
+	PRINTF("%s:%d: Port B:\n  pbpar=0x%.8x  pbdir=0x%.8x"
+		   "  pbodr=0x%.8x\n  pbdat=0x%.8x\n", __FUNCTION__, __LINE__,
+		   immr->im_cpm.cp_pbpar, immr->im_cpm.cp_pbdir,
+		   immr->im_cpm.cp_pbodr, immr->im_cpm.cp_pbdat);
+	PRINTF("%s:%d: Port C:\n  pcpar=0x%.4x  pcdir=0x%.4x"
+		   "  pcdat=0x%.4x\n  pcso=0x%.4x  pcint=0x%.4x\n  ",
+		   __FUNCTION__, __LINE__, immr->im_ioport.iop_pcpar,
+		   immr->im_ioport.iop_pcdir, immr->im_ioport.iop_pcdat,
+		   immr->im_ioport.iop_pcso, immr->im_ioport.iop_pcint);
+	PRINTF("%s:%d: Port D:\n  pdpar=0x%.4x  pddir=0x%.4x"
+		   "  pddat=0x%.4x\n", __FUNCTION__, __LINE__,
+		   immr->im_ioport.iop_pdpar, immr->im_ioport.iop_pddir,
+		   immr->im_ioport.iop_pddat);
+}
+
+/* vim: set ts=4 sw=4 tw=78: */

+ 135 - 0
board/gen860t/u-boot.lds

@@ -0,0 +1,135 @@
+/*
+ * Linker command file for the GEN860T board.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+SECTIONS
+{
+  /*
+   * Read-only sections, merged into text segment:
+   */
+  . = + SIZEOF_HEADERS;
+  .interp        : { *(.interp)		}
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)	}
+  .rela.text     : { *(.rela.text) 	}
+  .rel.data      : { *(.rel.data)	}
+  .rela.data     : { *(.rela.data) 	}
+  .rel.rodata    : { *(.rel.rodata) 	}
+  .rela.rodata   : { *(.rela.rodata) 	}
+  .rel.got       : { *(.rel.got)	}
+  .rela.got      : { *(.rela.got)	}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)	}
+  .rela.bss      : { *(.rela.bss)	}
+  .rel.plt       : { *(.rel.plt)	}
+  .rela.plt      : { *(.rela.plt)	}
+  .init          : { *(.init)		}
+  .plt           : { *(.plt)		}
+  .text :
+  {
+    cpu/mpc8xx/start.o		(.text)
+    common/dlmalloc.o		(.text)
+    lib_ppc/ppcstring.o		(.text)
+    lib_generic/vsprintf.o	(.text)
+    lib_generic/crc32.o		(.text)
+    lib_generic/zlib.o		(.text)
+
+/*    . = env_offset;
+    common/environment.o(.text) */
+
+    *(.text)
+    *(.fixup)
+    *(.got1)
+  }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /*
+   * Read-write section, merged into data segment:
+   */
+  . = (. + 0x00FF) & 0xFFFFFF00;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2;
+  __fixup_entries = (. - _FIXUP_TABLE_)>>2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(256);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(256);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+
+  _end = . ;
+  PROVIDE (end = .);
+}
+

+ 365 - 0
board/impa7/flash.c

@@ -0,0 +1,365 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#define FLASH_BANK_SIZE 0x800000
+#define MAIN_SECT_SIZE  0x20000
+#define PARAM_SECT_SIZE 0x4000
+
+flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+
+ulong flash_init(void)
+{
+    int i, j;
+    ulong size = 0;
+
+    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
+    {
+	ulong flashbase = 0;
+	flash_info[i].flash_id =
+	  (INTEL_MANUFACT & FLASH_VENDMASK) |
+	  (INTEL_ID_28F320B3T & FLASH_TYPEMASK);
+	flash_info[i].size = FLASH_BANK_SIZE;
+	flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
+	memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
+	if (i == 0)
+	  flashbase = PHYS_FLASH_1;
+	else if (i == 1)
+	  flashbase = PHYS_FLASH_2;
+	else
+	  panic("configured to many flash banks!\n");
+	for (j = 0; j < flash_info[i].sector_count; j++)
+	{
+	    if (j <= 7)
+	    {
+		flash_info[i].start[j] = flashbase + j * PARAM_SECT_SIZE;
+	    }
+	    else
+	    {
+		flash_info[i].start[j] = flashbase + (j - 7)*MAIN_SECT_SIZE;
+	    }
+	}
+	size += flash_info[i].size;
+    }
+
+    /* Protect monitor and environment sectors
+     */
+    flash_protect(FLAG_PROTECT_SET,
+		  CFG_FLASH_BASE,
+		  CFG_FLASH_BASE + _armboot_end_data - _armboot_start,
+		  &flash_info[0]);
+
+    flash_protect(FLAG_PROTECT_SET,
+		  CFG_ENV_ADDR,
+		  CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+		  &flash_info[0]);
+
+    return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i;
+
+    switch (info->flash_id & FLASH_VENDMASK)
+    {
+    case (INTEL_MANUFACT & FLASH_VENDMASK):
+	printf("Intel: ");
+	break;
+    default:
+	printf("Unknown Vendor ");
+	break;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK)
+    {
+    case (INTEL_ID_28F320B3T & FLASH_TYPEMASK):
+	printf("28F320F3B (16Mbit)\n");
+	break;
+    default:
+	printf("Unknown Chip Type\n");
+	goto Done;
+	break;
+    }
+
+    printf("  Size: %ld MB in %d Sectors\n",
+	   info->size >> 20, 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");
+
+Done:
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int	flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    int flag, prot, sect;
+    int rc = ERR_OK;
+
+    if (info->flash_id == FLASH_UNKNOWN)
+	return ERR_UNKNOWN_FLASH_TYPE;
+
+    if ((s_first < 0) || (s_first > s_last)) {
+	return ERR_INVAL;
+    }
+
+    if ((info->flash_id & FLASH_VENDMASK) !=
+	(INTEL_MANUFACT & FLASH_VENDMASK)) {
+	return ERR_UNKNOWN_FLASH_VENDOR;
+    }
+
+    prot = 0;
+    for (sect=s_first; sect<=s_last; ++sect) {
+	if (info->protect[sect]) {
+	    prot++;
+	}
+    }
+    if (prot)
+	return ERR_PROTECTED;
+
+    /*
+     * Disable interrupts which might cause a timeout
+     * here. Remember that our exception vectors are
+     * at address 0 in the flash, and we don't want a
+     * (ticker) exception to happen while the flash
+     * chip is in programming mode.
+     */
+    flag = disable_interrupts();
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect<=s_last && !ctrlc(); sect++) {
+
+	printf("Erasing sector %2d ... ", sect);
+
+	/* arm simple, non interrupt dependent timer */
+	reset_timer_masked();
+
+	if (info->protect[sect] == 0) {	/* not protected */
+	    vu_long *addr = (vu_long *)(info->start[sect]);
+
+	    *addr = 0x00200020;	/* erase setup */
+	    *addr = 0x00D000D0;	/* erase confirm */
+
+	    while ((*addr & 0x00800080) != 0x00800080) {
+		if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) {
+		    *addr = 0x00B000B0; /* suspend erase */
+		    *addr = 0x00FF00FF;	/* reset to read mode */
+		    rc = ERR_TIMOUT;
+		    goto outahere;
+		}
+	    }
+
+	    *addr = 0x00FF00FF;	/* reset to read mode */
+	}
+	printf("ok.\n");
+    }
+    if (ctrlc())
+      printf("User Interrupt!\n");
+
+outahere:
+
+    /* allow flash to settle - wait 10 ms */
+    udelay_masked(10000);
+
+    if (flag)
+      enable_interrupts();
+
+    return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash
+ */
+
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+    vu_long *addr = (vu_long *)dest;
+    ulong barf;
+    int rc = ERR_OK;
+    int flag;
+
+    /* Check if Flash is (sufficiently) erased
+     */
+    if ((*addr & data) != data)
+        return ERR_NOT_ERASED;
+
+    /*
+     * Disable interrupts which might cause a timeout
+     * here. Remember that our exception vectors are
+     * at address 0 in the flash, and we don't want a
+     * (ticker) exception to happen while the flash
+     * chip is in programming mode.
+     */
+    flag = disable_interrupts();
+
+    /* clear status register command */
+    *addr = 0x00500050;
+
+    /* program set-up command */
+    *addr = 0x00400040;
+
+    /* latch address/data */
+    *addr = data;
+
+    /* arm simple, non interrupt dependent timer */
+    reset_timer_masked();
+
+    /* read status register command */
+    *addr = 0x00700070;
+
+    /* wait while polling the status register */
+    while((*addr & 0x00800080) != 0x00800080)
+    {
+	if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) {
+	    rc = ERR_TIMOUT;
+	    /* suspend program command */
+	    *addr = 0x00B000B0;
+	    goto outahere;
+	}
+
+	if( *addr & 0x003A003A) {	/* check for error */
+	    barf = *addr;
+	    if( barf & 0x003A0000) {
+		barf >>=16;
+	    } else {
+		barf &= 0x0000003A;
+	    }
+	    printf("\nFlash write error %02lx at address %08lx\n",
+		   barf, (unsigned long)dest);
+	    if(barf & 0x0002) {
+		printf("Block locked, not erased.\n");
+		rc = ERR_NOT_ERASED;
+		goto outahere;
+	    }
+	    if(barf & 0x0010) {
+		printf("Programming error.\n");
+		rc = ERR_PROG_ERROR;
+		goto outahere;
+	    }
+	    if(barf & 0x0008) {
+		printf("Vpp Low error.\n");
+		rc = ERR_PROG_ERROR;
+		goto outahere;
+	    }
+	    rc = ERR_PROG_ERROR;
+	    goto outahere;
+	}
+    }
+
+
+outahere:
+    /* read array command */
+    *addr = 0x00FF00FF;
+
+    if (flag)
+      enable_interrupts();
+
+    return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong cp, wp, data;
+    int l;
+    int i, 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 << 24);
+	}
+	for (; i<4 && cnt>0; ++i) {
+	    data = (data >> 8) | (*src++ << 24);
+	    --cnt;
+	    ++cp;
+	}
+	for (; cnt==0 && i<4; ++i, ++cp) {
+	    data = (data >> 8) | (*(uchar *)cp << 24);
+	}
+
+	if ((rc = write_word(info, wp, data)) != 0) {
+	    return (rc);
+	}
+	wp += 4;
+    }
+
+    /*
+     * handle word aligned part
+     */
+    while (cnt >= 4) {
+	data = *((vu_long*)src);
+	if ((rc = write_word(info, wp, data)) != 0) {
+	    return (rc);
+	}
+	src += 4;
+	wp  += 4;
+	cnt -= 4;
+    }
+
+    if (cnt == 0) {
+	return ERR_OK;
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    data = 0;
+    for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+	data = (data >> 8) | (*src++ << 24);
+	--cnt;
+    }
+    for (; i<4; ++i, ++cp) {
+	data = (data >> 8) | (*(uchar *)cp << 24);
+    }
+
+    return write_word(info, wp, data);
+}

+ 53 - 0
board/impa7/u-boot.lds

@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+        . = 0x00000000;
+
+        . = ALIGN(4);
+	.text      :
+	{
+	  cpu/arm720t/start.o	(.text)
+	  *(.text)
+	}
+
+        . = ALIGN(4);
+        .rodata : { *(.rodata) }
+
+        . = ALIGN(4);
+        .data : { *(.data) }
+
+        . = ALIGN(4);
+        .got : { *(.got) }
+
+	armboot_end_data = .;
+
+        . = ALIGN(4);
+        .bss : { *(.bss) }
+
+	armboot_end = .;
+}

+ 53 - 0
board/lart/u-boot.lds

@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+        . = 0x00000000;
+
+        . = ALIGN(4);
+	.text      :
+	{
+	  cpu/sa1100/start.o	(.text)
+	  *(.text)
+	}
+
+        . = ALIGN(4);
+        .rodata : { *(.rodata) }
+
+        . = ALIGN(4);
+        .data : { *(.data) }
+
+        . = ALIGN(4);
+        .got : { *(.got) }
+
+	armboot_end_data = .;
+
+        . = ALIGN(4);
+        .bss : { *(.bss) }
+
+	armboot_end = .;
+}

+ 379 - 0
board/mbx8xx/mbx8xx.c

@@ -0,0 +1,379 @@
+/*
+ * (C) Copyright 2000
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Board specific routines for the MBX
+ *
+ * - initialisation
+ * - interface to VPD data (mac address, clock speeds)
+ * - memory controller
+ * - serial io initialisation
+ * - ethernet io initialisation
+ *
+ * -----------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <mpc8xx.h>
+#include "dimm.h"
+#include "vpd.h"
+#include "csr.h"
+
+/* ------------------------------------------------------------------------- */
+
+static const uint sdram_table_40[] = {
+	/* DRAM - single read. (offset 0 in upm RAM)
+	 */
+	0xCFAFC004, 0x0FAFC404, 0x0CAF0C04, 0x30AF0C00,
+	0xF1BF4805, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* DRAM - burst read. (offset 8 in upm RAM)
+	 */
+	0xCFAFC004, 0x0FAFC404, 0x0CAF0C04, 0x03AF0C08,
+	0x0CAF0C04, 0x03AF0C08, 0x0CAF0C04, 0x03AF0C08,
+	0x0CAF0C04, 0x30AF0C00, 0xF3BF4805, 0xFFFFC005,
+	0xFFFFC005, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* DRAM - single write. (offset 18 in upm RAM)
+	 */
+	0xCFFF0004, 0x0FFF0404, 0x0CFF0C00, 0x33FF4804,
+	0xFFFFC005, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* DRAM - burst write. (offset 20 in upm RAM)
+	 */
+	0xCFFF0004, 0x0FFF0404, 0x0CFF0C00, 0x03FF0C0C,
+	0x0CFF0C00, 0x03FF0C0C, 0x0CFF0C00, 0x03FF0C0C,
+	0x0CFF0C00, 0x33FF4804, 0xFFFFC005, 0xFFFFC005,
+	0xFFFFC005, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* refresh  (offset 30 in upm RAM)
+	 */
+	0xFCFFC004, 0xC0FFC004, 0x01FFC004, 0x0FFFC004,
+	0x3FFFC004, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+	0xFFFFC005, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* exception. (offset 3c in upm RAM)
+	 */
+	0xFFFFC007, 0xFFFFC007, 0xFFFFC007, 0xFFFFC007,
+};
+
+static const uint sdram_table_50[] = {
+	/* DRAM - single read. (offset 0 in upm RAM)
+	 */
+	0xCFAFC004, 0x0FAFC404, 0x0CAF8C04, 0x10AF0C04,
+	0xF0AF0C00, 0xF3BF4805, 0xFFFFC005, 0xFFFFC005,
+
+	/* DRAM - burst read. (offset 8 in upm RAM)
+	 */
+	0xCFAFC004, 0X0FAFC404, 0X0CAF8C04, 0X00AF0C04,
+  /*	0X07AF0C08, 0X0CAF0C04, 0X01AF0C04, 0X0FAF0C04,	*/
+	0X07AF0C08, 0X0CAF0C04, 0X01AF0C04, 0X0FAF0C08,
+	0X0CAF0C04, 0X01AF0C04, 0X0FAF0C08, 0X0CAF0C04,
+  /*	0X10AF0C04, 0XF0AFC000, 0XF3FF4805, 0XFFFFC005,	*/
+	0X10AF0C04, 0XF0AFC000, 0XF3BF4805, 0XFFFFC005,
+
+	/* DRAM - single write. (offset 18 in upm RAM)
+	 */
+	0xCFFF0004, 0x0FFF0404, 0x0CFF0C00, 0x13FF4804,
+	0xFFFFC004, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* DRAM - burst write. (offset 20 in upm RAM)
+	 */
+	0xCFFF0004, 0x0FFF0404, 0x0CFF0C00, 0x03FF0C0C,
+	0x0CFF0C00, 0x03FF0C0C, 0x0CFF0C00, 0x03FF0C0C,
+	0x0CFF0C00, 0x13FF4804, 0xFFFFC004, 0xFFFFC005,
+	0xFFFFC005, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* refresh  (offset 30 in upm RAM)
+	 */
+	0xFCFFC004, 0xC0FFC004, 0x01FFC004, 0x0FFFC004,
+	0x1FFFC004, 0xFFFFC004, 0xFFFFC005, 0xFFFFC005,
+	0xFFFFC005, 0xFFFFC005, 0xFFFFC005, 0xFFFFC005,
+
+	/* exception. (offset 3c in upm RAM)
+	 */
+	0xFFFFC007, 0xFFFFC007, 0xFFFFC007, 0xFFFFC007,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static unsigned int get_reffreq(void);
+static unsigned int board_get_cpufreq(void);
+
+void mbx_init (void)
+{
+	volatile immap_t *immr = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immr->im_memctl;
+	ulong speed, refclock, plprcr, sccr;
+	ulong br0_32 = memctl->memc_br0 & 0x400;
+
+	/* real-time clock status and control register */
+	immr->im_sitk.sitk_rtcsck = KAPWR_KEY;
+	immr->im_sit.sit_rtcsc = 0x00C3;
+
+	/* SIEL and SIMASK Registers (see MBX PRG 2-3) */
+	immr->im_siu_conf.sc_simask = 0x00000000;
+	immr->im_siu_conf.sc_siel = 0xAAAA0000;
+	immr->im_siu_conf.sc_tesr = 0xFFFFFFFF;
+
+	/*
+	 * Prepare access to i2c bus. The MBX offers 3 devices on the i2c bus:
+	 * 1. Vital Product Data (contains clock speeds, MAC address etc, see vpd.h)
+	 * 2. RAM  Specs (see dimm.h)
+	 * 2. DIMM Specs (see dimm.h)
+	 */
+	vpd_init ();
+
+	/* system clock and reset control register */
+	immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+	sccr = immr->im_clkrst.car_sccr;
+	sccr &= SCCR_MASK;
+	sccr |= CFG_SCCR;
+	immr->im_clkrst.car_sccr = sccr;
+
+	speed = board_get_cpufreq ();
+	refclock = get_reffreq ();
+
+#if ((CFG_PLPRCR & PLPRCR_MF_MSK) != 0)
+	plprcr = CFG_PLPRCR;
+#else
+	plprcr = immr->im_clkrst.car_plprcr;
+	plprcr &= PLPRCR_MF_MSK;	/* isolate MF field */
+	plprcr |= CFG_PLPRCR;		/* reset control bits   */
+#endif
+
+#ifdef CFG_USE_OSCCLK			/* See doc/README.MBX ! */
+	plprcr |= ((speed + refclock / 2) / refclock - 1) << 20;
+#endif
+
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+	immr->im_clkrst.car_plprcr = plprcr;
+
+	/*
+	 * preliminary setup of memory controller:
+	 * - map Flash, otherwise configuration/status
+	 *    registers won't be accessible when read
+	 *    by board_init_f.
+	 * - map NVRAM and configuation/status registers.
+	 * - map pci registers.
+	 * - DON'T map ram yet, this is done in initdram().
+	 */
+	switch (speed / 1000000) {
+	case 40:
+		memctl->memc_br0 = 0xFE000000 | br0_32 | 1;
+		memctl->memc_or0 = 0xFF800930;
+		memctl->memc_or4 = CFG_NVRAM_OR | 0x920;
+		memctl->memc_br4 = CFG_NVRAM_BASE | 0x401;
+		break;
+	case 50:
+		memctl->memc_br0 = 0xFE000000 | br0_32 | 1;
+		memctl->memc_or0 = 0xFF800940;
+		memctl->memc_or4 = CFG_NVRAM_OR | 0x930;
+		memctl->memc_br4 = CFG_NVRAM_BASE | 0x401;
+		break;
+	default:
+		hang ();
+		break;
+	}
+#ifdef CONFIG_USE_PCI
+	memctl->memc_or5 = CFG_PCIMEM_OR;
+	memctl->memc_br5 = CFG_PCIMEM_BASE | 0x001;
+	memctl->memc_or6 = CFG_PCIBRIDGE_OR;
+	memctl->memc_br6 = CFG_PCIBRIDGE_BASE | 0x001;
+#endif
+	/*
+	 * FIXME: I do not understand why I have to call this to
+	 * initialise the control register here before booting from
+	 * the PCMCIA card but if I do not the Linux kernel falls
+	 * over in a big heap. If you can answer this question I
+	 * would like to know about it.
+	 */
+	board_ether_init();
+}
+
+void board_serial_init (void)
+{
+	MBX_CSR1 &= ~(CSR1_COM1EN | CSR1_XCVRDIS);
+}
+
+void board_ether_init (void)
+{
+	MBX_CSR1 &= ~(CSR1_EAEN | CSR1_ELEN);
+	MBX_CSR1 |= CSR1_ETEN | CSR1_TPEN | CSR1_FDDIS;
+}
+
+static unsigned int board_get_cpufreq (void)
+{
+#ifndef CONFIG_8xx_GCLK_FREQ
+	vpd_packet_t *packet;
+
+	packet = vpd_find_packet (VPD_PID_ICS);
+	return *((ulong *) packet->data);
+#else
+	return((unsigned int)CONFIG_8xx_GCLK_FREQ );
+#endif /* CONFIG_8xx_GCLK_FREQ */
+}
+
+static unsigned int get_reffreq (void)
+{
+	vpd_packet_t *packet;
+
+	packet = vpd_find_packet (VPD_PID_RCS);
+	return *((ulong *) packet->data);
+}
+
+void board_get_enetaddr (uchar * addr)
+{
+	int i;
+	vpd_packet_t *packet;
+
+	packet = vpd_find_packet (VPD_PID_EA);
+	for (i = 0; i < 6; i++)
+		addr[i] = packet->data[i];
+}
+
+/*
+ * Check Board Identity:
+ */
+
+int checkboard (void)
+{
+	vpd_packet_t *packet;
+	int i;
+	const char *const fmt =
+		"\n	 *** Warning: Low Battery Status - %s Battery ***";
+
+	puts ("Board: ");
+
+	packet = vpd_find_packet (VPD_PID_PID);
+	for (i = 0; i < packet->size; i++) {
+		serial_putc (packet->data[i]);
+	}
+	packet = vpd_find_packet (VPD_PID_MT);
+	for (i = 0; i < packet->size; i++) {
+		serial_putc (packet->data[i]);
+	}
+	serial_putc ('(');
+	packet = vpd_find_packet (VPD_PID_FAN);
+	for (i = 0; i < packet->size; i++) {
+		serial_putc (packet->data[i]);
+	}
+	serial_putc (')');
+
+	if (!(MBX_CSR2 & SR2_BATGD))
+		printf (fmt, "On-Board");
+	if (!(MBX_CSR2 & SR2_NVBATGD))
+		printf (fmt, "NVRAM");
+
+	serial_putc ('\n');
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static ulong get_ramsize (dimm_t * dimm)
+{
+	ulong size = 0;
+
+	if (dimm->fmt == 1 || dimm->fmt == 2 || dimm->fmt == 3
+		|| dimm->fmt == 4) {
+		size = (1 << (dimm->n_row + dimm->n_col)) * dimm->n_banks *
+			((dimm->data_w_hi << 8 | dimm->data_w_lo) / 8);
+	}
+
+	return size;
+}
+
+long int initdram (int board_type)
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	unsigned long ram_sz = 0;
+	unsigned long dimm_sz = 0;
+	dimm_t vpd_dimm, vpd_dram;
+	unsigned int speed = board_get_cpufreq () / 1000000;
+
+	if (vpd_read (0xa2, (uchar *) & vpd_dimm, sizeof (vpd_dimm), 0) > 0) {
+		dimm_sz = get_ramsize (&vpd_dimm);
+	}
+	if (vpd_read (0xa6, (uchar *) & vpd_dram, sizeof (vpd_dram), 0) > 0) {
+		ram_sz = get_ramsize (&vpd_dram);
+	}
+
+	/*
+	 * Only initialize memory controller when running from FLASH.
+	 * When running from RAM, don't touch it.
+	 */
+	if ((ulong) initdram & 0xff000000) {
+		ulong dimm_bank;
+		ulong br0_32 = memctl->memc_br0 & 0x400;
+
+		switch (speed) {
+		case 40:
+			upmconfig (UPMA, (uint *) sdram_table_40,
+					   sizeof (sdram_table_40) / sizeof (uint));
+			memctl->memc_mptpr = 0x0200;
+			memctl->memc_mamr = dimm_sz ? 0x06801000 : 0x13801000;
+			memctl->memc_or7 = 0xff800930;
+			memctl->memc_br7 = 0xfc000000 | (br0_32 ^ br0_32) | 1;
+			break;
+		case 50:
+			upmconfig (UPMA, (uint *) sdram_table_50,
+					   sizeof (sdram_table_50) / sizeof (uint));
+			memctl->memc_mptpr = 0x0200;
+			memctl->memc_mamr = dimm_sz ? 0x08801000 : 0x1880100;
+			memctl->memc_or7 = 0xff800940;
+			memctl->memc_br7 = 0xfc000000 | (br0_32 ^ br0_32) | 1;
+			break;
+		default:
+			hang ();
+			break;
+		}
+
+		/* now map ram and dimm, largest one first */
+		dimm_bank = dimm_sz / 2;
+		if (!dimm_sz) {
+			memctl->memc_or1 = ~(ram_sz - 1) | 0x400;
+			memctl->memc_br1 = CFG_SDRAM_BASE | 0x81;
+			memctl->memc_br2 = 0;
+			memctl->memc_br3 = 0;
+		} else if (ram_sz > dimm_bank) {
+			memctl->memc_or1 = ~(ram_sz - 1) | 0x400;
+			memctl->memc_br1 = CFG_SDRAM_BASE | 0x81;
+			memctl->memc_or2 = ~(dimm_bank - 1) | 0x400;
+			memctl->memc_br2 = (CFG_SDRAM_BASE + ram_sz) | 0x81;
+			memctl->memc_or3 = ~(dimm_bank - 1) | 0x400;
+			memctl->memc_br3 = (CFG_SDRAM_BASE + ram_sz + dimm_bank) \
+								     | 0x81;
+		} else {
+			memctl->memc_or2 = ~(dimm_bank - 1) | 0x400;
+			memctl->memc_br2 = CFG_SDRAM_BASE | 0x81;
+			memctl->memc_or3 = ~(dimm_bank - 1) | 0x400;
+			memctl->memc_br3 = (CFG_SDRAM_BASE + dimm_bank) | 0x81;
+			memctl->memc_or1 = ~(ram_sz - 1) | 0x400;
+			memctl->memc_br1 = (CFG_SDRAM_BASE + dimm_sz) | 0x81;
+		}
+	}
+
+	return ram_sz + dimm_sz;
+}

+ 131 - 0
board/ml2/serial.c

@@ -0,0 +1,131 @@
+/*
+ * (C) Copyright 2002
+ * Peter De Schrijver (p2@mind.be), Mind Linux Solutions, NV.
+ *
+ * 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 <asm/u-boot.h>
+#include <asm/processor.h>
+#include <common.h>
+#include <command.h>
+#include <configs/ML2.h>
+
+#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2)
+#include <ns16550.h>
+#endif
+
+#if 0
+#include "serial.h"
+#endif
+
+#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2)
+const NS16550_t COM_PORTS[] = { (NS16550_t) CFG_NS16550_COM1,
+		                (NS16550_t) CFG_NS16550_COM2 };
+#endif
+
+int
+serial_init (void)
+{
+		DECLARE_GLOBAL_DATA_PTR;
+
+	    int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate;
+
+#ifdef CFG_INIT_CHAN1
+	    (void)NS16550_init(COM_PORTS[0], clock_divisor);
+#endif
+#ifdef CFG_INIT_CHAN2
+	    (void)NS16550_init(COM_PORTS[1], clock_divisor);
+#endif
+		return 0;
+
+}
+
+void
+serial_putc(const char c)
+{
+    if (c == '\n')
+        NS16550_putc(COM_PORTS[CFG_DUART_CHAN], '\r');
+
+    NS16550_putc(COM_PORTS[CFG_DUART_CHAN], c);
+}
+
+int
+serial_getc(void)
+{
+    return NS16550_getc(COM_PORTS[CFG_DUART_CHAN]);
+}
+
+int
+serial_tstc(void)
+{
+    return NS16550_tstc(COM_PORTS[CFG_DUART_CHAN]);
+}
+
+void
+serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+    int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate;
+
+#ifdef CFG_INIT_CHAN1
+    NS16550_reinit(COM_PORTS[0], clock_divisor);
+#endif
+#ifdef CFG_INIT_CHAN2
+    NS16550_reinit(COM_PORTS[1], clock_divisor);
+#endif
+}
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+void
+kgdb_serial_init(void)
+{
+}
+
+void
+putDebugChar (int c)
+{
+	serial_putc (c);
+}
+
+void
+putDebugStr (const char *str)
+{
+	serial_puts (str);
+}
+
+int
+getDebugChar (void)
+{
+	return serial_getc();
+}
+
+void
+kgdb_interruptible (int yes)
+{
+	return;
+}
+#endif	/* CFG_CMD_KGDB	*/

+ 283 - 0
board/mousse/pci.c

@@ -0,0 +1,283 @@
+/*
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001
+ * James Dougherty (jfd@cs.stanford.edu)
+ *
+ * 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 Configuration space access support for MPC824x/MPC107 PCI Bridge
+ */
+#include <common.h>
+#include <mpc824x.h>
+#include <pci.h>
+
+#include "mousse.h"
+
+/*
+ * Promise ATA/66 support.
+ */
+#define XFER_PIO_4	0x0C	/* 0000|1100 */
+#define XFER_PIO_3	0x0B	/* 0000|1011 */
+#define XFER_PIO_2	0x0A	/* 0000|1010 */
+#define XFER_PIO_1	0x09	/* 0000|1001 */
+#define XFER_PIO_0	0x08	/* 0000|1000 */
+#define XFER_PIO_SLOW	0x00	/* 0000|0000 */
+
+/* Promise Regs */
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+void
+pdc202xx_decode_registers (unsigned char registers, unsigned char value)
+{
+	unsigned char	bit = 0, bit1 = 0, bit2 = 0;
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printf("  A Register ");
+			if (value & 0x80) printf("SYNC_IN ");
+			if (value & 0x40) printf("ERRDY_EN ");
+			if (value & 0x20) printf("IORDY_EN ");
+			if (value & 0x10) printf("PREFETCH_EN ");
+			if (value & 0x08) { printf("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printf("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printf("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printf("PA0 ");bit2 |= 0x01; }
+			printf("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printf("  B Register ");
+			if (value & 0x80) { printf("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printf("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printf("MB0 ");bit1 |= 0x20; }
+			printf("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printf("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printf("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printf("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printf("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printf("PB0 ");bit2 |= 0x01; }
+			printf("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printf("  C Register ");
+			if (value & 0x80) printf("DMARQp ");
+			if (value & 0x40) printf("IORDYp ");
+			if (value & 0x20) printf("DMAR_EN ");
+			if (value & 0x10) printf("DMAW_EN ");
+
+			if (value & 0x08) { printf("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printf("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printf("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printf("MC0 ");bit2 |= 0x01; }
+			printf("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printf("  D Register ");
+			break;
+		default:
+			return;
+	}
+	printf("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printf("%s", (value & bit) ? "1" : "0");
+	printf("\n");
+}
+
+/*
+ * Promise ATA/66 Support: configure Promise ATA66 card in specified mode.
+ */
+int
+pdc202xx_tune_chipset (pci_dev_t dev, int drive, unsigned char speed)
+{
+	unsigned short		drive_conf;
+	int			err = 0;
+	unsigned char			drive_pci, AP, BP, CP, DP;
+	unsigned char			TA = 0, TB = 0;
+
+	switch (drive) {
+		case 0: drive_pci = 0x60; break;
+		case 1: drive_pci = 0x64; break;
+		case 2: drive_pci = 0x68; break;
+		case 3: drive_pci = 0x6c; break;
+		default: return -1;
+	}
+
+	pci_read_config_word(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if ((AP & 0x0F) || (BP & 0x07)) {
+	  /* clear PIO modes of lower 8421 bits of A Register */
+	  pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
+	  pci_read_config_byte(dev, (drive_pci), &AP);
+
+	  /* clear PIO modes of lower 421 bits of B Register */
+	  pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
+	  pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+	  pci_read_config_byte(dev, (drive_pci), &AP);
+	  pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	pci_write_config_byte(dev, (drive_pci), AP|TA);
+	pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+
+#ifdef PDC202XX_DEBUG
+	pdc202xx_decode_registers(REG_A, AP);
+	pdc202xx_decode_registers(REG_B, BP);
+	pdc202xx_decode_registers(REG_C, CP);
+	pdc202xx_decode_registers(REG_D, DP);
+#endif
+	return err;
+}
+/*
+ * Show/Init PCI devices on the specified bus number.
+ */
+
+void pci_mousse_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+	unsigned int line;
+
+	switch(PCI_DEV(dev)) {
+	case 0x0d:
+		line = 0x00000101;
+		break;
+
+	case 0x0e:
+	default:
+		line = 0x00000303;
+		break;
+	}
+
+	pci_write_config_dword(dev, PCI_INTERRUPT_LINE, line);
+}
+
+void pci_mousse_setup_pdc202xx(struct pci_controller *hose, pci_dev_t dev,
+			       struct pci_config_table *_)
+{
+	unsigned short vendorId;
+	unsigned int mbar0, cmd;
+	int bar, a;
+
+	pci_read_config_word(dev, PCI_VENDOR_ID, &vendorId);
+
+	if(vendorId == PCI_VENDOR_ID_PROMISE || vendorId == PCI_VENDOR_ID_CMD){
+		/* PDC 202xx card is handled differently, it is a bootable
+		 * device and needs all 5 MBAR's configured
+		 */
+		for(bar = 0; bar < 5; bar++){
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+bar*4, &mbar0);
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+bar*4, ~0);
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+bar*4, &mbar0);
+#ifdef DEBUG
+			printf("  ATA_bar[%d] = %dbytes\n", bar,
+			       ~(mbar0 & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+#endif
+		}
+
+		/* Program all BAR's */
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, PROMISE_MBAR0);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, PROMISE_MBAR1);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_2,	PROMISE_MBAR2);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_3,	PROMISE_MBAR3);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_4,	PROMISE_MBAR4);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_5,	PROMISE_MBAR5);
+
+		for(bar = 0; bar < 5; bar++){
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+bar*4, &mbar0);
+#ifdef DEBUG
+			printf("  ATA_bar[%d]@0x%x\n", bar, mbar0);
+#endif
+		}
+
+		/* Enable ROM Expansion base */
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, PROMISE_MBAR5|1);
+
+		/* Io enable, Memory enable, master enable */
+		pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+		cmd &= ~0xffff0000;
+		cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+		pci_write_config_dword(dev, PCI_COMMAND, cmd);
+
+		/* Breath some life into the controller */
+		for( a = 0; a < 4; a++)
+			pdc202xx_tune_chipset(dev, a, XFER_PIO_0);
+	}
+}
+
+static struct pci_config_table pci_sandpoint_config_table[] = {
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0x00, 0x0e, 0x00,
+	  pci_mousse_setup_pdc202xx },
+#ifndef CONFIG_PCI_PNP
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0x00, 0x0d, 0x00,
+	  pci_cfgfunc_config_device, {PCI_ENET_IOADDR,
+				      PCI_ENET_MEMADDR,
+				      PCI_COMMAND_MEMORY |
+				      PCI_COMMAND_MASTER}},
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  pci_cfgfunc_config_device, {PCI_SLOT_IOADDR,
+				      PCI_SLOT_MEMADDR,
+				      PCI_COMMAND_MEMORY |
+				      PCI_COMMAND_MASTER}},
+#endif
+	{ }
+};
+
+struct pci_controller hose = {
+	config_table: pci_sandpoint_config_table,
+	fixup_irq: pci_mousse_fixup_irq,
+};
+
+void pci_init(void)
+{
+	pci_mpc824x_init(&hose);
+}

+ 606 - 0
board/mpl/common/common_util.c

@@ -0,0 +1,606 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <video_fb.h>
+#include "common_util.h"
+#include <asm/processor.h>
+#include <i2c.h>
+#include <devices.h>
+#include <pci.h>
+
+extern int  gunzip (void *, int, unsigned char *, int *);
+extern int mem_test(unsigned long start, unsigned long ramsize, int quiet);
+
+#define I2C_BACKUP_ADDR 0x7C00 /* 0x200 bytes for backup */
+#define IMAGE_SIZE 0x80000
+
+extern flash_info_t flash_info[];	/* info for FLASH chips */
+
+image_header_t header;
+
+
+
+int mpl_prg(unsigned long src,unsigned long size)
+{
+	unsigned long start;
+	flash_info_t *info;
+	int i,rc;
+	unsigned long *magic = (unsigned long *)src;
+
+	info = &flash_info[0];
+  	start = 0 - size;
+	for(i=info->sector_count-1;i>0;i--)
+	{
+		info->protect[i] = 0; /* unprotect this sector */
+		if(start>=info->start[i])
+		break;
+	}
+	/* set-up flash location */
+	/* now erase flash */
+	if(magic[0]!=IH_MAGIC) {
+		printf("Bad Magic number\n");
+		return -1;
+	}
+	printf("Erasing at %lx (sector %d) (start %lx)\n",
+				start,i,info->start[i]);
+	flash_erase (info, i, info->sector_count-1);
+	printf("flash erased, programming from 0x%lx 0x%lx Bytes\n",src,size);
+	if ((rc = flash_write ((uchar *)src, start, size)) != 0) {
+		puts ("ERROR ");
+		flash_perror (rc);
+		return (1);
+	}
+	puts ("OK programming done\n");
+	return 0;
+}
+
+
+int mpl_prg_image(unsigned long ld_addr)
+{
+	unsigned long data,len,checksum;
+	image_header_t *hdr=&header;
+	/* Copy header so we can blank CRC field for re-calculation */
+	memcpy (&header, (char *)ld_addr, sizeof(image_header_t));
+	if (hdr->ih_magic  != IH_MAGIC) {
+		printf ("Bad Magic Number\n");
+		return 1;
+	}
+	print_image_hdr(hdr);
+	if (hdr->ih_os  != IH_OS_U_BOOT) {
+		printf ("No U-Boot Image\n");
+		return 1;
+	}
+	if (hdr->ih_type  != IH_TYPE_FIRMWARE) {
+		printf ("No Firmware Image\n");
+		return 1;
+	}
+	data = (ulong)&header;
+	len  = sizeof(image_header_t);
+	checksum = hdr->ih_hcrc;
+	hdr->ih_hcrc = 0;
+	if (crc32 (0, (char *)data, len) != checksum) {
+		printf ("Bad Header Checksum\n");
+		return 1;
+	}
+	data = ld_addr + sizeof(image_header_t);
+	len  = hdr->ih_size;
+	printf ("Verifying Checksum ... ");
+	if (crc32 (0, (char *)data, len) != hdr->ih_dcrc) {
+		printf ("Bad Data CRC\n");
+		return 1;
+	}
+	switch (hdr->ih_comp) {
+	case IH_COMP_NONE:
+		break;
+	case IH_COMP_GZIP:
+		printf ("  Uncompressing  ... ");
+		if (gunzip ((void *)(data+0x100000), 0x400000,
+			    (uchar *)data, (int *)&len) != 0) {
+			printf ("GUNZIP ERROR\n");
+			return 1;
+		}
+		data+=0x100000;
+		break;
+	default:
+		printf ("   Unimplemented compression type %d\n", hdr->ih_comp);
+		return 1;
+	}
+
+	printf ("  OK\n");
+	return(mpl_prg(data,len));
+}
+
+
+void get_backup_values(backup_t *buf)
+{
+	i2c_read(CFG_DEF_EEPROM_ADDR, I2C_BACKUP_ADDR,2,(void *)buf,sizeof(backup_t));
+}
+
+void set_backup_values(int overwrite)
+{
+	backup_t back;
+	int i;
+
+	get_backup_values(&back);
+	if(!overwrite) {
+		if(strncmp(back.signature,"MPL\0",4)==0) {
+			printf("Not possible to write Backup\n");
+			return;
+		}
+	}
+	memcpy(back.signature,"MPL\0",4);
+	i=getenv_r("serial#",back.serial_name,16);
+	if(i==0) {
+		printf("Not possible to write Backup\n");
+		return;
+	}
+	back.serial_name[16]=0;
+	i=getenv_r("ethaddr",back.eth_addr,20);
+	if(i==0) {
+		printf("Not possible to write Backup\n");
+		return;
+	}
+	back.eth_addr[20]=0;
+	i2c_write(CFG_DEF_EEPROM_ADDR, I2C_BACKUP_ADDR,2,(void *)&back,sizeof(backup_t));
+}
+
+void clear_env_values(void)
+{
+	backup_t back;
+	unsigned char env_crc[4];
+
+	memset(&back,0xff,sizeof(backup_t));
+	memset(env_crc,0x00,4);
+	i2c_write(CFG_DEF_EEPROM_ADDR,I2C_BACKUP_ADDR,2,(void *)&back,sizeof(backup_t));
+	i2c_write(CFG_DEF_EEPROM_ADDR,CFG_ENV_OFFSET,2,(void *)env_crc,4);
+}
+
+/*
+ * check crc of "older" environment
+ */
+int check_env_old_size(ulong oldsize)
+{
+	ulong crc, len, new;
+	unsigned off;
+	uchar buf[64];
+
+	/* read old CRC */
+	eeprom_read (CFG_DEF_EEPROM_ADDR,
+		     CFG_ENV_OFFSET,
+		     (uchar *)&crc, sizeof(ulong));
+
+	new = 0;
+	len = oldsize;
+	off = sizeof(long);
+	len = oldsize-off;
+	while (len > 0) {
+		int n = (len > sizeof(buf)) ? sizeof(buf) : len;
+
+		eeprom_read (CFG_DEF_EEPROM_ADDR, CFG_ENV_OFFSET+off, buf, n);
+		new = crc32 (new, buf, n);
+		len -= n;
+		off += n;
+	}
+
+	return (crc == new);
+}
+
+static ulong oldsizes[] = {
+	0x200,
+	0x800,
+	0
+};
+
+void copy_old_env(ulong size)
+{
+	uchar name_buf[64];
+	uchar value_buf[0x800];
+	uchar c;
+	ulong len;
+	unsigned off;
+	uchar *name, *value;
+
+	name=&name_buf[0];
+	value=&value_buf[0];
+	len=size;
+	off = sizeof(long);
+	while (len > off) {
+		eeprom_read (CFG_DEF_EEPROM_ADDR, CFG_ENV_OFFSET+off, &c, 1);
+		if(c != '=') {
+			*name++=c;
+			off++;
+		}
+		else {
+			*name++='\0';
+			off++;
+			do {
+				eeprom_read (CFG_DEF_EEPROM_ADDR, CFG_ENV_OFFSET+off, &c, 1);
+				*value++=c;
+				off++;
+				if(c == '\0')
+					break;
+			} while(len > off);
+			name=&name_buf[0];
+			value=&value_buf[0];
+			if(strncmp(name,"baudrate",8)!=0) {
+				setenv(name,value);
+			}
+
+		}
+	}
+}
+
+
+void check_env(void)
+{
+	unsigned char *s;
+	int i=0;
+	char buf[32];
+	backup_t back;
+
+	s=getenv("serial#");
+	if(!s) {
+		while(oldsizes[i]) {
+			if(check_env_old_size(oldsizes[i]))
+				break;
+			i++;
+		}
+		if(!oldsizes[i]) {
+			/* no old environment has been found */
+			get_backup_values (&back);
+			if (strncmp (back.signature, "MPL\0", 4) == 0) {
+				sprintf (buf, "%s", back.serial_name);
+				setenv ("serial#", buf);
+				sprintf (buf, "%s", back.eth_addr);
+				setenv ("ethaddr", buf);
+				printf ("INFO:  serial# and ethaddr recovered, use saveenv\n");
+				return;
+			}
+		}
+		else {
+			copy_old_env(oldsizes[i]);
+			printf ("INFO:  old environment ajusted, use saveenv\n");
+		}
+	}
+	else {
+		/* check if back up is set */
+		get_backup_values(&back);
+		if(strncmp(back.signature,"MPL\0",4)!=0) {
+			set_backup_values(0);
+		}
+	}
+}
+
+
+
+extern device_t *stdio_devices[];
+extern char *stdio_names[];
+
+void show_stdio_dev(void)
+{
+	/* Print informations */
+	printf ("In:    ");
+	if (stdio_devices[stdin] == NULL) {
+		printf ("No input devices available!\n");
+	} else {
+		printf ("%s\n", stdio_devices[stdin]->name);
+	}
+
+	printf ("Out:   ");
+	if (stdio_devices[stdout] == NULL) {
+		printf ("No output devices available!\n");
+	} else {
+		printf ("%s\n", stdio_devices[stdout]->name);
+	}
+
+	printf ("Err:   ");
+	if (stdio_devices[stderr] == NULL) {
+		printf ("No error devices available!\n");
+	} else {
+		printf ("%s\n", stdio_devices[stderr]->name);
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+	/* switches the cs0 and the cs1 to the locations.
+	   When boot is TRUE, the the mapping is switched
+	   to the boot configuration, If it is FALSE, the
+	   flash will be switched in the boot area */
+
+#undef SW_CS_DBG
+#ifdef SW_CS_DBG
+#define	SW_CS_PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define SW_CS_PRINTF(fmt,args...)
+#endif
+
+
+int switch_cs(unsigned char boot)
+{
+  	unsigned long pbcr;
+	mtdcr(ebccfga, pb0cr); /* get cs0 config reg */
+	pbcr = mfdcr(ebccfgd);
+	if((pbcr&0x00002000)==0) {
+		/* we need only to switch if boot from MPS */
+		/*printf(" MPS boot mode detected. ");*/
+		/* printf("cs0 cfg: %lx\n",pbcr); */
+		if(boot) {
+			/* switch to boot configuration */
+			/* this is a 8bit boot, switch cs0 to flash location */
+			SW_CS_PRINTF("switch to boot mode (MPS on High address\n");
+			pbcr&=0x000FFFFF; /*mask base address of the cs0 */
+			pbcr|=(FLASH_BASE0_PRELIM & 0xFFF00000);
+			mtdcr(ebccfga, pb0cr);
+			mtdcr(ebccfgd, pbcr);
+			SW_CS_PRINTF("  new cs0 cfg: %lx\n",pbcr);
+			mtdcr(ebccfga, pb1cr); /* get cs1 config reg (flash) */
+			pbcr = mfdcr(ebccfgd);
+			SW_CS_PRINTF(" old cs1 cfg: %lx\n",pbcr);
+			pbcr&=0x000FFFFF; /*mask base address of the cs1 */
+			pbcr|=(MULTI_PURPOSE_SOCKET_ADDR & 0xFFF00000);
+			mtdcr(ebccfga, pb1cr);
+			mtdcr(ebccfgd, pbcr);
+			SW_CS_PRINTF("  new cs1 cfg: %lx, MPS is on High Address\n",pbcr);
+		}
+		else
+		{
+			/* map flash to boot area, */
+			SW_CS_PRINTF("map Flash to boot area\n");
+			pbcr&=0x000FFFFF; /*mask base address of the cs0 */
+			pbcr|=(MULTI_PURPOSE_SOCKET_ADDR & 0xFFF00000);
+			mtdcr(ebccfga, pb0cr);
+			mtdcr(ebccfgd, pbcr);
+			SW_CS_PRINTF("  new cs0 cfg: %lx\n",pbcr);
+			mtdcr(ebccfga, pb1cr); /* get cs1 config reg (flash) */
+			pbcr = mfdcr(ebccfgd);
+			SW_CS_PRINTF("  cs1 cfg: %lx\n",pbcr);
+			pbcr&=0x000FFFFF; /*mask base address of the cs1 */
+			pbcr|=(FLASH_BASE0_PRELIM & 0xFFF00000);
+			mtdcr(ebccfga, pb1cr);
+			mtdcr(ebccfgd, pbcr);
+			SW_CS_PRINTF("  new cs1 cfg: %lx Flash is on High Address\n",pbcr);
+		}
+		return 1;
+	}
+	else {
+		SW_CS_PRINTF("Normal boot, no switching necessary\n");
+		return 0;
+	}
+}
+
+
+int do_mplcommon(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ 	ulong size,src,ld_addr;
+	int result;
+	backup_t back;
+	char sw;
+	src = MULTI_PURPOSE_SOCKET_ADDR;
+	size = IMAGE_SIZE;
+
+	if (strcmp(argv[1], "flash") == 0)
+	{
+		sw = switch_cs(0); /* Switch flash to normal location */
+#if (CONFIG_COMMANDS & CFG_CMD_FDC)
+		if (strcmp(argv[2], "floppy") == 0) {
+ 			char *local_args[3];
+			extern int do_fdcboot (cmd_tbl_t *, int, int, char *[]);
+			printf ("\nupdating bootloader image from floppy\n");
+			local_args[0] = argv[0];
+	    		if(argc==4) {
+				local_args[1] = argv[3];
+				local_args[2] = NULL;
+				ld_addr=simple_strtoul(argv[3], NULL, 16);
+				result=do_fdcboot(cmdtp, 0, 2, local_args);
+			}
+			else {
+				local_args[1] = NULL;
+				ld_addr=CFG_LOAD_ADDR;
+				result=do_fdcboot(cmdtp, 0, 1, local_args);
+			}
+			result=mpl_prg_image(ld_addr);
+			switch_cs(sw); /* Switch flash back */
+			return result;
+		}
+#endif /* (CONFIG_COMMANDS & CFG_CMD_FDC) */
+		if (strcmp(argv[2], "mem") == 0) {
+	    		if(argc==4) {
+				ld_addr=simple_strtoul(argv[3], NULL, 16);
+			}
+			else {
+				ld_addr=load_addr;
+			}
+			printf ("\nupdating bootloader image from memory at %lX\n",ld_addr);
+			result=mpl_prg_image(ld_addr);
+			switch_cs(sw); /* Switch flash back */
+			return result;
+		}
+		if (strcmp(argv[2], "mps") == 0) {
+			printf ("\nupdating bootloader image from MSP\n");
+			result=mpl_prg(src,size);
+			switch_cs(sw); /* Switch flash back */
+			return result;
+		}
+		switch_cs(sw); /* Switch flash back */
+
+	}
+	if (strcmp(argv[1], "mem") == 0)
+	{
+		result=0;
+		if(argc==3)
+		{
+			result = (int)simple_strtol(argv[2], NULL, 16);
+	    }
+	    src=(unsigned long)&result;
+	    src-=CFG_MEMTEST_START;
+	    src-=(100*1024); /* - 100k */
+	    src&=0xfff00000;
+	    size=0;
+	    do {
+	    	size++;
+			printf("\n\nPass %ld\n",size);
+			mem_test(CFG_MEMTEST_START,src,1);
+			if(ctrlc())
+				break;
+			if(result>0)
+				result--;
+
+		}while(result);
+		return 0;
+	}
+	if (strcmp(argv[1], "clearenvvalues") == 0)
+	{
+ 		if (strcmp(argv[2], "yes") == 0)
+		{
+			clear_env_values();
+			return 0;
+		}
+	}
+	if (strcmp(argv[1], "getback") == 0) {
+		get_backup_values(&back);
+		back.signature[3]=0;
+		back.serial_name[16]=0;
+		back.eth_addr[20]=0;
+		printf("GetBackUp: signature: %s\n",back.signature);
+		printf("           serial#:   %s\n",back.serial_name);
+		printf("           ethaddr:   %s\n",back.eth_addr);
+		return 0;
+	}
+	if (strcmp(argv[1], "setback") == 0) {
+		set_backup_values(1);
+		return 0;
+	}
+	printf("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+}
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+extern void doc_probe(ulong physadr);
+void doc_init (void)
+{
+  doc_probe(MULTI_PURPOSE_SOCKET_ADDR);
+}
+#endif
+
+
+#ifdef CONFIG_VIDEO
+/******************************************************
+ * Routines to display the Board information
+ * to the screen (since the VGA will be initialized as last,
+ * we must resend the infos)
+ */
+
+#ifdef CONFIG_CONSOLE_EXTRA_INFO
+extern GraphicDevice ctfb;
+
+void video_get_info_str (int line_number, char *info)
+{
+	/* init video info strings for graphic console */
+	DECLARE_GLOBAL_DATA_PTR;
+	PPC405_SYS_INFO sys_info;
+	char rev;
+	int i;
+	unsigned long pvr;
+	char buf[64];
+	char tmp[16];
+	unsigned char *s, *e, bc, sw;
+	switch (line_number)
+	{
+	case 2:
+		/* CPU and board infos */
+		pvr=get_pvr();
+		get_sys_info (&sys_info);
+		switch (pvr) {
+			case PVR_405GP_RB: rev='B'; break;
+			case PVR_405GP_RC: rev='C'; break;
+			case PVR_405GP_RD: rev='D'; break;
+			case PVR_405GP_RE: rev='E'; break;
+			default:           rev='?'; break;
+		}
+		/* Board info */
+		i=0;
+		s=getenv ("serial#");
+#ifdef CONFIG_PIP405
+		if (!s || strncmp (s, "PIP405", 6)) {
+			sprintf(buf,"### No HW ID - assuming PIP405");
+		}
+#endif
+#ifdef CONFIG_MIP405
+		if (!s || strncmp (s, "MIP405", 6)) {
+			sprintf(buf,"### No HW ID - assuming MIP405");
+		}
+#endif
+		else {
+			for (e = s; *e; ++e) {
+				if (*e == ' ')
+					break;
+			}
+			for (; s < e; ++s) {
+				if (*s == '_') {
+					++s;
+					break;
+				}
+				buf[i++]=*s;
+			}
+			sprintf(&buf[i]," SN ");
+			i+=4;
+			for (; s < e; ++s) {
+				buf[i++]=*s;
+			}
+			buf[i++]=0;
+		}
+		sprintf (info," %s PPC405GP %c %s MHz (%lu/%lu/%lu MHz)",
+			buf,rev,
+			strmhz (tmp, gd->cpu_clk), sys_info.freqPLB / 1000000,
+			sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,
+			sys_info.freqPLB / sys_info.pllExtBusDiv / 1000000);
+		return;
+	case 3:
+		/* Memory Info */
+		sw = switch_cs (0);
+		switch_cs (sw);
+		bc = in8 (CONFIG_PORT_ADDR);
+		sprintf(info, " %luMB RAM, %luMB Flash Cfg 0x%02X %s %s",
+			gd->bd->bi_memsize / 0x100000,
+			gd->bd->bi_flashsize / 0x100000,
+			bc,
+			sw ? "MPS boot" : "Flash boot",
+			ctfb.modeIdent);
+		return;
+	case 1:
+		sprintf	(buf, "%s",CONFIG_IDENT_STRING);
+		sprintf (info, " %s", &buf[1]);
+		return;
+    }
+    /* no more info lines */
+    *info = 0;
+    return;
+}
+#endif /* CONFIG_CONSOLE_EXTRA_INFO */
+
+#endif /* CONFIG_VIDEO */

+ 102 - 0
board/mpl/common/pci.c

@@ -0,0 +1,102 @@
+/*-----------------------------------------------------------------------------+
+|
+|       This source code has been made available to you by IBM on an AS-IS
+|       basis.  Anyone receiving this source is licensed under IBM
+|       copyrights to use it in any way he or she deems fit, including
+|       copying it, modifying it, compiling it, and redistributing it either
+|       with or without modifications.  No license under IBM patents or
+|       patent applications is to be implied by the copyright license.
+|
+|       Any user of this software should understand that IBM cannot provide
+|       technical support for this software and will not be responsible for
+|       any consequences resulting from the use of this software.
+|
+|       Any person who transfers this source code or any derivative work
+|       must include the IBM copyright notice, this paragraph, and the
+|       preceding two paragraphs in the transferred software.
+|
+|       COPYRIGHT   I B M   CORPORATION 1995
+|       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
++-----------------------------------------------------------------------------*/
+/*
+ * Adapted for PIP405 03.07.01
+ * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
+ *
+ * TODO: Clean-up
+ */
+
+#include <common.h>
+#include <pci.h>
+#include "isa.h"
+
+#ifdef CONFIG_405GP
+#ifdef CONFIG_PCI
+
+#undef DEBUG
+
+#include "piix4_pci.h"
+#include "pci_parts.h"
+
+void pci_pip405_write_regs(struct pci_controller *hose, pci_dev_t dev,
+			   struct pci_config_table *entry)
+{
+	struct pci_pip405_config_entry *table;
+	int i;
+
+	table = (struct pci_pip405_config_entry*) entry->priv[0];
+
+	for (i=0; table[i].width; i++)
+	{
+#ifdef DEBUG
+		printf("Reg 0x%02X Value 0x%08lX Width %02d written\n",
+		       table[i].index, table[i].val, table[i].width);
+#endif
+
+		switch(table[i].width)
+		{
+		case 1: pci_hose_write_config_byte(hose, dev, table[i].index, table[i].val); break;
+		case 2: pci_hose_write_config_word(hose, dev, table[i].index, table[i].val); break;
+		case 4: pci_hose_write_config_dword(hose, dev, table[i].index, table[i].val); break;
+		}
+	}
+}
+
+
+static void pci_pip405_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+	unsigned char int_line = 0xff;
+	/*
+	 * Write pci interrupt line register
+	 */
+	if(PCI_DEV(dev)==0) /* Device0 = PPC405 -> skip */
+		return;
+	if(PCI_FUNC(dev)==0)
+	{
+		/* assuming all function 0 are using their INTA# Pin*/
+		int_line=PCI_IRQ_VECTOR(dev);
+		pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line);
+#ifdef DEBUG
+		printf("Fixup IRQ: dev %d (%x) int line %d 0x%x\n",
+		       PCI_DEV(dev),dev,int_line,int_line);
+#endif
+	}
+}
+
+extern void pci_405gp_init(struct pci_controller *hose);
+
+
+static struct pci_controller hose = {
+  config_table: pci_pip405_config_table,
+  fixup_irq: pci_pip405_fixup_irq,
+};
+
+void pci_init(void)
+{
+	/*we want the ptrs to RAM not flash (ie don't use init list)*/
+	hose.fixup_irq    = pci_pip405_fixup_irq;
+	hose.config_table = pci_pip405_config_table;
+	pci_405gp_init(&hose);
+}
+
+#endif /* CONFIG_PCI */
+#endif /* CONFIG_405GP */

+ 192 - 0
board/mpl/common/pci_parts.h

@@ -0,0 +1,192 @@
+ /*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
+ *
+ * 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_PARTS_H_
+#define _PCI_PARTS_H_
+
+
+/* Board specific file containing:
+ * - PCI Memory Mapping
+ * - PCI IO Mapping
+ * - PCI Interrupt Mapping
+ */
+
+/* PIP405 PCI INT Routing:
+ *                      IRQ0  VECTOR
+ * PIXX4 IDSEL  = AD16  INTA#  28 (Function 2 USB is INTD# = 31)
+ * VGA   IDSEL  = AD17  INTB#  29
+ * SCSI  IDSEL  = AD18  INTC#  30
+ * PC104 IDSEL0 = AD20  INTA#  28
+ * PC104 IDSEL1 = AD21  INTB#  29
+ * PC104 IDSEL2 = AD22  INTC#  30
+ * PC104 IDSEL3 = AD23  INTD#  31
+ *
+ * busdevfunc = EXXX XXXX BBBB BBBB DDDD DFFF RRRR RR00
+ *              ^         ^         ^     ^   ^
+ *             31        23        15    10   7
+ * E = Enabled
+ * B = Bussnumber
+ * D = Devicenumber (Device0 = AD10)
+ * F = Functionnumber
+ * R = Registernumber
+ *
+ * Device = (busdevfunc>>11) + 10
+ * Vector = devicenumber % 4 + 28
+ *
+ */
+#define PCI_HIGHEST_ON_BOARD_ID	19
+/*#define PCI_DEV_NUMBER(x)	(((x>>11) & 0x1f) + 10) */
+#define PCI_IRQ_VECTOR(x)	((PCI_DEV(x) + 10) % 4) + 28
+
+
+
+/* PCI Device List for PIP405 */
+
+/* Mapping:
+ * +-------------+------------+------------+--------------------------------+
+ * ¦ PCI MemAddr | PCI IOAddr | Local Addr | Device / Function              |
+ * +-------------+------------+------------+--------------------------------+
+ * |  0x00000000 |            | 0xA0000000 | ISA Memory (hard wired)        |
+ * |  0x00FFFFFF |            | 0xA0FFFFFF |                                |
+ * +-------------+------------+------------+--------------------------------+
+ * |             | 0x00000000 | 0xE8000000 | ISA IO (hard wired)            |
+ * |             | 0x0000FFFF | 0xE800FFFF |                                |
+ * +-------------+------------+------------+--------------------------------+
+ * |  0x80000000 |            | 0x80000000 | VGA Controller Memory          |
+ * |  0x80FFFFFF |            | 0x80FFFFFF |                                |
+ * +-------------+------------+------------+--------------------------------+
+ * |  0x81000000 |            | 0x81000000 | SCSI Controller Memory         |
+ * |  0x81FFFFFF |            | 0x81FFFFFF |                                |
+ * +-------------+------------+------------+--------------------------------+
+ */
+
+struct pci_pip405_config_entry {
+	int 		index; 	/* address */
+	unsigned long 	val;	/* value */
+	int 		width;	/* data size */
+};
+
+extern void pci_pip405_write_regs(struct pci_controller *,
+				  pci_dev_t,
+				  struct pci_config_table *);
+
+/* PIIX4 ISA Bridge Function 0 */
+static struct pci_pip405_config_entry piix4_isa_bridge_f0[] = {
+	{PCI_CFG_PIIX4_SERIRQ,	0xD0,		1}, /* enable Continous SERIRQ Pin */
+	{PCI_CFG_PIIX4_GENCFG,	0x00010041,	4}, /* enable SERIRQs, ISA, PNP	*/
+	{PCI_CFG_PIIX4_TOM,	0xFE,		1}, /* Top of Memory		*/
+	{PCI_CFG_PIIX4_XBCS,	0x02C4,		2}, /* disable all peri CS	*/
+	{PCI_CFG_PIIX4_RTCCFG,	0x21,		1}, /* enable RTC	   	*/
+#if defined(CONFIG_PIP405)
+	{PCI_CFG_PIIX4_MBDMA,	0x82,		1}, /* set MBDMA0 to DMA 2   	*/
+	{PCI_CFG_PIIX4_MBDMA+1,	0x83,		1}, /* set MBDMA1 to DMA 3   	*/
+#endif
+	{PCI_CFG_PIIX4_DLC,	0x0,		1}, /* disable passive release feature */
+	{ }				    	    /* end of device table	*/
+};
+
+/* PIIX4 IDE Controller Function 1 */
+static struct pci_pip405_config_entry piix4_ide_cntrl_f1[] = {
+	{PCI_COMMAND,		0x0001,		2}, /* enable IO access 	*/
+	{PCI_CFG_PIIX4_IDETIM,	0x80008000,	4}, /* enable Both IDE channels	*/
+	{ }					    /* end of device table 	*/
+};
+
+/* PIIX4 USB Controller Function 2 */
+static struct pci_pip405_config_entry piix4_usb_cntrl_f2[] = {
+	{PCI_INTERRUPT_LINE,	31,		1}, /* Int vector = 31 		*/
+	{PCI_BASE_ADDRESS_4,	0x0000E001,	4}, /* Set IO Address to 0xe000 to 0xe01F */
+	{PCI_LATENCY_TIMER,	0x80,		1}, /* Latency Timer 0x80 	*/
+	{0xC0,			0x2000,		2}, /* Legacy support 		*/
+	{PCI_COMMAND,		0x0005,		2}, /* enable IO access and Master */
+	{ }					    /* end of device table 	*/
+};
+
+/* PIIX4 Power Management Function 3 */
+static struct pci_pip405_config_entry piix4_pmm_cntrl_f3[] = {
+	{PCI_COMMAND,		0x0001,		2}, /* enable IO access 	*/
+	{PCI_CFG_PIIX4_PMAB,	0x00004000,	4}, /* set PMBA to "valid" value */
+	{PCI_CFG_PIIX4_PMMISC,	0x01,		1}, /* enable PMBA IO access	*/
+	{PCI_CFG_PIIX4_SMBBA,	0x00005000,	4}, /* set SMBBA to "valid" value */
+	{ }					    /* end of device table 	*/
+};
+/* PPC405 Dummy only used to prevent autosetup on this host bridge */
+static struct pci_pip405_config_entry ibm405_dummy[] = {
+	{ }				    	    /* end of device table 	*/
+};
+
+void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev,
+			 struct pci_config_table *entry);
+
+
+static struct pci_config_table pci_pip405_config_table[]={
+	{PCI_VENDOR_ID_IBM, 			/* 405 dummy */
+	 PCI_DEVICE_ID_IBM_405GP,
+	 PCI_ANY_ID,
+	 PCI_ANY_ID, PCI_ANY_ID, 0,
+	 pci_pip405_write_regs, {(unsigned long) ibm405_dummy}},
+
+	{PCI_VENDOR_ID_INTEL, 			/* PIIX4 ISA Bridge Function 0 */
+	 PCI_DEVICE_ID_INTEL_82371AB_0,
+	 PCI_ANY_ID,
+	 PCI_ANY_ID, PCI_ANY_ID, 0,
+	 pci_pip405_write_regs, {(unsigned long) piix4_isa_bridge_f0}},
+
+	{PCI_VENDOR_ID_INTEL,			/* PIIX4 IDE Controller Function 1 */
+	 PCI_DEVICE_ID_INTEL_82371AB,
+	 PCI_ANY_ID,
+	 PCI_ANY_ID, PCI_ANY_ID, 1,
+	 pci_pip405_write_regs, {(unsigned long) piix4_ide_cntrl_f1}},
+
+	{PCI_VENDOR_ID_INTEL,			/* PIIX4 USB Controller Function 2 */
+	 PCI_DEVICE_ID_INTEL_82371AB_2,
+	 PCI_ANY_ID,
+	 PCI_ANY_ID, PCI_ANY_ID, 2,
+	 pci_pip405_write_regs, {(unsigned long) piix4_usb_cntrl_f2}},
+
+	{PCI_VENDOR_ID_INTEL,			/* PIIX4 USB Controller Function 3 */
+	 PCI_DEVICE_ID_INTEL_82371AB_3,
+	 PCI_ANY_ID,
+	 PCI_ANY_ID, PCI_ANY_ID, 3,
+	 pci_pip405_write_regs, {(unsigned long) piix4_pmm_cntrl_f3}},
+
+	{PCI_ANY_ID,
+	 PCI_ANY_ID,
+	 PCI_CLASS_DISPLAY_VGA,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	 pci_405gp_setup_vga},
+
+	{PCI_ANY_ID,
+	 PCI_ANY_ID,
+	 PCI_CLASS_NOT_DEFINED_VGA,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	 pci_405gp_setup_vga},
+
+	{ }
+};
+#endif /* _PCI_PARTS_H_ */
+
+
+
+
+

+ 49 - 0
board/mpl/mip405/Makefile

@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000, 2001
+# 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
+
+OBJS	= $(BOARD).o ../common/flash.o cmd_mip405.o ../common/pci.o \
+			../common/usb_uhci.o ../common/memtst.o ../common/common_util.o
+
+SOBJS	= init.o
+
+$(LIB):	$(OBJS) $(SOBJS)
+	$(AR) crv $@ $^
+
+clean:
+	rm -f $(SOBJS) $(OBJS)
+
+distclean:	clean
+	rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+.depend:	Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################

+ 52 - 0
board/mpl/pip405/Makefile

@@ -0,0 +1,52 @@
+#
+# (C) Copyright 2000, 2001
+# 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
+
+OBJS	= $(BOARD).o \
+	  ../common/flash.o cmd_pip405.o ../common/pci.o \
+	  ../common/isa.o ../common/kbd.o \
+	  ../common/usb_uhci.o \
+	  ../common/memtst.o ../common/common_util.o
+
+SOBJS	= init.o
+
+$(LIB):	$(OBJS) $(SOBJS)
+	$(AR) crv $@ $^
+
+clean:
+	rm -f $(SOBJS) $(OBJS)
+
+distclean:	clean
+	rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+.depend:	Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################

+ 130 - 0
board/musenki/musenki.c

@@ -0,0 +1,130 @@
+/*
+ * (C) Copyright 2001
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <pci.h>
+
+int checkboard (void)
+{
+	ulong busfreq  = get_bus_freq(0);
+	char  buf[32];
+
+	printf("Board: MUSENKI Local Bus at %s MHz\n", strmhz(buf, busfreq));
+	return 0;
+
+}
+
+#if 0 	/* NOT USED */
+int checkflash (void)
+{
+	/* TODO: XXX XXX XXX */
+	printf ("## Test not implemented yet ##\n");
+
+	return (0);
+}
+#endif
+
+long int initdram (int board_type)
+{
+	int              i, cnt;
+	volatile uchar * base= CFG_SDRAM_BASE;
+	volatile ulong * addr;
+	ulong            save[32];
+	ulong            val, ret  = 0;
+
+	for (i=0, cnt=(CFG_MAX_RAM_SIZE / sizeof(long)) >> 1; cnt > 0; cnt >>= 1) {
+		addr = (volatile ulong *)base + cnt;
+		save[i++] = *addr;
+		*addr = ~cnt;
+	}
+
+	addr = (volatile ulong *)base;
+	save[i] = *addr;
+	*addr = 0;
+
+	if (*addr != 0) {
+		*addr = save[i];
+		goto Done;
+	}
+
+	for (cnt = 1; cnt <= CFG_MAX_RAM_SIZE / sizeof(long); cnt <<= 1) {
+		addr = (volatile ulong *)base + cnt;
+		val = *addr;
+		*addr = save[--i];
+		if (val != ~cnt) {
+			ulong new_bank0_end = cnt * sizeof(long) - 1;
+			ulong mear1  = mpc824x_mpc107_getreg(MEAR1);
+			ulong emear1 = mpc824x_mpc107_getreg(EMEAR1);
+			mear1 =  (mear1  & 0xFFFFFF00) |
+			  ((new_bank0_end & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT);
+			emear1 = (emear1 & 0xFFFFFF00) |
+			  ((new_bank0_end & MICR_ADDR_MASK) >> MICR_EADDR_SHIFT);
+			mpc824x_mpc107_setreg(MEAR1,  mear1);
+			mpc824x_mpc107_setreg(EMEAR1, emear1);
+
+			ret = cnt * sizeof(long);
+			goto Done;
+		}
+	}
+
+	ret = CFG_MAX_RAM_SIZE;
+Done:
+	return ret;
+}
+
+/*
+ * Initialize PCI Devices
+ */
+#ifndef CONFIG_PCI_PNP
+static struct pci_config_table pci_sandpoint_config_table[] = {
+#if 0
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  0x0, 0x0, 0x0, /* unknown eth0 divice */
+	  pci_cfgfunc_config_device, { PCI_ENET0_IOADDR,
+				       PCI_ENET0_MEMADDR,
+				       PCI_COMMAND_IO |
+				       PCI_COMMAND_MEMORY |
+				       PCI_COMMAND_MASTER }},
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  0x0, 0x0, 0x0, /* unknown eth1 device */
+	  pci_cfgfunc_config_device, { PCI_ENET1_IOADDR,
+				       PCI_ENET1_MEMADDR,
+				       PCI_COMMAND_IO |
+				       PCI_COMMAND_MEMORY |
+				       PCI_COMMAND_MASTER }},
+#endif
+	{ }
+};
+#endif
+
+struct pci_controller hose = {
+#ifndef CONFIG_PCI_PNP
+	config_table: pci_sandpoint_config_table,
+#endif
+};
+
+void pci_init(void)
+{
+	pci_mpc824x_init(&hose);
+}

+ 40 - 0
board/mvs1/Makefile

@@ -0,0 +1,40 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= lib$(BOARD).a
+
+OBJS	= $(BOARD).o flash.o
+
+$(LIB):	.depend $(OBJS)
+	$(AR) crv $@ $^
+
+#########################################################################
+
+.depend:	Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################

+ 40 - 0
board/netvia/Makefile

@@ -0,0 +1,40 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= lib$(BOARD).a
+
+OBJS	= $(BOARD).o flash.o
+
+$(LIB):	.depend $(OBJS)
+	$(AR) crv $@ $^
+
+#########################################################################
+
+.depend:	Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################

+ 374 - 0
board/netvia/netvia.c

@@ -0,0 +1,374 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Pantelis Antoniou, Intracom S.A., panto@intracom.gr
+ * U-Boot port on NetVia board
+ */
+
+#include <common.h>
+#include "mpc8xx.h"
+
+/* some sane bit macros */
+#define _BD(_b)				(1U << (31-(_b)))
+#define _BDR(_l, _h)			(((((1U << (31-(_l))) - 1) << 1) | 1) & ~((1U << (31-(_h))) - 1))
+
+#define _BW(_b)				(1U << (15-(_b)))
+#define _BWR(_l, _h)			(((((1U << (15-(_l))) - 1) << 1) | 1) & ~((1U << (15-(_h))) - 1))
+
+#define _BB(_b)				(1U << (7-(_b)))
+#define _BBR(_l, _h)			(((((1U << (7-(_l))) - 1) << 1) | 1) & ~((1U << (7-(_h))) - 1))
+
+#define _B(_b)				_BD(_b)
+#define _BR(_l, _h)			_BDR(_l, _h)
+
+/* ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+
+#define _NOT_USED_	0xFFFFFFFF
+
+/* ------------------------------------------------------------------------- */
+
+#define CS_0000		0x00000000
+#define CS_0001		0x10000000
+#define CS_0010		0x20000000
+#define CS_0011		0x30000000
+#define CS_0100		0x40000000
+#define CS_0101		0x50000000
+#define CS_0110		0x60000000
+#define CS_0111		0x70000000
+#define CS_1000		0x80000000
+#define CS_1001		0x90000000
+#define CS_1010		0xA0000000
+#define CS_1011		0xB0000000
+#define CS_1100		0xC0000000
+#define CS_1101		0xD0000000
+#define CS_1110		0xE0000000
+#define CS_1111		0xF0000000
+
+#define BS_0000		0x00000000
+#define BS_0001		0x01000000
+#define BS_0010		0x02000000
+#define BS_0011		0x03000000
+#define BS_0100		0x04000000
+#define BS_0101		0x05000000
+#define BS_0110		0x06000000
+#define BS_0111		0x07000000
+#define BS_1000		0x08000000
+#define BS_1001		0x09000000
+#define BS_1010		0x0A000000
+#define BS_1011		0x0B000000
+#define BS_1100		0x0C000000
+#define BS_1101		0x0D000000
+#define BS_1110		0x0E000000
+#define BS_1111		0x0F000000
+
+#define A10_AAAA	0x00000000
+#define A10_AAA0	0x00200000
+#define A10_AAA1	0x00300000
+#define A10_000A	0x00800000
+#define A10_0000	0x00A00000
+#define A10_0001	0x00B00000
+#define A10_111A	0x00C00000
+#define A10_1110	0x00E00000
+#define A10_1111	0x00F00000
+
+#define RAS_0000	0x00000000
+#define RAS_0001	0x00040000
+#define RAS_1110	0x00080000
+#define RAS_1111	0x000C0000
+
+#define CAS_0000	0x00000000
+#define CAS_0001	0x00010000
+#define CAS_1110	0x00020000
+#define CAS_1111	0x00030000
+
+#define WE_0000		0x00000000
+#define WE_0001		0x00004000
+#define WE_1110		0x00008000
+#define WE_1111		0x0000C000
+
+#define GPL4_0000	0x00000000
+#define GPL4_0001	0x00001000
+#define GPL4_1110	0x00002000
+#define GPL4_1111	0x00003000
+
+#define GPL5_0000	0x00000000
+#define GPL5_0001	0x00000400
+#define GPL5_1110	0x00000800
+#define GPL5_1111	0x00000C00
+#define LOOP		0x00000080
+
+#define EXEN		0x00000040
+
+#define AMX_COL		0x00000000
+#define AMX_ROW		0x00000020
+#define AMX_MAR		0x00000030
+
+#define NA		0x00000008
+
+#define UTA		0x00000004
+
+#define TODT		0x00000002
+
+#define LAST		0x00000001
+
+const uint sdram_table[0x40] = {
+	/* RSS */
+	CS_0001 | BS_1111 | A10_AAAA | RAS_0001 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* ACT   */
+	CS_1111 | BS_1111 | A10_0000 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* NOP   */
+	CS_0000 | BS_1111 | A10_0001 | RAS_1111 | CAS_0001 | WE_1111 | AMX_COL | UTA,			/* READ  */
+	CS_0001 | BS_0001 | A10_1111 | RAS_0001 | CAS_1111 | WE_0001 | AMX_COL | UTA,			/* PALL  */
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,				/* NOP   */
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | UTA | TODT | LAST,	/* NOP   */
+	_NOT_USED_, _NOT_USED_,
+
+	/* RBS */
+	CS_0001 | BS_1111 | A10_AAAA | RAS_0001 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* ACT   */
+	CS_1111 | BS_1111 | A10_0000 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* NOP   */
+	CS_0001 | BS_1111 | A10_0001 | RAS_1111 | CAS_0001 | WE_1111 | AMX_COL | UTA,			/* READ  */
+	CS_1111 | BS_0000 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* NOP   */
+	CS_1111 | BS_0000 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,				/* NOP	 */
+	CS_1111 | BS_0000 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,				/* NOP	 */
+	CS_0001 | BS_0001 | A10_1111 | RAS_0001 | CAS_1111 | WE_0001 | AMX_COL,				/* PALL  */
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | TODT | LAST,		/* NOP	 */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+
+	/* WSS */
+	CS_0001 | BS_1111 | A10_AAAA | RAS_0001 | CAS_1111 | WE_1111 | AMX_COL | UTA,
+	CS_1111 | BS_1111 | A10_0000 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,
+	CS_0000 | BS_0001 | A10_0000 | RAS_1111 | CAS_0001 | WE_0000 | AMX_COL | UTA,
+	CS_0001 | BS_1111 | A10_1111 | RAS_0001 | CAS_1111 | WE_0001 | AMX_COL | UTA | TODT | LAST,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+
+	/* WBS */
+	CS_0001 | BS_1111 | A10_AAAA | RAS_0001 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* ACT   */
+	CS_1111 | BS_1111 | A10_0000 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,				/* NOP   */
+	CS_0001 | BS_0000 | A10_0000 | RAS_1111 | CAS_0001 | WE_0000 | AMX_COL,				/* WRITE */
+	CS_1111 | BS_0000 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,				/* NOP   */
+	CS_1111 | BS_0000 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,				/* NOP   */
+	CS_1111 | BS_0001 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* NOP   */
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | UTA,			/* NOP   */
+	CS_0001 | BS_1111 | A10_1111 | RAS_0001 | CAS_1111 | WE_0001 | AMX_COL | UTA,			/* PALL  */
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | UTA | TODT | LAST,	/* NOP   */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_,
+
+	/* UPT */
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,				/* NOP   */
+	CS_0001 | BS_1111 | A10_1111 | RAS_0001 | CAS_0001 | WE_1111 | AMX_COL | LOOP,
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL,
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | LOOP,
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | LAST,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_,
+
+	/* EXC */
+	CS_0001 | BS_1111 | A10_1111 | RAS_0001 | CAS_1111 | WE_0001 | AMX_COL,
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1111 | AMX_COL | TODT | LAST,
+
+	/* REG */
+	CS_1111 | BS_1111 | A10_1111 | RAS_1111 | CAS_1111 | WE_1110 | AMX_MAR,
+	CS_0001 | BS_1111 | A10_0001 | RAS_0001 | CAS_0001 | WE_0001 | AMX_MAR | TODT | LAST,
+};
+
+/* ------------------------------------------------------------------------- */
+
+
+/*
+ * Check Board Identity:
+ *
+ * Test ETX ID string (ETX_xxx...)
+ *
+ * Return 1 always.
+ */
+
+int checkboard(void)
+{
+	printf ("NETVIA\n");
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* 0xC8 = 0b11001000 , CAS3, >> 2 = 0b00 11 0 010 */
+#define MAR_SDRAM_INIT		0x000000C8LU
+
+#define MCR_OP(x)		((unsigned long)((x) & 3) << (31-1))
+#define MCR_OP_MASK		MCR_OP(3)
+
+#define MCR_UM(x)		((unsigned long)((x) & 1) << (31 - 8))
+#define MCR_UM_MASK		MCR_UM(1)
+#define MCR_UM_UPMA		MCR_UM(0)
+#define MCR_UM_UPMB		MCR_UM(1)
+
+#define MCR_MB(x)		((unsigned long)((x) & 7) << (31 - 18))
+#define MCR_MB_MASK		MCR_MB(7)
+#define MCR_MB_CS(x)		MCR_MB(x)
+
+#define MCR_MCLF(x)		((unsigned long)((x) & 15) << (31 - 23))
+#define MCR_MCLF_MASK		MCR_MCLF(15)
+
+long int initdram(int board_type)
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	long int size;
+
+	upmconfig(UPMA, (uint *) sdram_table, sizeof(sdram_table) / sizeof(uint));
+
+	/*
+	 * Preliminary prescaler for refresh
+	 */
+	memctl->memc_mptpr = CFG_MPTPR_1BK_8K;
+
+	memctl->memc_mar = MAR_SDRAM_INIT;	/* 32-bit address to be output on the address bus if AMX = 0b11 */
+
+    /*
+     * Map controller bank 3 to the SDRAM bank at preliminary address.
+     */
+	memctl->memc_or3 = CFG_OR3_PRELIM;
+	memctl->memc_br3 = CFG_BR3_PRELIM;
+
+	memctl->memc_mamr = CFG_MAMR_9COL & ~MAMR_PTAE;	/* no refresh yet */
+
+	udelay(200);
+
+	/* perform SDRAM initialisation sequence */
+	memctl->memc_mcr = MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS3 | MCR_MCLF(1) | MCR_MAD(0x3C);	/* precharge all			*/
+	udelay(1);
+	memctl->memc_mcr = MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS3 | MCR_MCLF(0) | MCR_MAD(0x30); /* refresh 16 times(0)		*/
+	udelay(1);
+	memctl->memc_mcr = MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS3 | MCR_MCLF(1) | MCR_MAD(0x3E);	/* exception program (write mar) */
+	udelay(1);
+
+	memctl->memc_mamr |= MAMR_PTAE;	/* enable refresh */
+
+	udelay(1000);
+
+	memctl->memc_mamr = CFG_MAMR_9COL;
+
+	size = SDRAM_MAX_SIZE;
+
+	udelay(10000);
+
+	/* do the ram test */
+	{
+		register unsigned long *rp;
+		register unsigned long v;
+
+		/* first fill */
+		for (rp = (unsigned long *)0; rp < (unsigned long *)SDRAM_MAX_SIZE; )
+		    *rp++ = (unsigned long)rp;
+
+		/* now check */
+		for (rp = (unsigned long *)0; rp < (unsigned long *)SDRAM_MAX_SIZE; rp++) {
+		    if ((v = *rp) != (unsigned long)rp) {
+			printf("ERROR at 0x%lx (0x%lx)\n", (unsigned long)rp, v);
+			return -1;
+		    }
+		}
+
+	}
+
+	return (size);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int misc_init_r(void)
+{
+	return(0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* bits that can have a special purpose or can be configured as inputs/outputs */
+#define PA_MASK		(_BWR(4, 9) | _BWR(12, 15))
+#define PA_ODR_MASK	(_BW(9) | _BW(12) | _BW(14))
+#define PA_ODR_VAL	0
+#define PA_GP_INMASK	0
+#define PA_GP_OUTMASK	(_BW(5) | _BW(14) | _BW(15))
+#define PA_SP_OUTMASK	0
+#define PA_GP_OUTVAL	_BW(5)
+#define PA_SP_OUTVAL	0
+
+#define PB_MASK		(_BR(16, 19) | _BR(22, 31))
+#define PB_ODR_MASK	PB_MASK
+#define PB_ODR_VAL	0
+#define PB_GP_INMASK	0
+#define PB_GP_OUTMASK	(_BR(16, 19) | _BR(26, 27) | _B(31))
+#define PB_SP_OUTMASK	_BR(28, 30)
+#define PB_SP_OUTVAL	_BR(28, 30)
+#define PB_GP_OUTVAL	(_BR(16, 19) | _BR(26, 27) | _B(31))
+
+#define PC_MASK		_BWR(4, 15)
+#define PC_SO_MASK	(_BWR(6, 11) | _BWR(14, 15))
+#define PC_SO_VAL	0
+#define PC_INT_MASK	PC_MASK
+#define PC_INT_VAL	0
+#define PC_GP_INMASK	(_BWR(5, 7) | _BWR(9, 10) | _BW(13))
+#define PC_GP_OUTMASK	_BW(12)
+#define PC_SP_OUTMASK	0
+#define PC_SP_OUTVAL	_BW(12)
+#define PC_GP_OUTVAL	0
+
+#define PD_MASK		_BWR(0, 15)
+#define PD_GP_INMASK	0
+#define PD_GP_OUTMASK	_BWR(3, 15)
+#define PD_SP_OUTMASK	0
+#define PD_GP_OUTVAL	(_BW(3) | _BW(5) | _BW(7) | _BWR(8, 15))
+#define PD_SP_OUTVAL	0
+
+int board_pre_init(void)
+{
+	register volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	register volatile iop8xx_t *ioport = &immap->im_ioport;
+	register volatile cpm8xx_t *cpm = &immap->im_cpm;
+
+	ioport->iop_padat = (ioport->iop_padat & ~PA_MASK)     | PA_SP_OUTVAL | PA_GP_OUTVAL;
+	ioport->iop_paodr = (ioport->iop_paodr & ~PA_ODR_MASK) | PA_ODR_VAL;
+	ioport->iop_padir = (ioport->iop_padir & ~PA_GP_INMASK)| PA_SP_OUTMASK | PA_GP_OUTMASK;
+	ioport->iop_papar = (ioport->iop_papar & ~(PA_GP_INMASK & PA_GP_OUTMASK));
+
+	cpm->cp_pbdat = (ioport->iop_padat & ~PB_MASK)     | PB_SP_OUTVAL | PB_GP_OUTVAL;
+	cpm->cp_pbodr = (ioport->iop_paodr & ~PB_ODR_MASK) | PB_ODR_VAL;
+	cpm->cp_pbdir = (ioport->iop_padir & ~PB_GP_INMASK)| PB_SP_OUTMASK | PB_GP_OUTMASK;
+	cpm->cp_pbpar = (ioport->iop_papar & ~(PB_GP_INMASK & PB_GP_OUTMASK));
+
+	ioport->iop_pcdat = (ioport->iop_pcdat & ~PC_MASK)     | PC_SP_OUTVAL | PC_GP_OUTVAL;
+	ioport->iop_pcdir = (ioport->iop_pcdir & ~PC_GP_INMASK)| PC_SP_OUTMASK | PC_GP_OUTMASK;
+	ioport->iop_pcso  = (ioport->iop_pcso  & ~PC_SO_MASK)  | PC_SO_VAL;
+	ioport->iop_pcint = (ioport->iop_pcint & ~PC_INT_MASK) | PC_INT_VAL;
+	ioport->iop_pcpar = (ioport->iop_pcpar & ~(PC_GP_INMASK & PC_GP_OUTMASK));
+
+	ioport->iop_pddat = (ioport->iop_pddat & ~PD_MASK)     | PD_SP_OUTVAL | PD_GP_OUTVAL;
+	ioport->iop_pddir = (ioport->iop_pddir & ~PD_GP_INMASK)| PD_SP_OUTMASK | PD_GP_OUTMASK;
+	ioport->iop_pdpar = (ioport->iop_pdpar & ~(PD_GP_INMASK & PD_GP_OUTMASK));
+
+	return 0;
+}
+

+ 132 - 0
board/netvia/u-boot.lds

@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* 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/mpc8xx/start.o		(.text)
+    cpu/mpc8xx/traps.o		(.text)
+    common/dlmalloc.o		(.text)
+    lib_ppc/ppcstring.o		(.text)
+    lib_generic/vsprintf.o	(.text)
+    lib_generic/crc32.o		(.text)
+    lib_generic/zlib.o		(.text)
+    lib_ppc/cache.o		(.text)
+    lib_ppc/time.o		(.text)
+
+    . = env_offset;
+    common/environment.o	(.ppcenv)
+
+    *(.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 = .);
+}

+ 131 - 0
board/netvia/u-boot.lds.debug

@@ -0,0 +1,131 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* 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      :
+  {
+    /* WARNING - the following is hand-optimized to fit within	*/
+    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
+
+    cpu/mpc8xx/start.o		(.text)
+    common/dlmalloc.o		(.text)
+    lib_generic/vsprintf.o	(.text)
+    lib_generic/crc32.o		(.text)
+
+    . = env_offset;
+    common/environment.o(.text)
+
+    *(.text)
+    *(.fixup)
+    *(.got1)
+  }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _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(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+

+ 372 - 0
board/oxc/flash.c

@@ -0,0 +1,372 @@
+/*
+ * (C) Copyright 2000
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for STM29W320DB/STM29W800D flash chips
+ *
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t	flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips	*/
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+static ulong flash_get_size (vu_char *addr, flash_info_t *info);
+static int write_byte (flash_info_t *info, ulong dest, uchar data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+    unsigned long size;
+    int i;
+
+    /* Init: no FLASHes known */
+    for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+	flash_info[i].flash_id = FLASH_UNKNOWN;
+    }
+
+    /*
+     * We use the following trick here: since flash is cyclically
+     * mapped in the 0xFF800000-0xFFFFFFFF area, we detect the type
+     * and the size of flash using 0xFF800000 as the base address,
+     * and then call flash_get_size() again to fill flash_info.
+     */
+    size = flash_get_size((vu_char *)CFG_FLASH_PRELIMBASE, &flash_info[0]);
+    if (size)
+    {
+	flash_get_size((vu_char *)(-size), &flash_info[0]);
+    }
+
+#if (CFG_MONITOR_BASE >= CFG_FLASH_PRELIMBASE)
+    /* monitor protection ON by default */
+    flash_protect(FLAG_PROTECT_SET,
+		  CFG_MONITOR_BASE,
+		  CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+		  &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE	CFG_ENV_SECT_SIZE
+# endif
+    flash_protect(FLAG_PROTECT_SET,
+		  CFG_ENV_ADDR,
+		  CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+		  &flash_info[0]);
+#endif
+
+    return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+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_STM:
+	printf ("ST ");
+	break;
+    default:
+	printf ("Unknown Vendor ");
+	break;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case FLASH_STM320DB:
+	printf ("M29W320DB (32 Mbit)\n");
+	break;
+    case FLASH_STM800DB:
+	printf ("M29W800DB (8 Mbit, bottom boot block)\n");
+	break;
+    case FLASH_STM800DT:
+	printf ("M29W800DT (8 Mbit, top boot block)\n");
+	break;
+    default:
+	printf ("Unknown Chip Type\n");
+	break;
+    }
+
+    printf ("  Size: %ld KB in %d Sectors\n",
+	    info->size >> 10, info->sector_count);
+
+    printf ("  Sector Start Addresses:");
+    for (i=0; i<info->sector_count; ++i) {
+	if ((i % 5) == 0)
+	    printf ("\n   ");
+	printf (" %08lX%s",
+		info->start[i],
+		info->protect[i] ? " (RO)" : "     "
+		);
+    }
+    printf ("\n");
+    return;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_char *addr, flash_info_t *info)
+{
+    short i;
+    uchar vendor, devid;
+    ulong base = (ulong)addr;
+
+    /* Write auto select command: read Manufacturer ID */
+    addr[0x0AAA] = 0xAA;
+    addr[0x0555] = 0x55;
+    addr[0x0AAA] = 0x90;
+
+    udelay(1000);
+
+    vendor = addr[0];
+    devid = addr[2];
+
+    /* only support STM */
+    if ((vendor << 16) != FLASH_MAN_STM) {
+	return 0;
+    }
+
+    if (devid == FLASH_STM320DB) {
+    	/* MPC8240 can address maximum 2Mb of flash, that is why the MSB
+	 * lead is grounded and we can access only 2 first Mb */
+	info->flash_id     = vendor << 16 | devid;
+	info->sector_count = 32;
+	info->size         = info->sector_count * 0x10000;
+	for (i = 0; i < info->sector_count; i++) {
+	    info->start[i] = base + i * 0x10000;
+	}
+    }
+    else if (devid == FLASH_STM800DB) {
+	info->flash_id     = vendor << 16 | devid;
+	info->sector_count = 19;
+	info->size         = 0x100000;
+	info->start[0]     = 0x0000;
+	info->start[1]     = 0x4000;
+	info->start[2]     = 0x6000;
+	info->start[3]     = 0x8000;
+	for (i = 4; i < info->sector_count; i++) {
+	    info->start[i] = base + (i-3) * 0x10000;
+	}
+    }
+    else if (devid == FLASH_STM800DT) {
+	info->flash_id     = vendor << 16 | devid;
+	info->sector_count = 19;
+	info->size         = 0x100000;
+	for (i = 0; i < info->sector_count-4; i++) {
+	    info->start[i] = base + i * 0x10000;
+	}
+	info->start[i]     = base + i * 0x10000;
+	info->start[i+1]   = base + i * 0x10000 + 0x8000;
+	info->start[i+2]   = base + i * 0x10000 + 0xa000;
+	info->start[i+3]   = base + i * 0x10000 + 0xc000;
+    }
+    else {
+	return 0;
+    }
+
+    /* mark all sectors as unprotected */
+    for (i = 0; i < info->sector_count; i++) {
+	info->protect[i] = 0;
+    }
+
+    /* Issue the reset command */
+    if (info->flash_id != FLASH_UNKNOWN) {
+	addr[0] = 0xF0;	/* reset bank */
+    }
+
+    return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int	flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    vu_char *addr = (vu_char *)(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;
+    }
+
+    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();
+
+    addr[0x0AAA] = 0xAA;
+    addr[0x0555] = 0x55;
+    addr[0x0AAA] = 0x80;
+    addr[0x0AAA] = 0xAA;
+    addr[0x0555] = 0x55;
+
+    /* wait at least 80us - let's wait 1 ms */
+    udelay (1000);
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect<=s_last; sect++) {
+	if (info->protect[sect] == 0) {	/* not protected */
+	    addr = (vu_char *)(info->start[sect]);
+	    addr[0] = 0x30;
+	    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 = (vu_char *)(info->start[l_sect]);
+    while ((addr[0] & 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 */
+	    serial_putc ('.');
+	    last = now;
+	}
+    }
+
+    DONE:
+    /* reset to read mode */
+    addr = (volatile unsigned char *)info->start[0];
+    addr[0] = 0xF0;	/* reset bank */
+
+    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)
+{
+    int rc;
+
+    while (cnt > 0) {
+	if ((rc = write_byte(info, addr, *src)) != 0) {
+	    return (rc);
+	}
+	addr++;
+	src++;
+	cnt--;
+    }
+
+    return (0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a byte to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_byte (flash_info_t *info, ulong dest, uchar data)
+{
+    vu_char *addr = (vu_char *)(info->start[0]);
+    ulong start;
+    int flag;
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*((vu_char *)dest) & data) != data) {
+	return (2);
+    }
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    addr[0x0AAA] = 0xAA;
+    addr[0x0555] = 0x55;
+    addr[0x0AAA] = 0xA0;
+
+    *((vu_char *)dest) = data;
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+    /* data polling for D7 */
+    start = get_timer (0);
+    while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
+	if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+	    return (1);
+	}
+    }
+    return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */

+ 237 - 0
board/oxc/oxc.c

@@ -0,0 +1,237 @@
+/*
+ * (C) Copyright 2000
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <pci.h>
+#include <i2c.h>
+
+int checkboard (void)
+{
+	puts (	"Board: OXC8240\n" );
+	return 0;
+}
+
+long int initdram (int board_type)
+{
+#ifndef CFG_RAMBOOT
+	int		 i, cnt;
+	volatile uchar * base= CFG_SDRAM_BASE;
+	volatile ulong * addr;
+	ulong		 save[32];
+	ulong		 val, ret  = 0;
+
+	for (i=0, cnt=(CFG_MAX_RAM_SIZE / sizeof(long)) >> 1; cnt > 0; cnt >>= 1) {
+		addr = (volatile ulong *)base + cnt;
+		save[i++] = *addr;
+		*addr = ~cnt;
+	}
+
+	addr = (volatile ulong *)base;
+	save[i] = *addr;
+	*addr = 0;
+
+	if (*addr != 0) {
+		*addr = save[i];
+		goto Done;
+	}
+
+	for (cnt = 1; cnt <= CFG_MAX_RAM_SIZE / sizeof(long); cnt <<= 1) {
+		addr = (volatile ulong *)base + cnt;
+		val = *addr;
+		*addr = save[--i];
+		if (val != ~cnt) {
+			ulong new_bank0_end = cnt * sizeof(long) - 1;
+			ulong mear1  = mpc824x_mpc107_getreg(MEAR1);
+			ulong emear1 = mpc824x_mpc107_getreg(EMEAR1);
+			mear1 =  (mear1  & 0xFFFFFF00) |
+			((new_bank0_end & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT);
+			emear1 = (emear1 & 0xFFFFFF00) |
+			((new_bank0_end & MICR_ADDR_MASK) >> MICR_EADDR_SHIFT);
+			mpc824x_mpc107_setreg(MEAR1,  mear1);
+			mpc824x_mpc107_setreg(EMEAR1, emear1);
+
+			ret = cnt * sizeof(long);
+			goto Done;
+		}
+	}
+
+	ret = CFG_MAX_RAM_SIZE;
+Done:
+	return ret;
+#else
+	/* if U-Boot starts from RAM, then suppose we have 16Mb of RAM */
+	return (16 << 20);
+#endif
+}
+
+/*
+ * Initialize PCI Devices, report devices found.
+ */
+#ifndef CONFIG_PCI_PNP
+static struct pci_config_table pci_oxc_config_table[] = {
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0x14, PCI_ANY_ID,
+	  pci_cfgfunc_config_device, { PCI_ENET0_IOADDR,
+				       PCI_ENET0_MEMADDR,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER }},
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0x15, PCI_ANY_ID,
+	  pci_cfgfunc_config_device, { PCI_ENET1_IOADDR,
+				       PCI_ENET1_MEMADDR,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER }},
+	{ }
+};
+#endif
+
+static struct pci_controller hose = {
+#ifndef CONFIG_PCI_PNP
+	config_table: pci_oxc_config_table,
+#endif
+};
+
+void pci_init (void)
+{
+	pci_mpc824x_init(&hose);
+}
+
+int board_pre_init (void)
+{
+	*(volatile unsigned char *)(CFG_CPLD_RESET) = 0x89;
+	return 0;
+}
+
+#ifdef CONFIG_WATCHDOG
+void oxc_wdt_reset(void)
+{
+	*(volatile unsigned char *)(CFG_CPLD_WATCHDOG) = 0xff;
+}
+
+void watchdog_reset(void)
+{
+	int re_enable = disable_interrupts();
+
+	oxc_wdt_reset();
+	if (re_enable)
+		enable_interrupts();
+}
+#endif
+
+static int oxc_get_expander(unsigned char addr, unsigned char * val)
+{
+	return i2c_read(addr, 0, 0, val, 1);
+}
+
+static int oxc_set_expander(unsigned char addr, unsigned char val)
+{
+	return i2c_write(addr, 0, 0, &val, 1);
+}
+
+static int expander0alive = 0;
+
+#ifdef CONFIG_SHOW_ACTIVITY
+static int ledtoggle = 0;
+static int ledstatus = 1;
+
+void oxc_toggle_activeled(void)
+{
+	ledtoggle++;
+}
+
+void show_activity(int arg)
+{
+	static unsigned char led = 0;
+	unsigned char val;
+
+	if (!expander0alive) return;
+
+	if ((ledtoggle > (2 * arg)) && ledstatus) {
+		led ^= 0x80;
+		oxc_get_expander(CFG_I2C_EXPANDER0_ADDR, &val);
+		udelay(200);
+		oxc_set_expander(CFG_I2C_EXPANDER0_ADDR, (val & 0x7F) | led);
+		ledtoggle = 0;
+	}
+}
+#endif
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+void show_boot_progress(int arg)
+{
+	unsigned char val;
+
+	if (!expander0alive) return;
+
+	if (arg > 0 && ledstatus) {
+		ledstatus = 0;
+		oxc_get_expander(CFG_I2C_EXPANDER0_ADDR, &val);
+		udelay(200);
+		oxc_set_expander(CFG_I2C_EXPANDER0_ADDR, val | 0x80);
+	} else if (arg < 0) {
+		oxc_get_expander(CFG_I2C_EXPANDER0_ADDR, &val);
+		udelay(200);
+		oxc_set_expander(CFG_I2C_EXPANDER0_ADDR, val & 0x7F);
+		ledstatus = 1;
+	}
+}
+#endif
+
+int misc_init_r (void)
+{
+	/* check whether the i2c expander #0 is accessible */
+	if (!oxc_set_expander(CFG_I2C_EXPANDER0_ADDR, 0x7F)) {
+		udelay(200);
+		expander0alive = 1;
+	}
+
+#ifdef CFG_OXC_GENERATE_IP
+	{
+		DECLARE_GLOBAL_DATA_PTR;
+
+		char str[32];
+		unsigned long ip = CFG_OXC_IPMASK;
+		bd_t *bd = gd->bd;
+
+		if (expander0alive) {
+			unsigned char val;
+
+			if (!oxc_get_expander(CFG_I2C_EXPANDER0_ADDR, &val)) {
+				ip = (ip & 0xffffff00) | ((val & 0x7c) >> 2);
+			}
+		}
+
+		if ((ip & 0xff) < 3) {
+			/* if fail, set x.x.x.254 */
+			ip = (ip & 0xffffff00) | 0xfe;
+		}
+
+		bd->bi_ip_addr = ip;
+		sprintf(str, "%ld.%ld.%ld.%ld",
+			(bd->bi_ip_addr & 0xff000000) >> 24,
+			(bd->bi_ip_addr & 0x00ff0000) >> 16,
+			(bd->bi_ip_addr & 0x0000ff00) >> 8,
+			(bd->bi_ip_addr & 0x000000ff));
+		setenv("ipaddr", str);
+		printf("ip:    %s\n", str);
+	}
+#endif
+	return (0);
+}

+ 254 - 0
board/pcippc2/cpc710_init_ram.c

@@ -0,0 +1,254 @@
+/*
+ * (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 <common.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 (! i2c_reset())
+  {
+    puts("Can't reset I2C!\n");
+    hang();
+  }
+
+  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_read_byte(& data, dev,offset))
+  {
+    puts("I2C error !\n");
+    hang();
+  }
+
+  return data;
+}

+ 309 - 0
board/pcippc2/cpc710_pci.c

@@ -0,0 +1,309 @@
+/*
+ * (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 <common.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#include "hardware.h"
+#include "pcippc2.h"
+
+struct pci_controller local_hose, cpci_hose;
+
+static u32	cpc710_mapped_ram;
+
+  /* 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), 0x00ffe000);
+  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_VAL << 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_VAL << 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();
+
+  local_hose.first_busno = 0;
+  local_hose.last_busno = 0xff;
+
+  /* System memory space */
+  pci_set_region(local_hose.regions + 0,
+		 PCI_MEMORY_BUS,
+		 PCI_MEMORY_PHYS,
+		 PCI_MEMORY_MAXSIZE,
+		 PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+  /* PCI memory space */
+  pci_set_region(local_hose.regions + 1,
+		 BRIDGE_LOCAL_MEM_BUS,
+		 BRIDGE_LOCAL_MEM_PHYS,
+		 BRIDGE_LOCAL_MEM_SIZE,
+		 PCI_REGION_MEM);
+
+  /* PCI I/O space */
+  pci_set_region(local_hose.regions + 2,
+		 BRIDGE_LOCAL_IO_BUS,
+		 BRIDGE_LOCAL_IO_PHYS,
+		 BRIDGE_LOCAL_IO_SIZE,
+		 PCI_REGION_IO);
+
+  local_hose.region_count = 3;
+
+  pci_setup_indirect(&local_hose,
+		     BRIDGE_LOCAL_PHYS + HW_BRIDGE_CFGADDR,
+		     BRIDGE_LOCAL_PHYS + HW_BRIDGE_CFGDATA);
+
+  pci_register_hose(&local_hose);
+
+  /* Initialize PCI32 bus registers */
+  pci_hose_write_config_byte(&local_hose,
+			  PCI_BDF(local_hose.first_busno,0,0),
+			  CPC710_BUS_NUMBER,
+			  local_hose.first_busno);
+  pci_hose_write_config_byte(&local_hose,
+			  PCI_BDF(local_hose.first_busno,0,0),
+			  CPC710_SUB_BUS_NUMBER,
+			  local_hose.last_busno);
+
+  local_hose.last_busno = pci_hose_scan(&local_hose);
+
+  /* Write out correct max subordinate bus number for local hose */
+  pci_hose_write_config_byte(&local_hose,
+			  PCI_BDF(local_hose.first_busno,0,0),
+			  CPC710_SUB_BUS_NUMBER,
+			  local_hose.last_busno);
+
+  cpci_hose.first_busno = local_hose.last_busno + 1;
+  cpci_hose.last_busno = 0xff;
+
+  /* System memory space */
+  pci_set_region(cpci_hose.regions + 0,
+		 PCI_MEMORY_BUS,
+		 PCI_MEMORY_PHYS,
+		 PCI_MEMORY_MAXSIZE,
+		 PCI_REGION_MEMORY);
+
+  /* PCI memory space */
+  pci_set_region(cpci_hose.regions + 1,
+		 BRIDGE_CPCI_MEM_BUS,
+		 BRIDGE_CPCI_MEM_PHYS,
+		 BRIDGE_CPCI_MEM_SIZE,
+		 PCI_REGION_MEM);
+
+  /* PCI I/O space */
+  pci_set_region(cpci_hose.regions + 2,
+		 BRIDGE_CPCI_IO_BUS,
+		 BRIDGE_CPCI_IO_PHYS,
+		 BRIDGE_CPCI_IO_SIZE,
+		 PCI_REGION_IO);
+
+  cpci_hose.region_count = 3;
+
+  pci_setup_indirect(&cpci_hose,
+		     BRIDGE_CPCI_PHYS + HW_BRIDGE_CFGADDR,
+		     BRIDGE_CPCI_PHYS + HW_BRIDGE_CFGDATA);
+
+  pci_register_hose(&cpci_hose);
+
+  /* Initialize PCI64 bus registers */
+  pci_hose_write_config_byte(&cpci_hose,
+			  PCI_BDF(cpci_hose.first_busno,0,0),
+			  CPC710_BUS_NUMBER,
+			  cpci_hose.first_busno);
+  pci_hose_write_config_byte(&cpci_hose,
+			  PCI_BDF(cpci_hose.first_busno,0,0),
+			  CPC710_SUB_BUS_NUMBER,
+			  cpci_hose.last_busno);
+
+  cpci_hose.last_busno = pci_hose_scan(&cpci_hose);
+
+  /* Write out correct max subordinate bus number for cpci hose */
+  pci_hose_write_config_byte(&cpci_hose,
+			  PCI_BDF(cpci_hose.first_busno,0,0),
+			  CPC710_SUB_BUS_NUMBER,
+			  cpci_hose.last_busno);
+}

+ 257 - 0
board/pcippc2/i2c.c

@@ -0,0 +1,257 @@
+/*
+ * (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 <common.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 void		i2c_read	(u8 *		data);
+
+static inline void	i2c_port_start  (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_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,
+  u8			offset)
+{
+  int			err = 0;
+
+  i2c_start();
+
+  err = ! i2c_write(dev);
+
+  if (! err)
+  {
+    err = ! i2c_write(offset);
+  }
+
+  if (! err)
+  {
+    i2c_start();
+  }
+
+  if (! err)
+  {
+    err = ! i2c_write(dev | 0x01);
+  }
+
+  if (! err)
+  {
+    i2c_read(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_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)?1:0;
+
+  iobarrier_rw();
+
+  return val;
+}
+
+
+  /* Protocol implementation
+   */
+
+static inline void i2c_write_bit (
+  unsigned int		val)
+{
+  i2c_data(val);
+  i2c_udelay(10);
+  i2c_clock(1);
+  i2c_udelay(10);
+  i2c_clock(0);
+  i2c_udelay(10);
+}
+
+static inline unsigned int i2c_read_bit (void)
+{
+  unsigned int		val;
+
+  i2c_data(1);
+  i2c_udelay(10);
+
+  i2c_clock(1);
+  i2c_udelay(10);
+
+  val = i2c_in();
+
+  i2c_clock(0);
+  i2c_udelay(10);
+
+  return val;
+}
+
+unsigned int i2c_reset (void)
+{
+  unsigned int		val;
+  int i;
+
+  i2c_port_start();
+
+  i=0;
+  do {
+    i2c_udelay(10);
+    i2c_clock(0);
+    i2c_udelay(10);
+    i2c_clock(1);
+    i2c_udelay(10);
+    val = i2c_in();
+    i++;
+  }  while ((i<9)&&(val==0));
+  return (val);
+}
+
+
+static void i2c_start (void)
+{
+  i2c_data(1);
+  i2c_clock(1);
+  i2c_udelay(10);
+  i2c_data(0);
+  i2c_udelay(10);
+  i2c_clock(0);
+  i2c_udelay(10);
+}
+
+static void i2c_stop (void)
+{
+  i2c_data(0);
+  i2c_udelay(10);
+  i2c_clock(1);
+  i2c_udelay(10);
+  i2c_data(1);
+  i2c_udelay(10);
+}
+
+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 void i2c_read (
+  u8 *			data)
+{
+  unsigned int		i;
+  u8			val = 0;
+
+  for (i = 0; i < 8; i++)
+  {
+    val <<= 1;
+    val |= i2c_read_bit();
+  }
+
+  *data = val;
+  i2c_write_bit(1); /* NoAck */
+}

+ 214 - 0
board/pcippc2/pcippc2.c

@@ -0,0 +1,214 @@
+/*
+ * (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 <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <linux/mtd/doc2000.h>
+#include <watchdog.h>
+#include <pci.h>
+
+#include "hardware.h"
+#include "pcippc2.h"
+#include "sconsole.h"
+#include "fpga_serial.h"
+
+#if defined(CONFIG_WATCHDOG)
+
+static int pcippc2_wdt_init_done = 0;
+
+void pcippc2_wdt_init (void);
+
+#endif
+
+  /* Check board identity
+   */
+int checkboard (void)
+{
+#ifdef CONFIG_PCIPPC2
+	puts ("Board: Gespac PCIPPC-2\n");
+#else
+	puts ("Board: Gespac PCIPPC-6\n");
+#endif
+	return 0;
+}
+
+  /* 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), 0x00000000);
+
+	out32 (REG (CPC0, SESR), 0x00000000);
+	out32 (REG (CPC0, SEAR), 0x00000000);
+
+	/* Detect IBM Avignon CPC710 Revision */
+	if ((in32 (REG (CPC0, UCTL)) & 0x000000F0) == CPC710_TYPE_100P)
+		out32 (REG (CPC0, PGCHP), 0xA0000040);
+	else
+		out32 (REG (CPC0, PGCHP), 0x80800040);
+
+
+	out32 (REG (CPC0, ATAS), 0x709C2508);
+
+	iobarrier_rw ();
+
+	return 0;
+}
+
+void after_reloc (ulong dest_addr)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	/* Jump to the main U-Boot board init code
+	 */
+	board_init_r (gd, dest_addr);
+}
+
+int misc_init_r (void)
+{
+	pcippc2_fpga_init ();
+
+#if defined(CONFIG_WATCHDOG)
+	pcippc2_wdt_init ();
+#endif
+
+	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 ();
+	return (0);
+}
+
+void pci_init (void)
+{
+	cpc710_pci_init ();
+
+	/* FPGA requires no retry timeouts to be enabled
+	 */
+	cpc710_pci_enable_timeout ();
+}
+
+void doc_init (void)
+{
+	doc_probe (pcippc2_fpga1_phys + HW_FPGA1_DOC);
+}
+
+#if defined(CONFIG_WATCHDOG)
+
+void pcippc2_wdt_init (void)
+{
+	out16r (FPGA (WDT, PROG), 0xffff);
+	out8 (FPGA (WDT, CTRL), 0x1);
+
+	pcippc2_wdt_init_done = 1;
+}
+
+void pcippc2_wdt_done (void)
+{
+	out8 (FPGA (WDT, CTRL), 0x0);
+
+	pcippc2_wdt_init_done = 0;
+}
+
+void pcippc2_wdt_reset (void)
+{
+	if (pcippc2_wdt_init_done == 1)
+		out8 (FPGA (WDT, REFRESH), 0x56);
+}
+
+void watchdog_reset (void)
+{
+	int re_enable = disable_interrupts ();
+
+	pcippc2_wdt_reset ();
+	if (re_enable)
+		enable_interrupts ();
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_BSP)
+int do_wd (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+	switch (argc) {
+	case 1:
+		printf ("Watchdog timer status is %s\n",
+			pcippc2_wdt_init_done == 1 ? "on" : "off");
+
+		return 0;
+	case 2:
+		if (!strcmp(argv[1],"on")) {
+			pcippc2_wdt_init();
+			printf("Watchdog timer now is on\n");
+
+			return 0;
+
+		} else if (!strcmp(argv[1],"off")) {
+			pcippc2_wdt_done();
+			printf("Watchdog timer now is off\n");
+
+			return 0;
+
+		} else
+			break;
+	default:
+		break;
+	}
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+}
+
+#endif	/* CFG_CMD_BSP */
+#endif	/* CONFIG_WATCHDOG */

+ 164 - 0
board/pn62/cmd_pn62.c

@@ -0,0 +1,164 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <cmd_autoscript.h>
+#include <cmd_bsp.h>
+
+#include "pn62.h"
+
+#if (CONFIG_COMMANDS & CFG_CMD_BSP)
+
+extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
+
+/*
+ * Command led: controls the various LEDs 0..11 on the PN62 card.
+ */
+int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    unsigned int number, function;
+
+    if (argc != 3) {
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    }
+    number = simple_strtoul(argv[1], NULL, 10);
+    if (number > PN62_LED_MAX)
+	return 1;
+    function = simple_strtoul(argv[2], NULL, 16);
+    set_led (number, function);
+    return 0;
+}
+
+/*
+ * Command loadpci: loads a image over PCI.
+ */
+#define CMD_MOVE_WINDOW 0x1
+#define CMD_BOOT_IMAGE  0x2
+
+int do_loadpci (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    char *s;
+    ulong addr = 0, count = 0;
+    u32 off;
+    int cmd, rcode = 0;
+
+    /* pre-set load_addr */
+    if ((s = getenv("loadaddr")) != NULL) {
+	addr = simple_strtoul(s, NULL, 16);
+    }
+
+    switch (argc) {
+    case 1:
+	break;
+    case 2:
+	addr = simple_strtoul(argv[1], NULL, 16);
+	break;
+    default:
+       printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    }
+
+    printf ("## Ready for image download ...\n");
+
+    show_startup_phase(12);
+
+    while (1) {
+	/* Alive indicator */
+	i2155x_write_scrapad(BOOT_PROTO, BOOT_PROTO_READY);
+
+	/* Toggle status LEDs */
+	cmd = (count / 200) % 4; /* downscale */
+	set_led(4, cmd == 0 ? LED_1 : LED_0);
+	set_led(5, cmd == 1 ? LED_1 : LED_0);
+	set_led(6, cmd == 2 ? LED_1 : LED_0);
+	set_led(7, cmd == 3 ? LED_1 : LED_0);
+	udelay(1000);
+	count++;
+
+	cmd = i2155x_read_scrapad(BOOT_CMD);
+
+	if (cmd == BOOT_CMD_MOVE) {
+	    off = i2155x_read_scrapad(BOOT_DATA);
+	    off += addr;
+	    i2155x_set_bar_base(3, off);
+	    printf ("## BAR3 Addr moved = 0x%08x\n", off);
+	    i2155x_write_scrapad(BOOT_CMD, ~cmd);
+	    show_startup_phase(13);
+	}
+	else if (cmd == BOOT_CMD_BOOT) {
+	    set_led(4, LED_1);
+	    set_led(5, LED_1);
+	    set_led(6, LED_1);
+	    set_led(7, LED_1);
+
+	    i2155x_write_scrapad(BOOT_CMD, ~cmd);
+	    show_startup_phase(14);
+	    break;
+	}
+
+	/* Abort if ctrl-c was pressed */
+	if (ctrlc()) {
+	    printf("\nAbort\n");
+	    return 0;
+	}
+
+    }
+
+    /* Repoint to the default shared memory */
+    i2155x_set_bar_base(3, PN62_SMEM_DEFAULT);
+
+    load_addr = addr;
+    printf ("## Start Addr      = 0x%08lx\n", addr);
+
+    show_startup_phase(15);
+
+    /* Loading ok, check if we should attempt an auto-start */
+    if (((s = getenv("autostart")) != NULL) && (strcmp(s,"yes") == 0)) {
+	char *local_args[2];
+	local_args[0] = argv[0];
+	local_args[1] = NULL;
+
+	printf ("Automatic boot of image at addr 0x%08lX ...\n",
+		load_addr);
+	rcode = do_bootm (cmdtp, 0, 1, local_args);
+    }
+
+#ifdef CONFIG_AUTOSCRIPT
+    if (load_addr) {
+	char *s;
+
+	if (((s = getenv("autoscript")) != NULL) && (strcmp(s,"yes") == 0)) {
+	    printf("Running autoscript at addr 0x%08lX ...\n", load_addr);
+	    rcode = autoscript (bd, load_addr);
+	}
+    }
+#endif
+    return rcode;
+}
+
+#endif

+ 235 - 0
board/pn62/misc.c

@@ -0,0 +1,235 @@
+/*
+ * (C) Copyright 2002 Wolfgang Grandegger <wg@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#include "pn62.h"
+
+typedef struct {
+    pci_dev_t    devno;
+    volatile u32 *csr;
+
+} i2155x_t;
+
+static i2155x_t i2155x = { 0, NULL };
+
+static struct pci_device_id i2155x_ids[] = {
+    { 0x1011, 0x0046 },		/* i21554 */
+    { 0x8086, 0xb555 }		/* i21555 */
+};
+
+int i2155x_init(void)
+{
+    pci_dev_t devno;
+    u32 val;
+    int i;
+
+    /*
+     * Find the Intel bridge.
+     */
+    if ((devno = pci_find_devices(i2155x_ids, 0)) < 0) {
+	printf("Error: Intel bridge 2155x not found!\n");
+	return -1;
+    }
+    i2155x.devno = devno;
+
+    /*
+     * Get auto-configured base address for CSR access.
+     */
+    pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &val);
+    if (val & PCI_BASE_ADDRESS_SPACE_IO) {
+	val &= PCI_BASE_ADDRESS_IO_MASK;
+	i2155x.csr = (volatile u32 *)(_IO_BASE + val);
+    } else {
+	val &= PCI_BASE_ADDRESS_MEM_MASK;
+	i2155x.csr =  (volatile u32 *)val;
+    }
+
+    /*
+     * Translate downstream memory 2 (bar3) to base of shared memory.
+     */
+    i2155x_set_bar_base(3, PN62_SMEM_DEFAULT);
+
+    /*
+     * Enable memory space, I/O space and bus master bits
+     * in both Primary and Secondary command registers.
+     */
+    val = PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+    pci_write_config_word(devno, 0x44, val);
+    pci_write_config_word(devno, 0x04, val);
+
+    /*
+     * Clear scratchpad registers.
+     */
+    for (i = 0; i < (I2155X_SCRAPAD_MAX - 1); i++) {
+	i2155x_write_scrapad(i, 0x0);
+    }
+
+    /*
+     * Set interrupt line for Linux.
+     */
+    pci_write_config_byte(devno, PCI_INTERRUPT_LINE, 3);
+
+    return 0;
+}
+
+/*
+ * Access the Scratchpad registers 0..7 of the Intel bridge.
+ */
+void i2155x_write_scrapad(int idx, u32 val)
+{
+    if (idx >= 0 && idx < I2155X_SCRAPAD_MAX)
+	out_le32(i2155x.csr + (I2155X_SCRAPAD_ADDR/4) + idx, val);
+    else
+	printf("i2155x_write_scrapad: invalid index\n");
+}
+
+u32 i2155x_read_scrapad(int idx)
+{
+    if (idx >= 0 && idx < I2155X_SCRAPAD_MAX)
+	return in_le32(i2155x.csr + (I2155X_SCRAPAD_ADDR/4) + idx);
+    else
+	printf("i2155x_read_scrapad: invalid index\n");
+    return -1;
+}
+
+void i2155x_set_bar_base(int bar, u32 base)
+{
+    if (bar >= 2 && bar <= 4) {
+	pci_write_config_dword(i2155x.devno,
+			       I2155X_BAR2_BASE + (bar - 2) * 4,
+			       base);
+    }
+}
+
+/*
+ * Read Vital Product Data (VPD) from the Serial EPROM attached
+ * to the Intel bridge.
+ */
+int i2155x_read_vpd(int offset, int size, unsigned char *data)
+{
+    int i, n;
+    u16 val16;
+
+    for (i = 0; i < size; i++) {
+	pci_write_config_word(i2155x.devno, I2155X_VPD_ADDR,
+			      offset + i - I2155X_VPD_START);
+	for (n = 10000; n > 0; n--) {
+	    pci_read_config_word(i2155x.devno, I2155X_VPD_ADDR, &val16);
+	    if ((val16 & 0x8000) != 0) /* wait for completion */
+		break;
+	    udelay(100);
+	}
+	if (n == 0) {
+	    printf("i2155x_read_vpd: TIMEOUT\n");
+	    return -1;
+	}
+
+	pci_read_config_byte(i2155x.devno, I2155X_VPD_DATA, &data[i]);
+    }
+
+    return i;
+}
+
+static struct pci_device_id am79c95x_ids [] = {
+        { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE },
+        { }
+};
+
+
+/*
+ * Initialize the AMD ethernet controllers.
+ */
+int am79c95x_init(void)
+{
+    pci_dev_t devno;
+    int i;
+
+    /*
+     * Set interrupt line for Linux.
+     */
+    for (i = 0; i < 2; i++) {
+	if ((devno = pci_find_devices(am79c95x_ids, i)) < 0)
+	    break;
+	pci_write_config_byte(devno, PCI_INTERRUPT_LINE, 2+i);
+    }
+    if (i < 2)
+	printf("Error: Only %d AMD Ethernet Controller found!\n", i);
+
+    return 0;
+}
+
+
+void set_led(unsigned int number, unsigned int function)
+{
+    volatile u8 *addr;
+
+    if ((number >= 0) && (number < PN62_LED_MAX) &&
+	(function >= 0) && (function <= LED_LAST_FUNCTION)) {
+	addr = (volatile u8 *)(PN62_LED_BASE + number * 8);
+	out_8(addr, function&0xff);
+    }
+}
+
+/*
+ * Show fatal error indicated by Kinght Rider(tm) effect
+ * in LEDS 0-7. LEDS 8-11 contain 4 bit error code.
+ * Note: this function will not terminate.
+ */
+void fatal_error(unsigned int error_code)
+{
+    int i, d;
+
+    for (i = 0; i < 12; i++) {
+	set_led(i, LED_0);
+    }
+
+    /*
+     * Write error code.
+     */
+    set_led(8,  (error_code & 0x01) ? LED_1 : LED_0);
+    set_led(9,  (error_code & 0x02) ? LED_1 : LED_0);
+    set_led(10, (error_code & 0x04) ? LED_1 : LED_0);
+    set_led(11, (error_code & 0x08) ? LED_1 : LED_0);
+
+    /*
+     * Yay - Knight Rider effect!
+     */
+    while(1) {
+	unsigned int delay = 2000;
+
+	for (i = 0; i < 8; i++) {
+	    set_led(i, LED_1);
+	    for (d = 0; d < delay; d++);
+	    set_led(i, LED_0);
+	}
+
+	for (i = 7; i > 0; i--) {
+	    set_led(i, LED_1);
+	    for (d = 0; d < delay; d++);
+	    set_led(i, LED_0);
+	}
+    }
+}

+ 216 - 0
board/pn62/pn62.c

@@ -0,0 +1,216 @@
+/*
+ * (C) Copyright 2002 Wolfgang Grandegger <wg@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <pci.h>
+
+#include "pn62.h"
+
+
+static int get_serial_number (char *string, int size);
+static int get_mac_address (int id, u8 * mac, char *string, int size);
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+void show_boot_progress (int phase)
+{
+	/*
+	 * Show phases of the bootm command on the front panel
+	 * LEDs and the scratchpad register #3 as well. We use
+	 * blinking LEDs for logical "1".
+	 */
+	if (phase > 0) {
+		set_led (8, (phase & 0x1) ? LED_SLOW_CLOCK : LED_0);
+		set_led (9, (phase & 0x2) ? LED_SLOW_CLOCK : LED_0);
+		set_led (10, (phase & 0x4) ? LED_SLOW_CLOCK : LED_0);
+		set_led (11, (phase & 0x8) ? LED_SLOW_CLOCK : LED_0);
+	}
+	i2155x_write_scrapad (BOOT_STATUS, phase);
+	if (phase < 0)
+		i2155x_write_scrapad (BOOT_DONE, BOOT_DONE_ERROR);
+}
+#endif
+
+void show_startup_phase (int phase)
+{
+	/*
+	 * Show the phase of U-Boot startup on the front panel
+	 * LEDs and the scratchpad register #3 as well.
+	 */
+	if (phase > 0) {
+		set_led (8, (phase & 0x1) ? LED_1 : LED_0);
+		set_led (9, (phase & 0x2) ? LED_1 : LED_0);
+		set_led (10, (phase & 0x4) ? LED_1 : LED_0);
+		set_led (11, (phase & 0x8) ? LED_1 : LED_0);
+	}
+	i2155x_write_scrapad (BOOT_STATUS, phase);
+	if (phase < 0)
+		i2155x_write_scrapad (BOOT_DONE, BOOT_DONE_ERROR);
+}
+
+int checkboard (void)
+{
+	show_startup_phase (1);
+	puts ("Board: PN62\n");
+	return 0;
+}
+
+long int initdram (int board_type)
+{
+	int i, cnt;
+	volatile uchar *base = CFG_SDRAM_BASE;
+	volatile ulong *addr;
+	ulong save[32];
+	ulong val, ret = 0;
+
+	show_startup_phase (2);
+
+	for (i = 0, cnt = (CFG_MAX_RAM_SIZE / sizeof (long)) >> 1; cnt > 0;
+		 cnt >>= 1) {
+		addr = (volatile ulong *) base + cnt;
+		save[i++] = *addr;
+		*addr = ~cnt;
+	}
+
+	addr = (volatile ulong *) base;
+	save[i] = *addr;
+	*addr = 0;
+
+	if (*addr != 0) {
+		*addr = save[i];
+		goto Done;
+	}
+
+	for (cnt = 1; cnt <= CFG_MAX_RAM_SIZE / sizeof (long); cnt <<= 1) {
+		addr = (volatile ulong *) base + cnt;
+		val = *addr;
+		*addr = save[--i];
+		if (val != ~cnt) {
+			ulong new_bank0_end = cnt * sizeof (long) - 1;
+			ulong mear1 = mpc824x_mpc107_getreg (MEAR1);
+			ulong emear1 = mpc824x_mpc107_getreg (EMEAR1);
+
+			mear1 = (mear1 & 0xFFFFFF00) |
+					((new_bank0_end & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT);
+			emear1 = (emear1 & 0xFFFFFF00) |
+					((new_bank0_end & MICR_ADDR_MASK) >> MICR_EADDR_SHIFT);
+			mpc824x_mpc107_setreg (MEAR1, mear1);
+			mpc824x_mpc107_setreg (EMEAR1, emear1);
+
+			ret = cnt * sizeof (long);
+			goto Done;
+		}
+	}
+
+	ret = CFG_MAX_RAM_SIZE;
+  Done:
+	show_startup_phase (3);
+	return ret;
+}
+
+/*
+ * Initialize PCI Devices. We rely on auto-configuration.
+ */
+#ifndef CONFIG_PCI_PNP
+#error "CONFIG_PCI_PNP is not defined, please correct!"
+#endif
+
+struct pci_controller hose = {
+};
+
+void pci_init (void)
+{
+	show_startup_phase (4);
+	pci_mpc824x_init (&hose);
+
+	show_startup_phase (5);
+	i2155x_init ();
+	show_startup_phase (6);
+	am79c95x_init ();
+	show_startup_phase (7);
+}
+
+int misc_init_r (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	char str[20];
+	u8 mac[6];
+
+	show_startup_phase (8);
+	/*
+	 * Get serial number and ethernet addresses if not already defined
+	 * and update the board info structure and the environment.
+	 */
+	if (getenv ("serial#") == NULL &&
+		get_serial_number (str, strlen (str)) > 0) {
+		setenv ("serial#", str);
+	}
+	show_startup_phase (9);
+
+	if (getenv ("ethaddr") == NULL &&
+		get_mac_address (0, mac, str, sizeof (str)) > 0) {
+		setenv ("ethaddr", str);
+		memcpy (gd->bd->bi_enetaddr, mac, 6);
+	}
+	show_startup_phase (10);
+
+	if (getenv ("eth1addr") == NULL &&
+		get_mac_address (1, mac, str, sizeof (str)) > 0) {
+		setenv ("eth1addr", str);
+		memcpy (gd->bd->bi_enet1addr, mac, 6);
+	}
+	show_startup_phase (11);
+
+	/* Tell everybody that U-Boot is up and runnig */
+	i2155x_write_scrapad (0, 0x12345678);
+	return (0);
+}
+
+static int get_serial_number (char *string, int size)
+{
+	int i;
+	char c;
+
+	if (size < I2155X_VPD_SN_SIZE)
+		size = I2155X_VPD_SN_SIZE;
+	for (i = 0; i < (size - 1); i++) {
+		i2155x_read_vpd (I2155X_VPD_SN_START + i, 1, &c);
+		if (c == '\0')
+			break;
+		string[i] = c;
+	}
+	string[i] = '\0';			/* make sure it's terminated */
+
+	return i;
+}
+
+static int get_mac_address (int id, u8 * mac, char *string, int size)
+{
+	if (size < 6 * 3)
+		return -1;
+
+	i2155x_read_vpd (I2155X_VPD_MAC0_START + 6 * id, 6, mac);
+	return sprintf (string, "%02x:%02x:%02x:%02x:%02x:%02x",
+				mac[0], mac[1], mac[2],
+				mac[3], mac[4], mac[5]);
+}

+ 423 - 0
board/r360mpi/r360mpi.c

@@ -0,0 +1,423 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <mpc8xx.h>
+#include <i2c.h>
+
+#include <commproc.h>
+#include <command.h>
+#include <cmd_bsp.h>
+#include <malloc.h>
+
+#include <linux/types.h>
+#include <linux/string.h>       /* for strdup */
+
+
+/*
+ *  Memory Controller Using
+ *
+ *  CS0 - Flash memory            (0x40000000)
+ *  CS1 - SDRAM                   (0x00000000}
+ *  CS2 -
+ *  CS3 -
+ *  CS4 -
+ *  CS5 -
+ *  CS6 - PCMCIA device
+ *  CS7 - PCMCIA device
+ */
+
+/* ------------------------------------------------------------------------- */
+
+#define _not_used_	0xffffffff
+
+const uint sdram_table[]=
+{
+        /* single read. (offset 0 in upm RAM) */
+        0x1f07fc04, 0xeeaefc04, 0x11adfc04, 0xefbbbc00,
+        0x1ff77c47,
+
+        /* MRS initialization (offset 5) */
+
+        0x1ff77c34, 0xefeabc34, 0x1fb57c35,
+
+        /* burst read. (offset 8 in upm RAM) */
+        0x1f07fc04, 0xeeaefc04, 0x10adfc04, 0xf0affc00,
+        0xf0affc00, 0xf1affc00, 0xefbbbc00, 0x1ff77c47,
+        _not_used_, _not_used_, _not_used_, _not_used_,
+        _not_used_, _not_used_, _not_used_, _not_used_,
+
+        /* single write. (offset 18 in upm RAM) */
+        0x1f27fc04, 0xeeaebc00, 0x01b93c04, 0x1ff77c47,
+        _not_used_, _not_used_, _not_used_, _not_used_,
+
+        /* burst write. (offset 20 in upm RAM) */
+        0x1f07fc04, 0xeeaebc00, 0x10ad7c00, 0xf0affc00,
+        0xf0affc00, 0xe1bbbc04, 0x1ff77c47, _not_used_,
+        _not_used_, _not_used_, _not_used_, _not_used_,
+        _not_used_, _not_used_, _not_used_, _not_used_,
+
+        /* refresh. (offset 30 in upm RAM) */
+        0x1ff5fc84, 0xfffffc04, 0xfffffc04, 0xfffffc04,
+        0xfffffc84, 0xfffffc07, _not_used_, _not_used_,
+        _not_used_, _not_used_, _not_used_, _not_used_,
+
+        /* exception. (offset 3c in upm RAM) */
+        0x7ffffc07, _not_used_, _not_used_, _not_used_ };
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Check Board Identity:
+ */
+
+int checkboard (void)
+{
+	puts ("Board: R360 MPI Board\n");
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static long int dram_size (long int, long int *, long int);
+
+/* ------------------------------------------------------------------------- */
+
+long int initdram (int board_type)
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	long int size8, size9;
+	long int size_b0 = 0;
+	unsigned long reg;
+
+	upmconfig (UPMA, (uint *) sdram_table,
+			   sizeof (sdram_table) / sizeof (uint));
+
+	/*
+	 * Preliminary prescaler for refresh (depends on number of
+	 * banks): This value is selected for four cycles every 62.4 us
+	 * with two SDRAM banks or four cycles every 31.2 us with one
+	 * bank. It will be adjusted after memory sizing.
+	 */
+	memctl->memc_mptpr = CFG_MPTPR_2BK_8K;
+
+	memctl->memc_mar = 0x00000088;
+
+	/*
+	 * Map controller bank 1 to the SDRAM bank at
+	 * preliminary address - these have to be modified after the
+	 * SDRAM size has been determined.
+	 */
+	memctl->memc_or1 = CFG_OR1_PRELIM;
+	memctl->memc_br1 = CFG_BR1_PRELIM;
+
+	memctl->memc_mamr = CFG_MAMR_8COL & (~(MAMR_PTAE));	/* no refresh yet */
+
+	udelay (200);
+
+	/* perform SDRAM initializsation sequence */
+
+	memctl->memc_mcr = 0x80002105;	/* SDRAM bank 0 */
+	udelay (200);
+	memctl->memc_mcr = 0x80002230;	/* SDRAM bank 0 - execute twice */
+	udelay (200);
+
+	memctl->memc_mamr |= MAMR_PTAE;	/* enable refresh */
+
+	udelay (1000);
+
+	/*
+	 * Check Bank 0 Memory Size for re-configuration
+	 *
+	 * try 8 column mode
+	 */
+	size8 = dram_size (CFG_MAMR_8COL, (ulong *) SDRAM_BASE1_PRELIM,
+					   SDRAM_MAX_SIZE);
+
+	udelay (1000);
+
+	/*
+	 * try 9 column mode
+	 */
+	size9 = dram_size (CFG_MAMR_9COL, (ulong *) SDRAM_BASE1_PRELIM,
+					   SDRAM_MAX_SIZE);
+
+	if (size8 < size9) {		/* leave configuration at 9 columns */
+		size_b0 = size9;
+/*	debug ("SDRAM Bank 0 in 9 column mode: %ld MB\n", size >> 20);	*/
+	} else {					/* back to 8 columns            */
+		size_b0 = size8;
+		memctl->memc_mamr = CFG_MAMR_8COL;
+		udelay (500);
+/*	debug ("SDRAM Bank 0 in 8 column mode: %ld MB\n", size >> 20);	*/
+	}
+
+	udelay (1000);
+
+	/*
+	 * Adjust refresh rate depending on SDRAM type, both banks
+	 * For types > 128 MBit leave it at the current (fast) rate
+	 */
+	if ((size_b0 < 0x02000000)) {
+		/* reduce to 15.6 us (62.4 us / quad) */
+		memctl->memc_mptpr = CFG_MPTPR_2BK_4K;
+		udelay (1000);
+	}
+
+	/*
+	 * Final mapping
+	 */
+
+	memctl->memc_or1 = ((-size_b0) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM;
+	memctl->memc_br1 = (CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V;
+
+	/* adjust refresh rate depending on SDRAM type, one bank */
+	reg = memctl->memc_mptpr;
+	reg >>= 1;		/* reduce to CFG_MPTPR_1BK_8K / _4K */
+	memctl->memc_mptpr = reg;
+
+	udelay (10000);
+
+	return (size_b0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'. Some (not all) hardware errors are detected:
+ * - short between address lines
+ * - short between data lines
+ */
+
+static long int dram_size (long int mamr_value, long int *base,
+						   long int maxsize)
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	volatile long int *addr;
+	ulong cnt, val;
+	ulong save[32];			/* to make test non-destructive */
+	unsigned char i = 0;
+
+	memctl->memc_mamr = mamr_value;
+
+	for (cnt = maxsize / sizeof (long); cnt > 0; cnt >>= 1) {
+		addr = base + cnt;	/* pointer arith! */
+
+		save[i++] = *addr;
+		*addr = ~cnt;
+	}
+
+	/* write 0 to base address */
+	addr = base;
+	save[i] = *addr;
+	*addr = 0;
+
+	/* check at base address */
+	if ((val = *addr) != 0) {
+		*addr = save[i];
+		return (0);
+	}
+
+	for (cnt = 1; cnt <= maxsize / sizeof (long); cnt <<= 1) {
+		addr = base + cnt;	/* pointer arith! */
+		val = *addr;
+		*addr = save[--i];
+
+		if (val != (~cnt)) {
+			return (cnt * sizeof (long));
+		}
+	}
+	return (maxsize);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void r360_pwm_write (uchar reg, uchar val)
+{
+	if (i2c_write (CFG_I2C_PWM_ADDR, reg, 1, &val, 1)) {
+		printf ("Can't write PWM register 0x%02X.\n", reg);
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*-----------------------------------------------------------------------
+ * Keyboard Controller
+ */
+
+/* Number of bytes returned from Keyboard Controller */
+#define KEYBD_KEY_MAX		20				/* maximum key number */
+#define KEYBD_DATALEN		((KEYBD_KEY_MAX + 7) / 8)	/* normal key scan data */
+
+static uchar kbd_addr = CFG_I2C_KBD_ADDR;
+
+static uchar *key_match (uchar *);
+
+int misc_init_r (void)
+{
+	uchar kbd_data[KEYBD_DATALEN];
+	uchar keybd_env[2 * KEYBD_DATALEN + 1];
+	uchar *str;
+	int i;
+
+	i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+
+	i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN);
+
+	for (i = 0; i < KEYBD_DATALEN; ++i) {
+		sprintf (keybd_env + i + i, "%02X", kbd_data[i]);
+	}
+	setenv ("keybd", keybd_env);
+
+	str = strdup (key_match (kbd_data));	/* decode keys */
+
+#ifdef CONFIG_PREBOOT	/* automatically configure "preboot" command on key match */
+	setenv ("preboot", str);	/* set or delete definition */
+#endif /* CONFIG_PREBOOT */
+	if (str != NULL) {
+		free (str);
+	}
+
+	return (0);
+}
+
+/*-----------------------------------------------------------------------
+ * Check if pressed key(s) match magic sequence,
+ * and return the command string associated with that key(s).
+ *
+ * If no key press was decoded, NULL is returned.
+ *
+ * Note: the first character of the argument will be overwritten with
+ * the "magic charcter code" of the decoded key(s), or '\0'.
+ *
+ *
+ * Note: the string points to static environment data and must be
+ * saved before you call any function that modifies the environment.
+ */
+#ifdef CONFIG_PREBOOT
+
+static uchar kbd_magic_prefix[] = "key_magic";
+static uchar kbd_command_prefix[] = "key_cmd";
+
+static uchar *key_match (uchar * kbd_data)
+{
+	uchar compare[KEYBD_DATALEN];
+	uchar magic[sizeof (kbd_magic_prefix) + 1];
+	uchar cmd_name[sizeof (kbd_command_prefix) + 1];
+	uchar key_mask;
+	uchar *str, *nxt, *suffix;
+	uchar *kbd_magic_keys;
+	char *cmd;
+	int i;
+
+	/*
+	 * The following string defines the characters that can pe appended
+	 * to "key_magic" to form the names of environment variables that
+	 * hold "magic" key codes, i. e. such key codes that can cause
+	 * pre-boot actions. If the string is empty (""), then only
+	 * "key_magic" is checked (old behaviour); the string "125" causes
+	 * checks for "key_magic1", "key_magic2" and "key_magic5", etc.
+	 */
+	if ((kbd_magic_keys = getenv ("magic_keys")) == NULL)
+		kbd_magic_keys = "";
+
+	/* loop over all magic keys;
+	 * use '\0' suffix in case of empty string
+	 */
+	for (suffix=kbd_magic_keys; *suffix || suffix==kbd_magic_keys; ++suffix) {
+		sprintf (magic, "%s%c", kbd_magic_prefix, *suffix);
+#if 0
+		printf ("### Check magic \"%s\"\n", magic);
+#endif
+
+		memcpy(compare, kbd_data, KEYBD_DATALEN);
+
+		for (str = getenv(magic); str != NULL; str = (*nxt) ? nxt+1 : nxt) {
+			uchar c;
+
+			c = (uchar) simple_strtoul (str, (char **) (&nxt), 16);
+
+			if (str == nxt)				/* invalid character */
+				break;
+
+			if (c >= KEYBD_KEY_MAX)			/* bad key number */
+				goto next_magic;
+
+			key_mask = 0x80 >> (c % 8);
+
+			if (!(compare[c / 8] & key_mask))	/* key not pressed */
+				goto next_magic;
+
+			compare[c / 8] &= ~key_mask;
+		}
+
+		for (i=0; i<KEYBD_DATALEN; i++)
+			if (compare[i])			/* key(s) not released */
+				goto next_magic;
+
+		sprintf (cmd_name, "%s%c", kbd_command_prefix, *suffix);
+
+		cmd = getenv (cmd_name);
+#if 0
+		printf ("### Set PREBOOT to $(%s): \"%s\"\n",
+			cmd_name, cmd ? cmd : "<<NULL>>");
+#endif
+		*kbd_data = *suffix;
+		return (cmd);
+
+	next_magic:;
+	}
+#if 0
+	printf ("### Delete PREBOOT\n");
+#endif
+	*kbd_data = '\0';
+	return (NULL);
+}
+#endif							/* CONFIG_PREBOOT */
+
+/* Read Keyboard status */
+int do_kbd (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	uchar kbd_data[KEYBD_DATALEN];
+	uchar keybd_env[2 * KEYBD_DATALEN + 1];
+	int i;
+
+	i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+
+	/* Read keys */
+	i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN);
+
+	puts ("Keys:");
+	for (i = 0; i < KEYBD_DATALEN; ++i) {
+		sprintf (keybd_env + i + i, "%02X", kbd_data[i]);
+		printf (" %02x", kbd_data[i]);
+	}
+	putc ('\n');
+	setenv ("keybd", keybd_env);
+	return 0;
+}

+ 884 - 0
board/sacsng/clkinit.c

@@ -0,0 +1,884 @@
+/*
+ * (C) Copyright 2002
+ * Custom IDEAS, Inc. <www.cideas.com>
+ * Jon Diekema <diekema@cideas.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ioports.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+#include <configs/sacsng.h>
+
+#include "clkinit.h"
+
+int Daq64xSampling = 0;
+
+
+void Daq_BRG_Reset(uint brg)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     volatile uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+     *brg_ptr |=  CPM_BRG_RST;
+     *brg_ptr &= ~CPM_BRG_RST;
+}
+
+void Daq_BRG_Disable(uint brg)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     volatile uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+     *brg_ptr &= ~CPM_BRG_EN;
+}
+
+void Daq_BRG_Enable(uint brg)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     volatile uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+     *brg_ptr |= CPM_BRG_EN;
+}
+
+uint Daq_BRG_Get_Div16(uint brg)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+
+     if (*brg_ptr & CPM_BRG_DIV16) {
+         /* DIV16 active */
+         return (TRUE);
+     }
+     else {
+         /* DIV16 inactive */
+         return (FALSE);
+     }
+}
+
+void Daq_BRG_Set_Div16(uint brg, uint div16)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+
+     if (div16) {
+         /* DIV16 active */
+         *brg_ptr |=  CPM_BRG_DIV16;
+     }
+     else {
+         /* DIV16 inactive */
+         *brg_ptr &= ~CPM_BRG_DIV16;
+     }
+}
+
+uint Daq_BRG_Get_Count(uint brg)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     uint *brg_ptr;
+     uint brg_cnt;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+
+     /* Get the clock divider
+      *
+      * Note: A clock divider of 0 means divide by 1,
+      *       therefore we need to add 1 to the count.
+      */
+     brg_cnt = (*brg_ptr & CPM_BRG_CD_MASK) >> CPM_BRG_DIV16_SHIFT;
+     brg_cnt++;
+     if (*brg_ptr & CPM_BRG_DIV16) {
+         brg_cnt *= 16;
+     }
+
+    return (brg_cnt);
+}
+
+void Daq_BRG_Set_Count(uint brg, uint brg_cnt)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+
+     /*
+      * Note: A clock divider of 0 means divide by 1,
+      *	 therefore we need to subtract 1 from the count.
+      */
+     if (brg_cnt > 4096) {
+         /* Prescale = Divide by 16 */
+         *brg_ptr = (*brg_ptr & ~CPM_BRG_CD_MASK)   |
+	     (((brg_cnt / 16) - 1) << CPM_BRG_DIV16_SHIFT);
+	 *brg_ptr |= CPM_BRG_DIV16;
+     }
+     else {
+         /* Prescale = Divide by 1 */
+         *brg_ptr = (*brg_ptr & ~CPM_BRG_CD_MASK) |
+	     ((brg_cnt - 1) << CPM_BRG_DIV16_SHIFT);
+	 *brg_ptr &= ~CPM_BRG_DIV16;
+     }
+}
+
+uint Daq_BRG_Get_ExtClk(uint brg)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+
+     return ((*brg_ptr & CPM_BRG_EXTC_MASK) >> CPM_BRG_EXTC_SHIFT);
+}
+
+char* Daq_BRG_Get_ExtClk_Description(uint brg)
+{
+     uint extc;
+
+     extc = Daq_BRG_Get_ExtClk(brg);
+
+     switch (brg + 1) {
+         case 1:
+         case 2:
+         case 5:
+         case 6: {
+             switch (extc) {
+                 case 0: {
+                     return ("BRG_INT");
+                 }
+                 case 1: {
+                     return ("CLK3");
+                 }
+                 case 2: {
+                     return ("CLK5");
+                 }
+             }
+             return ("??1245??");
+         }
+         case 3:
+         case 4:
+         case 7:
+         case 8: {
+             switch (extc) {
+                 case 0: {
+                     return ("BRG_INT");
+                 }
+                 case 1: {
+                     return ("CLK9");
+                 }
+                 case 2: {
+                     return ("CLK15");
+                 }
+             }
+             return ("??3478??");
+         }
+     }
+     return ("??9876??");
+}
+
+void Daq_BRG_Set_ExtClk(uint brg, uint extc)
+{
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     uint *brg_ptr;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg -= 4;
+     }
+     brg_ptr += brg;
+
+     *brg_ptr = (*brg_ptr & ~CPM_BRG_EXTC_MASK) |
+                ((extc << CPM_BRG_EXTC_SHIFT) & CPM_BRG_EXTC_MASK);
+}
+
+uint Daq_BRG_Rate(uint brg)
+{
+     DECLARE_GLOBAL_DATA_PTR;
+     volatile immap_t *immr = (immap_t *)CFG_IMMR;
+     uint *brg_ptr;
+     uint brg_cnt;
+     uint brg_freq = 0;
+
+     brg_ptr = (uint *)&immr->im_brgc1;
+     brg_ptr += brg;
+     if (brg >= 5) {
+         brg_ptr = (uint *)&immr->im_brgc5;
+         brg_ptr += (brg - 4);
+     }
+
+    brg_cnt = Daq_BRG_Get_Count(brg);
+
+    switch (Daq_BRG_Get_ExtClk(brg)) {
+        case CPM_BRG_EXTC_CLK3:
+        case CPM_BRG_EXTC_CLK5: {
+	    brg_freq = brg_cnt;
+	    break;
+	}
+	default: {
+	    brg_freq = (uint)BRG_INT_CLK / brg_cnt;
+	}
+    }
+    return (brg_freq);
+}
+
+uint Daq_Get_SampleRate(void)
+
+{
+     /*
+      * Read the BRG's to return the actual sample rate.
+      */
+     return (Daq_BRG_Rate(MCLK_BRG) / (MCLK_DIVISOR * SCLK_DIVISOR));
+}
+
+uint Daq_Set_SampleRate(uint rate, uint force)
+
+{
+    DECLARE_GLOBAL_DATA_PTR;
+    uint mclk_divisor; /* MCLK divisor */
+    uint rate_curr;    /* Current sample rate */
+
+    /*
+     * Limit the sample rate to some sensible values.
+     */
+    if (Daq64xSampling) {
+      if (rate > MAX_64x_SAMPLE_RATE) {
+	  rate = MAX_64x_SAMPLE_RATE;
+      }
+    }
+    else {
+      if (rate > MAX_128x_SAMPLE_RATE) {
+	  rate = MAX_128x_SAMPLE_RATE;
+      }
+    }
+    if (rate < MIN_SAMPLE_RATE) {
+        rate = MIN_SAMPLE_RATE;
+    }
+
+    /* Check to see if we are really changing rates */
+    rate_curr = Daq_Get_SampleRate();
+    if ((rate != rate_curr) || force) {
+        /*
+	 * Dynamically adjust MCLK based on the new sample rate.
+	 */
+
+        /* Compute the divisors */
+        mclk_divisor = BRG_INT_CLK / (rate * MCLK_DIVISOR * SCLK_DIVISOR);
+
+	/* Setup MCLK */
+	Daq_BRG_Set_Count(MCLK_BRG, mclk_divisor);
+
+	/* Setup SCLK */
+#       ifdef RUN_SCLK_ON_BRG_INT
+	   Daq_BRG_Set_Count(SCLK_BRG, mclk_divisor * MCLK_DIVISOR);
+#       else
+	   Daq_BRG_Set_Count(SCLK_BRG, MCLK_DIVISOR);
+#       endif
+
+#       ifdef RUN_LRCLK_ON_BRG_INT
+	    Daq_BRG_Set_Count(LRCLK_BRG,
+			      mclk_divisor * MCLK_DIVISOR * SCLK_DIVISOR);
+#       else
+	    Daq_BRG_Set_Count(LRCLK_BRG, SCLK_DIVISOR);
+#       endif
+
+	/* Read the BRG's to return the actual sample rate. */
+	rate_curr = Daq_Get_SampleRate();
+    }
+
+    return (rate_curr);
+}
+
+void Daq_Init_Clocks(int sample_rate, int sample_64x)
+
+{
+    volatile ioport_t *iopa = ioport_addr((immap_t *)CFG_IMMR, 0 /* port A */);
+
+    /* Save off the clocking data */
+    Daq64xSampling = sample_64x;
+
+    /*
+     * Limit the sample rate to some sensible values.
+     */
+    if (Daq64xSampling) {
+      if (sample_rate > MAX_64x_SAMPLE_RATE) {
+	  sample_rate = MAX_64x_SAMPLE_RATE;
+      }
+    }
+    else {
+      if (sample_rate > MAX_128x_SAMPLE_RATE) {
+	  sample_rate = MAX_128x_SAMPLE_RATE;
+      }
+    }
+    if (sample_rate < MIN_SAMPLE_RATE) {
+        sample_rate = MIN_SAMPLE_RATE;
+    }
+
+    /*
+     * Initialize the MCLK/SCLK/LRCLK baud rate generators.
+     */
+
+    /* Setup MCLK */
+    Daq_BRG_Set_ExtClk(MCLK_BRG, CPM_BRG_EXTC_BRGCLK);
+
+    /* Setup SCLK */
+#   ifdef RUN_SCLK_ON_BRG_INT
+        Daq_BRG_Set_ExtClk(SCLK_BRG, CPM_BRG_EXTC_BRGCLK);
+#   else
+        Daq_BRG_Set_ExtClk(SCLK_BRG, CPM_BRG_EXTC_CLK9);
+#   endif
+
+    /* Setup LRCLK */
+#   ifdef RUN_LRCLK_ON_BRG_INT
+        Daq_BRG_Set_ExtClk(LRCLK_BRG, CPM_BRG_EXTC_BRGCLK);
+#   else
+        Daq_BRG_Set_ExtClk(LRCLK_BRG, CPM_BRG_EXTC_CLK5);
+#   endif
+
+    /* Setup the BRG rates */
+    Daq_Set_SampleRate(sample_rate, TRUE);
+
+    /* Enable the clock drivers */
+    iopa->pdat &= ~SLRCLK_EN_MASK;
+}
+
+void Daq_Stop_Clocks(void)
+
+{
+#ifdef TIGHTEN_UP_BRG_TIMING
+    volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+#   ifdef TIGHTEN_UP_BRG_TIMING
+        /*
+         * Reset MCLK BRG
+         */
+#       if (MCLK_BRG == 0)
+            immr->im_brgc1 |=  CPM_BRG_RST;
+            immr->im_brgc1 &= ~CPM_BRG_RST;
+#       endif
+#       if (MCLK_BRG == 1)
+            immr->im_brgc2 |=  CPM_BRG_RST;
+            immr->im_brgc2 &= ~CPM_BRG_RST;
+#       endif
+#       if (MCLK_BRG == 2)
+            immr->im_brgc3 |=  CPM_BRG_RST;
+            immr->im_brgc3 &= ~CPM_BRG_RST;
+#       endif
+#       if (MCLK_BRG == 3)
+            immr->im_brgc4 |=  CPM_BRG_RST;
+            immr->im_brgc4 &= ~CPM_BRG_RST;
+#       endif
+#       if (MCLK_BRG == 4)
+            immr->im_brgc5 |=  CPM_BRG_RST;
+            immr->im_brgc5 &= ~CPM_BRG_RST;
+#       endif
+#       if (MCLK_BRG == 5)
+            immr->im_brgc6 |=  CPM_BRG_RST;
+            immr->im_brgc6 &= ~CPM_BRG_RST;
+#       endif
+#       if (MCLK_BRG == 6)
+            immr->im_brgc7 |=  CPM_BRG_RST;
+            immr->im_brgc7 &= ~CPM_BRG_RST;
+#       endif
+#       if (MCLK_BRG == 7)
+            immr->im_brgc8 |=  CPM_BRG_RST;
+            immr->im_brgc8 &= ~CPM_BRG_RST;
+#       endif
+
+        /*
+         * Reset SCLK BRG
+         */
+#       if (SCLK_BRG == 0)
+            immr->im_brgc1 |=  CPM_BRG_RST;
+            immr->im_brgc1 &= ~CPM_BRG_RST;
+#       endif
+#       if (SCLK_BRG == 1)
+            immr->im_brgc2 |=  CPM_BRG_RST;
+            immr->im_brgc2 &= ~CPM_BRG_RST;
+#       endif
+#       if (SCLK_BRG == 2)
+            immr->im_brgc3 |=  CPM_BRG_RST;
+            immr->im_brgc3 &= ~CPM_BRG_RST;
+#       endif
+#       if (SCLK_BRG == 3)
+            immr->im_brgc4 |=  CPM_BRG_RST;
+            immr->im_brgc4 &= ~CPM_BRG_RST;
+#       endif
+#       if (SCLK_BRG == 4)
+            immr->im_brgc5 |=  CPM_BRG_RST;
+            immr->im_brgc5 &= ~CPM_BRG_RST;
+#       endif
+#       if (SCLK_BRG == 5)
+            immr->im_brgc6 |=  CPM_BRG_RST;
+            immr->im_brgc6 &= ~CPM_BRG_RST;
+#       endif
+#       if (SCLK_BRG == 6)
+            immr->im_brgc7 |=  CPM_BRG_RST;
+            immr->im_brgc7 &= ~CPM_BRG_RST;
+#       endif
+#       if (SCLK_BRG == 7)
+            immr->im_brgc8 |=  CPM_BRG_RST;
+            immr->im_brgc8 &= ~CPM_BRG_RST;
+#       endif
+
+        /*
+         * Reset LRCLK BRG
+         */
+#       if (LRCLK_BRG == 0)
+            immr->im_brgc1 |=  CPM_BRG_RST;
+            immr->im_brgc1 &= ~CPM_BRG_RST;
+#       endif
+#       if (LRCLK_BRG == 1)
+            immr->im_brgc2 |=  CPM_BRG_RST;
+            immr->im_brgc2 &= ~CPM_BRG_RST;
+#       endif
+#       if (LRCLK_BRG == 2)
+            immr->im_brgc3 |=  CPM_BRG_RST;
+            immr->im_brgc3 &= ~CPM_BRG_RST;
+#       endif
+#       if (LRCLK_BRG == 3)
+            immr->im_brgc4 |=  CPM_BRG_RST;
+            immr->im_brgc4 &= ~CPM_BRG_RST;
+#       endif
+#       if (LRCLK_BRG == 4)
+            immr->im_brgc5 |=  CPM_BRG_RST;
+            immr->im_brgc5 &= ~CPM_BRG_RST;
+#       endif
+#       if (LRCLK_BRG == 5)
+            immr->im_brgc6 |=  CPM_BRG_RST;
+            immr->im_brgc6 &= ~CPM_BRG_RST;
+#       endif
+#       if (LRCLK_BRG == 6)
+            immr->im_brgc7 |=  CPM_BRG_RST;
+            immr->im_brgc7 &= ~CPM_BRG_RST;
+#       endif
+#       if (LRCLK_BRG == 7)
+            immr->im_brgc8 |=  CPM_BRG_RST;
+            immr->im_brgc8 &= ~CPM_BRG_RST;
+#       endif
+#   else
+        /*
+         * Reset the clocks
+         */
+        Daq_BRG_Reset(MCLK_BRG);
+        Daq_BRG_Reset(SCLK_BRG);
+        Daq_BRG_Reset(LRCLK_BRG);
+#   endif
+}
+
+void Daq_Start_Clocks(int sample_rate)
+
+{
+#ifdef TIGHTEN_UP_BRG_TIMING
+    volatile immap_t *immr = (immap_t *)CFG_IMMR;
+
+    uint          mclk_brg;       /* MCLK  BRG value */
+    uint          sclk_brg;       /* SCLK  BRG value */
+    uint          lrclk_brg;      /* LRCLK BRG value */
+    uint          temp_lrclk_brg; /* Temporary LRCLK BRG value */
+    uint	  real_lrclk_brg; /* Permanent LRCLK BRG value */
+    unsigned long flags;          /* Interrupt flags */
+    uint          sclk_cnt;       /* SCLK count */
+    uint          delay_cnt;      /* Delay count */
+#endif
+
+#   ifdef TIGHTEN_UP_BRG_TIMING
+        /*
+         * Obtain the enabled MCLK BRG value
+         */
+#       if (MCLK_BRG == 0)
+            mclk_brg = (immr->im_brgc1 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (MCLK_BRG == 1)
+            mclk_brg = (immr->im_brgc2 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (MCLK_BRG == 2)
+            mclk_brg = (immr->im_brgc3 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (MCLK_BRG == 3)
+            mclk_brg = (immr->im_brgc4 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (MCLK_BRG == 4)
+            mclk_brg = (immr->im_brgc5 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (MCLK_BRG == 5)
+            mclk_brg = (immr->im_brgc6 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (MCLK_BRG == 6)
+            mclk_brg = (immr->im_brgc7 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (MCLK_BRG == 7)
+            mclk_brg = (immr->im_brgc8 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+
+        /*
+         * Obtain the enabled SCLK BRG value
+         */
+#       if (SCLK_BRG == 0)
+            sclk_brg = (immr->im_brgc1 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (SCLK_BRG == 1)
+            sclk_brg = (immr->im_brgc2 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (SCLK_BRG == 2)
+            sclk_brg = (immr->im_brgc3 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (SCLK_BRG == 3)
+            sclk_brg = (immr->im_brgc4 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (SCLK_BRG == 4)
+            sclk_brg = (immr->im_brgc5 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (SCLK_BRG == 5)
+            sclk_brg = (immr->im_brgc6 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (SCLK_BRG == 6)
+            sclk_brg = (immr->im_brgc7 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (SCLK_BRG == 7)
+            sclk_brg = (immr->im_brgc8 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+
+        /*
+         * Obtain the enabled LRCLK BRG value
+         */
+#       if (LRCLK_BRG == 0)
+            lrclk_brg = (immr->im_brgc1 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (LRCLK_BRG == 1)
+            lrclk_brg = (immr->im_brgc2 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (LRCLK_BRG == 2)
+            lrclk_brg = (immr->im_brgc3 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (LRCLK_BRG == 3)
+            lrclk_brg = (immr->im_brgc4 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (LRCLK_BRG == 4)
+            lrclk_brg = (immr->im_brgc5 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (LRCLK_BRG == 5)
+            lrclk_brg = (immr->im_brgc6 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (LRCLK_BRG == 6)
+            lrclk_brg = (immr->im_brgc7 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+#       if (LRCLK_BRG == 7)
+            lrclk_brg = (immr->im_brgc8 & ~CPM_BRG_RST) | CPM_BRG_EN;
+#       endif
+
+	/* Save off the real LRCLK value */
+	real_lrclk_brg = lrclk_brg;
+
+	/* Obtain the current SCLK count */
+	sclk_cnt  = ((sclk_brg & 0x00001FFE) >> 1) + 1;
+
+	/* Compute the delay as a function of SCLK count */
+        delay_cnt = ((sclk_cnt / 4) - 2) * 10 + 6;
+	if (sample_rate == 43402) {
+	  delay_cnt++;
+	}
+
+        /* Clear out the count */
+	temp_lrclk_brg = sclk_brg & ~0x00001FFE;
+
+        /* Insert the count */
+	temp_lrclk_brg |= ((delay_cnt + (sclk_cnt / 2) - 1) << 1) &  0x00001FFE;
+
+        /*
+         * Enable MCLK BRG
+         */
+#       if (MCLK_BRG == 0)
+            immr->im_brgc1 = mclk_brg;
+#       endif
+#       if (MCLK_BRG == 1)
+            immr->im_brgc2 = mclk_brg;
+#       endif
+#       if (MCLK_BRG == 2)
+            immr->im_brgc3 = mclk_brg;
+#       endif
+#       if (MCLK_BRG == 3)
+            immr->im_brgc4 = mclk_brg;
+#       endif
+#       if (MCLK_BRG == 4)
+            immr->im_brgc5 = mclk_brg;
+#       endif
+#       if (MCLK_BRG == 5)
+            immr->im_brgc6 = mclk_brg;
+#       endif
+#       if (MCLK_BRG == 6)
+            immr->im_brgc7 = mclk_brg;
+#       endif
+#       if (MCLK_BRG == 7)
+            immr->im_brgc8 = mclk_brg;
+#       endif
+
+        /*
+         * Enable SCLK BRG
+         */
+#       if (SCLK_BRG == 0)
+            immr->im_brgc1 = sclk_brg;
+#       endif
+#       if (SCLK_BRG == 1)
+            immr->im_brgc2 = sclk_brg;
+#       endif
+#       if (SCLK_BRG == 2)
+            immr->im_brgc3 = sclk_brg;
+#       endif
+#       if (SCLK_BRG == 3)
+            immr->im_brgc4 = sclk_brg;
+#       endif
+#       if (SCLK_BRG == 4)
+            immr->im_brgc5 = sclk_brg;
+#       endif
+#       if (SCLK_BRG == 5)
+            immr->im_brgc6 = sclk_brg;
+#       endif
+#       if (SCLK_BRG == 6)
+            immr->im_brgc7 = sclk_brg;
+#       endif
+#       if (SCLK_BRG == 7)
+            immr->im_brgc8 = sclk_brg;
+#       endif
+
+        /*
+         * Enable LRCLK BRG (1st time - temporary)
+         */
+#       if (LRCLK_BRG == 0)
+             immr->im_brgc1 = temp_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 1)
+             immr->im_brgc2 = temp_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 2)
+             immr->im_brgc3 = temp_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 3)
+             immr->im_brgc4 = temp_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 4)
+             immr->im_brgc5 = temp_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 5)
+             immr->im_brgc6 = temp_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 6)
+             immr->im_brgc7 = temp_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 7)
+             immr->im_brgc8 = temp_lrclk_brg;
+#       endif
+
+        /*
+         * Enable LRCLK BRG (2nd time - permanent)
+         */
+#       if (LRCLK_BRG == 0)
+             immr->im_brgc1 = real_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 1)
+             immr->im_brgc2 = real_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 2)
+             immr->im_brgc3 = real_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 3)
+             immr->im_brgc4 = real_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 4)
+             immr->im_brgc5 = real_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 5)
+             immr->im_brgc6 = real_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 6)
+             immr->im_brgc7 = real_lrclk_brg;
+#       endif
+#       if (LRCLK_BRG == 7)
+             immr->im_brgc8 = real_lrclk_brg;
+#       endif
+#   else
+        /*
+         * Enable the clocks
+         */
+        Daq_BRG_Enable(LRCLK_BRG);
+        Daq_BRG_Enable(SCLK_BRG);
+        Daq_BRG_Enable(MCLK_BRG);
+#   endif
+}
+
+void Daq_Display_Clocks(void)
+
+{
+    volatile immap_t *immr = (immap_t *)CFG_IMMR;
+    uint mclk_divisor; /* Detected MCLK divisor */
+    uint sclk_divisor; /* Detected SCLK divisor */
+
+    printf("\nBRG:\n");
+    if (immr->im_brgc4 != 0) {
+        printf("\tbrgc4\t0x%08x @ 0x%08x, %5d count, %d extc, %8s,  MCLK\n",
+	       immr->im_brgc4,
+	       (uint)&(immr->im_brgc4),
+	       Daq_BRG_Get_Count(3),
+	       Daq_BRG_Get_ExtClk(3),
+	       Daq_BRG_Get_ExtClk_Description(3));
+    }
+    if (immr->im_brgc8 != 0) {
+        printf("\tbrgc8\t0x%08x @ 0x%08x, %5d count, %d extc, %8s,  SCLK\n",
+	       immr->im_brgc8,
+	       (uint)&(immr->im_brgc8),
+	       Daq_BRG_Get_Count(7),
+	       Daq_BRG_Get_ExtClk(7),
+	       Daq_BRG_Get_ExtClk_Description(7));
+    }
+    if (immr->im_brgc6 != 0) {
+        printf("\tbrgc6\t0x%08x @ 0x%08x, %5d count, %d extc, %8s,  LRCLK\n",
+	       immr->im_brgc6,
+	       (uint)&(immr->im_brgc6),
+	       Daq_BRG_Get_Count(5),
+	       Daq_BRG_Get_ExtClk(5),
+	       Daq_BRG_Get_ExtClk_Description(5));
+    }
+    if (immr->im_brgc1 != 0) {
+        printf("\tbrgc1\t0x%08x @ 0x%08x, %5d count, %d extc, %8s,  SMC1\n",
+	       immr->im_brgc1,
+	       (uint)&(immr->im_brgc1),
+	       Daq_BRG_Get_Count(0),
+	       Daq_BRG_Get_ExtClk(0),
+	       Daq_BRG_Get_ExtClk_Description(0));
+    }
+    if (immr->im_brgc2 != 0) {
+        printf("\tbrgc2\t0x%08x @ 0x%08x, %5d count, %d extc, %8s,  SMC2\n",
+	       immr->im_brgc2,
+	       (uint)&(immr->im_brgc2),
+	       Daq_BRG_Get_Count(1),
+	       Daq_BRG_Get_ExtClk(1),
+	       Daq_BRG_Get_ExtClk_Description(1));
+    }
+    if (immr->im_brgc3 != 0) {
+        printf("\tbrgc3\t0x%08x @ 0x%08x, %5d count, %d extc, %8s,  SCC1\n",
+	       immr->im_brgc3,
+	       (uint)&(immr->im_brgc3),
+	       Daq_BRG_Get_Count(2),
+	       Daq_BRG_Get_ExtClk(2),
+	       Daq_BRG_Get_ExtClk_Description(2));
+    }
+    if (immr->im_brgc5 != 0) {
+        printf("\tbrgc5\t0x%08x @ 0x%08x, %5d count, %d extc, %8s\n",
+	       immr->im_brgc5,
+	       (uint)&(immr->im_brgc5),
+	       Daq_BRG_Get_Count(4),
+	       Daq_BRG_Get_ExtClk(4),
+	       Daq_BRG_Get_ExtClk_Description(4));
+    }
+    if (immr->im_brgc7 != 0) {
+        printf("\tbrgc7\t0x%08x @ 0x%08x, %5d count, %d extc, %8s\n",
+	       immr->im_brgc7,
+	       (uint)&(immr->im_brgc7),
+	       Daq_BRG_Get_Count(6),
+	       Daq_BRG_Get_ExtClk(6),
+	       Daq_BRG_Get_ExtClk_Description(6));
+    }
+
+#   ifdef RUN_SCLK_ON_BRG_INT
+        mclk_divisor = Daq_BRG_Rate(MCLK_BRG) / Daq_BRG_Rate(SCLK_BRG);
+#   else
+        mclk_divisor = Daq_BRG_Get_Count(SCLK_BRG);
+#   endif
+#   ifdef RUN_LRCLK_ON_BRG_INT
+        sclk_divisor = Daq_BRG_Rate(SCLK_BRG) / Daq_BRG_Rate(LRCLK_BRG);
+#   else
+        sclk_divisor = Daq_BRG_Get_Count(LRCLK_BRG);
+#   endif
+
+    printf("\nADC/DAC Clocking (%d/%d):\n", sclk_divisor, mclk_divisor);
+    printf("\tMCLK  %8d Hz, or %3dx SCLK, or %3dx LRCLK\n",
+	   Daq_BRG_Rate(MCLK_BRG),
+	   mclk_divisor,
+	   mclk_divisor * sclk_divisor);
+#   ifdef RUN_SCLK_ON_BRG_INT
+        printf("\tSCLK  %8d Hz, or %3dx LRCLK\n",
+	       Daq_BRG_Rate(SCLK_BRG),
+	       sclk_divisor);
+#   else
+        printf("\tSCLK  %8d Hz, or %3dx LRCLK\n",
+	       Daq_BRG_Rate(MCLK_BRG) / mclk_divisor,
+	       sclk_divisor);
+#   endif
+#   ifdef RUN_LRCLK_ON_BRG_INT
+        printf("\tLRCLK %8d Hz\n",
+	       Daq_BRG_Rate(LRCLK_BRG));
+#   else
+#       ifdef RUN_SCLK_ON_BRG_INT
+            printf("\tLRCLK %8d Hz\n",
+		   Daq_BRG_Rate(SCLK_BRG) / sclk_divisor);
+#       else
+            printf("\tLRCLK %8d Hz\n",
+		   Daq_BRG_Rate(MCLK_BRG) / (mclk_divisor * sclk_divisor));
+#       endif
+#   endif
+    printf("\n");
+}

+ 218 - 0
board/sacsng/ioconfig.h

@@ -0,0 +1,218 @@
+/*
+ * I/O Port configuration table
+ *
+ * If conf is 1, then that port pin will be configured at boot time
+ * according to the five values podr/pdir/ppar/psor/pdat for that entry
+ */
+
+#ifdef SKIP
+#undef SKIP
+#endif
+
+#ifdef CONF
+#undef CONF
+#endif
+
+#ifdef DIN
+#undef DIN
+#endif
+
+#ifdef DOUT
+#undef DOUT
+#endif
+
+#ifdef GPIO
+#undef GPIO
+#endif
+
+#ifdef SPEC
+#undef SPEC
+#endif
+
+#ifdef ACTV
+#undef ACTV
+#endif
+
+#ifdef OPEN
+#undef OPEN
+#endif
+
+#define SKIP 0  /* SKIP over this port */
+#define CONF 1  /* CONFiguration the port */
+
+#define DIN  0  /* PDIRx 0: Direction IN  */
+#define DOUT 1  /* PDIRx 1: Direction OUT */
+
+#define GPIO 0  /* PPARx 0: General Purpose I/O */
+#define SPEC 1  /* PPARx 1: dedicated to a peripheral function, */
+                /*          i.e. the port has a SPECial use. */
+
+#define ACTV 0  /* PODRx 0: ACTiVely driven as an output */
+#define OPEN 1  /* PODRx 1: OPEN-drain driver */
+
+const iop_conf_t iop_conf_tab[4][32] = {
+
+    /* Port A configuration */
+    {	/*	     conf  ppar  psor  pdir  podr  pdat */
+	/* PA31 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS8*        */
+	/* PA30 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS7*        */
+	/* PA29 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS6*        */
+	/* PA28 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS5*        */
+	/* PA27 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS4*        */
+	/* PA26 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS3*        */
+	/* PA25 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS2*        */
+	/* PA24 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* RODIS1*        */
+	/* PA23 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* ODIS_EN*       */
+	/* PA22 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* STLED2_EN*     */
+	/* PA21 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* STLED1_EN*     */
+	/* PA20 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* PLED3_EN*      */
+	/* PA19 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* PLED2_EN*      */
+        /* PA18 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* PLED1_EN*      */
+	/* PA17 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PA16 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* DAC_RST*       */
+	/* PA15 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* CH34SDATA_PU   */
+        /* PA14 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* CH12SDATA_PU   */
+        /* PA13 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* SLRCLK_EN*     */
+	/* PA12 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_4ACDC*    */
+	/* PA11 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_4TEDS*    */
+	/* PA10 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_4XTDS*    */
+	/* PA9  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_3ACDC*    */
+	/* PA8  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_3TEDS*    */
+	/* PA7  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_3XTDS*    */
+	/* PA6  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_2ACDC*    */
+	/* PA5  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_2TEDS*    */
+	/* PA4  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_2XTDS*    */
+	/* PA3  */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PA2  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_1ACDC*    */
+	/* PA1  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* MTRX_1TEDS*    */
+	/* PA0  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }  /* MTRX_1XTDS*    */
+    },
+
+    /* Port B configuration */
+    {	/*	     conf  ppar  psor  pdir  podr  pdat */
+	/* PB31 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* FCC2 MII_TX_ER */
+	/* PB30 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_RX_DV */
+	/* PB29 */ { CONF, SPEC,   1,  DOUT, ACTV,   0   }, /* FCC2 MII_TX_EN */
+	/* PB28 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_RX_ER */
+	/* PB27 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_COL   */
+	/* PB26 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_CRS   */
+	/* PB25 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* FCC2 MII_TXD3  */
+	/* PB24 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* FCC2 MII_TXD2  */
+	/* PB23 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* FCC2 MII_TXD1  */
+	/* PB22 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* FCC2 MII_TXD0  */
+	/* PB21 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_RXD0  */
+	/* PB20 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_RXD1  */
+	/* PB19 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_RXD2  */
+	/* PB18 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* FCC2 MII_RXD3  */
+	/* PB17 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PB16 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PB15 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PB14 */ { CONF, SPEC,   1,  DIN,  ACTV,   0   }, /* L1RXDC1,   BSDATA_ADC12 */
+	/* PB13 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PB12 */ { CONF, SPEC,   1,  DIN,  ACTV,   0   }, /* L1RSYNCC1, LRCLK  */
+	/* PB11 */ { CONF, SPEC,   1,  DIN,  ACTV,   0   }, /* L1TXDD1,   RSDATA_DAC12 */
+	/* PB10 */ { CONF, SPEC,   1,  DIN,  ACTV,   0   }, /* L1RXDD1,   BSDATA_ADC34 */
+	/* PB9  */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PB8  */ { CONF, SPEC,   1,  DIN,  ACTV,   0   }, /* L1RSYNCD1, LRCLK  */
+	/* PB7  */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PB6  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* XCITE_SHDN     */
+	/* PB5  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* TRIGGER        */
+	/* PB4  */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* ARM            */
+	/* PB3  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }, /* pin doesn't exist */
+	/* PB2  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }, /* pin doesn't exist */
+	/* PB1  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }, /* pin doesn't exist */
+	/* PB0  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }  /* pin doesn't exist */
+    },
+
+    /* Port C */
+    {	/*	      conf ppar  psor  pdir  podr  pdat */
+	/* PC31 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC30 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC29 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* CLK3,  MCLK    */
+	/* PC28 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* TOUT2*         */
+#ifdef QQQ
+	/* PC28 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* TOUT2*         */
+#endif
+	/* PC27 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* CLK5,  SCLK    */
+	/* PC26 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC25 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* CLK7,  SCLK    */
+	/* PC24 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC23 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* CLK9,  MCLK    */
+	/* PC22 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC21 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* BRGO6 (LRCLK)  */
+	/* PC20 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC19 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* CLK13, MII_RXCLK  */
+	/* PC18 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* CLK14, MII_TXCLK  */
+        /* PC17 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* BRGO8 (SCLK)   */
+	/* PC16 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC15 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* SMC2_TX        */
+	/* PC14 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC13 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC12 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* TDM_STRB3      */
+	/* PC11 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC10 */ { CONF, SPEC,   1,  DOUT, ACTV,   0   }, /* TDM_STRB4      */
+	/* PC9  */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* BPDIS_IN3      */
+	/* PC8  */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* BPDIS_IN2      */
+	/* PC7  */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* BPDIS_IN1      */
+	/* PC6  */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PC5  */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* BTST_IN2*      */
+        /* PC4  */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* BTST_IN1*      */
+	/* PC3  */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* MUSH_STAT      */
+	/* PC2  */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* OUTDRV_STAT    */
+	/* PC1  */ { CONF, GPIO,   0,  DOUT, OPEN,   1   }, /* PHY_MDIO       */
+        /* PC0  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* PHY_MDC        */
+    },
+
+    /* Port D */
+    {	/*	      conf ppar  psor  pdir  podr  pdat */
+	/* PD31 */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* SCC1_RX        */
+	/* PD30 */ { CONF, SPEC,   1,  DOUT, ACTV,   0   }, /* SCC1_TX        */
+	/* PD29 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD28 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD27 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD26 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD25 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD24 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD23 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD22 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD21 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD20 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* SPI_ADC_CS*    */
+	/* PD19 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* SPI_DAC_CS*    */
+#if defined(CONFIG_SOFT_SPI)
+	/* PD18 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* SPI_CLK        */
+	/* PD17 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* SPI_MOSI       */
+	/* PD16 */ { CONF, GPIO,   0,  DIN,  ACTV,   0   }, /* SPI_MISO       */
+#else
+	/* PD18 */ { CONF, SPEC,   1,  DOUT, ACTV,   0   }, /* SPI_CLK        */
+	/* PD17 */ { CONF, SPEC,   1,  DOUT, ACTV,   0   }, /* SPI_MOSI       */
+	/* PD16 */ { CONF, SPEC,   1,  DIN,  ACTV,   0   }, /* SPI_MISO       */
+#endif
+#if defined(CONFIG_SOFT_I2C)
+	/* PD15 */ { CONF, GPIO,   0,  DOUT, OPEN,   1   }, /* I2C_SDA        */
+	/* PD14 */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* I2C_SCL        */
+#else
+#if defined(CONFIG_HARD_I2C)
+	/* PD15 */ { CONF, SPEC,   1,  DIN,  OPEN,   0   }, /* I2C_SDA        */
+	/* PD14 */ { CONF, SPEC,   1,  DIN,  OPEN,   0   }, /* I2C_SCL        */
+#else /* normal I/O port pins */
+	/* PD15 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* I2C_SDA        */
+	/* PD14 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* I2C_SCL        */
+#endif
+#endif
+	/* PD13 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* TDM_STRB1      */
+	/* PD12 */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* TDM_STRB2      */
+	/* PD11 */ { CONF, GPIO,   0,  DOUT, ACTV,   0   }, /* N/C            */
+	/* PD10 */ { CONF, SPEC,   1,  DOUT, ACTV,   0   }, /* BRGO4 (MCLK)   */
+	/* PD9  */ { CONF, SPEC,   0,  DOUT, ACTV,   0   }, /* SMC1_TX        */
+	/* PD8  */ { CONF, SPEC,   0,  DIN,  ACTV,   0   }, /* SMC1_RX        */
+	/* PD7  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* N/C            */
+	/* PD6  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* N/C            */
+	/* PD5  */ { CONF, GPIO,   0,  DOUT, ACTV,   1   }, /* N/C            */
+	/* PD4  */ { CONF, SPEC,   1,  DOUT, ACTV,   1   }, /* SMC2_RX        */
+	/* PD3  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }, /* pin doesn't exist */
+	/* PD2  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }, /* pin doesn't exist */
+	/* PD1  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }, /* pin doesn't exist */
+	/* PD0  */ { SKIP, GPIO,   0,  DIN,  ACTV,   0   }  /* pin doesn't exist */
+    }
+};
+

+ 127 - 0
board/sandpoint/sandpoint.c

@@ -0,0 +1,127 @@
+/*
+ * (C) Copyright 2000
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <pci.h>
+
+int checkboard (void)
+{
+	/*TODO: Check processor type */
+
+	puts (	"Board: Sandpoint "
+#ifdef CONFIG_MPC8240
+		"8240"
+#endif
+#ifdef CONFIG_MPC8245
+		"8245"
+#endif
+		" Unity ##Test not implemented yet##\n");
+	return 0;
+}
+
+#if 0 	/* NOT USED */
+int checkflash (void)
+{
+	/* TODO: XXX XXX XXX */
+	printf ("## Test not implemented yet ##\n");
+
+	return (0);
+}
+#endif
+
+long int initdram (int board_type)
+{
+	int		 i, cnt;
+	volatile uchar * base= CFG_SDRAM_BASE;
+	volatile ulong * addr;
+	ulong		 save[32];
+	ulong		 val, ret  = 0;
+
+	for (i=0, cnt=(CFG_MAX_RAM_SIZE / sizeof(long)) >> 1; cnt > 0; cnt >>= 1) {
+		addr = (volatile ulong *)base + cnt;
+		save[i++] = *addr;
+		*addr = ~cnt;
+	}
+
+	addr = (volatile ulong *)base;
+	save[i] = *addr;
+	*addr = 0;
+
+	if (*addr != 0) {
+		*addr = save[i];
+		goto Done;
+	}
+
+	for (cnt = 1; cnt <= CFG_MAX_RAM_SIZE / sizeof(long); cnt <<= 1) {
+		addr = (volatile ulong *)base + cnt;
+		val = *addr;
+		*addr = save[--i];
+		if (val != ~cnt) {
+			ulong new_bank0_end = cnt * sizeof(long) - 1;
+			ulong mear1  = mpc824x_mpc107_getreg(MEAR1);
+			ulong emear1 = mpc824x_mpc107_getreg(EMEAR1);
+			mear1 =  (mear1  & 0xFFFFFF00) |
+			((new_bank0_end & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT);
+			emear1 = (emear1 & 0xFFFFFF00) |
+			((new_bank0_end & MICR_ADDR_MASK) >> MICR_EADDR_SHIFT);
+			mpc824x_mpc107_setreg(MEAR1,  mear1);
+			mpc824x_mpc107_setreg(EMEAR1, emear1);
+
+			ret = cnt * sizeof(long);
+			goto Done;
+		}
+	}
+
+	ret = CFG_MAX_RAM_SIZE;
+Done:
+	return ret;
+}
+
+/*
+ * Initialize PCI Devices, report devices found.
+ */
+#ifndef CONFIG_PCI_PNP
+static struct pci_config_table pci_sandpoint_config_table[] = {
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0x0f, PCI_ANY_ID,
+	  pci_cfgfunc_config_device, { PCI_ENET0_IOADDR,
+				       PCI_ENET0_MEMADDR,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER }},
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0x10, PCI_ANY_ID,
+	  pci_cfgfunc_config_device, { PCI_ENET1_IOADDR,
+				       PCI_ENET1_MEMADDR,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER }},
+	{ }
+};
+#endif
+
+struct pci_controller hose = {
+#ifndef CONFIG_PCI_PNP
+	config_table: pci_sandpoint_config_table,
+#endif
+};
+
+void pci_init(void)
+{
+	pci_mpc824x_init(&hose);
+}

+ 53 - 0
board/shannon/u-boot.lds

@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+        . = 0x00000000;
+
+        . = ALIGN(4);
+	.text      :
+	{
+	  cpu/sa1100/start.o	(.text)
+	  *(.text)
+	}
+
+        . = ALIGN(4);
+        .rodata : { *(.rodata) }
+
+        . = ALIGN(4);
+        .data : { *(.data) }
+
+        . = ALIGN(4);
+        .got : { *(.got) }
+
+	armboot_end_data = .;
+
+        . = ALIGN(4);
+        .bss : { *(.bss) }
+
+	armboot_end = .;
+}

+ 440 - 0
board/siemens/CCM/ccm.c

@@ -0,0 +1,440 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <command.h>
+
+/* ------------------------------------------------------------------------- */
+
+static long int dram_size (long int, long int *, long int);
+void can_driver_enable (void);
+void can_driver_disable (void);
+
+int fpga_init(void);
+
+/* ------------------------------------------------------------------------- */
+
+#define	_NOT_USED_	0xFFFFFFFF
+
+const uint sdram_table[] =
+{
+	/*
+	 * Single Read. (Offset 0 in UPMA RAM)
+	 */
+	0x1F0DFC04, 0xEEAFBC04, 0x11AF7C04, 0xEFBAFC00,
+	0x1FF5FC47, /* last */
+	/*
+	 * SDRAM Initialization (offset 5 in UPMA RAM)
+	 *
+	 * This is no UPM entry point. The following definition uses
+	 * the remaining space to establish an initialization
+	 * sequence, which is executed by a RUN command.
+	 *
+	 */
+		    0x1FF5FC34, 0xEFEABC34, 0x1FB57C35, /* last */
+	/*
+	 * Burst Read. (Offset 8 in UPMA RAM)
+	 */
+	0x1F0DFC04, 0xEEAFBC04, 0x10AF7C04, 0xF0AFFC00,
+	0xF0AFFC00, 0xF1AFFC00, 0xEFBAFC00, 0x1FF5FC47, /* last */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Single Write. (Offset 18 in UPMA RAM)
+	 */
+	0x1F0DFC04, 0xEEABBC00, 0x01B27C04, 0x1FF5FC47, /* last */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Burst Write. (Offset 20 in UPMA RAM)
+	 */
+	0x1F0DFC04, 0xEEABBC00, 0x10A77C00, 0xF0AFFC00,
+	0xF0AFFC00, 0xE1BAFC04, 0x1FF5FC47, /* last */
+					    _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Refresh  (Offset 30 in UPMA RAM)
+	 */
+	0x1FFD7C84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04,
+	0xFFFFFC84, 0xFFFFFC07, /* last */
+				_NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Exception. (Offset 3c in UPMA RAM)
+	 */
+	0x7FFFFC07, /* last */
+		    _NOT_USED_, _NOT_USED_, _NOT_USED_,
+};
+
+/* ------------------------------------------------------------------------- */
+
+
+/*
+ * Check Board Identity:
+ *
+ * Always return 1 (no second DRAM bank since based on TQM8xxL module)
+ */
+
+int checkboard (void)
+{
+    unsigned char *s;
+    unsigned char buf[64];
+
+    s = (getenv_r ("serial#", buf, sizeof(buf)) > 0) ? buf : NULL;
+
+    puts ("Board: Siemens CCM");
+
+    if (s) {
+	    puts (" (");
+
+	    for (; *s; ++s) {
+		if (*s == ' ')
+		    break;
+		putc (*s);
+	    }
+	    putc (')');
+    }
+
+    putc ('\n');
+
+    return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * If Power-On-Reset switch off the Red and Green LED: At reset, the
+ * data direction registers are cleared and must therefore be restored.
+ */
+#define RSR_CSRS	0x08000000
+
+int power_on_reset(void)
+{
+    /* Test Reset Status Register */
+    return ((volatile immap_t *)CFG_IMMR)->im_clkrst.car_rsr & RSR_CSRS ? 0:1;
+}
+
+#define PB_LED_GREEN	0x10000		/* red LED is on PB.15 */
+#define PB_LED_RED	0x20000		/* red LED is on PB.14 */
+#define PB_LEDS		(PB_LED_GREEN | PB_LED_RED);
+
+static void init_leds (void)
+{
+    volatile immap_t *immap  = (immap_t *)CFG_IMMR;
+
+    immap->im_cpm.cp_pbpar &= ~PB_LEDS;
+    immap->im_cpm.cp_pbodr &= ~PB_LEDS;
+    immap->im_cpm.cp_pbdir |=  PB_LEDS;
+    /* Check stop reset status */
+    if (power_on_reset()) {
+	    immap->im_cpm.cp_pbdat &= ~PB_LEDS;
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+
+long int initdram (int board_type)
+{
+    volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immap->im_memctl;
+    long int size8, size9;
+    long int size = 0;
+    unsigned long reg;
+
+    upmconfig(UPMA, (uint *)sdram_table, sizeof(sdram_table)/sizeof(uint));
+
+    /*
+     * Preliminary prescaler for refresh (depends on number of
+     * banks): This value is selected for four cycles every 62.4 us
+     * with two SDRAM banks or four cycles every 31.2 us with one
+     * bank. It will be adjusted after memory sizing.
+     */
+    memctl->memc_mptpr = CFG_MPTPR_2BK_8K;
+
+    memctl->memc_mar  = 0x00000088;
+
+    /*
+     * Map controller banks 2 and 3 to the SDRAM banks 2 and 3 at
+     * preliminary addresses - these have to be modified after the
+     * SDRAM size has been determined.
+     */
+    memctl->memc_or2 = CFG_OR2_PRELIM;
+    memctl->memc_br2 = CFG_BR2_PRELIM;
+
+    memctl->memc_mamr = CFG_MAMR_8COL & (~(MAMR_PTAE)); /* no refresh yet */
+
+    udelay(200);
+
+    /* perform SDRAM initializsation sequence */
+
+    memctl->memc_mcr  = 0x80004105;	/* SDRAM bank 0 */
+    udelay(1);
+    memctl->memc_mcr  = 0x80004230;	/* SDRAM bank 0 - execute twice */
+    udelay(1);
+
+    memctl->memc_mamr |= MAMR_PTAE;	/* enable refresh */
+
+    udelay (1000);
+
+    /*
+     * Check Bank 0 Memory Size for re-configuration
+     *
+     * try 8 column mode
+     */
+    size8 = dram_size (CFG_MAMR_8COL, (ulong *)SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE);
+
+    udelay (1000);
+
+    /*
+     * try 9 column mode
+     */
+    size9 = dram_size (CFG_MAMR_9COL, (ulong *)SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE);
+
+    if (size8 < size9) {		/* leave configuration at 9 columns	*/
+	size = size9;
+/*	debug ("SDRAM in 9 column mode: %ld MB\n", size >> 20);	*/
+    } else {				/* back to 8 columns			*/
+	size = size8;
+	memctl->memc_mamr = CFG_MAMR_8COL;
+	udelay(500);
+/*	debug ("SDRAM in 8 column mode: %ld MB\n", size >> 20);	*/
+    }
+
+    udelay (1000);
+
+    /*
+     * Adjust refresh rate depending on SDRAM type
+     * For types > 128 MBit leave it at the current (fast) rate
+     */
+    if (size < 0x02000000) {
+	/* reduce to 15.6 us (62.4 us / quad) */
+	memctl->memc_mptpr = CFG_MPTPR_2BK_4K;
+	udelay(1000);
+    }
+
+    /*
+     * Final mapping
+     */
+
+    memctl->memc_or2 = ((-size) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM;
+    memctl->memc_br2 = (CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V;
+
+
+    /* adjust refresh rate depending on SDRAM type, one bank */
+    reg = memctl->memc_mptpr;
+    reg >>= 1;	/* reduce to CFG_MPTPR_1BK_8K / _4K */
+    memctl->memc_mptpr = reg;
+
+    can_driver_enable ();
+    init_leds ();
+
+    udelay(10000);
+
+    return (size);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Warning - both the PUMA load mode and the CAN driver use UPM B,
+ * so make sure only one of both is active.
+ */
+void can_driver_enable (void)
+{
+    volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immap->im_memctl;
+
+    /* Initialize MBMR */
+    memctl->memc_mbmr = MAMR_GPL_B4DIS;	/* GPL_B4 ouput line Disable */
+
+    /* Initialize UPMB for CAN: single read */
+    memctl->memc_mdr = 0xFFFFC004;
+    memctl->memc_mcr = 0x0100 | UPMB;
+
+    memctl->memc_mdr = 0x0FFFD004;
+    memctl->memc_mcr = 0x0101 | UPMB;
+
+    memctl->memc_mdr = 0x0FFFC000;
+    memctl->memc_mcr = 0x0102 | UPMB;
+
+    memctl->memc_mdr = 0x3FFFC004;
+    memctl->memc_mcr = 0x0103 | UPMB;
+
+    memctl->memc_mdr = 0xFFFFDC05;
+    memctl->memc_mcr = 0x0104 | UPMB;
+
+    /* Initialize UPMB for CAN: single write */
+    memctl->memc_mdr = 0xFFFCC004;
+    memctl->memc_mcr = 0x0118 | UPMB;
+
+    memctl->memc_mdr = 0xCFFCD004;
+    memctl->memc_mcr = 0x0119 | UPMB;
+
+    memctl->memc_mdr = 0x0FFCC000;
+    memctl->memc_mcr = 0x011A | UPMB;
+
+    memctl->memc_mdr = 0x7FFCC004;
+    memctl->memc_mcr = 0x011B | UPMB;
+
+    memctl->memc_mdr = 0xFFFDCC05;
+    memctl->memc_mcr = 0x011C | UPMB;
+
+    /* Initialize OR3 / BR3 for CAN Bus Controller */
+    memctl->memc_or3 = CFG_OR3_CAN;
+    memctl->memc_br3 = CFG_BR3_CAN;
+}
+
+void can_driver_disable (void)
+{
+    volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immap->im_memctl;
+
+    /* Reset OR3 / BR3 to disable  CAN Bus Controller */
+    memctl->memc_br3 = 0;
+    memctl->memc_or3 = 0;
+
+    memctl->memc_mbmr = 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'. Some (not all) hardware errors are detected:
+ * - short between address lines
+ * - short between data lines
+ */
+
+static long int dram_size (long int mamr_value, long int *base, long int maxsize)
+{
+    volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immap->im_memctl;
+    volatile long int	 *addr;
+    ulong		  cnt, val;
+    ulong		  save[32];	/* to make test non-destructive */
+    unsigned char	  i = 0;
+
+    memctl->memc_mamr = mamr_value;
+
+    for (cnt = maxsize/sizeof(long); cnt > 0; cnt >>= 1) {
+	addr = base + cnt;	/* pointer arith! */
+
+	save[i++] = *addr;
+	*addr = ~cnt;
+    }
+
+    /* write 0 to base address */
+    addr = base;
+    save[i] = *addr;
+    *addr = 0;
+
+    /* check at base address */
+    if ((val = *addr) != 0) {
+	*addr = save[i];
+	return (0);
+    }
+
+    for (cnt = 1; cnt <= maxsize/sizeof(long); cnt <<= 1) {
+	addr = base + cnt;	/* pointer arith! */
+
+	val = *addr;
+	*addr = save[--i];
+
+	if (val != (~cnt)) {
+	    return (cnt * sizeof(long));
+	}
+    }
+    return (maxsize);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#define	ETH_CFG_BITS	(CFG_PB_ETH_CFG1 | CFG_PB_ETH_CFG2  | CFG_PB_ETH_CFG3 )
+
+#define ETH_ALL_BITS	(ETH_CFG_BITS | CFG_PB_ETH_POWERDOWN)
+
+void	reset_phy(void)
+{
+	immap_t *immr = (immap_t *)CFG_IMMR;
+	ulong value;
+
+	/* Configure all needed port pins for GPIO */
+#if CFG_ETH_MDDIS_VALUE
+	immr->im_ioport.iop_padat |=   CFG_PA_ETH_MDDIS;
+#else
+	immr->im_ioport.iop_padat &= ~(CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET);	/* Set low */
+#endif
+	immr->im_ioport.iop_papar &= ~(CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET);	/* GPIO */
+	immr->im_ioport.iop_paodr &= ~(CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET);	/* active output */
+	immr->im_ioport.iop_padir |=   CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET;	/* output */
+
+	immr->im_cpm.cp_pbpar &= ~(ETH_ALL_BITS);	/* GPIO */
+	immr->im_cpm.cp_pbodr &= ~(ETH_ALL_BITS);	/* active output */
+
+	value  = immr->im_cpm.cp_pbdat;
+
+	/* Assert Powerdown and Reset signals */
+	value |=  CFG_PB_ETH_POWERDOWN;
+
+	/* PHY configuration includes MDDIS and CFG1 ... CFG3 */
+#if CFG_ETH_CFG1_VALUE
+	value |=   CFG_PB_ETH_CFG1;
+#else
+	value &= ~(CFG_PB_ETH_CFG1);
+#endif
+#if CFG_ETH_CFG2_VALUE
+	value |=   CFG_PB_ETH_CFG2;
+#else
+	value &= ~(CFG_PB_ETH_CFG2);
+#endif
+#if CFG_ETH_CFG3_VALUE
+	value |=   CFG_PB_ETH_CFG3;
+#else
+	value &= ~(CFG_PB_ETH_CFG3);
+#endif
+
+	/* Drive output signals to initial state */
+	immr->im_cpm.cp_pbdat  = value;
+	immr->im_cpm.cp_pbdir |= ETH_ALL_BITS;
+	udelay (10000);
+
+	/* De-assert Ethernet Powerdown */
+	immr->im_cpm.cp_pbdat &= ~(CFG_PB_ETH_POWERDOWN); /* Enable PHY power */
+	udelay (10000);
+
+	/* de-assert RESET signal of PHY */
+	immr->im_ioport.iop_padat |= CFG_PA_ETH_RESET;
+	udelay (1000);
+}
+
+
+int misc_init_r (void)
+{
+	fpga_init();
+	return (0);
+}
+/* ------------------------------------------------------------------------- */

+ 170 - 0
board/siemens/CCM/fpga_ccm.c

@@ -0,0 +1,170 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <common.h>
+
+#include "../common/fpga.h"
+
+fpga_t fpga_list[] = {
+    { "PUMA" , PUMA_CONF_BASE ,
+      CFG_PC_PUMA_INIT , CFG_PC_PUMA_PROG , CFG_PC_PUMA_DONE  }
+};
+int fpga_count = sizeof(fpga_list) / sizeof(fpga_t);
+
+void can_driver_enable (void);
+void can_driver_disable (void);
+
+#define	_NOT_USED_	0xFFFFFFFF
+
+/*
+ * PUMA access using UPM B
+ */
+const uint puma_table[] =
+{
+	/*
+	 * Single Read. (Offset 0 in UPM RAM)
+	 */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_,
+	/*
+	 * Precharge and MRS
+	 */
+		    _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Burst Read. (Offset 8 in UPM RAM)
+	 */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Single Write. (Offset 18 in UPM RAM)
+	 */
+	0x0FFCF804, 0x0FFCF400, 0x3FFDFC47, /* last */
+					    _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Burst Write. (Offset 20 in UPM RAM)
+	 */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Refresh  (Offset 30 in UPM RAM)
+	 */
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+	/*
+	 * Exception. (Offset 3c in UPM RAM)
+	 */
+	0x7FFFFC07, /* last */
+		    _NOT_USED_, _NOT_USED_, _NOT_USED_,
+};
+
+
+ulong fpga_control (fpga_t* fpga, int cmd)
+{
+    volatile immap_t     *immr  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immr->im_memctl;
+
+    switch (cmd) {
+    case FPGA_INIT_IS_HIGH:
+	immr->im_ioport.iop_pcdir &= ~fpga->init_mask; /* input */
+	return (immr->im_ioport.iop_pcdat & fpga->init_mask) ? 1:0;
+
+    case FPGA_INIT_SET_LOW:
+	immr->im_ioport.iop_pcdir |=  fpga->init_mask; /* output */
+	immr->im_ioport.iop_pcdat &= ~fpga->init_mask;
+	break;
+
+    case FPGA_INIT_SET_HIGH:
+	immr->im_ioport.iop_pcdir |= fpga->init_mask; /* output */
+	immr->im_ioport.iop_pcdat |= fpga->init_mask;
+	break;
+
+    case FPGA_PROG_SET_LOW:
+	immr->im_ioport.iop_pcdat &= ~fpga->prog_mask;
+	break;
+
+    case FPGA_PROG_SET_HIGH:
+	immr->im_ioport.iop_pcdat |= fpga->prog_mask;
+	break;
+
+    case FPGA_DONE_IS_HIGH:
+	return (immr->im_ioport.iop_pcdat & fpga->done_mask) ? 1:0;
+
+    case FPGA_READ_MODE:
+	/* disable FPGA in memory controller */
+	memctl->memc_br4 = 0;
+	memctl->memc_or4 = PUMA_CONF_OR_READ;
+	memctl->memc_br4 = PUMA_CONF_BR_READ;
+
+	/* (re-) enable CAN drivers */
+	can_driver_enable ();
+
+	break;
+
+    case FPGA_LOAD_MODE:
+	/* disable FPGA in memory controller */
+	memctl->memc_br4 = 0;
+	/*
+	 * We must disable the CAN drivers first because
+	 * they use UPM B, too.
+	 */
+	can_driver_disable ();
+	/*
+	 * Configure UPMB for FPGA
+	 */
+	upmconfig(UPMB,(uint *)puma_table,sizeof(puma_table)/sizeof(uint));
+	memctl->memc_or4 = PUMA_CONF_OR_LOAD;
+	memctl->memc_br4 = PUMA_CONF_BR_LOAD;
+	break;
+
+    case FPGA_GET_ID:
+	return *(volatile ulong *)fpga->conf_base;
+
+    case FPGA_INIT_PORTS:
+	immr->im_ioport.iop_pcpar &= ~fpga->init_mask; /* INIT I/O */
+	immr->im_ioport.iop_pcso  &= ~fpga->init_mask;
+	immr->im_ioport.iop_pcdir &= ~fpga->init_mask;
+
+	immr->im_ioport.iop_pcpar &= ~fpga->prog_mask; /* PROG Output */
+	immr->im_ioport.iop_pcso  &= ~fpga->prog_mask;
+	immr->im_ioport.iop_pcdir |=  fpga->prog_mask;
+
+	immr->im_ioport.iop_pcpar &= ~fpga->done_mask; /* DONE Input */
+	immr->im_ioport.iop_pcso  &= ~fpga->done_mask;
+	immr->im_ioport.iop_pcdir &= ~fpga->done_mask;
+
+	break;
+
+    }
+    return 0;
+}
+

+ 104 - 0
board/siemens/SCM/fpga_scm.c

@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <common.h>
+#include <mpc8260.h>
+#include <common.h>
+#include "../common/fpga.h"
+
+fpga_t fpga_list[] = {
+    { "FIOX" , CFG_FIOX_BASE ,
+      CFG_PD_FIOX_INIT , CFG_PD_FIOX_PROG , CFG_PD_FIOX_DONE  },
+    { "FDOHM", CFG_FDOHM_BASE,
+      CFG_PD_FDOHM_INIT, CFG_PD_FDOHM_PROG, CFG_PD_FDOHM_DONE }
+};
+int fpga_count = sizeof(fpga_list) / sizeof(fpga_t);
+
+
+ulong fpga_control (fpga_t* fpga, int cmd)
+{
+    volatile immap_t *immr  = (immap_t *)CFG_IMMR;
+
+    switch (cmd) {
+    case FPGA_INIT_IS_HIGH:
+	immr->im_ioport.iop_pdird &= ~fpga->init_mask; /* input */
+	return (immr->im_ioport.iop_pdatd & fpga->init_mask) ? 1:0;
+
+    case FPGA_INIT_SET_LOW:
+	immr->im_ioport.iop_pdird |=  fpga->init_mask; /* output */
+	immr->im_ioport.iop_pdatd &= ~fpga->init_mask;
+	break;
+
+    case FPGA_INIT_SET_HIGH:
+	immr->im_ioport.iop_pdird |= fpga->init_mask; /* output */
+	immr->im_ioport.iop_pdatd |= fpga->init_mask;
+	break;
+
+    case FPGA_PROG_SET_LOW:
+	immr->im_ioport.iop_pdatd &= ~fpga->prog_mask;
+	break;
+
+    case FPGA_PROG_SET_HIGH:
+	immr->im_ioport.iop_pdatd |= fpga->prog_mask;
+	break;
+
+    case FPGA_DONE_IS_HIGH:
+	return (immr->im_ioport.iop_pdatd & fpga->done_mask) ? 1:0;
+
+    case FPGA_READ_MODE:
+	break;
+
+    case FPGA_LOAD_MODE:
+	break;
+
+    case FPGA_GET_ID:
+	if (fpga->conf_base == CFG_FIOX_BASE) {
+	    ulong ver = *(volatile ulong *)(fpga->conf_base + 0x10);
+	    return ((ver >> 10) & 0xf) + ((ver >> 2) & 0xf0);
+	}
+	else if (fpga->conf_base == CFG_FDOHM_BASE) {
+	    return (*(volatile ushort *)fpga->conf_base) & 0xff;
+	}
+	else {
+	    return *(volatile ulong *)fpga->conf_base;
+	}
+
+    case FPGA_INIT_PORTS:
+	immr->im_ioport.iop_ppard &= ~fpga->init_mask; /* INIT I/O */
+	immr->im_ioport.iop_psord &= ~fpga->init_mask;
+	immr->im_ioport.iop_pdird &= ~fpga->init_mask;
+
+	immr->im_ioport.iop_ppard &= ~fpga->prog_mask; /* PROG Output */
+	immr->im_ioport.iop_psord &= ~fpga->prog_mask;
+	immr->im_ioport.iop_pdird |=  fpga->prog_mask;
+
+	immr->im_ioport.iop_ppard &= ~fpga->done_mask; /* DONE Input */
+	immr->im_ioport.iop_psord &= ~fpga->done_mask;
+	immr->im_ioport.iop_pdird &= ~fpga->done_mask;
+
+	break;
+
+    }
+    return 0;
+}

+ 27 - 0
board/siemens/common/README

@@ -0,0 +1,27 @@
+CCM/SCM-Ergaenzungen fuer U-Boot und Linux:
+-------------------------------------------
+
+Es gibt nun ein gemeinsames Kommando zum Laden der FPGAs:
+
+  => help fpga
+  fpga fpga status [name] - print FPGA status
+  fpga reset  [name] - reset FPGA
+  fpga load [name] addr - load FPGA configuration data
+
+Der Name kann beim CCM-Module auch weggelassen werden.
+Die Laengenangabe und damit "puma_len" ist nicht mehr
+noetig:
+
+  => fpga load puma 40600000
+  FPGA load PUMA: addr 40600000: (00000005)... done
+
+Die MTD-Partitionierung kann nun mittels "bootargs" ueber-
+geben werden:
+
+  => printenv addmtd
+  addmtd=setenv bootargs $(bootargs)
+    mtdparts=0:256k(U-Boot)ro,768k(Kernel),-(Rest)\;1:-(myJFFS2)
+
+Die Portierung auf SMC ist natuerlich noch nicht getestet.
+
+Wolfgang Grandegger (04.06.2002)

+ 358 - 0
board/siemens/common/fpga.c

@@ -0,0 +1,358 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <common.h>
+#include <cmd_boot.h>
+#include <cmd_bsp.h>
+
+#include "fpga.h"
+
+int  power_on_reset(void);
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
+
+
+static int fpga_get_version(fpga_t* fpga, char* name)
+{
+    char vname[12];
+    /*
+     * Net-list string format:
+     *     "vvvvvvvvddddddddn...".
+     *     Version Date    Name
+     *     "0000000322042002PUMA" = PUMA version 3 from 22.04.2002.
+     */
+    if (strlen(name) < (16 + strlen(fpga->name)))
+	goto failure;
+    /* Check FPGA name */
+    if (strcmp(&name[16], fpga->name) != 0)
+	goto failure;
+    /* Get version number */
+    memcpy(vname, name, 8);
+    vname[8] = '\0';
+    return simple_strtoul(vname, NULL, 16);
+
+ failure:
+    printf("Image name %s is invalid\n", name);
+    return -1;
+}
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
+
+static fpga_t* fpga_get(char* fpga_name)
+{
+    char name[FPGA_NAME_LEN];
+    int i;
+
+    if (strlen(fpga_name) >= FPGA_NAME_LEN)
+	goto failure;
+    for (i = 0; i < strlen(fpga_name); i++)
+	name[i] = toupper(fpga_name[i]);
+    name[i] = '\0';
+    for (i = 0; i < fpga_count; i++) {
+	if (strcmp(name, fpga_list[i].name) == 0)
+	    return &fpga_list[i];
+    }
+ failure:
+    printf("FPGA: name %s is invalid\n", fpga_name);
+    return NULL;
+}
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
+
+static void fpga_status (fpga_t* fpga)
+{
+    /* Check state */
+    if (fpga_control(fpga, FPGA_DONE_IS_HIGH))
+	printf ("%s is loaded (%08lx)\n",
+		fpga->name, fpga_control(fpga, FPGA_GET_ID));
+    else
+	printf ("%s is NOT loaded\n", fpga->name);
+}
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
+
+#define FPGA_RESET_TIMEOUT 100 /* = 10 ms */
+
+static int fpga_reset (fpga_t* fpga)
+{
+    int i;
+
+    /* Set PROG to low and wait til INIT goes low */
+    fpga_control(fpga, FPGA_PROG_SET_LOW);
+    for (i = 0; i < FPGA_RESET_TIMEOUT; i++) {
+	udelay (100);
+	if (!fpga_control(fpga, FPGA_INIT_IS_HIGH))
+	    break;
+    }
+    if (i == FPGA_RESET_TIMEOUT)
+	goto failure;
+
+    /* Set PROG to high and wait til INIT goes high */
+    fpga_control(fpga, FPGA_PROG_SET_HIGH);
+    for (i = 0; i < FPGA_RESET_TIMEOUT; i++) {
+	udelay (100);
+	if (fpga_control(fpga, FPGA_INIT_IS_HIGH))
+	    break;
+    }
+    if (i == FPGA_RESET_TIMEOUT)
+	goto failure;
+
+    return 0;
+ failure:
+    return 1;
+}
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
+
+#define FPGA_LOAD_TIMEOUT 100 /* = 10 ms */
+
+static int fpga_load (fpga_t* fpga, ulong addr, int checkall)
+{
+    volatile uchar *fpga_addr = (volatile uchar *)fpga->conf_base;
+    image_header_t hdr;
+    ulong len, checksum;
+    uchar *data = (uchar *)&hdr;
+    char *s, msg[32];
+    int verify, i;
+
+    /*
+     * Check the image header and data of the net-list
+     */
+    memcpy (&hdr, (char *)addr, sizeof(image_header_t));
+
+    if (hdr.ih_magic != IH_MAGIC) {
+	strcpy (msg, "Bad Image Magic Number");
+        goto failure;
+    }
+
+    len  = sizeof(image_header_t);
+
+    checksum = hdr.ih_hcrc;
+    hdr.ih_hcrc = 0;
+
+    if (crc32 (0, data, len) != checksum) {
+	strcpy (msg, "Bad Image Header CRC");
+	goto failure;
+    }
+
+    data = (uchar*)(addr + sizeof(image_header_t));
+    len  = hdr.ih_size;
+
+    s = getenv ("verify");
+    verify = (s && (*s == 'n')) ? 0 : 1;
+    if (verify) {
+	if (crc32 (0, data, len) != hdr.ih_dcrc) {
+	    strcpy (msg, "Bad Image Data CRC");
+	    goto failure;
+	}
+    }
+
+    if (checkall && fpga_get_version(fpga, hdr.ih_name) < 0)
+	return 1;
+
+    /* align length */
+    if (len & 1)
+	++len;
+
+    /*
+     * Reset FPGA and wait for completion
+     */
+    if (fpga_reset(fpga)) {
+	strcpy (msg, "Reset Timeout");
+	goto failure;
+    }
+
+    printf ("(%s)... ", hdr.ih_name);
+    /*
+     * Copy data to FPGA
+     */
+    fpga_control (fpga, FPGA_LOAD_MODE);
+    while (len--) {
+	*fpga_addr = *data++;
+    }
+    fpga_control (fpga, FPGA_READ_MODE);
+
+    /*
+     * Wait for completion and check error status if timeout
+     */
+    for (i = 0; i < FPGA_LOAD_TIMEOUT; i++) {
+	udelay (100);
+	if (fpga_control (fpga, FPGA_DONE_IS_HIGH))
+	    break;
+    }
+    if (i == FPGA_LOAD_TIMEOUT) {
+	if (fpga_control(fpga, FPGA_INIT_IS_HIGH))
+	    strcpy(msg, "Invalid Size");
+	else
+	    strcpy(msg, "CRC Error");
+	goto failure;
+    }
+
+    printf("done\n");
+    return 0;
+
+ failure:
+
+    printf("ERROR: %s\n", msg);
+    return 1;
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_BSP)
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
+
+int do_fpga (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    ulong addr = 0;
+    int i;
+    fpga_t* fpga;
+
+    if (argc < 2)
+	goto failure;
+
+    if (strncmp(argv[1], "stat", 4) == 0) {		/* status */
+	if (argc == 2) {
+	    for (i = 0; i < fpga_count; i++) {
+		fpga_status (&fpga_list[i]);
+	    }
+	}
+	else if (argc == 3) {
+	    if ((fpga = fpga_get(argv[2])) == 0)
+		goto failure;
+	    fpga_status (fpga);
+	}
+	else
+	    goto failure;
+    }
+    else if (strcmp(argv[1],"load") == 0) {		/* load */
+	if (argc == 3 && fpga_count == 1) {
+	    fpga = &fpga_list[0];
+	}
+	else if (argc == 4) {
+	    if ((fpga = fpga_get(argv[2])) == 0)
+		goto failure;
+	}
+	else
+	    goto failure;
+
+	addr = simple_strtoul(argv[argc-1], NULL, 16);
+
+	printf ("FPGA load %s: addr %08lx: ",
+		fpga->name, addr);
+	fpga_load (fpga, addr, 1);
+
+    }
+    else if (strncmp(argv[1], "rese", 4) == 0) {	/* reset */
+	if (argc == 2 && fpga_count == 1) {
+	    fpga = &fpga_list[0];
+	}
+	else if (argc == 3) {
+	    if ((fpga = fpga_get(argv[2])) == 0)
+		goto failure;
+	}
+	else
+	    goto failure;
+
+	printf ("FPGA reset %s: ", fpga->name);
+	if (fpga_reset(fpga))
+	    printf ("ERROR: Timeout\n");
+	else
+	    printf ("done\n");
+    }
+    else
+	goto failure;
+
+    return 0;
+
+ failure:
+    printf ("Usage:\n%s\n", cmdtp->usage);
+    return 1;
+}
+
+#endif	/* CONFIG_COMMANDS & CFG_CMD_BSP */
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
+
+int fpga_init (void)
+{
+    ulong addr;
+    ulong new_id, old_id = 0;
+    image_header_t *hdr;
+    fpga_t* fpga;
+    int do_load, i, j;
+    char name[16], *s;
+
+    /*
+     *  Port setup for FPGA control
+     */
+    for (i = 0; i < fpga_count; i++) {
+	fpga_control(&fpga_list[i], FPGA_INIT_PORTS);
+    }
+
+    /*
+     * Load FPGA(s): a new net-list is loaded if the FPGA is
+     * empty, Power-on-Reset or the old one is not up-to-date
+     */
+    for (i = 0; i < fpga_count; i++) {
+	fpga = &fpga_list[i];
+	printf ("%s:  ", fpga->name);
+
+	for (j = 0; j < strlen(fpga->name); j++)
+	    name[j] = tolower(fpga->name[j]);
+	name[j] = '\0';
+	sprintf(name, "%s_addr", name);
+	addr = 0;
+	if ((s = getenv(name)) != NULL)
+	    addr = simple_strtoul(s, NULL, 16);
+
+	if (!addr) {
+	    printf ("env. variable %s undefined\n", name);
+	    return 1;
+	}
+
+	hdr = (image_header_t *)addr;
+	if ((new_id = fpga_get_version(fpga, hdr->ih_name)) == -1)
+	    return 1;
+
+	do_load = 1;
+
+	if (!power_on_reset() && fpga_control(fpga, FPGA_DONE_IS_HIGH)) {
+	    old_id = fpga_control(fpga, FPGA_GET_ID);
+	    if (new_id == old_id)
+		do_load = 0;
+	}
+
+	if (do_load) {
+	    printf ("loading ");
+	    fpga_load (fpga, addr, 0);
+	} else {
+	    printf ("loaded (%08lx)\n", old_id);
+	}
+    }
+
+    return 0;
+}

+ 54 - 0
board/smdk2400/u-boot.lds

@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+        . = 0x00000000;
+
+        . = ALIGN(4);
+	.text      :
+	{
+	  cpu/arm920t/start.o	(.text)
+	  *(.text)
+	}
+
+        . = ALIGN(4);
+        .rodata : { *(.rodata) }
+
+        . = ALIGN(4);
+        .data : { *(.data) }
+
+        . = ALIGN(4);
+        .got : { *(.got) }
+
+	armboot_end_data = .;
+
+        . = ALIGN(4);
+        .bss : { *(.bss) }
+
+	armboot_end = .;
+}

+ 124 - 0
board/smdk2410/smdk2410.c

@@ -0,0 +1,124 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <s3c2410.h>
+
+/* ------------------------------------------------------------------------- */
+
+#define FCLK_SPEED 1
+
+#if FCLK_SPEED==0		/* Fout = 203MHz, Fin = 12MHz for Audio */
+#define M_MDIV	0xC3
+#define M_PDIV	0x4
+#define M_SDIV	0x1
+#elif FCLK_SPEED==1		/* Fout = 202.8MHz */
+#define M_MDIV	0xA1
+#define M_PDIV	0x3
+#define M_SDIV	0x1
+#endif
+
+#define USB_CLOCK 1
+
+#if USB_CLOCK==0
+#define U_M_MDIV	0xA1
+#define U_M_PDIV	0x3
+#define U_M_SDIV	0x1
+#elif USB_CLOCK==1
+#define U_M_MDIV	0x48
+#define U_M_PDIV	0x3
+#define U_M_SDIV	0x2
+#endif
+
+static inline void delay (unsigned long loops)
+{
+	__asm__ volatile ("1:\n"
+	  "subs %0, %1, #1\n"
+	  "bne 1b":"=r" (loops):"0" (loops));
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	/* to reduce PLL lock time, adjust the LOCKTIME register */
+	rLOCKTIME = 0xFFFFFF;
+
+	/* configure MPLL */
+	rMPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
+
+	/* some delay between MPLL and UPLL */
+	delay (4000);
+
+	/* configure UPLL */
+	rUPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
+
+	/* some delay between MPLL and UPLL */
+	delay (8000);
+
+	/* set up the I/O ports */
+	rGPACON = 0x007FFFFF;
+	rGPBCON = 0x00044555;
+	rGPBUP = 0x000007FF;
+	rGPCCON = 0xAAAAAAAA;
+	rGPCUP = 0x0000FFFF;
+	rGPDCON = 0xAAAAAAAA;
+	rGPDUP = 0x0000FFFF;
+	rGPECON = 0xAAAAAAAA;
+	rGPEUP = 0x0000FFFF;
+	rGPFCON = 0x000055AA;
+	rGPFUP = 0x000000FF;
+	rGPGCON = 0xFF95FFBA;
+	rGPGUP = 0x0000FFFF;
+	rGPHCON = 0x002AFAAA;
+	rGPHUP = 0x000007FF;
+
+	/* arch number of SMDK2410-Board */
+	gd->bd->bi_arch_number = 193;
+
+	/* adress of boot parameters */
+	gd->bd->bi_boot_params = 0x30000100;
+
+	icache_enable();
+	dcache_enable();
+
+	return 0;
+}
+
+int dram_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
+
+	return 0;
+}

+ 569 - 0
board/tqm8xx/flash.c

@@ -0,0 +1,569 @@
+/*
+ * (C) Copyright 2000-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 <common.h>
+#include <mpc8xx.h>
+
+#ifndef	CFG_ENV_ADDR
+#define CFG_ENV_ADDR	(CFG_FLASH_BASE + CFG_ENV_OFFSET)
+#endif
+
+flash_info_t	flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips	*/
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+	volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	unsigned long size_b0, size_b1;
+	int i;
+
+	/* Init: no FLASHes known */
+	for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+		flash_info[i].flash_id = FLASH_UNKNOWN;
+	}
+
+	/* Static FLASH Bank configuration here - FIXME XXX */
+
+	size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+	if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+		printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+			size_b0, size_b0<<20);
+	}
+
+	size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+	if (size_b1 > size_b0) {
+		printf ("## ERROR: "
+			"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+			size_b1, size_b1<<20,
+			size_b0, size_b0<<20
+		);
+		flash_info[0].flash_id	= FLASH_UNKNOWN;
+		flash_info[1].flash_id	= FLASH_UNKNOWN;
+		flash_info[0].sector_count	= -1;
+		flash_info[1].sector_count	= -1;
+		flash_info[0].size		= 0;
+		flash_info[1].size		= 0;
+		return (0);
+	}
+
+	/* Remap FLASH according to real size */
+	memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
+	memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+	/* Re-do sizing to get full correct info */
+	size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+	/* monitor protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CFG_MONITOR_BASE,
+		      CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+		      &flash_info[0]);
+#endif
+
+#ifdef	CFG_ENV_IS_IN_FLASH
+	/* ENV protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CFG_ENV_ADDR,
+		      CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+		      &flash_info[0]);
+#endif
+
+	if (size_b1) {
+		memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+		memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+				    BR_MS_GPCM | BR_V;
+
+		/* Re-do sizing to get full correct info */
+		size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+					  &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+		/* monitor protection ON by default */
+		flash_protect(FLAG_PROTECT_SET,
+			      CFG_MONITOR_BASE,
+			      CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+			      &flash_info[1]);
+#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_SIZE-1,
+			      &flash_info[1]);
+#endif
+	} else {
+		memctl->memc_br1 = 0;		/* invalidate bank */
+
+		flash_info[1].flash_id = FLASH_UNKNOWN;
+		flash_info[1].sector_count = -1;
+	}
+
+	flash_info[0].size = size_b0;
+	flash_info[1].size = size_b1;
+
+	return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+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;
+	default:		printf ("Unknown Vendor ");	break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	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;
+	}
+
+	printf ("  Size: %ld MB in %d Sectors\n",
+		info->size >> 20, info->sector_count);
+
+	printf ("  Sector Start Addresses:");
+	for (i=0; i<info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			printf ("\n   ");
+		printf (" %08lX%s",
+			info->start[i],
+			info->protect[i] ? " (RO)" : "     "
+		);
+	}
+	printf ("\n");
+	return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+	short i;
+	ulong value;
+	ulong base = (ulong)addr;
+
+	/* Write auto select command: read Manufacturer ID */
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+	addr[0x0555] = 0x00900090;
+
+	value = addr[0];
+
+	switch (value) {
+	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;
+		info->sector_count = 0;
+		info->size = 0;
+		return (0);			/* no or unknown flash	*/
+	}
+
+	value = addr[1];			/* device ID		*/
+
+	switch (value) {
+	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 = 71;
+		info->size = 0x00800000;
+		break;				/* => 8 MB		*/
+
+	case AMD_ID_LV320B:
+		info->flash_id += FLASH_AM320B;
+		info->sector_count = 71;
+		info->size = 0x00800000;
+		break;				/* => 8 MB		*/
+	default:
+		info->flash_id = FLASH_UNKNOWN;
+		return (0);			/* => no or unknown flash */
+	}
+
+	/* set up sector start address table */
+	switch (value) {
+	case AMD_ID_LV400B:
+	case AMD_ID_LV800B:
+	case AMD_ID_LV160B:
+		/* set sector offsets for bottom boot block type	*/
+		info->start[0] = base + 0x00000000;
+		info->start[1] = base + 0x00008000;
+		info->start[2] = base + 0x0000C000;
+		info->start[3] = base + 0x00010000;
+		for (i = 4; i < info->sector_count; i++) {
+			info->start[i] = base + (i * 0x00020000) - 0x00060000;
+		}
+		break;
+	case AMD_ID_LV400T:
+	case AMD_ID_LV800T:
+	case AMD_ID_LV160T:
+		/* set sector offsets for top boot block type		*/
+		i = info->sector_count - 1;
+		info->start[i--] = base + info->size - 0x00008000;
+		info->start[i--] = base + info->size - 0x0000C000;
+		info->start[i--] = base + info->size - 0x00010000;
+		for (; i >= 0; i--) {
+			info->start[i] = base + i * 0x00020000;
+		}
+		break;
+	case AMD_ID_LV320B:
+		for (i = 0; i < info->sector_count; i++) {
+			info->start[i] = base;
+			/*
+			 * The first 8 sectors are 8 kB,
+			 * all the other ones  are 64 kB
+			 */
+			base += (i < 8)
+				?  2 * ( 8 << 10)
+				:  2 * (64 << 10);
+		}
+		break;
+	case AMD_ID_LV320T:
+		for (i = 0; i < info->sector_count; i++) {
+			info->start[i] = base;
+			/*
+			 * The last 8 sectors are 8 kB,
+			 * all the other ones  are 64 kB
+			 */
+			base += (i < (info->sector_count - 8))
+				?  2 * (64 << 10)
+				:  2 * ( 8 << 10);
+		}
+		break;
+	default:
+		return (0);
+		break;
+	}
+
+	/* 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 */
+		addr = (volatile unsigned long *)(info->start[i]);
+		info->protect[i] = addr[2] & 1;
+	}
+
+	/*
+	 * Prevent writes to uninitialized FLASH.
+	 */
+	if (info->flash_id != FLASH_UNKNOWN) {
+		addr = (volatile unsigned long *)info->start[0];
+
+		*addr = 0x00F000F0;	/* reset bank */
+	}
+
+	return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int	flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+	vu_long *addr = (vu_long*)(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();
+
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+	addr[0x0555] = 0x00800080;
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+
+	/* Start erase on unprotected sectors */
+	for (sect = s_first; sect<=s_last; sect++) {
+		if (info->protect[sect] == 0) {	/* not protected */
+			addr = (vu_long*)(info->start[sect]);
+			addr[0] = 0x00300030;
+			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 = (vu_long*)(info->start[l_sect]);
+	while ((addr[0] & 0x00800080) != 0x00800080) {
+		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;
+		}
+	}
+
+DONE:
+	/* reset to read mode */
+	addr = (volatile unsigned long *)info->start[0];
+	addr[0] = 0x00F000F0;	/* reset bank */
+
+	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)
+{
+	vu_long *addr = (vu_long*)(info->start[0]);
+	ulong start;
+	int flag;
+
+	/* Check if Flash is (sufficiently) erased */
+	if ((*((vu_long *)dest) & data) != data) {
+		return (2);
+	}
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts();
+
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+	addr[0x0555] = 0x00A000A0;
+
+	*((vu_long *)dest) = data;
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts();
+
+	/* data polling for D7 */
+	start = get_timer (0);
+	while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+			return (1);
+		}
+	}
+	return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */

+ 105 - 0
board/tqm8xx/load_sernum_ethaddr.c

@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2000, 2001, 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 <common.h>
+#include <mpc8xx.h>
+
+/*-----------------------------------------------------------------------
+ * Process Hardware Information Block:
+ *
+ * If we boot on a system fresh from factory, check if the Hardware
+ * Information Block exists and save the information it contains.
+ *
+ * The TQM8xxL / TQM82xx Hardware Information Block is defined as
+ * follows:
+ * - located in first flash bank
+ * - starts at offset 0x0003FFC0
+ * - size 0x00000040
+ *
+ * Internal structure:
+ * - sequence of ASCII character strings
+ * - fields separated by a single space character (0x20)
+ * - last field terminated by NUL character (0x00)
+ * - remaining space filled with NUL characters (0x00)
+ *
+ * Fields in Hardware Information Block:
+ * 1) Module Type
+ * 2) Serial Number
+ * 3) First MAC Address
+ * 4) Number of additional MAC addresses
+ */
+
+void load_sernum_ethaddr (void)
+{
+	unsigned char *hwi;
+	unsigned char  serial [CFG_HWINFO_SIZE];
+	unsigned char  ethaddr[CFG_HWINFO_SIZE];
+	unsigned short ih, is, ie, part;
+
+	hwi = (unsigned char *)(CFG_FLASH_BASE + CFG_HWINFO_OFFSET);
+	ih = is = ie = 0;
+
+	if (*((unsigned long *)hwi) != (unsigned long)CFG_HWINFO_MAGIC) {
+		return;
+	}
+
+	part = 1;
+
+	/* copy serial # / MAC address */
+	while ((hwi[ih] != '\0') && (ih < CFG_HWINFO_SIZE)) {
+		if (hwi[ih] < ' ' || hwi[ih] > '~') { /* ASCII strings! */
+			return;
+		}
+		switch (part) {
+		default:		/* Copy serial # */
+			if (hwi[ih] == ' ') {
+				++part;
+			}
+			serial[is++] = hwi[ih];
+			break;
+		case 3:			/* Copy MAC address */
+			if (hwi[ih] == ' ') {
+				++part;
+				break;
+			}
+			ethaddr[ie++] = hwi[ih];
+			if ((ie % 3) == 2)
+				ethaddr[ie++] = ':';
+			break;
+		}
+		++ih;
+	}
+	serial[is]  = '\0';
+	if (ie && ethaddr[ie-1] == ':')
+		--ie;
+	ethaddr[ie] = '\0';
+
+	/* set serial# and ethaddr if not yet defined */
+	if (getenv("serial#") == NULL) {
+		setenv ("serial#", serial);
+	}
+
+	if (getenv("ethaddr") == NULL) {
+		setenv ("ethaddr", ethaddr);
+	}
+}

+ 44 - 0
board/trab/README.kbd

@@ -0,0 +1,44 @@
+
+The TRAB keyboard implementation is similar to that for LWMON and
+R360MPI boards. The only difference concerns key naming. There are 4
+keys on TRAB: 1, 2, 3, 4.
+
+1) The "kbd" command provides information about the current state of
+   the keys. For example,
+
+	TRAB # kbd
+	Keys: 1 0 1 0
+
+   means that keys 1 and 3 are pressed. The keyboard status is also
+   stored in the "keybd" environment variable. In this example we get
+
+	keybd=1010
+
+2) The "preboot" variable is set according to current environment
+   settings and keys pressed. This is an example:
+
+	TRAB # setenv magic_keys XY
+	TRAB # setenv key_magicX 12
+	TRAB # setenv key_cmdX echo ## Keys 1 + 2 pressed ##\;echo
+	TRAB # setenv key_magicY 13
+	TRAB # setenv key_cmdY echo ## Keys 1 + 3 pressed ##\;echo
+
+   Here "magic_keys=XY" means that the "key_magicX" and "key_magicY"
+   variables will be checked for a match. Each variable "key_magic*"
+   defines a set of keys. In the our example, if keys 1 and 3 are
+   pressed during reset, then "key_magicY" matches, so the "preboot"
+   variable will be set to the contents of "key_cmdY":
+
+	preboot=echo ## Keys 1 + 3 pressed ##;echo
+
+3) The TRAB board has optional modem support. When a certain key
+   combination is pressed on the keyboard at power-on, the firmware
+   performs the necessary initialization of the modem and allows for
+   dial-in. The key combination is specified in the
+   "include/configs/trab.h" file. For example:
+
+	#define        CONFIG_MODEM_KEY_MAGIC  "23"
+
+   means that modem will be initialized if and only if both keys 2, 3
+   are pressed. Note that the format of this string is similar to the
+   format of "key_magic*" environment variables described above.

+ 301 - 0
board/trab/trab.c

@@ -0,0 +1,301 @@
+/*
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@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
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <cmd_bsp.h>
+#include <malloc.h>
+#include <s3c2400.h>
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_MODEM_SUPPORT
+static int key_pressed(void);
+extern void disable_putc(void);
+extern int do_mdm_init; /* defined in common/main.c */
+
+/*
+ * We need a delay of at least 500 us after turning on the VFD clock
+ * before we can read any useful information for the CPLD controlling
+ * the keyboard switches. Let's play safe and wait 5 ms. The problem
+ * is that timers are not available yet, so we use a manually timed
+ * loop.
+ */
+#define KBD_MDELAY	100000	/* 1000 */
+static void mdelay_no_timer (int msec)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int i;
+	int delay = msec * 3;
+
+	for (i = 0; i < delay; i ++) gd->bd->bi_arch_number = 145;
+}
+#endif /* CONFIG_MODEM_SUPPORT */
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init ()
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	/* memory and cpu-speed are setup before relocation */
+#ifdef CONFIG_TRAB_50MHZ
+	/* change the clock to be 50 MHz 1:1:1 */
+	/* MDIV:0x5c PDIV:4 SDIV:2 */
+	rMPLLCON = 0x5c042;
+	rCLKDIVN = 0;
+#else
+	/* change the clock to be 133 MHz 1:2:4 */
+	/* MDIV:0x7d PDIV:4 SDIV:1 */
+	rMPLLCON = 0x7d041;
+	rCLKDIVN = 3;
+#endif
+
+	/* set up the I/O ports */
+	rPACON = 0x3ffff;
+	rPBCON = 0xaaaaaaaa;
+	rPBUP  = 0xffff;
+	/* INPUT nCTS0 nRTS0 TXD[1] TXD[0] RXD[1] RXD[0]	*/
+	/*  00,    10,      10,      10,      10,      10,      10 	*/
+	rPFCON = (2<<0) | (2<<2) | (2<<4) | (2<<6) | (2<<8) | (2<<10);
+#ifdef CONFIG_HWFLOW
+	/* do not pull up RXD0, RXD1, TXD0, TXD1, CTS0, RTS0 */
+	rPFUP  = (1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5);
+#else
+	/* do not pull up RXD0, RXD1, TXD0, TXD1 */
+	rPFUP  = (1<<0) | (1<<1) | (1<<2) | (1<<3);
+#endif
+	rPGCON = 0x0;
+	rPGUP  = 0x0;
+	rOPENCR= 0x0;
+
+	/* arch number of SAMSUNG-Board */
+	/* MACH_TYPE_SMDK2400 */
+	/* XXX this isn't really correct, but keep it for now */
+	gd->bd->bi_arch_number = 145;
+
+	/* adress of boot parameters */
+	gd->bd->bi_boot_params = 0x0c000100;
+
+#ifdef CONFIG_MODEM_SUPPORT
+	/* This stuff is needed to get interrupts on stop-position
+	 * contact events.
+	 * (Copied from the LCD initialization routine.)
+	 */
+	if (rLCDCON1 == 0)
+	{
+		rPCCON = (rPCCON & 0xFFFFFF00)| 0x000000AA;
+		rPDCON = (rPDCON & 0xFFFFFF03)| 0x000000A8;
+#if 0
+		rPDCON = (rPDCON & 0xFFFFFF00)| 0x000000AA;
+#endif
+		rLCDCON2 = 0x000DC000;
+		rLCDCON3 = 0x0051000A;
+		rLCDCON4 = 0x00000001;
+		rLCDCON5 = 0x00000440;
+		rLCDCON1 = 0x00000B75;
+	}
+
+	mdelay_no_timer (KBD_MDELAY);
+
+	if (key_pressed()) {
+		disable_putc();	/* modem doesn't understand banner etc */
+		do_mdm_init = 1;
+	}
+#endif	/* CONFIG_MODEM_SUPPORT */
+
+	return 0;
+}
+
+int dram_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Keyboard Controller
+ */
+
+/* Maximum key number */
+#define KEYBD_KEY_NUM		4
+
+#define KBD_DATA	(((*(volatile ulong *)0x04020000) >> 16) & 0xF)
+
+static uchar *key_match (ulong);
+
+int misc_init_r (void)
+{
+	ulong kbd_data = KBD_DATA;
+	uchar keybd_env[KEYBD_KEY_NUM + 1];
+	uchar *str;
+	int i;
+
+	for (i = 0; i < KEYBD_KEY_NUM; ++i) {
+		keybd_env[i] = '0' + ((kbd_data >> i) & 1);
+	}
+	keybd_env[i] = '\0';
+	debug ("** Setting keybd=\"%s\"\n", keybd_env);
+	setenv ("keybd", keybd_env);
+
+	str = strdup (key_match (kbd_data));	/* decode keys */
+
+#ifdef CONFIG_PREBOOT	/* automatically configure "preboot" command on key match */
+	debug ("** Setting preboot=\"%s\"\n", str);
+	setenv ("preboot", str);	/* set or delete definition */
+#endif /* CONFIG_PREBOOT */
+	if (str != NULL) {
+		free (str);
+	}
+
+	return (0);
+}
+
+#ifdef CONFIG_PREBOOT
+
+static uchar kbd_magic_prefix[] = "key_magic";
+static uchar kbd_command_prefix[] = "key_cmd";
+
+static int compare_magic (ulong kbd_data, uchar *str)
+{
+	uchar key_mask;
+
+	debug ("compare_magic: kbd: %04lx  str: \"%s\"\n",kbd_data,str);
+	for (; *str; str++)
+	{
+		uchar c = *str - '1';
+
+		if (c >= KEYBD_KEY_NUM)		/* bad key number */
+			return -1;
+
+		key_mask = 1 << c;
+
+		if (!(kbd_data & key_mask)) {	/* key not pressed */
+			debug ( "compare_magic: "
+				"kbd: %04lx mask: %04lx - key not pressed\n",
+				kbd_data, key_mask );
+			return -1;
+		}
+
+		kbd_data &= ~key_mask;
+	}
+
+	if (kbd_data) {				/* key(s) not released */
+		debug ( "compare_magic: "
+			"kbd: %04lx - key(s) not released\n", kbd_data);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Check if pressed key(s) match magic sequence,
+ * and return the command string associated with that key(s).
+ *
+ * If no key press was decoded, NULL is returned.
+ *
+ * Note: the first character of the argument will be overwritten with
+ * the "magic charcter code" of the decoded key(s), or '\0'.
+ *
+ *
+ * Note: the string points to static environment data and must be
+ * saved before you call any function that modifies the environment.
+ */
+static uchar *key_match (ulong kbd_data)
+{
+	uchar magic[sizeof (kbd_magic_prefix) + 1];
+	uchar cmd_name[sizeof (kbd_command_prefix) + 1];
+	uchar *suffix;
+	uchar *kbd_magic_keys;
+
+	/*
+	 * The following string defines the characters that can pe appended
+	 * to "key_magic" to form the names of environment variables that
+	 * hold "magic" key codes, i. e. such key codes that can cause
+	 * pre-boot actions. If the string is empty (""), then only
+	 * "key_magic" is checked (old behaviour); the string "125" causes
+	 * checks for "key_magic1", "key_magic2" and "key_magic5", etc.
+	 */
+	if ((kbd_magic_keys = getenv ("magic_keys")) == NULL)
+		kbd_magic_keys = "";
+
+	debug ("key_match: magic_keys=\"%s\"\n", kbd_magic_keys);
+
+	/* loop over all magic keys;
+	 * use '\0' suffix in case of empty string
+	 */
+	for (suffix=kbd_magic_keys; *suffix || suffix==kbd_magic_keys; ++suffix)
+	{
+		sprintf (magic, "%s%c", kbd_magic_prefix, *suffix);
+
+		debug ("key_match: magic=\"%s\"\n",
+			getenv(magic) ? getenv(magic) : "<UNDEFINED>");
+
+		if (compare_magic(kbd_data, getenv(magic)) == 0)
+		{
+			sprintf (cmd_name, "%s%c", kbd_command_prefix, *suffix);
+			debug ("key_match: cmdname %s=\"%s\"\n",
+				cmd_name,
+				getenv (cmd_name) ?
+					getenv (cmd_name) :
+					"<UNDEFINED>");
+			return (getenv (cmd_name));
+		}
+	}
+	debug ("key_match: no match\n");
+	return (NULL);
+}
+#endif							/* CONFIG_PREBOOT */
+
+/* Read Keyboard status */
+int do_kbd (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong kbd_data = KBD_DATA;
+	uchar keybd_env[KEYBD_KEY_NUM + 1];
+	int i;
+
+	puts ("Keys:");
+	for (i = 0; i < KEYBD_KEY_NUM; ++i) {
+		keybd_env[i] = '0' + ((kbd_data >> i) & 1);
+		printf (" %c", keybd_env[i]);
+	}
+	keybd_env[i] = '\0';
+	putc ('\n');
+	setenv ("keybd", keybd_env);
+	return 0;
+}
+
+#ifdef CONFIG_MODEM_SUPPORT
+static int key_pressed(void)
+{
+	return (compare_magic(KBD_DATA, CONFIG_MODEM_KEY_MAGIC) == 0);
+}
+#endif	/* CONFIG_MODEM_SUPPORT */

+ 63 - 0
board/trab/u-boot.lds

@@ -0,0 +1,63 @@
+/*
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+        . = 0x00000000;
+
+        . = ALIGN(4);
+	.text      :
+	{
+	  cpu/arm920t/start.o	(.text)
+	  lib_arm/_udivsi3.o	(.text)
+	  lib_arm/_umodsi3.o	(.text)
+	  lib_generic/zlib.o	(.text)
+	  lib_generic/crc32.o	(.text)
+	  lib_generic/string.o	(.text)
+
+	. = env_offset;
+	common/environment.o	(.ppcenv)
+
+	  *(.text)
+	}
+
+        . = ALIGN(4);
+        .rodata : { *(.rodata) }
+
+        . = ALIGN(4);
+        .data : { *(.data) }
+
+        . = ALIGN(4);
+        .got : { *(.got) }
+
+	armboot_end_data = .;
+
+        . = ALIGN(4);
+        .bss : { *(.bss) }
+
+	armboot_end = .;
+}

+ 414 - 0
board/trab/vfd.c

@@ -0,0 +1,414 @@
+/*
+ * (C) Copyright 2001
+ * 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
+ */
+
+/************************************************************************/
+/* ** DEBUG SETTINGS							*/
+/************************************************************************/
+
+/* #define DEBUG	*/
+
+/************************************************************************/
+/* ** HEADER FILES							*/
+/************************************************************************/
+
+#include <config.h>
+#include <common.h>
+#include <version.h>
+#include <stdarg.h>
+#include <linux/types.h>
+#include <devices.h>
+#include <s3c2400.h>
+
+#ifdef CONFIG_VFD
+
+/************************************************************************/
+/* ** CONFIG STUFF -- should be moved to board config file		*/
+/************************************************************************/
+
+/************************************************************************/
+
+#ifndef PAGE_SIZE
+#define	PAGE_SIZE	4096
+#endif
+
+#define ROT	0x09
+#define BLAU	0x0C
+#define VIOLETT	0X0D
+
+ulong vfdbase;
+ulong frame_buf_size;
+#define frame_buf_offs 4
+
+/* taken from armboot/common/vfd.c */
+ulong         adr_vfd_table[112][18][2][4][2];
+unsigned char bit_vfd_table[112][18][2][4][2];
+
+/*
+ * initialize the values for the VFD-grid-control in the framebuffer
+ */
+void init_grid_ctrl(void)
+{
+	ulong adr, grid_cycle;
+	unsigned int bit, display;
+	unsigned char temp, bit_nr;
+
+	for (adr=vfdbase; adr<=(vfdbase+7168); adr+=4) /*clear frame buffer */
+		(*(volatile ulong*)(adr))=0;
+
+	for(display=0;display<=3;display++)
+	{
+		for(grid_cycle=0;grid_cycle<=55;grid_cycle++)
+		{
+			bit = grid_cycle*256*4+(grid_cycle+200)*4+frame_buf_offs+display;
+ 			/* wrap arround if offset (see manual S3C2400) */
+			if (bit>=frame_buf_size*8)
+				bit = bit-(frame_buf_size*8);
+			adr = vfdbase+(bit/32)*4+(3-(bit%32)/8);
+			bit_nr = bit%8;
+			bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
+			temp=(*(volatile unsigned char*)(adr));
+			temp|=(1<<bit_nr);
+			(*(volatile unsigned char*)(adr))=temp;
+
+			if(grid_cycle<55)
+				bit = grid_cycle*256*4+(grid_cycle+201)*4+frame_buf_offs+display;
+			else
+				bit = grid_cycle*256*4+200*4+frame_buf_offs+display-4; 	/* grid nr. 0 */
+			/* wrap arround if offset (see manual S3C2400) */
+			if (bit>=frame_buf_size*8)
+				bit = bit-(frame_buf_size*8);
+			adr = vfdbase+(bit/32)*4+(3-(bit%32)/8);
+			bit_nr = bit%8;
+			bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
+			temp=(*(volatile unsigned char*)(adr));
+			temp|=(1<<bit_nr);
+			(*(volatile unsigned char*)(adr))=temp;
+		}
+	}
+}
+
+/*
+ *create translation table for getting easy the right position in the
+ *physical framebuffer for some x/y-coordinates of the VFDs
+ */
+void create_vfd_table(void)
+{
+	unsigned int vfd_table[112][18][2][4][2];
+	ulong adr;
+	unsigned int x, y, color, display, entry, pixel, bit_nr;
+
+	/*
+	 * Create translation table for Noritake-T119C-VFD-specific
+	 * organized frame-buffer.
+	 * Created is the number of the bit in the framebuffer (the
+	 * first transferred pixel of each frame is bit 0).
+	 */
+	for(y=0;y<=17;y++)   /* Zeile */
+	{
+		for(x=0;x<=111;x++)  /* Spalten */
+		{
+			/*Display 0 blaue Pixel Eintrag 1 */
+			vfd_table[x][y][0][0][0]=((x%4)*4+y*16+(x/4)*2048);
+			/*Display 0 rote Pixel Eintrag 1 */
+			vfd_table[x][y][1][0][0]=((x%4)*4+y*16+(x/4)*2048+512);
+			if(x<=1)
+			{
+				/*Display 0 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][0][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+1024);
+				/*Display 0 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][0][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+1024);
+			}
+			else
+			{
+				/*Display 0 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][0][1]=((x%4)*4+y*16+((x-2)/4)*2048+1024);
+				/*Display 0 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][0][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+1024);
+			}
+			/*Display 1 blaue Pixel Eintrag 1 */
+			vfd_table[x][y][0][1][0]=((x%4)*4+y*16+(x/4)*2048+1);
+			/*Display 1 rote Pixel Eintrag 1 */
+			vfd_table[x][y][1][1][0]=((x%4)*4+y*16+(x/4)*2048+512+1);
+			if(x<=1)
+			{
+				/*Display 1 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][1][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+1+1024);
+				/*Display 1 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][1][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+1+1024);
+			}
+			else
+			{
+				/*Display 1 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][1][1]=((x%4)*4+y*16+((x-2)/4)*2048+1+1024);
+				/*Display 1 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][1][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+1+1024);
+			}
+			/*Display 2 blaue Pixel Eintrag 1 */
+			vfd_table[x][y][0][2][0]=((x%4)*4+y*16+(x/4)*2048+2);
+			/*Display 2 rote Pixel Eintrag 1 */
+			vfd_table[x][y][1][2][0]=((x%4)*4+y*16+(x/4)*2048+512+2);
+			if(x<=1)
+			{
+				/*Display 2 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][2][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+2+1024);
+				/*Display 2 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][2][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+2+1024);
+			}
+			else
+			{
+				/*Display 2 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][2][1]=((x%4)*4+y*16+((x-2)/4)*2048+2+1024);
+				/*Display 2 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][2][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+2+1024);
+			}
+			/*Display 3 blaue Pixel Eintrag 1 */
+			vfd_table[x][y][0][3][0]=((x%4)*4+y*16+(x/4)*2048+3);
+			/*Display 3 rote Pixel Eintrag 1 */
+			vfd_table[x][y][1][3][0]=((x%4)*4+y*16+(x/4)*2048+512+3);
+			if(x<=1)
+			{
+				/*Display 3 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][3][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+3+1024);
+				/*Display 3 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][3][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+3+1024);
+			}
+			else
+			{
+				/*Display 3 blaue Pixel Eintrag 2 */
+				vfd_table[x][y][0][3][1]=((x%4)*4+y*16+((x-2)/4)*2048+3+1024);
+				/*Display 3 rote Pixel Eintrag 2 */
+				vfd_table[x][y][1][3][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+3+1024);
+			}
+		}
+	}
+
+	/*
+	 * Create translation table for Noritake-T119C-VFD-specific
+	 * organized frame-buffer
+	 * Create table with entries for physical byte adresses and
+	 * bit-number within the byte
+	 * from table with bit-numbers within the total framebuffer
+	 */
+	for(y=0;y<=17;y++)
+	{
+		for(x=0;x<=111;x++)
+		{
+			for(color=0;color<=1;color++)
+			{
+				for(display=0;display<=3;display++)
+				{
+					for(entry=0;entry<=1;entry++)
+					{
+						pixel  = vfd_table[x][y][color][display][entry] + frame_buf_offs;
+						 /*
+						  * wrap arround if offset
+						  * (see manual S3C2400)
+						  */
+						if (pixel>=frame_buf_size*8)
+							pixel = pixel-(frame_buf_size*8);
+						adr    = vfdbase+(pixel/32)*4+(3-(pixel%32)/8);
+						bit_nr = pixel%8;
+						bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
+						adr_vfd_table[x][y][color][display][entry] = adr;
+						bit_vfd_table[x][y][color][display][entry] = bit_nr;
+					}
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Set/clear pixel of the VFDs
+ */
+void set_vfd_pixel(unsigned char x, unsigned char y, unsigned char color, unsigned char display, unsigned char value)
+{
+	ulong adr;
+	unsigned char bit_nr, temp;
+
+	if (value!=0)
+	{
+		/* Pixel-Eintrag Nr. 1 */
+		adr = adr_vfd_table[x][y][color][display][0];
+		/* Pixel-Eintrag Nr. 1 */
+		bit_nr = bit_vfd_table[x][y][color][display][0];
+		temp=(*(volatile unsigned char*)(adr));
+		temp|=1<<bit_nr;
+		(*(volatile unsigned char*)(adr))=temp;
+
+		/* Pixel-Eintrag Nr. 2 */
+		adr = adr_vfd_table[x][y][color][display][1];
+		/* Pixel-Eintrag Nr. 2 */
+		bit_nr = bit_vfd_table[x][y][color][display][1];
+		temp=(*(volatile unsigned char*)(adr));
+		temp|=1<<bit_nr;
+		(*(volatile unsigned char*)(adr))=temp;
+	}
+	else
+	{
+		/* Pixel-Eintrag Nr. 1 */
+		adr = adr_vfd_table[x][y][color][display][0];
+		/* Pixel-Eintrag Nr. 1 */
+		bit_nr = bit_vfd_table[x][y][color][display][0];
+		temp=(*(volatile unsigned char*)(adr));
+		temp&=~(1<<bit_nr);
+		(*(volatile unsigned char*)(adr))=temp;
+
+		/* Pixel-Eintrag Nr. 2 */
+		adr = adr_vfd_table[x][y][color][display][1];
+		/* Pixel-Eintrag Nr. 2 */
+		bit_nr = bit_vfd_table[x][y][color][display][1];
+		temp=(*(volatile unsigned char*)(adr));
+		temp&=~(1<<bit_nr);
+		(*(volatile unsigned char*)(adr))=temp;
+	}
+}
+
+/*
+ * transfer image from BMP-File
+ */
+void transfer_pic(int display, unsigned char *adr, int height, int width)
+{
+	int x, y;
+	unsigned char temp;
+
+	for (; height > 0; height -= 18)
+	{
+		if (height > 18)
+			y = 18;
+		else
+			y = height;
+		for (; y > 0; y--)
+		{
+			for (x = 0; x < width; x += 2)
+			{
+				temp = *adr++;
+				set_vfd_pixel(x, y-1, 0, display, 0);
+				set_vfd_pixel(x, y-1, 1, display, 0);
+				if ((temp >> 4) == BLAU)
+					set_vfd_pixel(x, y-1, 0, display, 1);
+				else if ((temp >> 4) == ROT)
+					set_vfd_pixel(x, y-1, 1, display, 1);
+				else if ((temp >> 4) == VIOLETT)
+				{
+					set_vfd_pixel(x, y-1, 0, display, 1);
+					set_vfd_pixel(x, y-1, 1, display, 1);
+				}
+				set_vfd_pixel(x+1, y-1, 0, display, 0);
+				set_vfd_pixel(x+1, y-1, 1, display, 0);
+				if ((temp & 0x0F) == BLAU)
+					set_vfd_pixel(x+1, y-1, 0, display, 1);
+				else if ((temp & 0x0F) == ROT)
+					set_vfd_pixel(x+1, y-1, 1, display, 1);
+				else if ((temp & 0x0F) == VIOLETT)
+				{
+					set_vfd_pixel(x+1, y-1, 0, display, 1);
+					set_vfd_pixel(x+1, y-1, 1, display, 1);
+				}
+			}
+		}
+		display++;
+		if (display > 3)
+			display = 0;
+	}
+}
+
+/*
+ * initialize LCD-Controller of the S3C2400 for using VFDs
+ */
+int drv_vfd_init(void)
+{
+	ulong palette;
+
+	DECLARE_GLOBAL_DATA_PTR;
+
+	vfdbase = gd->fb_base;
+	create_vfd_table();
+	init_grid_ctrl();
+
+	/*
+	 * Hinweis: Der Framebuffer ist um genau ein Nibble verschoben
+	 * Das erste angezeigte Pixel wird aus dem zweiten Nibble geholt
+	 * das letzte angezeigte Pixel wird aus dem ersten Nibble geholt
+	 * (wrap around)
+	 * see manual S3C2400
+	 */
+	/* frame buffer startadr */
+	rLCDSADDR1 = vfdbase >> 1;
+ 	/* frame buffer endadr */
+	rLCDSADDR2 = (vfdbase + frame_buf_size) >> 1;
+	rLCDSADDR3 = ((256/4));
+
+	/* Port-Pins als LCD-Ausgang */
+	rPCCON =   (rPCCON & 0xFFFFFF00)| 0x000000AA;
+	/* Port-Pins als LCD-Ausgang */
+	rPDCON =   (rPDCON & 0xFFFFFF03)| 0x000000A8;
+#ifdef WITH_VFRAME
+	/* mit VFRAME zum Messen */
+	rPDCON =   (rPDCON & 0xFFFFFF00)| 0x000000AA;
+#endif
+
+	rLCDCON2 = 0x000DC000;
+	rLCDCON3 = 0x0051000A;
+	rLCDCON4 = 0x00000001;
+	rLCDCON5 = 0x00000440;
+	rLCDCON1 = 0x00000B75;
+
+	debug ("LCDSADDR1: %lX\n", rLCDSADDR1);
+	debug ("LCDSADDR2: %lX\n", rLCDSADDR2);
+	debug ("LCDSADDR3: %lX\n", rLCDSADDR3);
+
+	for(palette=0;palette<=15;palette++)
+		(*(volatile unsigned int*)(PALETTE+(palette*4)))=palette;
+	for(palette=16;palette<=255;palette++)
+		(*(volatile unsigned int*)(PALETTE+(palette*4)))=0x00;
+
+	return 0;
+}
+
+/************************************************************************/
+/* ** ROM capable initialization part - needed to reserve FB memory	*/
+/************************************************************************/
+
+/*
+ * This is called early in the system initialization to grab memory
+ * for the VFD controller.
+ *
+ * Note that this is running from ROM, so no write access to global data.
+ */
+ulong vfd_setmem (ulong addr)
+{
+	ulong size;
+
+	/* MAGIC */
+	frame_buf_size = (256*4*56)/8;
+
+	/* Round up to nearest full page */
+	size = (frame_buf_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+
+	debug ("Reserving %ldk for VFD Framebuffer at: %08lx\n", size>>10, addr);
+
+	return (size);
+}
+
+#endif /* CONFIG_VFD */

+ 152 - 0
board/utx8245/utx8245.c

@@ -0,0 +1,152 @@
+/*
+ * (C) Copyright 2001
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
+ *
+ * (C) Copyright 2002
+ * Gregory E. Allen, gallen@arlut.utexas.edu
+ * Matthew E. Karger, karger@arlut.utexas.edu
+ * Applied Research Laboratories, The University of Texas at Austin
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define	SAVE_SZ	32
+
+
+int checkboard(void)
+{
+	ulong busfreq  = get_bus_freq(0);
+	char  buf[32];
+
+	printf("Board: UTX8245 Local Bus at %s MHz\n", strmhz(buf, busfreq));
+	return 0;
+}
+
+
+long int initdram(int board_type)
+{
+#if 1
+	int				i, cnt;
+	volatile uchar	*base =	CFG_SDRAM_BASE;
+	volatile ulong	*addr;
+	ulong			save[SAVE_SZ];
+	ulong			val, ret  = 0;
+
+	for (i=0; i<SAVE_SZ; i++)	{save[i] = 0;}		/* clear table */
+
+	for (i=0, cnt=(CFG_MAX_RAM_SIZE / sizeof(long)) >> 1; cnt > 0; cnt >>= 1)
+	{
+		addr = (volatile ulong *)base + cnt;
+		save[i++] = *addr;
+		*addr = ~cnt;
+	}
+
+	addr = (volatile ulong *)base;
+	save[i] = *addr;
+	*addr = 0;
+
+	if (*addr != 0)
+	{
+		*addr = save[i];
+		goto Done;
+	}
+
+	for (cnt = 1; cnt < CFG_MAX_RAM_SIZE / sizeof(long); cnt <<= 1)
+	{
+		addr = (volatile ulong *)base + cnt;
+		val = *addr;
+		*addr = save[--i];
+		if (val != ~cnt)
+		{
+			ulong new_bank0_end = cnt * sizeof(long) - 1;
+			ulong mear1  = mpc824x_mpc107_getreg(MEAR1);
+			ulong emear1 = mpc824x_mpc107_getreg(EMEAR1);
+			mear1 =  (mear1  & 0xFFFFFF00) |
+			  ((new_bank0_end & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT);
+			emear1 = (emear1 & 0xFFFFFF00) |
+			  ((new_bank0_end & MICR_ADDR_MASK) >> MICR_EADDR_SHIFT);
+			mpc824x_mpc107_setreg(MEAR1,  mear1);
+			mpc824x_mpc107_setreg(EMEAR1, emear1);
+
+			ret = cnt * sizeof(long);
+			goto Done;
+		}
+	}
+
+	ret = CFG_MAX_RAM_SIZE;
+Done:
+	return ret;
+#else
+	return (CFG_MAX_RAM_SIZE);
+#endif
+
+}
+
+
+/*
+ * Initialize PCI Devices, report devices found.
+ */
+
+static struct pci_config_table pci_utx8245_config_table[] = {
+#ifndef CONFIG_PCI_PNP
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  pci_cfgfunc_config_device, { PCI_ENET0_IOADDR,
+				       PCI_ENET0_MEMADDR,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER }},
+	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  pci_cfgfunc_config_device, { PCI_FIREWIRE_IOADDR,
+				       PCI_FIREWIRE_MEMADDR,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER }},
+#endif /*CONFIG_PCI_PNP*/
+	{ }
+};
+
+
+static void pci_utx8245_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+	if (PCI_DEV(dev) == 11)
+		/* assign serial interrupt line 9 (int25) to FireWire */
+		pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, 25);
+
+	else if (PCI_DEV(dev) == 12)
+		/* assign serial interrupt line 8 (int24) to Ethernet */
+		pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, 24);
+}
+
+static struct pci_controller utx8245_hose = {
+#ifndef CONFIG_PCI_PNP
+	config_table: pci_utx8245_config_table,
+	fixup_irq: pci_utx8245_fixup_irq,
+	write_byte: pci_hose_write_config_byte
+#endif /*CONFIG_PCI_PNP*/
+};
+
+void pci_init (void)
+{
+	pci_mpc824x_init(&utx8245_hose);
+
+	icache_enable();
+}
+

+ 941 - 0
board/w7o/flash.c

@@ -0,0 +1,941 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *  Based on code by:
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+#include <watchdog.h>
+
+flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips    */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word8(flash_info_t *info, ulong dest, ulong data);
+static int write_word32 (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+    int i;
+    unsigned long size_b0, base_b0;
+    unsigned long size_b1, base_b1;
+
+    /* Init: no FLASHes known */
+    for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+        flash_info[i].flash_id = FLASH_UNKNOWN;
+    }
+
+    /* Get Size of Boot and Main Flashes */
+    size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+    if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+        printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+            size_b0, size_b0<<20);
+        return 0;
+    }
+    size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+    if (flash_info[1].flash_id == FLASH_UNKNOWN) {
+        printf ("## Unknown FLASH on Bank 1 - Size = 0x%08lx = %ld MB\n",
+            size_b1, size_b1<<20);
+        return 0;
+    }
+
+    /* Calculate base addresses */
+    base_b0 = -size_b0;
+    base_b1 = -size_b1;
+
+    /* Setup offsets for Boot Flash */
+    flash_get_offsets (base_b0, &flash_info[0]);
+
+    /* Protect board level data */
+    (void)flash_protect(FLAG_PROTECT_SET,
+			base_b0,
+			flash_info[0].start[1] - 1,
+			&flash_info[0]);
+
+
+    /* Monitor protection ON by default */
+    (void)flash_protect(FLAG_PROTECT_SET,
+                        base_b0 + size_b0 - CFG_MONITOR_LEN,
+                        base_b0 + size_b0 - 1,
+                        &flash_info[0]);
+
+    /* Protect the FPGA image */
+    (void)flash_protect(FLAG_PROTECT_SET,
+                        FLASH_BASE1_PRELIM,
+                        FLASH_BASE1_PRELIM + CFG_FPGA_IMAGE_LEN - 1,
+                        &flash_info[1]);
+
+    /* Protect the default boot image */
+    (void)flash_protect(FLAG_PROTECT_SET,
+                        FLASH_BASE1_PRELIM + CFG_FPGA_IMAGE_LEN,
+                        FLASH_BASE1_PRELIM + CFG_FPGA_IMAGE_LEN + 0x600000 - 1,
+                        &flash_info[1]);
+
+    /* Setup offsets for Main Flash */
+    flash_get_offsets (FLASH_BASE1_PRELIM, &flash_info[1]);
+
+    return (size_b0 + size_b1);
+} /* end flash_init() */
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+    int i;
+
+    /* set up sector start address table - FOR BOOT ROM ONLY!!! */
+    if ((info->flash_id & FLASH_TYPEMASK)  == FLASH_AM040) {
+        for (i = 0; i < info->sector_count; i++)
+            info->start[i] = base + (i * 0x00010000);
+    }
+} /* end flash_get_offsets() */
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i;
+    int k;
+    int size;
+    int erased;
+    volatile unsigned long *flash;
+
+    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 ("1 x AMD ");    break;
+	case FLASH_MAN_STM:	printf ("1 x STM ");	break;
+        case FLASH_MAN_INTEL:   printf ("2 x Intel ");  break;
+        default:                printf ("Unknown Vendor ");
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+        case FLASH_AM040:
+	    if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
+            	printf ("AM29LV040 (4096 Kbit, uniform sector size)\n");
+	    else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM)
+            	printf ("M29W040B (4096 Kbit, uniform block size)\n");
+	    else
+            	printf ("UNKNOWN 29x040x (4096 Kbit, uniform sector size)\n");
+            break;
+        case FLASH_28F320J3A:
+            printf ("28F320J3A (32 Mbit = 128K x 32)\n");
+            break;
+        case FLASH_28F640J3A:
+            printf ("28F640J3A (64 Mbit = 128K x 64)\n");
+            break;
+        case FLASH_28F128J3A:
+            printf ("28F128J3A (128 Mbit = 128K x 128)\n");
+            break;
+        default:
+            printf ("Unknown Chip Type\n");
+    }
+
+    if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM) {
+    	printf ("  Size: %ld KB in %d Blocks\n",
+        	info->size >> 10, info->sector_count);
+    } else {
+    	printf ("  Size: %ld KB in %d Sectors\n",
+        	info->size >> 10, info->sector_count);
+    }
+
+    printf ("  Sector Start Addresses:");
+    for (i=0; i<info->sector_count; ++i) {
+        /*
+         * Check if whole sector is erased
+         */
+        if (i != (info->sector_count-1))
+            size = info->start[i+1] - info->start[i];
+        else
+            size = info->start[0] + info->size - info->start[i];
+        erased = 1;
+        flash = (volatile unsigned long *)info->start[i];
+        size = size >> 2;        /* divide by 4 for longword access */
+        for (k=0; k<size; k++)
+        {
+            if (*flash++ != 0xffffffff)
+            {
+                erased = 0;
+                break;
+            }
+        }
+
+        if ((i % 5) == 0)
+            printf ("\n   ");
+        printf (" %08lX%s%s",
+            info->start[i],
+            erased ? " E" : "  ",
+            info->protect[i] ? "RO " : "   "
+        );
+    }
+    printf ("\n");
+} /* end flash_print_info() */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+    short i;
+    ulong base = (ulong)addr;
+
+    /* Setup default type */
+    info->flash_id = FLASH_UNKNOWN;
+    info->sector_count =0;
+    info->size = 0;
+
+    /* Test for Boot Flash */
+    if (base == FLASH_BASE0_PRELIM) {
+        unsigned char value;
+        volatile unsigned char * addr2 = (unsigned char *)addr;
+
+        /* Write auto select command: read Manufacturer ID */
+        *(addr2 + 0x555) = 0xaa;
+        *(addr2 + 0x2aa) = 0x55;
+        *(addr2 + 0x555) = 0x90;
+
+        /* Manufacture ID */
+        value = *addr2;
+        switch (value) {
+            case (unsigned char)AMD_MANUFACT:
+                info->flash_id = FLASH_MAN_AMD;
+                break;
+	    case (unsigned char)STM_MANUFACT:
+		info->flash_id = FLASH_MAN_STM;
+		break;
+            default:
+                *addr2 = 0xf0;              /* no or unknown flash  */
+                return 0;
+        }
+
+        /* Device ID */
+        value = *(addr2 + 1);
+        switch (value) {
+            case (unsigned char)AMD_ID_LV040B:
+	    case (unsigned char)STM_ID_29W040B:
+                info->flash_id += FLASH_AM040;
+                info->sector_count = 8;
+                info->size = 0x00080000;
+                break;                       /* => 512Kb */
+            default:
+                *addr2 = 0xf0;               /* => no or unknown flash */
+                return 0;
+        }
+    }
+    else { /* MAIN Flash */
+        unsigned long value;
+        volatile unsigned long * addr2 = (unsigned long *)addr;
+
+        /* Write auto select command: read Manufacturer ID */
+        *addr2 = 0x90909090;
+
+        /* Manufacture ID */
+        value = *addr2;
+        switch (value) {
+            case (unsigned long)INTEL_MANUFACT:
+                info->flash_id = FLASH_MAN_INTEL;
+                break;
+            default:
+                *addr2 = 0xff;              /* no or unknown flash  */
+                return 0;
+        }
+
+        /* Device ID - This shit is interleaved... */
+        value = *(addr2 + 1);
+        switch (value) {
+            case (unsigned long)INTEL_ID_28F320J3A:
+                info->flash_id += FLASH_28F320J3A;
+                info->sector_count = 32;
+                info->size = 0x00400000 * 2;
+                break;                       /* => 2 X 4 MB */
+            case (unsigned long)INTEL_ID_28F640J3A:
+                info->flash_id += FLASH_28F640J3A;
+                info->sector_count = 64;
+                info->size = 0x00800000 * 2;
+                break;                       /* => 2 X 8 MB */
+            case (unsigned long)INTEL_ID_28F128J3A:
+                info->flash_id += FLASH_28F128J3A;
+                info->sector_count = 128;
+                info->size = 0x01000000 * 2;
+                break;                       /* => 2 X 16 MB */
+            default:
+                *addr2 = 0xff;               /* => no or unknown flash */
+        }
+    }
+
+    /* Make sure we don't exceed CFG_MAX_FLASH_SECT */
+    if (info->sector_count > CFG_MAX_FLASH_SECT) {
+        printf ("** ERROR: sector count %d > max (%d) **\n",
+                info->sector_count, CFG_MAX_FLASH_SECT);
+        info->sector_count = CFG_MAX_FLASH_SECT;
+    }
+
+    /* set up sector start address table */
+    switch (info->flash_id & FLASH_TYPEMASK) {
+        case FLASH_AM040:
+            for (i = 0; i < info->sector_count; i++)
+                info->start[i] = base + (i * 0x00010000);
+            break;
+        case FLASH_28F320J3A:
+        case FLASH_28F640J3A:
+        case FLASH_28F128J3A:
+            for (i = 0; i < info->sector_count; i++)
+                info->start[i] = base + (i * 0x00020000 * 2); /* 2 Banks */
+            break;
+    }
+
+    /* Test for Boot Flash */
+    if (base == FLASH_BASE0_PRELIM) {
+        volatile unsigned char *addr2;
+        /* check for protected sectors */
+        for (i = 0; i < info->sector_count; i++) {
+            /* read sector protection at sector address, (AX .. A0) = 0x02 */
+            /* D0 = 1 if protected */
+            addr2 = (volatile unsigned char *)(info->start[i]);
+            info->protect[i] = *(addr2 + 2) & 1;
+        }
+
+        /* Restore read mode */
+        *(unsigned char *)base = 0xF0;       /* Reset NORMAL Flash */
+    }
+    else { /* Main Flash */
+        volatile unsigned long *addr2;
+        /* check for protected sectors */
+        for (i = 0; i < info->sector_count; i++) {
+            /* read sector protection at sector address, (AX .. A0) = 0x02 */
+            /* D0 = 1 if protected */
+            addr2 = (volatile unsigned long *)(info->start[i]);
+            info->protect[i] = *(addr2 + 2) & 0x1;
+        }
+
+        /* Restore read mode */
+        *(unsigned long *)base = 0xFFFFFFFF; /* Reset  Flash */
+    }
+
+    return (info->size);
+} /* end flash_get_size() */
+
+/*-----------------------------------------------------------------------
+ */
+
+static int wait_for_DQ7(ulong addr, uchar cmp_val, ulong tout)
+{
+    int i;
+
+    volatile uchar *vaddr =  (uchar *)addr;
+
+    /* Loop X times */
+    for (i = 1; i <= (100 * tout); i++) {    /* Wait up to tout ms */
+        udelay(10);
+        /* Pause 10 us */
+
+        /* Check for completion */
+        if ((vaddr[0] & 0x80) == (cmp_val & 0x80)) {
+            return 0;
+        }
+
+        /* KEEP THE LUSER HAPPY - Print a dot every 1.1 seconds */
+        if (!(i % 110000))
+            putc('.');
+
+        /* Kick the dog if needed */
+        WATCHDOG_RESET();
+    }
+
+    return 1;
+} /* wait_for_DQ7() */
+
+/*-----------------------------------------------------------------------
+ */
+
+static int flash_erase8(flash_info_t *info, int s_first, int s_last)
+{
+    int tcode, rcode = 0;
+    volatile uchar *addr = (uchar *)(info->start[0]);
+    volatile uchar *sector_addr;
+    int flag, prot, sect;
+
+    /* Validate arguments */
+    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;
+    }
+
+    /* Check for KNOWN flash type */
+    if (info->flash_id == FLASH_UNKNOWN) {
+        printf ("Can't erase unknown flash type - aborted\n");
+        return 1;
+    }
+
+    /* Check for protected sectors */
+    prot = 0;
+    for (sect = s_first; sect <= s_last; ++sect) {
+        if (info->protect[sect])
+            prot++;
+    }
+    if (prot)
+        printf ("- Warning: %d protected sectors will not be erased!\n", prot);
+    else
+        printf ("\n");
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect <= s_last; sect++) {
+        if (info->protect[sect] == 0) {      /* not protected */
+            sector_addr = (uchar *)(info->start[sect]);
+
+    		if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM)
+		    printf("Erasing block %p\n", sector_addr);
+		else
+		    printf("Erasing sector %p\n", sector_addr);
+
+            /* Disable interrupts which might cause Flash to timeout */
+            flag = disable_interrupts();
+
+            *(addr + 0x555) = (uchar)0xAA;
+            *(addr + 0x2aa) = (uchar)0x55;
+            *(addr + 0x555) = (uchar)0x80;
+            *(addr + 0x555) = (uchar)0xAA;
+            *(addr + 0x2aa) = (uchar)0x55;
+            *sector_addr = (uchar)0x30;      /* sector erase */
+
+            /*
+             * Wait for each sector to complete, it's more
+             * reliable.  According to AMD Spec, you must
+             * issue all erase commands within a specified
+             * timeout.  This has been seen to fail, especially
+             * if printf()s are included (for debug)!!
+             * Takes up to 6 seconds.
+             */
+            tcode  = wait_for_DQ7((ulong)sector_addr, 0x80, 6000);
+
+            /* re-enable interrupts if necessary */
+            if (flag)
+                enable_interrupts();
+
+            /* Make sure we didn't timeout */
+            if (tcode) {
+                printf ("Timeout\n");
+                rcode = 1;
+            }
+        }
+    }
+
+    /* wait at least 80us - let's wait 1 ms */
+    udelay (1000);
+
+    /* reset to read mode */
+    addr = (uchar *)info->start[0];
+    *addr = (uchar)0xF0;                     /* reset bank */
+
+    printf (" done\n");
+    return rcode;
+} /* end flash_erase8() */
+
+static int flash_erase32(flash_info_t *info, int s_first, int s_last)
+{
+    int flag, sect;
+    ulong start, now, last;
+    int prot = 0;
+
+    /* Validate arguments */
+    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;
+    }
+
+    /* Check for KNOWN flash type */
+    if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
+        printf ("Can erase only Intel flash types - aborted\n");
+        return 1;
+    }
+
+    /* Check for protected sectors */
+    for (sect = s_first; sect <= s_last; ++sect) {
+        if (info->protect[sect])
+            prot++;
+    }
+    if (prot)
+        printf ("- Warning: %d protected sectors will not be erased!\n", prot);
+    else
+        printf ("\n");
+
+    start = get_timer (0);
+    last  = start;
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect <= s_last; sect++) {
+        WATCHDOG_RESET();
+        if (info->protect[sect] == 0) {      /* not protected */
+            vu_long *addr = (vu_long *)(info->start[sect]);
+            unsigned long status;
+
+            /* Disable interrupts which might cause a timeout here */
+            flag = disable_interrupts();
+
+            *addr = 0x00500050;              /* clear status register */
+            *addr = 0x00200020;              /* erase setup */
+            *addr = 0x00D000D0;              /* erase confirm */
+
+            /* re-enable interrupts if necessary */
+            if (flag)
+                enable_interrupts();
+
+            /* Wait at least 80us - let's wait 1 ms */
+            udelay (1000);
+
+            while (((status = *addr) & 0x00800080) != 0x00800080) {
+                if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                    printf ("Timeout\n");
+                    *addr = 0x00B000B0;      /* suspend erase      */
+                    *addr = 0x00FF00FF;      /* reset to read mode */
+                    return 1;
+                }
+
+                /* show that we're waiting */
+                if ((now - last) > 990) {   /* every second */
+                    putc ('.');
+                    last = now;
+                }
+            }
+            *addr = 0x00FF00FF;              /* reset to read mode */
+        }
+    }
+    printf (" done\n");
+    return 0;
+} /* end flash_erase32() */
+
+int flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+    if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040)
+        return flash_erase8(info, s_first, s_last);
+    else
+        return flash_erase32(info, s_first, s_last);
+} /* end flash_erase() */
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_buff8(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong cp, wp, data;
+    ulong start;
+    int i, l, rc;
+
+    start = get_timer (0);
+
+    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_word8(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_word8(info, wp, data)) != 0) {
+            return (rc);
+        }
+        wp  += 4;
+        cnt -= 4;
+        if (get_timer(start) > 1000) {   /* every second */
+           WATCHDOG_RESET();
+           putc ('.');
+           start = get_timer(0);
+        }
+    }
+
+    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_word8(info, wp, data));
+} /* end write_buff8() */
+
+#define	FLASH_WIDTH	4	/* flash bus width in bytes */
+static int write_buff32 (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+	ulong cp, wp, data;
+	int i, l, rc;
+	ulong start;
+
+	start = get_timer (0);
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		return 4;
+	}
+
+	wp = (addr & ~(FLASH_WIDTH-1));	/* get lower FLASH_WIDTH 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<FLASH_WIDTH && cnt>0; ++i) {
+			data = (data << 8) | *src++;
+			--cnt;
+			++cp;
+		}
+		for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
+			data = (data << 8) | (*(uchar *)cp);
+		}
+
+		if ((rc = write_word32(info, wp, data)) != 0) {
+			return (rc);
+		}
+		wp += FLASH_WIDTH;
+	}
+
+	/*
+	 * handle FLASH_WIDTH aligned part
+	 */
+	while (cnt >= FLASH_WIDTH) {
+		data = 0;
+		for (i=0; i<FLASH_WIDTH; ++i) {
+			data = (data << 8) | *src++;
+		}
+		if ((rc = write_word32(info, wp, data)) != 0) {
+			return (rc);
+		}
+		wp  += FLASH_WIDTH;
+		cnt -= FLASH_WIDTH;
+          if (get_timer(start) > 990) {   /* every second */
+			putc ('.');
+			start = get_timer(0);
+		}
+	}
+
+	if (cnt == 0) {
+		return (0);
+	}
+
+	/*
+	 * handle unaligned tail bytes
+	 */
+	data = 0;
+	for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
+		data = (data << 8) | *src++;
+		--cnt;
+	}
+	for (; i<FLASH_WIDTH; ++i, ++cp) {
+		data = (data << 8) | (*(uchar *)cp);
+	}
+
+	return (write_word32(info, wp, data));
+} /* write_buff32() */
+
+int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    int retval;
+
+    if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040)
+        retval = write_buff8(info, src, addr, cnt);
+    else
+        retval = write_buff32(info, src, addr, cnt);
+
+    return retval;
+} /* end write_buff() */
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+static int write_word8(flash_info_t *info, ulong dest, ulong data)
+{
+    volatile uchar *addr2 = (uchar *)(info->start[0]);
+    volatile uchar *dest2 = (uchar *)dest;
+    volatile uchar *data2 = (uchar *)&data;
+    int flag;
+    int i, tcode, rcode = 0;
+
+    /* Check if Flash is (sufficently) erased */
+    if ((*((volatile uchar *)dest) &
+        (uchar)data) != (uchar)data) {
+        return (2);
+    }
+
+    for (i=0; i < (4 / sizeof(uchar)); i++) {
+        /* Disable interrupts which might cause a timeout here */
+        flag = disable_interrupts();
+
+        *(addr2 + 0x555) = (uchar)0xAA;
+        *(addr2 + 0x2aa) = (uchar)0x55;
+        *(addr2 + 0x555) = (uchar)0xA0;
+
+        dest2[i] = data2[i];
+
+        /* Wait for write to complete, up to 1ms */
+        tcode = wait_for_DQ7((ulong)&dest2[i], data2[i], 1);
+
+        /* re-enable interrupts if necessary */
+        if (flag)
+            enable_interrupts();
+
+        /* Make sure we didn't timeout */
+        if (tcode) {
+            rcode = 1;
+        }
+    }
+
+    return rcode;
+} /* end write_word8() */
+
+static int write_word32(flash_info_t *info, ulong dest, ulong data)
+{
+    vu_long *addr = (vu_long *)dest;
+    ulong status;
+    ulong start;
+    int flag;
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*addr & data) != data) {
+        return (2);
+    }
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    *addr = 0x00400040;                      /* write setup */
+    *addr = data;
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+        enable_interrupts();
+
+    start = get_timer (0);
+
+    while (((status = *addr) & 0x00800080) != 0x00800080) {
+        WATCHDOG_RESET();
+        if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+            *addr = 0x00FF00FF;              /* restore read mode */
+            return (1);
+        }
+    }
+
+    *addr = 0x00FF00FF;                      /* restore read mode */
+
+    return (0);
+} /* end write_word32() */
+
+
+static int _flash_protect(flash_info_t *info, long sector)
+{
+    int i;
+    int flag;
+    ulong status;
+    int rcode = 0;
+    volatile long *addr = (unsigned long *)sector;
+
+    switch(info->flash_id & FLASH_TYPEMASK) {
+        case FLASH_28F320J3A:
+        case FLASH_28F640J3A:
+        case FLASH_28F128J3A:
+            /* Disable interrupts which might cause Flash to timeout */
+            flag = disable_interrupts();
+
+            /* Issue command */
+            *addr = 0x00500050L;             /* Clear the status register */
+            *addr = 0x00600060L;             /* Set lock bit setup */
+            *addr = 0x00010001L;             /* Set lock bit confirm */
+
+            /* Wait for command completion */
+            for (i = 0; i < 10; i++) {       /* 75us timeout, wait 100us */
+                udelay(10);
+                if ((*addr & 0x00800080L) == 0x00800080L)
+                    break;
+            }
+
+            /* Not successful? */
+            status = *addr;
+            if (status != 0x00800080L) {
+                printf("Protect %x sector failed: %x\n",
+                       (uint)sector, (uint)status);
+                rcode = 1;
+            }
+
+            /* Restore read mode */
+            *addr = 0x00ff00ffL;
+
+            /* re-enable interrupts if necessary */
+            if (flag)
+                enable_interrupts();
+
+            break;
+        case FLASH_AM040:                    /* No soft sector protection */
+            break;
+    }
+
+    /* Turn protection on for this sector */
+    for (i = 0; i < info->sector_count; i++) {
+        if (info->start[i] == sector) {
+            info->protect[i] = 1;
+            break;
+        }
+    }
+
+    return rcode;
+} /* end _flash_protect() */
+
+static int _flash_unprotect(flash_info_t *info, long sector)
+{
+    int i;
+    int flag;
+    ulong status;
+    int rcode = 0;
+    volatile long *addr = (unsigned long *)sector;
+
+    switch(info->flash_id & FLASH_TYPEMASK) {
+        case FLASH_28F320J3A:
+        case FLASH_28F640J3A:
+        case FLASH_28F128J3A:
+            /* Disable interrupts which might cause Flash to timeout */
+            flag = disable_interrupts();
+
+            *addr = 0x00500050L;             /* Clear the status register */
+            *addr = 0x00600060L;             /* Clear lock bit setup */
+            *addr = 0x00D000D0L;             /* Clear lock bit confirm */
+
+            /* Wait for command completion */
+            for (i = 0; i < 80 ; i++) {      /* 700ms timeout, wait 800 */
+                udelay(10000);               /* Delay 10ms */
+                if ((*addr & 0x00800080L) == 0x00800080L)
+                    break;
+            }
+
+            /* Not successful? */
+            status = *addr;
+            if (status != 0x00800080L) {
+                printf("Un-protect %x sector failed: %x\n",
+                       (uint)sector, (uint)status);
+                *addr = 0x00ff00ffL;
+                rcode = 1;
+            }
+
+            /* restore read mode */
+            *addr = 0x00ff00ffL;
+
+            /* re-enable interrupts if necessary */
+            if (flag)
+                enable_interrupts();
+
+            break;
+        case FLASH_AM040:                    /* No soft sector protection */
+            break;
+    }
+
+    /*
+     * Fix Intel's little red wagon.  Reprotect
+     * sectors that were protected before we undid
+     * protection on a specific sector.
+     */
+    for (i = 0; i < info->sector_count; i++) {
+        if (info->start[i] != sector) {
+            if (info->protect[i]) {
+                if (_flash_protect(info, info->start[i]))
+                    rcode = 1;
+	    }
+        }
+        else /* Turn protection off for this sector */
+            info->protect[i] = 0;
+    }
+
+    return rcode;
+} /* end _flash_unprotect() */
+
+
+int flash_real_protect(flash_info_t *info, long sector, int prot)
+{
+    int rcode;
+
+    if (prot)
+        rcode = _flash_protect(info, info->start[sector]);
+    else
+        rcode = _flash_unprotect(info, info->start[sector]);
+
+    return rcode;
+} /* end flash_real_protect() */
+
+/*-----------------------------------------------------------------------
+ */
+

+ 380 - 0
board/w7o/fpga.c

@@ -0,0 +1,380 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
+ *  and
+ * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net
+ *
+ * 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 <common.h>
+#include "w7o.h"
+#include <asm/processor.h>
+#include "errors.h"
+
+static void
+fpga_img_write(unsigned long *src, unsigned long len, unsigned short *daddr)
+{
+    unsigned long i;
+    volatile unsigned long val;
+    volatile unsigned short *dest = daddr;	/* volatile-bypass optimizer */
+
+    for (i = 0; i < len; i++, src++) {
+        val = *src;
+        *dest = (unsigned short)((val & 0xff000000L) >> 16);
+        *dest = (unsigned short)((val & 0x00ff0000L) >> 8);
+        *dest = (unsigned short)(val & 0x0000ff00L);
+        *dest = (unsigned short)((val & 0x000000ffL) << 8);
+    }
+
+    /* Terminate programming with 4 C clocks */
+    dest = daddr;
+    val = *(unsigned short *)dest;
+    val = *(unsigned short *)dest;
+    val = *(unsigned short *)dest;
+    val = *(unsigned short *)dest;
+
+}
+
+
+int
+fpgaDownload(unsigned char *saddr,
+	     unsigned long size,
+	     unsigned short *daddr)
+{
+    int i;					/* index, intr disable flag */
+    int start;					/* timer */
+    unsigned long greg, grego;			/* GPIO & output register */
+    unsigned long length;			/* image size in words */
+    unsigned long *source;			/* image source addr */
+    unsigned short *dest;			/* destination FPGA addr */
+    volatile unsigned short *ndest;		/* temp dest FPGA addr */
+    volatile unsigned short val;		/* temp val */
+    unsigned long cnfg = GPIO_XCV_CNFG;		/* FPGA CNFG */
+    unsigned long eirq = GPIO_XCV_IRQ;
+    int retval = -1;				/* Function return value */
+
+    /* Setup some basic values */
+    length = (size / 4) + 1;			/* size in words, rounding UP
+						    is OK */
+    source = (unsigned long *)saddr;
+    dest = (unsigned short *)daddr;
+
+    /* Get DCR output register */
+    grego = in32(IBM405GP_GPIO0_OR);
+
+    /* Reset FPGA */
+    grego &= ~GPIO_XCV_PROG;			/* PROG line low */
+    out32(IBM405GP_GPIO0_OR, grego);
+
+    /* Setup timeout timer */
+    start = get_timer(0);
+
+    /* Wait for FPGA init line */
+    while(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_INIT) { /* Wait INIT line low */
+        /* Check for timeout - 100us max, so use 3ms */
+        if (get_timer(start) > 3) {
+            printf("     failed to start init.\n");
+            log_warn(ERR_XINIT0);		/* Don't halt */
+
+            /* Reset line stays low */
+            goto done;				/* I like gotos... */
+        }
+    }
+
+    /* Unreset FPGA */
+    grego |= GPIO_XCV_PROG;			/* PROG line high */
+    out32(IBM405GP_GPIO0_OR, grego);
+
+    /* Wait for FPGA end of init period .  */
+    while(!(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_INIT)) { /* Wait for INIT hi */
+
+        /* Check for timeout */
+        if (get_timer(start) > 3) {
+            printf("     failed to exit init.\n");
+            log_warn(ERR_XINIT1);
+
+            /* Reset FPGA */
+            grego &= ~GPIO_XCV_PROG;		/* PROG line low */
+            out32(IBM405GP_GPIO0_OR, grego);
+
+            goto done;
+        }
+    }
+
+    /* Now program FPGA ... */
+    ndest = dest;
+    for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
+        /* Toggle IRQ/GPIO */
+        greg = mfdcr(CPC0_CR0);			/* get chip ctrl register */
+        greg |= eirq;				/* toggle irq/gpio */
+        mtdcr(CPC0_CR0, greg);			/*  ... just do it */
+
+        /* turn on open drain for CNFG */
+        greg = in32(IBM405GP_GPIO0_ODR);	/* get open drain register */
+        greg |= cnfg;				/* CNFG open drain */
+        out32(IBM405GP_GPIO0_ODR, greg);	/*  .. just do it */
+
+        /* Turn output enable on for CNFG */
+        greg = in32(IBM405GP_GPIO0_TCR);	/* get tristate register */
+        greg |= cnfg;				/* CNFG tristate inactive */
+        out32(IBM405GP_GPIO0_TCR, greg);	/*  ... just do it */
+
+        /* Setup FPGA for programming */
+        grego &= ~cnfg;				/* CONFIG line low */
+        out32(IBM405GP_GPIO0_OR, grego);
+
+        /*
+         * Program the FPGA
+         */
+        printf("\n       destination: 0x%lx ", (unsigned long)ndest);
+
+        fpga_img_write(source,  length,  (unsigned short *)ndest);
+
+        /* Done programming */
+        grego |= cnfg;				/* CONFIG line high */
+        out32(IBM405GP_GPIO0_OR, grego);
+
+        /* Turn output enable OFF for CNFG */
+        greg = in32(IBM405GP_GPIO0_TCR);	/* get tristate register */
+        greg &= ~cnfg;				/* CNFG tristate inactive */
+        out32(IBM405GP_GPIO0_TCR, greg);	/*  ... just do it */
+
+        /* Toggle IRQ/GPIO */
+        greg = mfdcr(CPC0_CR0);			/* get chip ctrl register */
+        greg &= ~eirq;				/* toggle irq/gpio */
+        mtdcr(CPC0_CR0, greg);			/*  ... just do it */
+
+        ndest = (unsigned short *)((char *)ndest + 0x00100000L); /* XXX - Next FPGA addr */
+        cnfg >>= 1;				/* XXX - Next  */
+        eirq >>= 1;
+    }
+
+    /* Terminate programming with 4 C clocks */
+    ndest = dest;
+    for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
+        val = *ndest;
+        val = *ndest;
+        val = *ndest;
+        val = *ndest;
+        ndest = (unsigned short *)((char *)ndest + 0x00100000L);
+    }
+
+    /* Setup timer */
+    start = get_timer(0);
+
+    /* Wait for FPGA end of programming period .  */
+    while(!(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_DONE)) { /* Test DONE low */
+
+        /* Check for timeout */
+        if (get_timer(start) > 3) {
+            printf("     done failed to come high.\n");
+            log_warn(ERR_XDONE1);
+
+            /* Reset FPGA */
+            grego &= ~GPIO_XCV_PROG;		/* PROG line low */
+            out32(IBM405GP_GPIO0_OR, grego);
+
+            goto done;
+        }
+    }
+
+    printf("\n       FPGA load succeeded\n");
+    retval = 0;					/* Program OK */
+
+done:
+    return retval;
+}
+
+/* FPGA image is stored in flash */
+extern flash_info_t    flash_info[];
+
+int init_fpga(void)
+{
+    unsigned int i,j,ptr;			/* General purpose */
+    unsigned char bufchar;			/* General purpose character */
+    unsigned char *buf;				/* Start of image pointer */
+    unsigned long len;				/* Length of image */
+    unsigned char *fn_buf;			/* Start of filename string */
+    unsigned int fn_len;			/* Length of filename string */
+    unsigned char *xcv_buf;			/* Pointer to start of image */
+    unsigned long xcv_len;			/* Length of image */
+    unsigned long crc;				/* 30bit crc in image */
+    unsigned long calc_crc;			/* Calc'd 30bit crc */
+    int retval = -1;
+
+    /* Tell the world what we are doing */
+    printf("FPGA:  ");
+
+    /*
+     * Get address of first sector where the FPGA
+     * image is stored.
+     */
+    buf = (unsigned char *)flash_info[1].start[0];
+
+    /*
+     * Get the stored image's CRC & length.
+     */
+    crc = *(unsigned long *)(buf+4);		/* CRC is first long word */
+    len = *(unsigned long *)(buf+8);		/* Image len is next long */
+
+    /* Pedantic */
+    if ((len < 0x133A4) || (len > 0x80000))
+        goto bad_image;
+
+    /*
+     * Get the file name pointer and length.
+     */
+    fn_len = (*(unsigned short *)(buf+12) & 0xff); /* filename length
+						      is next short */
+    fn_buf = buf + 14;
+
+    /*
+     * Get the FPGA image pointer and length length.
+     */
+    xcv_buf = fn_buf + fn_len;			/* pointer to fpga image */
+    xcv_len = len - 14 - fn_len;		/* fpga image length */
+
+    /* Check for uninitialized FLASH */
+    if ((strncmp(buf, "w7o", 3)!=0) || (len > 0x0007ffffL) || (len == 0))
+	goto bad_image;
+
+    /*
+     * Calculate and Check the image's CRC.
+     */
+    calc_crc = crc32(0, xcv_buf, xcv_len);
+    if (crc != calc_crc) {
+        printf("\nfailed - bad CRC\n");
+        goto done;
+    }
+
+    /* Output the file name */
+    printf("file name  : ");
+    for (i=0;i<fn_len;i++) {
+        bufchar = fn_buf[+i];
+        if (bufchar<' ' || bufchar>'~') bufchar = '.';
+        putc(bufchar);
+    }
+
+    /*
+     * find rest of display data
+     */
+    ptr = 15;					/* Offset to ncd filename
+						   length in fpga image */
+    j = xcv_buf[ptr];				/* Get len of ncd filename */
+    if (j > 32) goto bad_image;
+    ptr = ptr + j + 3;				/* skip ncd filename string +
+						   3 bytes more bytes */
+
+    /*
+     * output target device string
+     */
+    j = xcv_buf[ptr++] - 1;			/* len of targ str less term */
+    if (j > 32) goto bad_image;
+    printf("\n       target     : ");
+    for (i = 0; i < j; i++) {
+	bufchar = (xcv_buf[ptr++]);
+	if (bufchar<' ' || bufchar>'~') bufchar = '.';
+	putc(bufchar);
+    }
+
+    /*
+     * output compilation date string and time string
+     */
+    ptr += 3;					/* skip 2 bytes */
+    printf("\n       synth time : ");
+    j = (xcv_buf[ptr++] - 1);			/* len of date str less term */
+    if (j > 32) goto bad_image;
+    for (i = 0; i < j; i++) {
+	bufchar = (xcv_buf[ptr++]);
+	if (bufchar<' ' || bufchar>'~') bufchar = '.';
+	putc(bufchar);
+    }
+
+    ptr += 3;					/* Skip 2 bytes */
+    printf(" - ");
+    j = (xcv_buf[ptr++] - 1);			/* slen = targ dev str len */
+    if (j > 32) goto bad_image;
+    for (i = 0; i < j; i++) {
+	bufchar = (xcv_buf[ptr++]);
+	if (bufchar<' ' || bufchar>'~') bufchar = '.';
+	putc(bufchar);
+    }
+
+    /*
+     * output crc and length strings
+     */
+    printf("\n       len & crc  : 0x%lx  0x%lx", len, crc);
+
+    /*
+     * Program the FPGA.
+     */
+    retval = fpgaDownload((unsigned char*)xcv_buf, xcv_len,
+                          (unsigned short *)0xfd000000L);
+    return retval;
+
+bad_image:
+    printf("\n       BAD FPGA image format @ %lx\n", flash_info[1].start[0]);
+    log_warn(ERR_XIMAGE);
+done:
+    return retval;
+}
+
+void test_fpga(unsigned short *daddr)
+{
+    int i;
+    volatile unsigned short *ndest = daddr;
+
+    for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
+#if defined(CONFIG_W7OLMG)
+	ndest[0x7e] = 0x55aa;
+	if (ndest[0x7e] != 0x55aa)
+	    log_warn(ERR_XRW1 + i);
+	ndest[0x7e] = 0xaa55;
+	if (ndest[0x7e] != 0xaa55)
+	    log_warn(ERR_XRW1 + i);
+	ndest[0x7e] = 0xc318;
+	if (ndest[0x7e] != 0xc318)
+	    log_warn(ERR_XRW1 + i);
+
+#elif defined(CONFIG_W7OLMC)
+	ndest[0x800] = 0x55aa;
+	ndest[0x801] = 0xaa55;
+	ndest[0x802] = 0xc318;
+	ndest[0x4800] = 0x55aa;
+	ndest[0x4801] = 0xaa55;
+	ndest[0x4802] = 0xc318;
+	if ((ndest[0x800] != 0x55aa) ||
+	    (ndest[0x801] != 0xaa55) ||
+	    (ndest[0x802] != 0xc318))
+	    log_warn(ERR_XRW1 + (2 * i));       /* Auto gen error code */
+	if ((ndest[0x4800] != 0x55aa) ||
+	    (ndest[0x4801] != 0xaa55) ||
+	    (ndest[0x4802] != 0xc318))
+	    log_warn(ERR_XRW2 + (2 * i));       /* Auto gen error code */
+
+#else
+# error "Unknown W7O board configuration"
+#endif
+    }
+
+    printf("       FPGA ready\n");
+    return;
+}
+

+ 264 - 0
board/w7o/init.S

@@ -0,0 +1,264 @@
+/******************************************************************************
+ *
+ *	 This source code has been made available to you by IBM on an AS-IS
+ *	 basis.	 Anyone receiving this source is licensed under IBM
+ *	 copyrights to use it in any way he or she deems fit, including
+ *	 copying it, modifying it, compiling it, and redistributing it either
+ *	 with or without modifications.	 No license under IBM patents or
+ *	 patent applications is to be implied by the copyright license.
+ *
+ *	 Any user of this software should understand that IBM cannot provide
+ *	 technical support for this software and will not be responsible for
+ *	 any consequences resulting from the use of this software.
+ *
+ *	 Any person who transfers this source code or any derivative work
+ *	 must include the IBM copyright notice, this paragraph, and the
+ *	 preceding two paragraphs in the transferred software.
+ *
+ *	 COPYRIGHT   I B M   CORPORATION 1995
+ *	 LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
+ *
+ *****************************************************************************/
+#include <config.h>
+#include <ppc4xx.h>
+
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/******************************************************************************
+ * Function:	ext_bus_cntlr_init
+ *
+ * Description:	Configures EBC Controller and a few basic chip selects.
+ *
+ *		CS0 is setup to get the Boot Flash out of the addresss range
+ *		so that we may setup a stack.  CS7 is setup so that we can
+ *		access and reset the hardware watchdog.
+ *
+ *		IMPORTANT: For pass1 this code must run from
+ *		cache since you can not reliably change a peripheral banks
+ *		timing register (pbxap) while running code from that bank.
+ *		For ex., since we are running from ROM on bank 0, we can NOT
+ *		execute the code that modifies bank 0 timings from ROM, so
+ *		we run it from cache.
+ *
+ * Notes:	Does NOT use the stack.
+ *****************************************************************************/
+	.section ".text"
+	.align	2
+	.globl	ext_bus_cntlr_init
+	.type	ext_bus_cntlr_init, @function
+ext_bus_cntlr_init:
+	mflr	r0
+	/********************************************************************
+	 * Prefetch entire ext_bus_cntrl_init function into the icache.
+	 * This is necessary because we are going to change the same CS we
+	 * are executing from.  Otherwise a CPU lockup may occur.
+	 *******************************************************************/
+	bl	..getAddr
+..getAddr:
+	mflr	r3			/* get address of ..getAddr */
+
+	/* Calculate number of cache lines for this function */
+	addi	r4, 0, (((.Lfe0 - ..getAddr) / CFG_CACHELINE_SIZE) + 2)
+	mtctr	r4
+..ebcloop:
+	icbt	r0, r3			/* prefetch cache line for addr in r3*/
+	addi	r3, r3, CFG_CACHELINE_SIZE /* move to next cache line */
+	bdnz	..ebcloop		/* continue for $CTR cache lines */
+
+	/********************************************************************
+	 * Delay to ensure all accesses to ROM are complete before changing
+	 * bank 0 timings. 200usec should be enough.
+	 * 200,000,000 (cycles/sec) X .000200 (sec) = 0x9C40 cycles.
+	 *******************************************************************/
+	addis	r3, 0, 0x0
+	ori	r3, r3, 0xA000		/* wait 200us from reset */
+	mtctr	r3
+..spinlp:
+	bdnz	..spinlp		/* spin loop */
+
+	/********************************************************************
+	 * Setup External Bus Controller (EBC).
+	 *******************************************************************/
+	addi	r3, 0, epcr
+	mtdcr	ebccfga, r3
+	addis	r4, 0, 0xb040		/* Device base timeout = 1024 cycles */
+	ori	r4, r4, 0x0		/* Drive CS with external master */
+	mtdcr	ebccfgd, r4
+
+	/********************************************************************
+	 * Change PCIINT signal to PerWE
+	 *******************************************************************/
+	mfdcr	r4, cntrl1
+	ori	r4, r4, 0x4000
+	mtdcr	cntrl1, r4
+
+	/********************************************************************
+	 * Memory Bank 0 (Flash Bank 0) initialization
+	 *******************************************************************/
+	addi	r3, 0, pb0ap
+	mtdcr	ebccfga, r3
+	addis	r4, 0, CFG_W7O_EBC_PB0AP@h
+	ori	r4, r4, CFG_W7O_EBC_PB0AP@l
+	mtdcr	ebccfgd, r4
+
+	addi	r3, 0, pb0cr
+	mtdcr	ebccfga, r3
+	addis	r4, 0, CFG_W7O_EBC_PB0CR@h
+	ori	r4, r4, CFG_W7O_EBC_PB0CR@l
+	mtdcr	ebccfgd, r4
+
+	/********************************************************************
+	 * Memory Bank 7 LEDs - NEEDED BECAUSE OF HW WATCHDOG AND LEDs.
+	 *******************************************************************/
+	addi	r3, 0, pb7ap
+	mtdcr	ebccfga, r3
+	addis	r4, 0, CFG_W7O_EBC_PB7AP@h
+	ori	r4, r4, CFG_W7O_EBC_PB7AP@l
+	mtdcr	ebccfgd, r4
+
+	addi	r3, 0, pb7cr
+	mtdcr	ebccfga, r3
+	addis	r4, 0, CFG_W7O_EBC_PB7CR@h
+	ori	r4, r4, CFG_W7O_EBC_PB7CR@l
+	mtdcr	ebccfgd, r4
+
+	/* We are all done */
+	mtlr	r0			/* Restore link register */
+	blr				/* Return to calling function */
+.Lfe0:	.size	ext_bus_cntlr_init,.Lfe0-ext_bus_cntlr_init
+/* end ext_bus_cntlr_init() */
+
+/******************************************************************************
+ * Function:	sdram_init
+ *
+ * Description:	Configures SDRAM memory banks.
+ *
+ *		Serial Presence Detect, "SPD," reads the SDRAM EEPROM
+ *		via the IIC bus and then configures the SDRAM memory
+ *		banks appropriately. If Auto Memory Configuration is
+ *		is not used, it is assumed that a 4MB 11x8x2, non-ECC,
+ *		SDRAM is soldered down.
+ *
+ * Notes:	Expects that the stack is already setup.
+ *****************************************************************************/
+	.section ".text"
+	.align	2
+	.globl	sdram_init
+	.type	sdram_init, @function
+sdram_init:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	stw	r0, +12(r1)		/* Save link register */
+
+	/*
+	 * First call spd_sdram to try to init SDRAM according to the
+	 * contents of the SPD EEPROM.  If the SPD EEPROM is blank or
+	 * erronious, spd_sdram returns 0 in R3.
+	 */
+	bl	spd_sdram
+	addic.	r3, r3, 0		/* Check for error, save dram size */
+	bne	..sdri_done		/* If it worked, we're done... */
+
+	/********************************************************************
+	 * If SPD detection fails, we'll default to 4MB, 11x8x2, as this
+	 * is the SMALLEST SDRAM size the 405 supports.  We can do this
+	 * because W7O boards have soldered on RAM, and there will always
+	 * be some amount present.  If we were using DIMMs, we should hang
+	 * the board instead, since it doesn't have any RAM to continue
+	 * running with.
+	 *******************************************************************/
+
+	/*
+	 * Disable memory controller to allow
+	 * values to be changed.
+	 */
+	addi    r3, 0, mem_mcopt1
+	mtdcr   memcfga, r3
+	addis   r4, 0, 0x0
+	ori     r4, r4, 0x0
+	mtdcr   memcfgd, r4
+
+	/*
+	 * Set MB0CF for ext bank 0. (0-4MB) Address Mode 5 since 11x8x2
+	 * All other banks are disabled.
+	 */
+	addi	r3, 0, mem_mb0cf
+	mtdcr	memcfga, r3
+	addis	r4, 0, 0x0000		/* BA=0x0, SZ=4MB */
+	ori	r4, r4, 0x8001		/* Mode is 5, 11x8x2or4, BE=Enabled */
+	mtdcr	memcfgd, r4
+
+	/* Clear MB1CR,MB2CR,MB3CR to turn other banks off */
+	addi	r4, 0, 0		/* Zero the data reg */
+
+	addi	r3, r3, 4		/* Point to MB1CF reg */
+	mtdcr	memcfga, r3		/* Set the address */
+	mtdcr	memcfgd, r4		/* Zero the reg */
+
+	addi	r3, r3, 4		/* Point to MB2CF reg */
+	mtdcr	memcfga, r3		/* Set the address */
+	mtdcr	memcfgd, r4		/* Zero the reg */
+
+	addi	r3, r3, 4		/* Point to MB3CF reg */
+	mtdcr	memcfga, r3		/* Set the address */
+	mtdcr	memcfgd, r4		/* Zero the reg */
+
+	/********************************************************************
+	 * Set the SDRAM Timing reg, SDTR1 and the refresh timer reg, RTR.
+	 * To set the appropriate timings, we assume sdram is
+	 * 100MHz (pc100 compliant).
+	 *******************************************************************/
+
+	/*
+	 * Set up SDTR1
+	 */
+	addi    r3, 0, mem_sdtr1
+	mtdcr   memcfga, r3
+	addis   r4, 0, 0x0086		/* SDTR1 value for 100Mhz */
+	ori     r4, r4, 0x400D
+	mtdcr   memcfgd, r4
+
+	/*
+	 * Set RTR
+	 */
+	addi    r3, 0, mem_rtr
+	mtdcr   memcfga, r3
+	addis   r4, 0, 0x05F0		/* RTR refresh val = 15.625ms@100Mhz */
+	mtdcr   memcfgd, r4
+
+	/********************************************************************
+	 * Delay to ensure 200usec have elapsed since reset. Assume worst
+	 * case that the core is running 200Mhz:
+	 *	  200,000,000 (cycles/sec) X .000200 (sec) = 0x9C40 cycles
+	 *******************************************************************/
+	addis   r3, 0, 0x0000
+	ori     r3, r3, 0xA000		/* Wait 200us from reset */
+	mtctr   r3
+..spinlp2:
+	bdnz    ..spinlp2		/* spin loop */
+
+	/********************************************************************
+	 * Set memory controller options reg, MCOPT1.
+	 *******************************************************************/
+	addi    r3, 0, mem_mcopt1
+	mtdcr   memcfga, r3
+	addis   r4, 0, 0x80E0		/* DC_EN=1,SRE=0,PME=0,MEMCHK=0 */
+	ori     r4, r4, 0x0000		/* REGEN=0,DRW=00,BRPF=01,ECCDD=1 */
+	mtdcr   memcfgd, r4		/* EMDULR=1 */
+
+..sdri_done:
+	/* restore and return */
+	lwz	r0, +12(r1)		/* Get saved link register */
+	addi	r1, r1, +8		/* Remove frame from stack */
+	mtlr	r0			/* Restore link register */
+	blr				/* Return to calling function */
+.Lfe1:	.size	sdram_init,.Lfe1-sdram_init
+/* end sdram_init() */
+

+ 745 - 0
board/w7o/post1.S

@@ -0,0 +1,745 @@
+/*
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net
+ *  and
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+/*
+ * Description:
+ *	Routine to exercise memory for the bringing up of our boards.
+ */
+#include <config.h>
+#include <ppc4xx.h>
+
+#define _LINUX_CONFIG_H 1       /* avoid reading Linux autoconf.h file  */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#include <watchdog.h>
+
+#include "errors.h"
+
+#define _ASMLANGUAGE
+
+	.globl	test_sdram
+	.globl	test_led
+	.globl	log_stat
+	.globl	log_warn
+	.globl	log_err
+	.globl  temp_uart_init
+	.globl  post_puts
+	.globl  disp_hex
+
+/*****************************************************
+*******   Text Strings for low level printing   ******
+*******          In section got2               *******
+*****************************************************/
+
+/*
+ * Define the text strings for errors and warnings.
+ * Switch to .data section.
+ */
+	.section ".data"
+err_str: 	.asciz "*** POST ERROR   = "
+warn_str:	.asciz "*** POST WARNING = "
+end_str:  .asciz "\r\n"
+
+/*
+ * Enter the labels in Global Entry Table (GOT).
+ * Switch to .got2 section.
+ */
+	START_GOT
+	GOT_ENTRY(err_str)
+	GOT_ENTRY(warn_str)
+	GOT_ENTRY(end_str)
+	END_GOT
+
+/*
+ * Switch  back to .text section.
+ */
+	.text
+
+/****************************************
+ ****************************************
+ ********    LED register test   ********
+ ****************************************
+ ***************************************/
+test_led:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -12(r1)		/* Save back chain and move SP */
+	stw	r0, +16(r1)		/* Save link register */
+	stw	r4, +8(r1)		/* save R4 */
+
+	WATCHDOG_RESET        		/* Reset the watchdog */
+
+	addi    r3, 0, ERR_FF		/* first test value is ffff */
+	addi	r4, r3, 0		/* save copy of pattern */
+	bl	set_led			/* store first test value */
+	bl	get_led			/* read it back */
+	xor.	r4, r4, r3		/* compare to original */
+#if defined(CONFIG_W7OLMC)
+	andi.   r4, r4, 0x00ff		/* lmc has 8 bits */
+#else
+	andi.   r4, r4, 0xffff		/* lmg has 16 bits */
+#endif
+	beq     LED2			/* next test */
+	addi    r3, 0, ERR_LED		/* error code = 1 */
+	bl	log_err			/* display error and halt */
+LED2:	addi    r3, 0, ERR_00		/* 2nd test value is 0000 */
+	addi	r4, r3, 0		/* save copy of pattern */
+	bl	set_led			/* store first test value */
+	bl	get_led			/* read it back */
+	xor.	r4, r4, r3		/* compare to original */
+#if defined(CONFIG_W7OLMC)
+	andi.   r4, r4, 0x00ff		/* lmc has 8 bits */
+#else
+	andi.   r4, r4, 0xffff		/* lmg has 16 bits */
+#endif
+	beq     LED3			/* next test */
+	addi    r3, 0, ERR_LED		/* error code = 1 */
+	bl	log_err			/* display error and halt */
+
+LED3:	/* restore stack and return */
+	lwz	r0, +16(r1)		/* Get saved link register */
+	mtlr	r0			/* Restore link register */
+	lwz	r4, +8(r1)		/* restore r4 */
+	addi	r1, r1, +12		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+/****************************************
+ ****************************************
+ ********     SDRAM TESTS        ********
+ ****************************************
+ ***************************************/
+test_sdram:
+	/* called with mem size in r3 */
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -16(r1)		/* Save back chain and move SP */
+	stw	r0, +20(r1)		/* Save link register */
+	stmw	r30, +8(r1)		/* save R30,R31 */
+					/* r30 is log2(mem size) */
+					/* r31 is mem size */
+
+	/* take log2 of total mem size */
+	addi	r31, r3, 0		/* save total mem size */
+	addi	r30, 0, 0		/* clear r30 */
+l2_loop:
+	srwi.	r31, r31, 1		/* shift right 1 */
+	addi	r30, r30, 1		/* count shifts */
+	bne	l2_loop			/* loop till done */
+	addi	r30, r30, -1		/* correct for over count */
+	addi	r31, r3, 0		/* save original size */
+
+	/* now kick the dog and test the mem */
+	WATCHDOG_RESET        		/* Reset the watchdog */
+	bl	Data_Buster		/* test crossed/shorted data lines */
+	addi	r3, r30, 0		/* get log2(memsize) */
+	addi	r4, r31, 0		/* get memsize */
+	bl	Ghost_Buster		/* test crossed/shorted addr lines */
+	addi	r3, r31, 0		/* get mem size */
+	bl	Bit_Buster		/* check for bad internal bits */
+
+	/* restore stack and return */
+	lmw	r30, +8(r1)		/* Restore r30, r31 */
+	lwz	r0, +20(r1)		/* Get saved link register */
+	mtlr	r0			/* Restore link register */
+	addi	r1, r1, +16		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+
+/****************************************
+ ********  sdram data bus test   ********
+ ***************************************/
+Data_Buster:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -24(r1)		/* Save back chain and move SP */
+	stw	r0, +28(r1)		/* Save link register */
+	stmw	r28, 8(r1)		/* save r28 - r31 on stack */
+					/* r31 i/o register */
+					/* r30 sdram base address */
+					/* r29 5555 syndrom */
+					/* r28 aaaa syndrom */
+
+	/* set up led register for this test */
+	addi    r3, 0, ERR_RAMG		/* set led code to 1 */
+	bl	log_stat		/* store test value */
+	/* now test the dram data bus */
+	xor	r30, r30, r30		/* load r30 with base addr of sdram */
+	addis	r31, 0, 0x5555		/* load r31 with test value */
+	ori	r31, r31, 0x5555
+	stw	r31,0(r30)		/* sto the value */
+	lwz	r29,0(r30)		/* read it back */
+	xor	r29,r31,r29		/* compare it to original */
+	addis	r31, 0, 0xaaaa		/* load r31 with test value */
+	ori	r31, r31, 0xaaaa
+	stw	r31,0(r30)		/* sto the value */
+	lwz	r28,0(r30)		/* read it back */
+	xor	r28,r31,r28		/* compare it to original */
+	or	r3,r28,r29		/* or together both error terms */
+	/*
+	 * Now that we have the error bits,
+	 * we have to decide which part they are in.
+	 */
+	bl	get_idx			/* r5 is now index to error */
+	addi	r3, r3, ERR_RAMG
+	cmpwi	r3, ERR_RAMG		/* check for errors */
+	beq	db_done			/* skip if no errors */
+	bl	log_err			/* log the error */
+
+db_done:
+	lmw	r28, 8(r1)		/* restore r28 - r31 from stack */
+	lwz	r0, +28(r1)		/* Get saved link register */
+	addi	r1, r1, +24		/* Remove frame from stack */
+	mtlr	r0			/* Restore link register */
+	blr				/* Return to calling function */
+
+
+/****************************************************
+ ********  test for address ghosting in dram ********
+ ***************************************************/
+
+Ghost_Buster:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -36(r1)		/* Save back chain and move SP */
+	stw	r0, +40(r1)		/* Save link register */
+	stmw	r25, 8(r1)		/* save r25 - r31 on stack */
+					/* r31 = scratch register */
+					/* r30 is main referance loop counter,
+					   0 to 23 */
+					/* r29 is ghost loop count, 0 to 22 */
+					/* r28 is referance address */
+					/* r27 is ghost address */
+					/* r26 is log2 (mem size) =
+					     number of byte addr bits */
+					/* r25 is mem size */
+
+	/* save the log2(mem size) and mem size */
+	addi	r26, r3, 0		/* r26 is number of byte addr bits */
+	addi	r25, r4, 0		/* r25 is mem size in bytes */
+
+	/* set the leds for address ghost test */
+	addi	r3, 0, ERR_ADDG
+	bl	set_led
+
+	/* first fill memory with zeros */
+	srwi	r31, r25, 2		/* convert bytes to longs */
+	mtctr	r31			/* setup byte counter */
+	addi	r28, 0, 0		/* start at address at 0 */
+	addi	r31, 0, 0		/* data value = 0 */
+clr_loop:
+	stw	r31, 0(r28)		/* Store zero value */
+	addi	r28, r28, 4		/* Increment to next word */
+	andi.	r27, r28, 0xffff	/* check for 2^16 loops */
+	bne	clr_skip		/* if not there, then skip */
+	WATCHDOG_RESET   		/* kick the dog every now and then */
+clr_skip:
+	bdnz	clr_loop		/* Round and round... */
+
+	/* now do main test */
+	addi	r30, 0, 0		/* start referance counter at 0 */
+outside:
+	/*
+	 * Calculate the referance address
+	 *   the referance address is calculated by setting the (r30-1)
+	 *   bit of the base address
+	 * when r30=0, the referance address is the base address.
+	 * thus the sequence 0,1,2,4,8,..,2^(n-1)
+	 * setting the bit is done with the following shift functions.
+	 */
+	WATCHDOG_RESET   		/* Reset the watchdog */
+
+	addi	r31, 0, 1		/* r31 = 1 */
+	slw	r28, r31, r30		/* set bit coresponding to loop cnt */
+	srwi	r28, r28, 1		/* then shift it right one so  */
+					/*   we start at location 0 */
+	/* fill referance address with Fs */
+	addi	r31, 0, 0x00ff		/* r31 = one byte of set bits */
+	stb     r31,0(r28)		/* save ff in referance address */
+
+        /* ghost (inner) loop, now check all posible ghosted addresses */
+	addi	r29, 0, 0		/* start ghosted loop counter at 0 */
+inside:
+	/*
+	 * Calculate the ghost address by flipping one
+	 *  bit of referance address.  This gives the
+	 *  sequence 1,2,4,8,...,2^(n-1)
+	 */
+	addi	r31, 0, 1		/* r31 = 1 */
+	slw     r27, r31, r29		/* set  bit coresponding to loop cnt */
+	xor	r27, r28, r27		/* ghost address = ref addr with
+					     bit flipped*/
+
+	/* now check for ghosting */
+	lbz     r31,0(r27)		/* get content of ghost addr */
+	cmpwi   r31, 0			/* compare read value to 0 */
+	bne	Casper			/*   we found a ghost! */
+
+	/* now close ghost ( inner ) loop */
+	addi 	r29, r29, 1		/* increment inner loop counter */
+	cmpw 	r29, r26		/* check for last inner loop */
+	blt		inside		/* do more inner loops */
+
+	/* now close referance ( outer ) loop */
+	addi 	r31, 0, 0 		/* r31 = zero */
+	stb	r31, 0(28)		/* zero out the altered address loc. */
+	/*
+	 * Increment and check for end, count is zero based.
+	 * With the ble, this gives us one more loops than
+	 * address bits for sequence 0,1,2,4,8,...2^(n-1)
+	*/
+	addi 	r30, r30, 1		/* increment outer loop counter */
+	cmpw 	r30, r26		/* check for last inner loop */
+	ble	outside			/* do more outer loops */
+
+	/* were done, lets go home */
+	b	gb_done
+Casper:					/* we found a ghost !! */
+	addi	r3, 0, ERR_ADDF		/* get indexed error message */
+	bl	log_err			/* log error led error code */
+gb_done: /*  pack your bags, and go home */
+        lmw     r25, 8(r1)              /* restore r25 - r31 from stack */
+        lwz     r0, +40(r1)             /* Get saved link register */
+        addi    r1, r1, +36             /* Remove frame from stack */
+        mtlr    r0                      /* Restore link register */
+        blr                             /* Return to calling function */
+
+/****************************************************
+ ********      SDRAM data fill tests       **********
+ ***************************************************/
+Bit_Buster:
+	/* called with mem size in r3 */
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -16(r1)		/* Save back chain and move SP */
+	stw	r0, +20(r1)		/* Save link register */
+	stw	r4, +8(r1)		/* save R4 */
+	stw	r5, +12(r1)		/* save r5 */
+
+	addis	r5, r3, 0		/* save mem size */
+
+	/* Test 55555555 */
+	addi	r3, 0, ERR_R55G		/* set up error code in case we fail */
+	bl	log_stat		/* store test value */
+	addis	r4, 0, 0x5555
+	ori	r4, r4, 0x5555
+	bl	fill_test
+
+	/* Test aaaaaaaa  */
+	addi	r3, 0, ERR_RAAG		/* set up error code in case we fail */
+	bl	log_stat		/* store test value */
+	addis	r4, 0, 0xAAAA
+	ori	r4, r4, 0xAAAA
+	bl	fill_test
+
+	/* Test 00000000  */
+	addi	r3, 0, ERR_R00G		/* set up error code in case we fail */
+	bl	log_stat		/* store test value */
+	addis	r4, 0, 0
+	ori	r4, r4, 0
+	bl	fill_test
+
+	/* restore stack and return */
+	lwz	r5, +12(r1)		/* restore r4 */
+	lwz	r4, +8(r1)		/* restore r4 */
+	lwz	r0, +20(r1)		/* Get saved link register */
+	addi	r1, r1, +16		/* Remove frame from stack */
+	mtlr	r0			/* Restore link register */
+	blr				/* Return to calling function */
+
+
+
+/****************************************************
+ ********             fill test              ********
+ ***************************************************/
+/*	tests memory by filling with value, and reading back */
+/*	r5 = Size of memory in bytes */
+/*	r4 = Value to write */
+/*	r3 = Error code */
+fill_test:
+        mflr    r0                      /* Get link register */
+        stwu    r1, -32(r1)             /* Save back chain and move SP */
+        stw     r0, +36(r1)             /* Save link register */
+        stmw    r27, 8(r1)              /* save r27 - r31 on stack */
+                                        /* r31 - scratch register */
+                                        /* r30 - memory address */
+	mr	r27, r3
+	mr	r28, r4
+	mr	r29, r5
+
+	WATCHDOG_RESET   		/* Reset the watchdog */
+
+	/* first fill memory with Value */
+	srawi	r31, r29, 2		/* convert bytes to longs */
+	mtctr	r31			/* setup counter */
+	addi	r30, 0, 0		/* Make r30 = addr 0 */
+ft_0:	stw	r28, 0(r30)		/* Store value */
+	addi	r30, r30, 4		/* Increment to next word */
+	andi.	r31, r30, 0xffff	/* check for 2^16 loops */
+	bne	ft_0a			/* if not there, then skip */
+	WATCHDOG_RESET   		/* kick the dog every now and then */
+ft_0a:	bdnz	ft_0			/* Round and round... */
+
+	WATCHDOG_RESET   		/* Reset the watchdog */
+
+	/* Now confirm Value is in memory */
+	srawi	r31, r29, 2		/* convert bytes to longs */
+	mtctr	r31			/* setup counter */
+	addi	r30, 0, 0		/* Make r30 = addr 0 */
+ft_1:	lwz	r31, 0(r30)		/* get value from memory */
+        xor.	r31, r31, r28		/* Writen = Read ? */
+        bne	ft_err			/* If bad, than halt */
+	addi	r30, r30, 4		/* Increment to next word */
+	andi.	r31, r30, 0xffff	/* check for 2^16 loops*/
+	bne	ft_1a			/* if not there, then skip */
+	WATCHDOG_RESET			/* kick the dog every now and then */
+ft_1a:	bdnz	ft_1			/* Round and round... */
+
+	WATCHDOG_RESET   		/* Reset the watchdog */
+
+	b	fill_done		/* restore and return */
+
+ft_err:	addi	r29, r27, 0		/* save current led code */
+	addi	r27, r31, 0		/* get pattern in r27 */
+	bl	get_idx			/* get index from r27 */
+	add	r27, r27, r29		/* add index to old led code */
+	bl	log_err			/* output led err code, halt CPU */
+
+fill_done:
+        lmw     r27, 8(r1)              /* restore r27 - r31 from stack */
+        lwz     r0, +36(r1)             /* Get saved link register */
+        addi    r1, r1, +32             /* Remove frame from stack */
+        mtlr    r0                      /* Restore link register */
+        blr                             /* Return to calling function */
+
+
+/****************************************************
+ *******  get error index from r3 pattern    ********
+ ***************************************************/
+get_idx:				/* r3 = (MSW(r3) !=0)*2 +
+					    (LSW(r3) !=0) */
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -12(r1)		/* Save back chain and move SP */
+	stw	r0, +16(r1)		/* Save link register */
+	stw	r4, +8(r1)		/* save R4 */
+
+	andi.	r4, r3, 0xffff		/* check for lower bits */
+	beq	gi2			/* skip if no bits set */
+	andis.	r4, r3, 0xffff		/* check for upper bits */
+	beq	gi3			/* skip if no bits set */
+	addi	r3, 0, 3		/* both upper and lower bits set */
+	b	gi_done
+gi2:	andis.	r4, r3, 0xffff		/* check for upper bits*/
+	beq	gi4			/* skip if no bits set */
+	addi	r3, 0, 2		/* only upper bits set */
+	b	gi_done
+gi3:	addi	r3, 0, 1		/* only lower bits set */
+	b	gi_done
+gi4:	addi	r3, 0, 0		/* no bits set */
+gi_done:
+	/* restore stack and return */
+	lwz	r0, +16(r1)		/* Get saved link register */
+	mtlr	r0			/* Restore link register */
+	lwz	r4, +8(r1)		/* restore r4 */
+	addi	r1, r1, +12		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+/****************************************************
+ ********       set LED to R5 and hang       ********
+ ***************************************************/
+log_stat:				/* output a led code and continue */
+set_led:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -12(r1)		/* Save back chain and move SP */
+	stw	r0, +16(r1)		/* Save link register */
+	stw	r4, +8(r1)		/* save R4 */
+
+	addis	r4, 0, 0xfe00		/* LED buffer is at 0xfe000000 */
+#if defined(CONFIG_W7OLMG)		/* only on gateway, invert outputs */
+	xori	r3,r3, 0xffff		/* complement led code, active low */
+	sth	r3, 0(r4)		/* store first test value */
+	xori	r3,r3, 0xffff		/* complement led code, active low */
+#else					/* if not gateway, then don't invert */
+	sth	r3, 0(r4)		/* store first test value */
+#endif
+
+	/* restore stack and return */
+	lwz	r0, +16(r1)		/* Get saved link register */
+	mtlr	r0			/* Restore link register */
+	lwz	r4, +8(r1)		/* restore r4 */
+	addi	r1, r1, +12		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+get_led:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -12(r1)		/* Save back chain and move SP */
+	stw	r0, +16(r1)		/* Save link register */
+	stw	r4, +8(r1)		/* save R4 */
+
+	addis	r4, 0, 0xfe00		/* LED buffer is at 0xfe000000 */
+	lhz	r3, 0(r4)		/* store first test value */
+#if defined(CONFIG_W7OLMG)		/* only on gateway, invert inputs */
+	xori	r3,r3, 0xffff		/* complement led code, active low */
+#endif
+
+	/* restore stack and return */
+	lwz	r0, +16(r1)		/* Get saved link register */
+	mtlr	r0			/* Restore link register */
+	lwz	r4, +8(r1)		/* restore r4 */
+	addi	r1, r1, +12		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+log_err:	/* output the error and hang the board ( for now ) */
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -12(r1)		/* Save back chain and move SP */
+	stw	r0, +16(r1)		/* Save link register */
+	stw	r3, +8(r1)		/* save a copy of error code */
+	bl	set_led			/* set the led pattern */
+	GET_GOT				/* get GOT address in r14 */
+	lwz	r3,GOT(err_str)		/* get address of string */
+	bl	post_puts		/* output the warning string */
+	lwz	r3, +8(r1)		/* get error code */
+	addi	r4, 0, 2		/* set disp length to 2 nibbles */
+	bl	disp_hex		/* output the error code */
+	lwz	r3,GOT(end_str)		/* get address of string */
+	bl	post_puts		/* output the warning string */
+halt:
+	b	halt			/* hang */
+
+	/* restore stack and return */
+	lwz	r0, +16(r1)		/* Get saved link register */
+	mtlr	r0			/* Restore link register */
+	addi	r1, r1, +12		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+log_warn:	/* output a warning, then continue with operations */
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -16(r1)		/* Save back chain and move SP */
+	stw	r0, +20(r1)		/* Save link register */
+	stw	r3, +8(r1)		/* save a copy of error code */
+	stw	r14, +12(r1)		/* save a copy of r14 (used by GOT) */
+
+	bl	set_led			/* set the led pattern */
+	GET_GOT				/* get GOT address in r14 */
+	lwz	r3,GOT(warn_str)	/* get address of string */
+	bl	post_puts		/* output the warning string */
+	lwz	r3, +8(r1)		/* get error code */
+	addi	r4, 0, 2		/* set disp length to 2 nibbles */
+	bl	disp_hex		/* output the error code */
+	lwz	r3,GOT(end_str)		/* get address of string */
+	bl	post_puts		/* output the warning string */
+
+	addis	r3, 0, 64		/* has a long delay */
+	mtctr	r3
+log_2:
+	WATCHDOG_RESET			/* this keeps dog from barking, */
+				     	/*   and takes time */
+	bdnz	log_2			/* loop till time expires */
+
+	/* restore stack and return */
+	lwz	r0, +20(r1)		/* Get saved link register */
+	lwz	r14, +12(r1)		/* restore r14 */
+	mtlr	r0			/* Restore link register */
+	addi	r1, r1, +16		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+/*******************************************************************
+ *	temp_uart_init
+ *	Temporary UART initialization routine
+ *	Sets up UART0 to run at 9600N81 off of the internal clock.
+ *	R3-R4 are used.
+ ******************************************************************/
+temp_uart_init:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	stw	r0, +12(r1)		/* Save link register */
+
+        addis   r3, 0, 0xef60
+        ori     r3, r3, 0x0303          /* r3 = UART0_LCR */
+        addi    r4, 0, 0x83             /* n81 format, divisor regs enabled */
+        stb     r4, 0(r3)
+
+	/* set baud rate to use internal clock,
+	   baud = (200e6/16)/31/42 = 9600 */
+
+        addis   r3, 0, 0xef60		/* Address of baud divisor reg */
+        ori     r3, r3, 0x0300		/*   UART0_DLM */
+        addi    r4, 0, +42		/* uart baud divisor LSB = 93 */
+        stb     r4, 0(r3)               /* baud = (200 /16)/14/93 */
+
+        addi    r3, r3, 0x0001		/* uart baud divisor addr */
+        addi    r4, 0, 0
+        stb     r4, 0(r3)               /* Divisor Latch MSB = 0 */
+
+        addis   r3, 0, 0xef60
+        ori     r3, r3, 0x0303          /* r3 = UART0_LCR */
+        addi    r4, 0, 0x03             /* n81 format, tx/rx regs enabled */
+        stb     r4, 0(r3)
+
+	/* output a few line feeds */
+	addi	r3, 0, '\n'		/* load line feed */
+	bl 	post_putc		/* output the char */
+	addi	r3, 0, '\n'		/* load line feed */
+	bl 	post_putc		/* output the char */
+
+        /* restore stack and return */
+	lwz	r0, +12(r1)		/* Get saved link register */
+	mtlr	r0			/* Restore link register */
+	addi	r1, r1, +8		/* Remove frame from stack */
+	blr				/* Return to calling function */
+
+/**********************************************************************
+ **	post_putc
+ **	outputs charactor in R3
+ **	r3 returns the error code ( -1 if there is an error )
+ *********************************************************************/
+
+post_putc:
+
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -20(r1)		/* Save back chain and move SP */
+	stw	r0, +24(r1)		/* Save link register */
+	stmw	r29, 8(r1)		/* save	r29 - r31 on stack
+					   r31 - uart base address
+       					   r30 - delay counter
+					   r29 - scratch reg */
+
+     addis   r31, 0, 0xef60		/* Point to uart base */
+     ori     r31, r31, 0x0300
+     addis   r30, 0, 152 		/* Load about 10,000,000 ticks. */
+pputc_lp:
+	lbz     r29, 5(r31) 		/* Read Line Status Register */
+	andi.   r29, r29, 0x20		/* Check THRE status */
+	bne     thre_set		/* Branch if FIFO empty */
+	addic.  r30, r30, -1		/* Decrement and check if empty. */
+	bne     pputc_lp		/* Try, try again */
+	addi    r3, 0, -1		/* Load error code for timeout */
+	b       pputc_done 		/* Bail out with error code set */
+thre_set:
+	stb     r3, 0(r31)		/* Store character to UART */
+	addi	r3, 0, 0		/* clear error code */
+pputc_done:
+	lmw	r29, 8(r1)		/*restore r29 - r31 from stack */
+	lwz	r0, +24(r1)		/* Get saved link register */
+	addi	r1, r1, +20		/* Remove frame from stack */
+	mtlr	r0			/* Restore link register */
+	blr				/* Return to calling function */
+
+
+/****************************************************************
+    post_puts
+    Accepts a null-terminated string pointed to by R3
+    Outputs to the serial port until 0x00 is found.
+    r3 returns the error code ( -1 if there is an error )
+*****************************************************************/
+post_puts:
+
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -12(r1)		/* Save back chain and move SP */
+	stw	r0, +16(r1)		/* Save link register */
+	stw	r31, 8(r1)		/* save r31 - char pointer */
+
+	addi 	r31, r3, 0              /* move pointer to R31 */
+pputs_nxt:
+	lbz	r3, 0(r31)		/* Get next character */
+	addic.  r3, r3, 0		/* Check for zero */
+	beq	pputs_term		/* bail out if zero */
+	bl	post_putc		/* output the char */
+	addic.	r3, r3, 0		/* check for error */
+	bne	pputs_err
+	addi 	r31, r31, 1		/* point to next char */
+	b	pputs_nxt 		/* loop till term */
+pputs_err:
+	addi 	r3, 0, -1		/* set error code */
+	b	pputs_end		/* were outa here */
+pputs_term:
+	addi 	r3, 0, 1		/* set success code */
+ 	/* restore stack and return */
+pputs_end:
+	lwz	r31, 8(r1)		/* restore r27 - r31 from stack */
+	lwz	r0, +16(r1)		/* Get saved link register */
+	addi	r1, r1, +12		/* Remove frame from stack */
+	mtlr	r0			/* Restore link register */
+	blr				/* Return to calling function */
+
+
+
+/********************************************************************
+ *****	disp_hex
+ *****	Routine to display a hex value from a register.
+ *****	R3 is value to display
+ *****	R4 is number of nibbles to display ie 2 for byte 8 for (long)word
+ *****	Returns -1 in R3 if there is an error ( ie serial port hangs )
+ *****	Returns 0 in R3 if no error
+ *******************************************************************/
+disp_hex:
+	/* save the return info on stack */
+	mflr	r0			/* Get link register */
+	stwu	r1, -16(r1)		/* Save back chain and move SP */
+	stw	r0, +20(r1)		/* Save link register */
+	stmw	r30, 8(r1)		/* save r30 - r31 on stack */
+					/* r31 output char */
+					/* r30 uart base address */
+	addi 	r30, 0, 8               /* Go through 8 nibbles. */
+	addi 	r31, r3, 0
+pputh_nxt:
+	rlwinm	r31, r31, 4, 0, 31	/* Rotate next nibble into position */
+	andi. 	r3, r31, 0x0f		/* Get nibble. */
+	addi 	r3, r3, 0x30		/* Add zero's ASCII code. */
+	cmpwi	r3, 0x03a
+	blt	pputh_out
+	addi 	r3, r3, 0x07            /* 0x27 for lower case. */
+pputh_out:
+	cmpw 	r30, r4
+	bgt	pputh_skip
+	bl	post_putc
+	addic. 	r3, r3, 0 		/* check for error */
+	bne	pputh_err
+pputh_skip:
+	addic.	r30, r30, -1
+	bne	pputh_nxt
+	xor	r3, r3, r3		/* Clear error code */
+	b	pputh_done
+pputh_err:
+	addi 	r3, 0, -1 		/* set error code */
+pputh_done:
+        /* restore stack and return */
+	lmw	r30, 8(r1)		/*  restore r30 - r31 from stack */
+	lwz	r0, +20(r1)		/* Get saved link register */
+	addi	r1, r1, +16		/* Remove frame from stack */
+	mtlr	r0			/* Restore link register */
+	blr				/* Return to calling function */
+

+ 109 - 0
board/w7o/post2.c

@@ -0,0 +1,109 @@
+/*
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@mediaone.net
+ *   and
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <rtc.h>
+#include "errors.h"
+#include "dtt.h"
+
+#if defined(CONFIG_RTC_M48T35A)
+void rtctest(void)
+{
+    volatile uchar *tchar = (uchar*)(CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 9);
+    struct rtc_time tmp;
+
+    /* set up led code for RTC tests */
+    log_stat(ERR_RTCG);
+
+    /*
+     * Do RTC battery test. The first write after power up
+     * fails if battery is low.
+     */
+    *tchar = 0xaa;
+    if ((*tchar ^ 0xaa) != 0x0) log_warn(ERR_RTCBAT);
+    *tchar = 0x55;				/* Reset test address */
+
+    /*
+     * Now lets check the validity of the values in the RTC.
+     */
+    rtc_get(&tmp);
+    if ((tmp.tm_sec < 0)	| (tmp.tm_sec  > 59)   |
+	(tmp.tm_min < 0)	| (tmp.tm_min  > 59)   |
+	(tmp.tm_hour < 0)	| (tmp.tm_hour > 23)   |
+	(tmp.tm_mday < 1 )	| (tmp.tm_mday > 31)   |
+	(tmp.tm_mon < 1 )	| (tmp.tm_mon  > 12)   |
+	(tmp.tm_year < 2000)	| (tmp.tm_year > 2500) |
+	(tmp.tm_wday < 1 )	| (tmp.tm_wday > 7)) {
+	log_warn(ERR_RTCTIM);
+	rtc_reset();
+    }
+
+    /*
+     * Now lets do a check to see if the NV RAM is there.
+     */
+    *tchar = 0xaa;
+    if ((*tchar ^ 0xaa) != 0x0) log_err(ERR_RTCVAL);
+    *tchar = 0x55;				/* Reset test address */
+
+} /* rtctest() */
+#endif	/* CONFIG_RTC_M48T35A */
+
+
+#ifdef CONFIG_DTT_LM75
+int dtt_test(int sensor)
+{
+    short temp, trip, hyst;
+
+    /* get values */
+    temp = dtt_read(sensor, DTT_READ_TEMP) / 256;
+    trip = dtt_read(sensor, DTT_TEMP_SET) / 256;
+    hyst = dtt_read(sensor, DTT_TEMP_HYST) / 256;
+
+    /* check values */
+    if ((hyst != (CFG_DTT_MAX_TEMP - CFG_DTT_HYSTERESIS)) ||
+	(trip != CFG_DTT_MAX_TEMP) ||
+	(temp < CFG_DTT_LOW_TEMP) || (temp > CFG_DTT_MAX_TEMP))
+	return 1;
+
+    return 0;
+} /* dtt_test() */
+#endif /* CONFIG_DTT_LM75 */
+
+/*****************************************/
+
+void post2(void)
+{
+#if defined(CONFIG_RTC_M48T35A)
+    rtctest();
+#endif	/* CONFIG_RTC_M48T35A */
+
+#ifdef CONFIG_DTT_LM75
+    log_stat(ERR_TempG);
+    if(dtt_test(2) != 0) log_warn(ERR_Ttest0);
+    if(dtt_test(4) != 0) log_warn(ERR_Ttest1);
+#endif /* CONFIG_DTT_LM75 */
+} /* post2() */
+

+ 408 - 0
board/w7o/vpd.c

@@ -0,0 +1,408 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#if defined(VXWORKS)
+# include <stdio.h>
+# include <string.h>
+# define CFG_DEF_EEPROM_ADDR 0xa0
+extern char iicReadByte( char, char );
+extern ulong_t crc32( unsigned char *, unsigned long );
+#else
+#include <common.h>
+#endif
+
+#include "vpd.h"
+
+/*
+ * vpd_reader() - reads VPD data from I2C EEPROMS.
+ *                returns pointer to buffer or NULL.
+ */
+static unsigned char *
+vpd_reader(unsigned char *buf, unsigned dev_addr, unsigned off, unsigned count)
+{
+    unsigned offset = off;			/* Calculated offset */
+
+    /*
+     * The main board EEPROM contains
+     * SDRAM SPD in the first 128 bytes,
+     * so skew the offset.
+     */
+    if (dev_addr == CFG_DEF_EEPROM_ADDR)
+	offset += SDRAM_SPD_DATA_SIZE;
+
+    /* Try to read the I2C EEPROM */
+#if defined(VXWORKS)
+    {
+	int i;
+	for( i = 0; i < count; ++i ) {
+	    buf[ i ] = iicReadByte( dev_addr, offset+i );
+	}
+    }
+#else
+    if (eeprom_read(dev_addr, offset, buf, count)) {
+	printf("Failed to read %d bytes from VPD EEPROM 0x%x @ 0x%x\n",
+	       count, dev_addr, offset);
+	return NULL;
+    }
+#endif
+
+    return buf;
+} /* vpd_reader() */
+
+
+/*
+ * vpd_get_packet() - returns next VPD packet or NULL.
+ */
+static vpd_packet_t *vpd_get_packet(vpd_packet_t *vpd_packet)
+{
+    vpd_packet_t *packet = vpd_packet;
+
+    if (packet != NULL) {
+	if (packet->identifier == VPD_PID_TERM)
+	    return NULL;
+	else
+	    packet = (vpd_packet_t *)((char *)packet + packet->size + 2);
+    }
+
+    return packet;
+} /* vpd_get_packet() */
+
+
+/*
+ * vpd_find_packet() - Locates and returns the specified
+ *		       VPD packet or NULL on error.
+ */
+static vpd_packet_t *vpd_find_packet(vpd_t *vpd, unsigned char ident)
+{
+    vpd_packet_t *packet = (vpd_packet_t *)&vpd->packets;
+
+    /* Guaranteed illegal */
+    if (ident == VPD_PID_GI)
+	return NULL;
+
+    /* Scan tuples looking for a match */
+    while ((packet->identifier != ident) &&
+	   (packet->identifier != VPD_PID_TERM))
+	packet = vpd_get_packet(packet);
+
+    /* Did we find it? */
+    if ((packet->identifier) && (packet->identifier != ident))
+	return NULL;
+    return packet;
+}
+
+
+/*
+ * vpd_is_valid() - Validates contents of VPD data
+ *		    in I2C EEPROM.  Returns 1 for
+ *		    success or 0 for failure.
+ */
+static int vpd_is_valid(unsigned dev_addr, unsigned char *buf)
+{
+    unsigned	    num_bytes;
+    vpd_packet_t    *packet;
+    vpd_t	    *vpd = (vpd_t *)buf;
+    unsigned short  stored_crc16, calc_crc16 = 0xffff;
+
+    /* Check Eyecatcher */
+    if (strncmp(vpd->header.eyecatcher, VPD_EYECATCHER, VPD_EYE_SIZE) != 0) {
+	unsigned offset = 0;
+	if (dev_addr == CFG_DEF_EEPROM_ADDR)
+	    offset += SDRAM_SPD_DATA_SIZE;
+	printf("Error: VPD EEPROM 0x%x corrupt @ 0x%x\n", dev_addr, offset);
+
+	return 0;
+    }
+
+    /* Check Length */
+    if (vpd->header.size> VPD_MAX_EEPROM_SIZE) {
+	printf("Error: VPD EEPROM 0x%x contains bad size 0x%x\n",
+	       dev_addr, vpd->header.size);
+	return 0;
+    }
+
+    /* Now find the termination packet */
+    if ((packet = vpd_find_packet(vpd, VPD_PID_TERM)) == NULL) {
+	printf("Error: VPD EEPROM 0x%x missing termination packet\n",
+	       dev_addr);
+	return 0;
+    }
+
+    /* Calculate data size */
+    num_bytes = (unsigned long)((unsigned char *)packet -
+				(unsigned char *)vpd + sizeof(vpd_packet_t));
+
+    /* Find stored CRC and clear it */
+    if ((packet = vpd_find_packet(vpd, VPD_PID_CRC)) == NULL) {
+	printf("Error: VPD EEPROM 0x%x missing CRC\n", dev_addr);
+	return 0;
+    }
+    stored_crc16 = *((ushort *)packet->data);
+    *(ushort *)packet->data = 0;
+
+    /* OK, lets calculate the CRC and check it */
+#if defined(VXWORKS)
+    calc_crc16 = (0xffff & crc32(buf, num_bytes));
+#else
+    calc_crc16 = (0xffff & crc32(0, buf, num_bytes));
+#endif
+    *(ushort *)packet->data = stored_crc16;     /* Now restore the CRC */
+    if (stored_crc16 != calc_crc16) {
+	printf("Error: VPD EEPROM 0x%x has bad CRC 0x%x\n",
+	       dev_addr, stored_crc16);
+	return 0;
+    }
+
+    return 1;
+} /* vpd_is_valid() */
+
+
+/*
+ * size_ok() - Check to see if packet size matches
+ *	       size of data we want. Returns 1 for
+ *	       good match or 0 for failure.
+ */
+static int size_ok(vpd_packet_t *packet, unsigned long size)
+{
+    if (packet->size != size) {
+	printf("VPD Packet 0x%x corrupt.\n", packet->identifier);
+	return 0;
+    }
+    return 1;
+} /* size_ok() */
+
+
+/*
+ * strlen_ok() - Check to see if packet size matches
+ *		 strlen of the string we want to populate.
+ *		 Returns 1 for valid length or 0 for failure.
+ */
+static int strlen_ok(vpd_packet_t *packet, unsigned long length)
+{
+    if (packet->size >= length) {
+	printf("VPD Packet 0x%x corrupt.\n", packet->identifier);
+	return 0;
+    }
+    return 1;
+} /* strlen_ok() */
+
+
+/*
+ * get_vpd_data() - populates the passed VPD structure 'vpdInfo'
+ *		    with data obtained from the specified
+ *		    I2C EEPROM 'dev_addr'.  Returns 0 for
+ *		    success or 1 for failure.
+ */
+int vpd_get_data(unsigned char dev_addr, VPD *vpdInfo)
+{
+    unsigned char buf[VPD_EEPROM_SIZE];
+    vpd_t *vpd = (vpd_t *)buf;
+    vpd_packet_t *packet;
+
+    if (vpdInfo == NULL)
+	return 1;
+
+     /*
+      * Fill vpdInfo with 0s to blank out
+      * unused fields, fill vpdInfo->ethAddrs
+      * with all 0xffs so that other's code can
+      * determine how many real Ethernet addresses
+      * there are.  OUIs starting with 0xff are
+      * broadcast addresses, and would never be
+      * permantely stored.
+      */
+    memset((void *)vpdInfo, 0, sizeof(VPD));
+    memset((void *)&vpdInfo->ethAddrs, 0xff, sizeof(vpdInfo->ethAddrs));
+    vpdInfo->_devAddr = dev_addr;
+
+    /* Read the minimum size first */
+    if (vpd_reader(buf, dev_addr, 0, VPD_EEPROM_SIZE) == NULL) {
+	return 1;
+    }
+
+    /* Check validity of VPD data */
+    if (!vpd_is_valid(dev_addr, buf)) {
+	printf("VPD Data is INVALID!\n");
+	return 1;
+    }
+
+    /*
+      * Walk all the packets and populate
+      * the VPD info structure.
+      */
+    packet = (vpd_packet_t *)&vpd->packets;
+    do {
+	switch (packet->identifier) {
+	    case VPD_PID_GI:
+		printf("Error: Illegal VPD value\n");
+		break;
+	    case VPD_PID_PID:
+		if (strlen_ok(packet, MAX_PROD_ID)) {
+		    strncpy(vpdInfo->productId,
+			    packet->data, packet->size);
+		}
+		break;
+	    case VPD_PID_REV:
+		if (size_ok(packet, sizeof(char)))
+		    vpdInfo->revisionId = *packet->data;
+		break;
+	    case VPD_PID_SN:
+		if (size_ok(packet, sizeof(unsigned long))) {
+		    vpdInfo->serialNum =
+			*(unsigned long *)packet->data;
+		}
+		break;
+	    case VPD_PID_MANID:
+		if (size_ok(packet, sizeof(unsigned char)))
+		    vpdInfo->manuID = *packet->data;
+		break;
+	    case VPD_PID_PCO:
+		if (size_ok(packet, sizeof(unsigned long))) {
+		    vpdInfo->configOpt =
+			*(unsigned long *)packet->data;
+		}
+		break;
+	    case VPD_PID_SYSCLK:
+		if (size_ok(packet, sizeof(unsigned long)))
+		    vpdInfo->sysClk = *(unsigned long *)packet->data;
+		break;
+	    case VPD_PID_SERCLK:
+		if (size_ok(packet, sizeof(unsigned long)))
+		    vpdInfo->serClk = *(unsigned long *)packet->data;
+		break;
+	    case VPD_PID_FLASH:
+		if (size_ok(packet, 9)) {	/* XXX - hardcoded,
+						   padding in struct */
+		    memcpy(&vpdInfo->flashCfg, packet->data, 9);
+		}
+		break;
+	    case VPD_PID_ETHADDR:
+		memcpy(vpdInfo->ethAddrs, packet->data, packet->size);
+		break;
+	    case VPD_PID_POTS:
+		if (size_ok(packet, sizeof(char)))
+		    vpdInfo->numPOTS = (unsigned)*packet->data;
+		break;
+	    case VPD_PID_DS1:
+		if (size_ok(packet, sizeof(char)))
+		    vpdInfo->numDS1 = (unsigned)*packet->data;
+	    case VPD_PID_GAL:
+	    case VPD_PID_CRC:
+	    case VPD_PID_TERM:
+		break;
+	    default:
+		printf("Warning: Found unknown VPD packet ID 0x%x\n",
+		       packet->identifier);
+		break;
+	}
+    } while ((packet = vpd_get_packet(packet)));
+
+    return 0;
+} /* end get_vpd_data() */
+
+
+/*
+ * vpd_init() - Initialize default VPD environment
+ */
+int vpd_init(unsigned char dev_addr)
+{
+    return (0);
+} /* vpd_init() */
+
+
+/*
+ * vpd_print() - Pretty print the VPD data.
+ */
+void vpd_print(VPD *vpdInfo)
+{
+    const char *const sp    = "";
+    const char *const sfmt  = "%4s%-20s: \"%s\"\n";
+    const char *const cfmt  = "%4s%-20s: '%c'\n";
+    const char *const dfmt  = "%4s%-20s: %ld\n";
+    const char *const hfmt  = "%4s%-20s: %08lX\n";
+    const char *const dsfmt = "%4s%-20s: %d\n";
+    const char *const hsfmt = "%4s%-20s: %04X\n";
+    const char *const dhfmt = "%4s%-20s: %ld (%lX)\n";
+
+    printf("VPD read from I2C device: %02X\n", vpdInfo->_devAddr);
+
+    if (vpdInfo->productId[0])
+	printf(sfmt, sp, "Product ID", vpdInfo->productId);
+    else
+	printf(sfmt, sp, "Product ID", "UNKNOWN");
+
+    if (vpdInfo->revisionId)
+	printf(cfmt, sp, "Revision ID", vpdInfo->revisionId);
+
+    if (vpdInfo->serialNum)
+	printf(dfmt, sp, "Serial Number", vpdInfo->serialNum);
+
+    if (vpdInfo->manuID)
+	printf(dfmt, sp, "Manufacture ID", (long)vpdInfo->manuID);
+
+    if (vpdInfo->configOpt)
+	printf(hfmt, sp, "Configuration", vpdInfo->configOpt);
+
+    if (vpdInfo->sysClk)
+	printf(dhfmt, sp, "System Clock", vpdInfo->sysClk, vpdInfo->sysClk);
+
+    if (vpdInfo->serClk)
+	printf(dhfmt, sp, "Serial Clock", vpdInfo->serClk, vpdInfo->serClk);
+
+    if (vpdInfo->numPOTS)
+	printf(dfmt, sp, "Number of POTS lines", vpdInfo->numPOTS);
+
+    if (vpdInfo->numDS1)
+	printf(dfmt, sp, "Number of DS1s", vpdInfo->numDS1);
+
+    /* Print Ethernet Addresses */
+    if (vpdInfo->ethAddrs[0][0] != 0xff) {
+	int i, j;
+	printf("%4sEtherNet Address(es): ", sp);
+	for (i = 0; i < MAX_ETH_ADDRS; i++) {
+	    if (vpdInfo->ethAddrs[i][0] != 0xff) {
+		for (j = 0; j < 6; j++) {
+		    printf("%02X", vpdInfo->ethAddrs[i][j]);
+		    if (((j + 1) % 6) != 0)
+			printf(":");
+		    else
+			printf(" ");
+		}
+		if (((i + 1) % 3) == 0) printf("\n%24s: ", sp);
+	    }
+	}
+	printf("\n");
+    }
+
+    if (vpdInfo->flashCfg.mfg && vpdInfo->flashCfg.dev) {
+	printf("Main Flash Configuration:\n");
+	printf(hsfmt, sp, "Manufacture ID", vpdInfo->flashCfg.mfg);
+	printf(hsfmt, sp, "Device ID",      vpdInfo->flashCfg.dev);
+	printf(dsfmt, sp, "Device Width",   vpdInfo->flashCfg.devWidth);
+	printf(dsfmt, sp, "Num. Devices",   vpdInfo->flashCfg.numDevs);
+	printf(dsfmt, sp, "Num. Columns",   vpdInfo->flashCfg.numCols);
+	printf(dsfmt, sp, "Column Width",   vpdInfo->flashCfg.colWidth);
+	printf(dsfmt, sp, "WE Data Width",  vpdInfo->flashCfg.weDataWidth);
+    }
+} /* vpd_print() */
+

+ 135 - 0
board/w7o/vpd.h

@@ -0,0 +1,135 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _VPD_H_
+#define _VPD_H_
+
+/*
+ * Main Flash Configuration.
+ */
+typedef struct flashCfg_s {
+    unsigned short mfg;				/* Manufacture ID */
+    unsigned short dev;				/* Device ID */
+    unsigned char devWidth;			/* Device Width */
+    unsigned char numDevs;			/* Number of devices */
+    unsigned char numCols;			/* Number of columns */
+    unsigned char colWidth;			/* Width of a column */
+    unsigned char weDataWidth;			/* Write/Erase Data Width */
+} flashCfg_t;
+
+/*
+ * Vital Product Data - VPD
+ */
+#define MAX_PROD_ID		15
+#define MAX_ETH_ADDRS		10
+typedef unsigned char EthAddr[6];
+typedef struct vpd {
+    unsigned char _devAddr;			/* Device address during read */
+    char productId[MAX_PROD_ID];		/* Product ID */
+    char revisionId;				/* Revision ID as a char */
+    unsigned long serialNum;			/* Serial number */
+    unsigned char  manuID;			/* Manufact ID - byte int */
+    unsigned long configOpt;			/* Config Option - bit field */
+    unsigned long sysClk;			/* System clock in Hertz */
+    unsigned long serClk;			/* Ext. clock in Hertz */
+    flashCfg_t flashCfg;			/* Flash configuration */
+    unsigned long numPOTS;			/* Number of POTS lines */
+    unsigned long numDS1;			/* Number of DS1 circuits */
+    EthAddr ethAddrs[MAX_ETH_ADDRS];		/* Ethernet MAC, 1st = craft */
+} VPD;
+
+
+#define VPD_MAX_EEPROM_SIZE	512		/* Max size VPD EEPROM */
+#define SDRAM_SPD_DATA_SIZE	128		/* Size SPD in VPD EEPROM */
+
+/*
+ * PIDs - Packet Identifiers
+ */
+#define VPD_PID_GI		0x0		/* Guaranted Illegal */
+#define VPD_PID_PID		0x1		/* Product Identifier */
+#define VPD_PID_REV		0x2		/* Product Revision */
+#define VPD_PID_SN		0x3		/* Serial Number */
+#define VPD_PID_MANID		0x4		/* Manufacture ID */
+#define VPD_PID_PCO		0x5		/* Product configuration */
+#define VPD_PID_SYSCLK		0x6		/* System Clock */
+#define VPD_PID_SERCLK		0x7		/* Ser. Clk. Speed in Hertz */
+#define VPD_PID_CRC		0x8		/* VPD CRC */
+#define VPD_PID_FLASH		0x9		/* Flash Configuration */
+#define VPD_PID_ETHADDR		0xA		/* Ethernet Address(es) */
+#define VPD_PID_GAL		0xB		/* Galileo Switch Config */
+#define VPD_PID_POTS		0xC		/* Number of POTS Lines */
+#define VPD_PID_DS1		0xD		/* Number of DS1s */
+#define VPD_PID_TERM		0xFF		/* Termination packet */
+
+/*
+ * VPD - Eyecatcher/Magic
+ */
+#define VPD_EYECATCHER		"W7O"
+#define VPD_EYE_SIZE		3
+typedef struct vpd_header {
+    unsigned char eyecatcher[VPD_EYE_SIZE];	/* eyecatcher - "W7O" */
+    unsigned short size __attribute__((packed)); /* size of EEPROM */
+} vpd_header_t;
+
+
+#define VPD_DATA_SIZE (VPD_MAX_EEPROM_SIZE - SDRAM_SPD_DATA_SIZE - \
+                        sizeof(vpd_header_t))
+typedef struct vpd_s {
+    vpd_header_t header;
+    unsigned char packets[VPD_DATA_SIZE];
+} vpd_t;
+
+typedef struct vpd_packet {
+    unsigned char identifier;
+    unsigned char size;
+    unsigned char data[1];
+} vpd_packet_t;
+
+/*
+ * VPD configOpt bit mask
+ */
+#define VPD_HAS_BBRAM		0x1		/* Battery backed SRAM */
+#define VPD_HAS_RTC		0x2		/* Battery backed RTC */
+#define VPD_HAS_EXT_SER_CLK	0x4		/* External serial clock */
+#define VPD_HAS_SER_TRANS_1	0x8		/* COM1 transceiver */
+#define VPD_HAS_SER_TRANS_2	0x10		/* COM2 transceiver */
+#define VPD_HAS_CRAFT_PHY	0x20		/* CRAFT Ethernet */
+#define VPD_HAS_DTT_1		0x40		/* I2C Digital therm. #1 */
+#define VPD_HAS_DTT_2		0x80		/* I2C Digital therm. #2 */
+#define VPD_HAS_1000_UP_LASER	0x100		/* GMM - 1000Mbit Uplink */
+#define VPD_HAS_70KM_UP_LASER	0x200		/* CMM - 70KM Uplink laser */
+#define VPD_HAS_2_UPLINKS	0x400		/* CMM - 2 uplink lasers */
+#define VPD_HAS_FPGA		0x800		/* Has 1 or more FPGAs */
+#define VPD_HAS_DFA		0x1000		/* CLM - Has 2 Fiber Inter. */
+#define VPD_HAS_GAL_SWITCH	0x2000		/* GMM - Has a Gal switch */
+#define VPD_HAS_POTS_LINES	0x4000		/* GMM - Has POTS lines */
+#define VPD_HAS_DS1_CHANNELS	0x8000		/* GMM - Has DS1 channels */
+#define VPD_HAS_CABLE_RETURN	0x10000		/* GBM/GBR - Cable ret. path */
+
+#define VPD_EEPROM_SIZE         (256 - SDRAM_SPD_DATA_SIZE) /* Size EEPROM */
+
+extern int vpd_get_data(unsigned char dev_addr, VPD *vpd);
+extern void vpd_print(VPD *vpdInfo);
+
+#endif /* _VPD_H_ */
+

+ 271 - 0
board/w7o/w7o.c

@@ -0,0 +1,271 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include "w7o.h"
+#include <asm/processor.h>
+
+#include "vpd.h"
+#include "errors.h"
+#include <watchdog.h>
+
+unsigned long get_dram_size(void);
+
+/*
+ * Macros to transform values
+ * into environment strings.
+ */
+#define XMK_STR(x)	#x
+#define MK_STR(x)	XMK_STR(x)
+
+/* ------------------------------------------------------------------------- */
+
+int board_pre_init (void)
+{
+#if defined(CONFIG_W7OLMG)
+    /*
+     * Setup GPIO pins - reset devices.
+     */
+    out32(IBM405GP_GPIO0_ODR, 0x10000000);	/* one open drain pin */
+    out32(IBM405GP_GPIO0_OR, 0x3E000000);	/* set output pins to default */
+    out32(IBM405GP_GPIO0_TCR, 0x7f800000);	/* setup for output */
+
+    /*
+     * IRQ 0-15  405GP internally generated; active high; level sensitive
+     * IRQ 16    405GP internally generated; active low; level sensitive
+     * IRQ 17-24 RESERVED
+     * IRQ 25 (EXT IRQ 0) XILINX; active low; level sensitive
+     * IRQ 26 (EXT IRQ 1) PCI INT A; active low; level sensitive
+     * IRQ 27 (EXT IRQ 2) PCI INT B; active low; level sensitive
+     * IRQ 28 (EXT IRQ 3) SAM 2; active low; level sensitive
+     * IRQ 29 (EXT IRQ 4) Battery Bad; active low; level sensitive
+     * IRQ 30 (EXT IRQ 5) Level One PHY; active low; level sensitive
+     * IRQ 31 (EXT IRQ 6) SAM 1; active high; level sensitive
+     */
+    mtdcr(uicsr, 0xFFFFFFFF);			/* clear all ints */
+    mtdcr(uicer, 0x00000000);			/* disable all ints */
+
+    mtdcr(uiccr, 0x00000000);			/* set all to be non-critical*/
+    mtdcr(uicpr, 0xFFFFFF80);			/* set int polarities */
+    mtdcr(uictr, 0x10000000);			/* set int trigger levels */
+    mtdcr(uicvcr, 0x00000001);			/* set vect base=0,
+						   INT0 highest priority*/
+
+    mtdcr(uicsr, 0xFFFFFFFF);			/* clear all ints */
+
+#elif defined(CONFIG_W7OLMC)
+    /*
+     * Setup GPIO pins
+     */
+    out32(IBM405GP_GPIO0_ODR, 0x01800000);	/* XCV Done Open Drain */
+    out32(IBM405GP_GPIO0_OR,  0x03800000);	/* set out pins to default */
+    out32(IBM405GP_GPIO0_TCR, 0x66C00000);	/* setup for output */
+
+    /*
+     * IRQ 0-15  405GP internally generated; active high; level sensitive
+     * IRQ 16    405GP internally generated; active low; level sensitive
+     * IRQ 17-24 RESERVED
+     * IRQ 25 (EXT IRQ 0) DBE 0; active low; level sensitive
+     * IRQ 26 (EXT IRQ 1) DBE 1; active low; level sensitive
+     * IRQ 27 (EXT IRQ 2) DBE 2; active low; level sensitive
+     * IRQ 28 (EXT IRQ 3) DBE Common; active low; level sensitive
+     * IRQ 29 (EXT IRQ 4) PCI; active low; level sensitive
+     * IRQ 30 (EXT IRQ 5) RCMM Reset; active low; level sensitive
+     * IRQ 31 (EXT IRQ 6) PHY; active high; level sensitive
+     */
+    mtdcr(uicsr, 0xFFFFFFFF);			/* clear all ints */
+    mtdcr(uicer, 0x00000000);			/* disable all ints */
+
+    mtdcr(uiccr, 0x00000000);			/* set all to be non-critical*/
+    mtdcr(uicpr, 0xFFFFFF80);			/* set int polarities */
+    mtdcr(uictr, 0x10000000);			/* set int trigger levels */
+    mtdcr(uicvcr, 0x00000001);			/* set vect base=0,
+						   INT0 highest priority*/
+
+    mtdcr(uicsr, 0xFFFFFFFF);			/* clear all ints */
+
+#else /* Unknown */
+#    error "Unknown W7O board configuration"
+#endif
+
+    WATCHDOG_RESET();				/* Reset the watchdog */
+    temp_uart_init();				/* init the uart for debug */
+    WATCHDOG_RESET();				/* Reset the watchdog */
+    test_led();					/* test the LEDs */
+    test_sdram(get_dram_size());		/* test the dram */
+    log_stat(ERR_POST1);			/* log status,post1 complete */
+    return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Check Board Identity:
+ */
+int checkboard (void)
+{
+    VPD vpd;
+
+    puts ("Board: ");
+
+    /* VPD data present in I2C EEPROM */
+    if (vpd_get_data(CFG_DEF_EEPROM_ADDR, &vpd) == 0) {
+	/*
+	 * Known board type.
+	 */
+	if (vpd.productId[0] &&
+	    ((strncmp(vpd.productId, "GMM", 3) == 0) ||
+	     (strncmp(vpd.productId, "CMM", 3) == 0))) {
+
+	    /* Output board information on startup */
+	    printf("\"%s\", revision '%c', serial# %ld, manufacturer %u\n",
+		   vpd.productId, vpd.revisionId, vpd.serialNum, vpd.manuID);
+	    return (0);
+	}
+    }
+
+    puts ("### Unknown HW ID - assuming NOTHING\n");
+    return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+long int initdram (int board_type)
+{
+    return get_dram_size();
+}
+
+unsigned long get_dram_size (void)
+{
+    int tmp, i, regs[4];
+    int size = 0;
+
+    /* Get bank Size registers */
+    mtdcr(memcfga, mem_mb0cf);			/* get bank 0 config reg */
+    regs[0] = mfdcr(memcfgd);
+
+    mtdcr(memcfga, mem_mb1cf);			/* get bank 1 config reg */
+    regs[1] = mfdcr(memcfgd);
+
+    mtdcr(memcfga, mem_mb2cf);			/* get bank 2 config reg */
+    regs[2] = mfdcr(memcfgd);
+
+    mtdcr(memcfga, mem_mb3cf);			/* get bank 3 config reg */
+    regs[3] = mfdcr(memcfgd);
+
+    /* compute the size, add each bank if enabled */
+    for(i = 0; i < 4; i++) {
+	if (regs[i] & 0x0001) {			/* if enabled, */
+	    tmp = ((regs[i] >> (31 - 14)) & 0x7); /* get size bits */
+	    tmp = 0x400000 << tmp;		/* Size bits X 4MB = size */
+	    size += tmp;
+	}
+    }
+
+    return size;
+}
+
+int misc_init_f (void)
+{
+    return 0;
+}
+
+static void
+w7o_env_init(VPD *vpd)
+{
+    /*
+     * Read VPD
+     */
+    if (vpd_get_data(CFG_DEF_EEPROM_ADDR, vpd) != 0)
+	return;
+
+     /*
+      * Known board type.
+      */
+    if (vpd->productId[0] &&
+	((strncmp(vpd->productId, "GMM", 3) == 0) ||
+	 (strncmp(vpd->productId, "CMM", 3) == 0))) {
+	char buf[30];
+	char *eth;
+	unsigned char *serial = getenv("serial#");
+	unsigned char *ethaddr = getenv("ethaddr");
+
+	/* Set 'serial#' envvar if serial# isn't set */
+	if (!serial) {
+	    sprintf(buf, "%s-%ld", vpd->productId, vpd->serialNum);
+	    setenv("serial#", buf);
+	}
+
+	/* Set 'ethaddr' envvar if 'ethaddr' envvar is the default */
+	eth = vpd->ethAddrs[0];
+	if (ethaddr && (strcmp(ethaddr, MK_STR(CONFIG_ETHADDR)) == 0)) {
+	    /* Now setup ethaddr */
+	    sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+		    eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+	    setenv("ethaddr", buf);
+	}
+    }
+} /* w7o_env_init() */
+
+
+int misc_init_r (void)
+{
+    VPD vpd;					/* VPD information */
+
+#if defined(CONFIG_W7OLMG)
+    unsigned long greg;				/* GPIO Register */
+
+    greg = in32(IBM405GP_GPIO0_OR);
+
+    /*
+     * XXX - Unreset devices - this should be moved into VxWorks driver code
+     */
+    greg |= 0x41800000L;			/* SAM, PHY, Galileo */
+
+    out32(IBM405GP_GPIO0_OR, greg);		/* set output pins to default */
+#endif /* CONFIG_W7OLMG */
+
+    /*
+     * Initialize W7O environment variables
+     */
+    w7o_env_init(&vpd);
+
+    /*
+     * Initialize the FPGA(s).
+     */
+    if (init_fpga() == 0)
+	test_fpga((unsigned short *)CONFIG_FPGAS_BASE);
+
+    /* More POST testing. */
+    post2();
+
+    /* Done with hardware initialization and POST. */
+    log_stat(ERR_POSTOK);
+
+    /* Call silly, fail safe boot init routine */
+    init_fsboot();
+
+	return (0);
+}
+

+ 1563 - 0
common/cmd_doc.c

@@ -0,0 +1,1563 @@
+/*
+ * 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 <common.h>
+#include <config.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg)	show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/doc2000.h>
+#include <linux/mtd/nftl.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
+#undef	NFTL_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, 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 ret, total;
+
+		printf ("\nDOC %s: device %d offset %ld, size %ld ... ",
+			cmd ? "read" : "write", curr_device, off, size);
+
+		ret = doc_rw(doc_dev_desc + curr_device, cmd, off, size,
+			     &total, (u_char*)addr);
+
+		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;
+    }
+}
+
+int do_docboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *boot_device = NULL;
+	char *ep;
+	int dev;
+	ulong cnt;
+	ulong addr;
+	ulong offset = 0;
+	image_header_t *hdr;
+	int rcode = 0;
+
+	switch (argc) {
+	case 1:
+		addr = CFG_LOAD_ADDR;
+		boot_device = getenv ("bootdevice");
+		break;
+	case 2:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = getenv ("bootdevice");
+		break;
+	case 3:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = argv[2];
+		break;
+	case 4:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = argv[2];
+		offset = simple_strtoul(argv[3], NULL, 16);
+		break;
+	default:
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (!boot_device) {
+		puts ("\n** No boot device **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	dev = simple_strtoul(boot_device, &ep, 16);
+
+	if ((dev >= CFG_MAX_DOC_DEVICE) ||
+	    (doc_dev_desc[dev].ChipID == DOC_ChipID_UNKNOWN)) {
+		printf ("\n** Device %d not available\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	printf ("\nLoading from device %d: %s at 0x%lX (offset 0x%lX)\n",
+		dev, doc_dev_desc[dev].name, doc_dev_desc[dev].physadr,
+		offset);
+
+	if (doc_rw (doc_dev_desc + dev, 1, offset,
+		    SECTORSIZE, NULL, (u_char *)addr)) {
+		printf ("** Read error on %d\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	hdr = (image_header_t *)addr;
+
+	if (hdr->ih_magic == IH_MAGIC) {
+
+		print_image_hdr (hdr);
+
+		cnt = (hdr->ih_size + sizeof(image_header_t));
+		cnt -= SECTORSIZE;
+	} else {
+		puts ("\n** Bad Magic Number **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (doc_rw (doc_dev_desc + dev, 1, offset + SECTORSIZE, cnt,
+		    NULL, (u_char *)(addr+SECTORSIZE))) {
+		printf ("** Read error on %d\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	/* Loading ok, update default load address */
+
+	load_addr = addr;
+
+	/* Check if we should attempt an auto-start */
+	if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+		char *local_args[2];
+		extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
+
+		local_args[0] = argv[0];
+		local_args[1] = NULL;
+
+		printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
+
+		do_bootm (cmdtp, 0, 1, local_args);
+		rcode = 1;
+	}
+	return rcode;
+}
+
+int doc_rw (struct DiskOnChip* this, int cmd,
+	    loff_t from, size_t len,
+	    size_t * retlen, u_char * buf)
+{
+	int noecc, ret = 0, n, total = 0;
+	char eccbuf[6];
+
+	while(len) {
+		/* The ECC will not be calculated correctly if
+		   less than 512 is written or read */
+		noecc = (from != (from | 0x1ff) + 1) ||	(len < 0x200);
+
+		if (cmd)
+			ret = doc_read_ecc(this, from, len,
+					   &n, (u_char*)buf,
+					   noecc ? NULL : eccbuf);
+		else
+			ret = doc_write_ecc(this, from, len,
+					    &n, (u_char*)buf,
+					    noecc ? NULL : eccbuf);
+
+		if (ret)
+			break;
+
+		from  += n;
+		buf   += n;
+		total += n;
+		len   -= n;
+	}
+
+	if (retlen)
+		*retlen = total;
+
+	return ret;
+}
+
+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);
+
+	if (this->nftl_found) {
+		struct NFTLrecord *nftl = &this->nftl;
+		unsigned long bin_size, flash_size;
+
+		bin_size = nftl->nb_boot_blocks * this->erasesize;
+		flash_size = (nftl->nb_blocks - nftl->nb_boot_blocks) * this->erasesize;
+
+		printf("\t  NFTL boot record:\n"
+		       "\t    Binary partition: size %ld%s\n"
+		       "\t    Flash disk partition: size %ld%s, offset 0x%lx\n",
+		       bin_size > (1 << 20) ? bin_size >> 20 : bin_size >> 10,
+		       bin_size > (1 << 20) ? "MB" : "kB",
+		       flash_size > (1 << 20) ? flash_size >> 20 : flash_size >> 10,
+		       flash_size > (1 << 20) ? "MB" : "kB", bin_size);
+	} else {
+		puts ("\t  No NFTL boot record found.\n");
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* 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
+	puts ("_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)) {
+#ifdef CFG_DOC_SHORT_TIMEOUT
+		/* it seems that after a certain time the DoC deasserts
+		 * the CDSN_CTRL_FR_B although it is not ready...
+		 * using a short timout solve this (timer increments every ms) */
+		if (get_timer(start) > 10) {
+			return DOC_ETIMEOUT;
+		}
+#else
+		if (get_timer(start) > 10 * 1000) {
+			puts ("_DoC_WaitReady timed out.\n");
+			return DOC_ETIMEOUT;
+		}
+#endif
+		udelay(1);
+        }
+
+	return 0;
+}
+
+static 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) {
+		puts ("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) {
+		puts ("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
+}
+
+/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
+ *	various device information of the NFTL partition and Bad Unit Table. Update
+ *	the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
+ *	is used for management of Erase Unit in other routines in nftl.c and nftlmount.c
+ */
+static int find_boot_record(struct NFTLrecord *nftl)
+{
+	struct nftl_uci1 h1;
+	struct nftl_oob oob;
+	unsigned int block, boot_record_count = 0;
+	int retlen;
+	u8 buf[SECTORSIZE];
+	struct NFTLMediaHeader *mh = &nftl->MediaHdr;
+	unsigned int i;
+
+	nftl->MediaUnit = BLOCK_NIL;
+	nftl->SpareMediaUnit = BLOCK_NIL;
+
+	/* search for a valid boot record */
+	for (block = 0; block < nftl->nb_blocks; block++) {
+		int ret;
+
+		/* Check for ANAND header first. Then can whinge if it's found but later
+		   checks fail */
+		if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
+					&retlen, buf, NULL))) {
+			static int warncount = 5;
+
+			if (warncount) {
+				printf("Block read at 0x%x failed\n", block * nftl->EraseSize);
+				if (!--warncount)
+					puts ("Further failures for this block will not be printed\n");
+			}
+			continue;
+		}
+
+		if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
+			/* ANAND\0 not found. Continue */
+#ifdef PSYCHO_DEBUG
+			printf("ANAND header not found at 0x%x\n", block * nftl->EraseSize);
+#endif
+			continue;
+		}
+
+#ifdef NFTL_DEBUG
+		printf("ANAND header found at 0x%x\n", block * nftl->EraseSize);
+#endif
+
+		/* To be safer with BIOS, also use erase mark as discriminant */
+		if ((ret = doc_read_oob(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+				8, &retlen, (char *)&h1) < 0)) {
+#ifdef NFTL_DEBUG
+			printf("ANAND header found at 0x%x, but OOB data read failed\n",
+			       block * nftl->EraseSize);
+#endif
+			continue;
+		}
+
+		/* OK, we like it. */
+
+		if (boot_record_count) {
+			/* We've already processed one. So we just check if
+			   this one is the same as the first one we found */
+			if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {
+#ifdef NFTL_DEBUG
+				printf("NFTL Media Headers at 0x%x and 0x%x disagree.\n",
+				       nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
+#endif
+				/* if (debug) Print both side by side */
+				return -1;
+			}
+			if (boot_record_count == 1)
+				nftl->SpareMediaUnit = block;
+
+			boot_record_count++;
+			continue;
+		}
+
+		/* This is the first we've seen. Copy the media header structure into place */
+		memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
+
+		/* Do some sanity checks on it */
+		if (mh->UnitSizeFactor != 0xff) {
+			puts ("Sorry, we don't support UnitSizeFactor "
+			      "of != 1 yet.\n");
+			return -1;
+		}
+
+		nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
+		if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
+			printf ("NFTL Media Header sanity check failed:\n"
+				"nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
+				nftl->nb_boot_blocks, nftl->nb_blocks);
+			return -1;
+		}
+
+		nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
+		if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
+			printf ("NFTL Media Header sanity check failed:\n"
+				"numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
+				nftl->numvunits,
+				nftl->nb_blocks,
+				nftl->nb_boot_blocks);
+			return -1;
+		}
+
+		nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
+
+		/* If we're not using the last sectors in the device for some reason,
+		   reduce nb_blocks accordingly so we forget they're there */
+		nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
+
+		/* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
+		for (i = 0; i < nftl->nb_blocks; i++) {
+			if ((i & (SECTORSIZE - 1)) == 0) {
+				/* read one sector for every SECTORSIZE of blocks */
+				if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize +
+						       i + SECTORSIZE, SECTORSIZE,
+						       &retlen, buf, (char *)&oob)) < 0) {
+					puts ("Read of bad sector table failed\n");
+					return -1;
+				}
+			}
+			/* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
+			if (buf[i & (SECTORSIZE - 1)] != 0xff)
+				nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+		}
+
+		nftl->MediaUnit = block;
+		boot_record_count++;
+
+	} /* foreach (block) */
+
+	return boot_record_count?0:-1;
+}
+
+/* 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)
+{
+	struct NFTLrecord *nftl;
+
+	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);
+
+	nftl = &this->nftl;
+
+	/* Get physical parameters */
+	nftl->EraseSize = this->erasesize;
+        nftl->nb_blocks = this->totlen / this->erasesize;
+	nftl->mtd = this;
+
+	if (find_boot_record(nftl) != 0)
+		this->nftl_found = 0;
+	else
+		this->nftl_found = 1;
+
+	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) {
+		puts ("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) {
+		puts ("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) {
+			puts ("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) {
+		puts ("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) {
+			puts ("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) {
+		puts ("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)) {
+		puts ("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
+/*
+ * if the ID isn't the DoC2000 or DoCMillenium ID, so we can assume
+ * the DOC is missing
+ */
+# if 0
+		printf("Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+		       ChipID, physadr);
+# endif
+#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;
+	}
+
+	puts ("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) {
+			puts ("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);
+	} else {
+		puts ("No DiskOnChip found\n");
+	}
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */

+ 1563 - 0
common/cmd_ide.c

@@ -0,0 +1,1563 @@
+/*
+ * (C) Copyright 2000-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
+ *
+ */
+
+/*
+ * IDE support
+ */
+#include <common.h>
+#include <config.h>
+#include <watchdog.h>
+#include <command.h>
+#include <image.h>
+#include <asm/byteorder.h>
+#if defined(CONFIG_IDE_8xx_DIRECT) || defined(CONFIG_IDE_PCMCIA)
+# include <pcmcia.h>
+#endif
+#ifdef CONFIG_8xx
+# include <mpc8xx.h>
+#endif
+#include <ide.h>
+#include <ata.h>
+#include <cmd_ide.h>
+#include <cmd_disk.h>
+#ifdef CONFIG_STATUS_LED
+# include <status_led.h>
+#endif
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg)	show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+
+#undef	IDE_DEBUG
+
+#ifdef	IDE_DEBUG
+#define	PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_IDE)
+
+/* Timings for IDE Interface
+ *
+ * SETUP / LENGTH / HOLD - cycles valid for 50 MHz clk
+ * 70	   165	    30	   PIO-Mode 0, [ns]
+ *  4	     9	     2		       [Cycles]
+ * 50	   125	    20	   PIO-Mode 1, [ns]
+ *  3	     7	     2		       [Cycles]
+ * 30	   100	    15	   PIO-Mode 2, [ns]
+ *  2	     6	     1		       [Cycles]
+ * 30	    80	    10	   PIO-Mode 3, [ns]
+ *  2	     5	     1		       [Cycles]
+ * 25	    70	    10	   PIO-Mode 4, [ns]
+ *  2	     4	     1		       [Cycles]
+ */
+
+const static pio_config_t pio_config_ns [IDE_MAX_PIO_MODE+1] =
+{
+    /*	Setup  Length  Hold  */
+	{ 70,	165,	30 },		/* PIO-Mode 0, [ns]	*/
+	{ 50,	125,	20 },		/* PIO-Mode 1, [ns]	*/
+	{ 30,	101,	15 },		/* PIO-Mode 2, [ns]	*/
+	{ 30,	 80,	10 },		/* PIO-Mode 3, [ns]	*/
+	{ 25,	 70,	10 },		/* PIO-Mode 4, [ns]	*/
+};
+
+static pio_config_t pio_config_clk [IDE_MAX_PIO_MODE+1];
+
+#ifndef	CFG_PIO_MODE
+#define	CFG_PIO_MODE	0		/* use a relaxed default */
+#endif
+static int pio_mode = CFG_PIO_MODE;
+
+/* Make clock cycles and always round up */
+
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U )
+
+/* ------------------------------------------------------------------------- */
+
+/* Current I/O Device	*/
+static int curr_device = -1;
+
+/* Current offset for IDE0 / IDE1 bus access	*/
+ulong ide_bus_offset[CFG_IDE_MAXBUS] = {
+#if defined(CFG_ATA_IDE0_OFFSET)
+	CFG_ATA_IDE0_OFFSET,
+#endif
+#if defined(CFG_ATA_IDE1_OFFSET) && (CFG_IDE_MAXBUS > 1)
+	CFG_ATA_IDE1_OFFSET,
+#endif
+};
+
+#define	ATA_CURR_BASE(dev)	(CFG_ATA_BASE_ADDR+ide_bus_offset[IDE_BUS(dev)])
+
+static int	    ide_bus_ok[CFG_IDE_MAXBUS];
+
+static  block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_LED
+static void  ide_led   (uchar led, uchar status);
+#else
+#define ide_led(a,b)	/* dummy */
+#endif
+
+#ifdef CONFIG_IDE_RESET
+static void  ide_reset (void);
+#else
+#define ide_reset()	/* dummy */
+#endif
+
+static void  ide_ident (block_dev_desc_t *dev_desc);
+static uchar ide_wait  (int dev, ulong t);
+
+#define IDE_TIME_OUT	2000	/* 2 sec timeout */
+
+#define ATAPI_TIME_OUT	7000	/* 7 sec timeout (5 sec seems to work...) */
+
+#define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
+
+static void __inline__ outb(int dev, int port, unsigned char val);
+static unsigned char __inline__ inb(int dev, int port);
+static void input_swap_data(int dev, ulong *sect_buf, int words);
+static void input_data(int dev, ulong *sect_buf, int words);
+static void output_data(int dev, ulong *sect_buf, int words);
+static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
+
+
+#ifdef CONFIG_ATAPI
+static void	atapi_inquiry(block_dev_desc_t *dev_desc);
+ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer);
+#endif
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+static void set_pcmcia_timing (int pmode);
+#else
+#define set_pcmcia_timing(a)	/* dummy */
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+int do_ide (cmd_tbl_t *cmdtp, 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 (strncmp(argv[1],"res",3) == 0) {
+		puts ("\nReset IDE"
+#ifdef CONFIG_IDE_8xx_DIRECT
+			" on PCMCIA " PCMCIA_SLOT_MSG
+#endif
+			": ");
+
+		ide_init ();
+		return 0;
+	} else if (strncmp(argv[1],"inf",3) == 0) {
+		int i;
+
+		putc ('\n');
+
+		for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
+			if (ide_dev_desc[i].type==DEV_TYPE_UNKNOWN)
+				continue; /* list only known devices */
+			printf ("IDE device %d: ", i);
+			dev_print(&ide_dev_desc[i]);
+		}
+		return 0;
+
+	} else if (strncmp(argv[1],"dev",3) == 0) {
+		if ((curr_device < 0) || (curr_device >= CFG_IDE_MAXDEVICE)) {
+			puts ("\nno IDE devices available\n");
+			return 1;
+		}
+		printf ("\nIDE device %d: ", curr_device);
+		dev_print(&ide_dev_desc[curr_device]);
+		return 0;
+	} else if (strncmp(argv[1],"part",4) == 0) {
+		int dev, ok;
+
+		for (ok=0, dev=0; dev<CFG_IDE_MAXDEVICE; ++dev) {
+			if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+				++ok;
+				if (dev)
+					putc ('\n');
+				print_part(&ide_dev_desc[dev]);
+			}
+		}
+		if (!ok) {
+			puts ("\nno IDE devices available\n");
+			rcode ++;
+		}
+		return rcode;
+	}
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    case 3:
+	if (strncmp(argv[1],"dev",3) == 0) {
+		int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+		printf ("\nIDE device %d: ", dev);
+		if (dev >= CFG_IDE_MAXDEVICE) {
+			puts ("unknown device\n");
+			return 1;
+		}
+		dev_print(&ide_dev_desc[dev]);
+		/*ide_print (dev);*/
+
+		if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
+			return 1;
+		}
+
+		curr_device = dev;
+
+		puts ("... is now current device\n");
+
+		return 0;
+	} else if (strncmp(argv[1],"part",4) == 0) {
+		int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+		if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+				print_part(&ide_dev_desc[dev]);
+		} else {
+			printf ("\nIDE device %d not available\n", dev);
+			rcode = 1;
+		}
+		return rcode;
+#if 0
+	} else if (strncmp(argv[1],"pio",4) == 0) {
+		int mode = (int)simple_strtoul(argv[2], NULL, 10);
+
+		if ((mode >= 0) && (mode <= IDE_MAX_PIO_MODE)) {
+			puts ("\nSetting ");
+			pio_mode = mode;
+			ide_init ();
+		} else {
+			printf ("\nInvalid PIO mode %d (0 ... %d only)\n",
+				mode, IDE_MAX_PIO_MODE);
+		}
+		return;
+#endif
+	}
+
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    default:
+	/* at least 4 args */
+
+	if (strcmp(argv[1],"read") == 0) {
+		ulong addr = simple_strtoul(argv[2], NULL, 16);
+		ulong blk  = simple_strtoul(argv[3], NULL, 16);
+		ulong cnt  = simple_strtoul(argv[4], NULL, 16);
+		ulong n;
+
+		printf ("\nIDE read: device %d block # %ld, count %ld ... ",
+			curr_device, blk, cnt);
+
+		n = ide_dev_desc[curr_device].block_read (curr_device,
+							  blk, cnt,
+							  (ulong *)addr);
+		/* flush cache after read */
+		flush_cache (addr, cnt*ide_dev_desc[curr_device].blksz);
+
+		printf ("%ld blocks read: %s\n",
+			n, (n==cnt) ? "OK" : "ERROR");
+		if (n==cnt) {
+			return 0;
+		} else {
+			return 1;
+		}
+	} else if (strcmp(argv[1],"write") == 0) {
+		ulong addr = simple_strtoul(argv[2], NULL, 16);
+		ulong blk  = simple_strtoul(argv[3], NULL, 16);
+		ulong cnt  = simple_strtoul(argv[4], NULL, 16);
+		ulong n;
+
+		printf ("\nIDE write: device %d block # %ld, count %ld ... ",
+			curr_device, blk, cnt);
+
+		n = ide_write (curr_device, blk, cnt, (ulong *)addr);
+
+		printf ("%ld blocks written: %s\n",
+			n, (n==cnt) ? "OK" : "ERROR");
+		if (n==cnt) {
+			return 0;
+		} else {
+			return 1;
+		}
+	} else {
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		rcode = 1;
+	}
+
+	return rcode;
+    }
+}
+
+int do_diskboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *boot_device = NULL;
+	char *ep;
+	int dev, part = 0;
+	ulong cnt;
+	ulong addr;
+	disk_partition_t info;
+	image_header_t *hdr;
+	int rcode = 0;
+
+	switch (argc) {
+	case 1:
+		addr = CFG_LOAD_ADDR;
+		boot_device = getenv ("bootdevice");
+		break;
+	case 2:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = getenv ("bootdevice");
+		break;
+	case 3:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = argv[2];
+		break;
+	default:
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (!boot_device) {
+		puts ("\n** No boot device **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	dev = simple_strtoul(boot_device, &ep, 16);
+
+	if (ide_dev_desc[dev].type==DEV_TYPE_UNKNOWN) {
+		printf ("\n** Device %d not available\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (*ep) {
+		if (*ep != ':') {
+			puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+			SHOW_BOOT_PROGRESS (-1);
+			return 1;
+		}
+		part = simple_strtoul(++ep, NULL, 16);
+	}
+	if (get_partition_info (&ide_dev_desc[dev], part, &info)) {
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+	if (strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) {
+		printf ("\n** Invalid partition type \"%.32s\""
+			" (expect \"" BOOT_PART_TYPE "\")\n",
+			info.type);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	printf ("\nLoading from IDE device %d, partition %d: "
+		"Name: %.32s  Type: %.32s\n",
+		dev, part, info.name, info.type);
+
+	PRINTF ("First Block: %ld,  # of blocks: %ld, Block Size: %ld\n",
+		info.start, info.size, info.blksz);
+
+	if (ide_dev_desc[dev].block_read (dev, info.start, 1, (ulong *)addr) != 1) {
+		printf ("** Read error on %d:%d\n", dev, part);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	hdr = (image_header_t *)addr;
+
+	if (ntohl(hdr->ih_magic) == IH_MAGIC) {
+
+		print_image_hdr (hdr);
+
+		cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
+		cnt += info.blksz - 1;
+		cnt /= info.blksz;
+		cnt -= 1;
+	} else {
+		printf("\n** Bad Magic Number **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (ide_dev_desc[dev].block_read (dev, info.start+1, cnt,
+		      (ulong *)(addr+info.blksz)) != cnt) {
+		printf ("** Read error on %d:%d\n", dev, part);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+
+	/* Loading ok, update default load address */
+
+	load_addr = addr;
+
+	/* Check if we should attempt an auto-start */
+	if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+		char *local_args[2];
+		extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
+
+		local_args[0] = argv[0];
+		local_args[1] = NULL;
+
+		printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
+
+		do_bootm (cmdtp, 0, 1, local_args);
+		rcode = 1;
+	}
+	return rcode;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void ide_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+	volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+#endif
+	unsigned char c;
+	int i, bus;
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	extern int pcmcia_on (void);
+
+	WATCHDOG_RESET();
+
+	/* initialize the PCMCIA IDE adapter card */
+	if (pcmcia_on())
+		return;
+	udelay (1000000);	/* 1 s */
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+	WATCHDOG_RESET();
+
+	/* Initialize PIO timing tables */
+	for (i=0; i <= IDE_MAX_PIO_MODE; ++i) {
+	    pio_config_clk[i].t_setup  = PCMCIA_MK_CLKS(pio_config_ns[i].t_setup,
+							    gd->bus_clk);
+	    pio_config_clk[i].t_length = PCMCIA_MK_CLKS(pio_config_ns[i].t_length,
+							    gd->bus_clk);
+	    pio_config_clk[i].t_hold   = PCMCIA_MK_CLKS(pio_config_ns[i].t_hold,
+							    gd->bus_clk);
+	    PRINTF ("PIO Mode %d: setup=%2d ns/%d clk"
+		    "  len=%3d ns/%d clk"
+		    "  hold=%2d ns/%d clk\n",
+		    i,
+		    pio_config_ns[i].t_setup,  pio_config_clk[i].t_setup,
+		    pio_config_ns[i].t_length, pio_config_clk[i].t_length,
+		    pio_config_ns[i].t_hold,   pio_config_clk[i].t_hold);
+	}
+
+	/* Reset the IDE just to be sure.
+	 * Light LED's to show
+	 */
+	ide_led ((LED_IDE1 | LED_IDE2), 1);		/* LED's on	*/
+	ide_reset (); /* ATAPI Drives seems to need a proper IDE Reset */
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+	/* PCMCIA / IDE initialization for common mem space */
+	pcmp->pcmc_pgcrb = 0;
+#endif
+
+	/* start in PIO mode 0 - most relaxed timings */
+	pio_mode = 0;
+	set_pcmcia_timing (pio_mode);
+
+	/*
+	 * Wait for IDE to get ready.
+	 * According to spec, this can take up to 31 seconds!
+	 */
+	for (bus=0; bus<CFG_IDE_MAXBUS; ++bus) {
+		int dev = bus * (CFG_IDE_MAXDEVICE / CFG_IDE_MAXBUS);
+
+		printf ("Bus %d: ", bus);
+
+		ide_bus_ok[bus] = 0;
+
+		/* Select device
+		 */
+		udelay (100000);		/* 100 ms */
+		outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
+		udelay (100000);		/* 100 ms */
+
+		i = 0;
+		do {
+			udelay (10000);		/* 10 ms */
+
+			c = inb (dev, ATA_STATUS);
+			i++;
+			if (i > (ATA_RESET_TIME * 100)) {
+				puts ("** Timeout **\n");
+				ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
+				return;
+			}
+			if ((i >= 100) && ((i%100)==0)) {
+				putc ('.');
+			}
+		} while (c & ATA_STAT_BUSY);
+
+		if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
+			puts ("not available  ");
+			PRINTF ("Status = 0x%02X ", c);
+#ifndef CONFIG_ATAPI /* ATAPI Devices do not set DRDY */
+		} else  if ((c & ATA_STAT_READY) == 0) {
+			puts ("not available  ");
+			PRINTF ("Status = 0x%02X ", c);
+#endif
+		} else {
+			puts ("OK ");
+			ide_bus_ok[bus] = 1;
+		}
+		WATCHDOG_RESET();
+	}
+	putc ('\n');
+
+	ide_led ((LED_IDE1 | LED_IDE2), 0);	/* LED's off	*/
+
+	curr_device = -1;
+	for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
+#ifdef CONFIG_IDE_LED
+		int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2;
+#endif
+		ide_dev_desc[i].if_type=IF_TYPE_IDE;
+		ide_dev_desc[i].dev=i;
+		ide_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
+		ide_dev_desc[i].blksz=0;
+		ide_dev_desc[i].lba=0;
+		ide_dev_desc[i].block_read=ide_read;
+		if (!ide_bus_ok[IDE_BUS(i)])
+			continue;
+		ide_led (led, 1);		/* LED on	*/
+		ide_ident(&ide_dev_desc[i]);
+		ide_led (led, 0);		/* LED off	*/
+		dev_print(&ide_dev_desc[i]);
+/*		ide_print (i); */
+		if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
+			init_part (&ide_dev_desc[i]);			/* initialize partition type */
+			if (curr_device < 0)
+				curr_device = i;
+		}
+	}
+	WATCHDOG_RESET();
+}
+
+/* ------------------------------------------------------------------------- */
+
+block_dev_desc_t * ide_get_dev(int dev)
+{
+	return ((block_dev_desc_t *)&ide_dev_desc[dev]);
+}
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+
+static void
+set_pcmcia_timing (int pmode)
+{
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+	volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+	ulong timings;
+
+	PRINTF ("Set timing for PIO Mode %d\n", pmode);
+
+	timings = PCMCIA_SHT(pio_config_clk[pmode].t_hold)
+		| PCMCIA_SST(pio_config_clk[pmode].t_setup)
+		| PCMCIA_SL (pio_config_clk[pmode].t_length)
+		;
+
+	/* IDE 0
+	 */
+	pcmp->pcmc_pbr0 = CFG_PCMCIA_PBR0;
+	pcmp->pcmc_por0 = CFG_PCMCIA_POR0
+#if (CFG_PCMCIA_POR0 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR0: %08x  POR0: %08x\n", pcmp->pcmc_pbr0, pcmp->pcmc_por0);
+
+	pcmp->pcmc_pbr1 = CFG_PCMCIA_PBR1;
+	pcmp->pcmc_por1 = CFG_PCMCIA_POR1
+#if (CFG_PCMCIA_POR1 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR1: %08x  POR1: %08x\n", pcmp->pcmc_pbr1, pcmp->pcmc_por1);
+
+	pcmp->pcmc_pbr2 = CFG_PCMCIA_PBR2;
+	pcmp->pcmc_por2 = CFG_PCMCIA_POR2
+#if (CFG_PCMCIA_POR2 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR2: %08x  POR2: %08x\n", pcmp->pcmc_pbr2, pcmp->pcmc_por2);
+
+	pcmp->pcmc_pbr3 = CFG_PCMCIA_PBR3;
+	pcmp->pcmc_por3 = CFG_PCMCIA_POR3
+#if (CFG_PCMCIA_POR3 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR3: %08x  POR3: %08x\n", pcmp->pcmc_pbr3, pcmp->pcmc_por3);
+
+	/* IDE 1
+	 */
+	pcmp->pcmc_pbr4 = CFG_PCMCIA_PBR4;
+	pcmp->pcmc_por4 = CFG_PCMCIA_POR4
+#if (CFG_PCMCIA_POR4 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR4: %08x  POR4: %08x\n", pcmp->pcmc_pbr4, pcmp->pcmc_por4);
+
+	pcmp->pcmc_pbr5 = CFG_PCMCIA_PBR5;
+	pcmp->pcmc_por5 = CFG_PCMCIA_POR5
+#if (CFG_PCMCIA_POR5 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR5: %08x  POR5: %08x\n", pcmp->pcmc_pbr5, pcmp->pcmc_por5);
+
+	pcmp->pcmc_pbr6 = CFG_PCMCIA_PBR6;
+	pcmp->pcmc_por6 = CFG_PCMCIA_POR6
+#if (CFG_PCMCIA_POR6 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR6: %08x  POR6: %08x\n", pcmp->pcmc_pbr6, pcmp->pcmc_por6);
+
+	pcmp->pcmc_pbr7 = CFG_PCMCIA_PBR7;
+	pcmp->pcmc_por7 = CFG_PCMCIA_POR7
+#if (CFG_PCMCIA_POR7 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR7: %08x  POR7: %08x\n", pcmp->pcmc_pbr7, pcmp->pcmc_por7);
+
+}
+
+#endif	/* CONFIG_IDE_8xx_DIRECT */
+
+/* ------------------------------------------------------------------------- */
+
+static void __inline__
+outb(int dev, int port, unsigned char val)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	*((uchar *)(ATA_CURR_BASE(dev)+port)) = val;
+#if 0
+	printf ("OUTB: 0x%08lx <== 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
+#endif
+}
+
+static unsigned char __inline__
+inb(int dev, int port)
+{
+	uchar val;
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	val = *((uchar *)(ATA_CURR_BASE(dev)+port));
+#if 0
+	printf ("INB: 0x%08lx ==> 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
+#endif
+	return (val);
+}
+
+__inline__ unsigned ld_le16(const volatile unsigned short *addr)
+{
+	unsigned val;
+
+	__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r"(val) : "r"(addr), "m"(*addr));
+	return val;
+}
+
+static void
+input_swap_data(int dev, ulong *sect_buf, int words)
+{
+	volatile ushort	*pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	ushort	*dbuf = (ushort *)sect_buf;
+
+	while (words--) {
+		*dbuf++ = ld_le16(pbuf);
+		*dbuf++ = ld_le16(pbuf);
+	}
+}
+
+static void
+output_data(int dev, ulong *sect_buf, int words)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (words--) {
+		__asm__ volatile ("eieio");
+		*pbuf = *dbuf++;
+		__asm__ volatile ("eieio");
+		*pbuf = *dbuf++;
+	}
+}
+
+static void
+input_data(int dev, ulong *sect_buf, int words)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (words--) {
+		__asm__ volatile ("eieio");
+		*dbuf++ = *pbuf;
+		__asm__ volatile ("eieio");
+		*dbuf++ = *pbuf;
+	}
+}
+
+/* -------------------------------------------------------------------------
+ */
+static void ide_ident (block_dev_desc_t *dev_desc)
+{
+	ulong iobuf[ATA_SECTORWORDS];
+	unsigned char c;
+	hd_driveid_t *iop = (hd_driveid_t *)iobuf;
+
+#if 0
+	int mode, cycle_time;
+#endif
+	int device;
+	device=dev_desc->dev;
+	printf ("  Device %d: ", device);
+
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+	/* Select device
+	 */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	dev_desc->if_type=IF_TYPE_IDE;
+#ifdef CONFIG_ATAPI
+	/* check signature */
+	if ((inb(device,ATA_SECT_CNT)==0x01) &&
+		 (inb(device,ATA_SECT_NUM)==0x01) &&
+		 (inb(device,ATA_CYL_LOW)==0x14) &&
+		 (inb(device,ATA_CYL_HIGH)==0xEB)) {
+		/* ATAPI Signature found */
+		dev_desc->if_type=IF_TYPE_ATAPI;
+		/* Start Ident Command
+		 */
+		outb (device, ATA_COMMAND, ATAPI_CMD_IDENT);
+		/*
+		 * Wait for completion - ATAPI devices need more time
+		 * to become ready
+		 */
+		c = ide_wait (device, ATAPI_TIME_OUT);
+	}
+	else
+#endif
+	{
+		/* Start Ident Command
+		 */
+		outb (device, ATA_COMMAND, ATA_CMD_IDENT);
+
+		/* Wait for completion
+		 */
+		c = ide_wait (device, IDE_TIME_OUT);
+	}
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+
+	if (((c & ATA_STAT_DRQ) == 0) ||
+	    ((c & (ATA_STAT_FAULT|ATA_STAT_ERR)) != 0) ) {
+		dev_desc->type=DEV_TYPE_UNKNOWN;
+		return;
+	}
+
+	input_swap_data (device, iobuf, ATA_SECTORWORDS);
+
+	ident_cpy (dev_desc->revision, iop->fw_rev, sizeof(dev_desc->revision));
+	ident_cpy (dev_desc->vendor, iop->model, sizeof(dev_desc->vendor));
+	ident_cpy (dev_desc->product, iop->serial_no, sizeof(dev_desc->product));
+
+	if ((iop->config & 0x0080)==0x0080)
+		dev_desc->removable = 1;
+	else
+		dev_desc->removable = 0;
+
+#if 0
+	/*
+	 * Drive PIO mode autoselection
+	 */
+	mode = iop->tPIO;
+
+	printf ("tPIO = 0x%02x = %d\n",mode, mode);
+	if (mode > 2) {		/* 2 is maximum allowed tPIO value */
+		mode = 2;
+		PRINTF ("Override tPIO -> 2\n");
+	}
+	if (iop->field_valid & 2) {	/* drive implements ATA2? */
+		PRINTF ("Drive implements ATA2\n");
+		if (iop->capability & 8) {	/* drive supports use_iordy? */
+			cycle_time = iop->eide_pio_iordy;
+		} else {
+			cycle_time = iop->eide_pio;
+		}
+		PRINTF ("cycle time = %d\n", cycle_time);
+		mode = 4;
+		if (cycle_time > 120) mode = 3;	/* 120 ns for PIO mode 4 */
+		if (cycle_time > 180) mode = 2;	/* 180 ns for PIO mode 3 */
+		if (cycle_time > 240) mode = 1;	/* 240 ns for PIO mode 4 */
+		if (cycle_time > 383) mode = 0;	/* 383 ns for PIO mode 4 */
+	}
+	printf ("PIO mode to use: PIO %d\n", mode);
+#endif /* 0 */
+
+#ifdef CONFIG_ATAPI
+	if (dev_desc->if_type==IF_TYPE_ATAPI) {
+		atapi_inquiry(dev_desc);
+		return;
+	}
+#endif /* CONFIG_ATAPI */
+
+	/* swap shorts */
+	dev_desc->lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
+	/* assuming HD */
+	dev_desc->type=DEV_TYPE_HARDDISK;
+	dev_desc->blksz=ATA_BLOCKSIZE;
+	dev_desc->lun=0; /* just to fill something in... */
+
+#if 0 	/* only used to test the powersaving mode,
+	 * if enabled, the drive goes after 5 sec
+	 * in standby mode */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = ide_wait (device, IDE_TIME_OUT);
+	outb (device, ATA_SECT_CNT, 1);
+	outb (device, ATA_LBA_LOW,  0);
+	outb (device, ATA_LBA_MID,  0);
+	outb (device, ATA_LBA_HIGH, 0);
+	outb (device, ATA_DEV_HD,   ATA_LBA		|
+				    ATA_DEVICE(device));
+	outb (device, ATA_COMMAND,  0xe3);
+	udelay (50);
+	c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+#endif
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+	ulong n = 0;
+	unsigned char c;
+	unsigned char pwrsave=0; /* power save */
+
+	PRINTF ("ide_read dev %d start %lX, blocks %lX buffer at %lX\n",
+		device, blknr, blkcnt, (ulong)buffer);
+
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+
+	/* Select device
+	 */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = ide_wait (device, IDE_TIME_OUT);
+
+	if (c & ATA_STAT_BUSY) {
+		printf ("IDE read: device %d not ready\n", device);
+		goto IDE_READ_E;
+	}
+
+	/* first check if the drive is in Powersaving mode, if yes,
+	 * increase the timeout value */
+	outb (device, ATA_COMMAND,  ATA_CMD_CHK_PWR);
+	udelay (50);
+
+	c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+
+	if (c & ATA_STAT_BUSY) {
+		printf ("IDE read: device %d not ready\n", device);
+		goto IDE_READ_E;
+	}
+	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+		printf ("No Powersaving mode %X\n", c);
+	} else {
+		c = inb(device,ATA_SECT_CNT);
+		PRINTF("Powersaving %02X\n",c);
+		if(c==0)
+			pwrsave=1;
+	}
+
+
+	while (blkcnt-- > 0) {
+
+		c = ide_wait (device, IDE_TIME_OUT);
+
+		if (c & ATA_STAT_BUSY) {
+			printf ("IDE read: device %d not ready\n", device);
+			break;
+		}
+
+		outb (device, ATA_SECT_CNT, 1);
+		outb (device, ATA_LBA_LOW,  (blknr >>  0) & 0xFF);
+		outb (device, ATA_LBA_MID,  (blknr >>  8) & 0xFF);
+		outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+		outb (device, ATA_DEV_HD,   ATA_LBA		|
+					    ATA_DEVICE(device)	|
+					    ((blknr >> 24) & 0xF) );
+		outb (device, ATA_COMMAND,  ATA_CMD_READ);
+
+		udelay (50);
+
+		if(pwrsave) {
+			c = ide_wait (device, IDE_SPIN_UP_TIME_OUT);	/* may take up to 4 sec */
+			pwrsave=0;
+		} else {
+			c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+		}
+
+		if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+			printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+				device, blknr, c);
+			break;
+		}
+
+		input_data (device, buffer, ATA_SECTORWORDS);
+		(void) inb (device, ATA_STATUS);	/* clear IRQ */
+
+		++n;
+		++blknr;
+		buffer += ATA_SECTORWORDS;
+	}
+IDE_READ_E:
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+	return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+	ulong n = 0;
+	unsigned char c;
+
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+
+	/* Select device
+	 */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+	while (blkcnt-- > 0) {
+
+		c = ide_wait (device, IDE_TIME_OUT);
+
+		if (c & ATA_STAT_BUSY) {
+			printf ("IDE read: device %d not ready\n", device);
+			goto WR_OUT;
+		}
+
+		outb (device, ATA_SECT_CNT, 1);
+		outb (device, ATA_LBA_LOW,  (blknr >>  0) & 0xFF);
+		outb (device, ATA_LBA_MID,  (blknr >>  8) & 0xFF);
+		outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+		outb (device, ATA_DEV_HD,   ATA_LBA		|
+					    ATA_DEVICE(device)	|
+					    ((blknr >> 24) & 0xF) );
+		outb (device, ATA_COMMAND,  ATA_CMD_WRITE);
+
+		udelay (50);
+
+		c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+
+		if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+			printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+				device, blknr, c);
+			goto WR_OUT;
+		}
+
+		output_data (device, buffer, ATA_SECTORWORDS);
+		c = inb (device, ATA_STATUS);	/* clear IRQ */
+		++n;
+		++blknr;
+		buffer += ATA_SECTORWORDS;
+	}
+WR_OUT:
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+	return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * copy src to dest, skipping leading and trailing blanks and null
+ * terminate the string
+ */
+static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len)
+{
+	int start,end;
+
+	start=0;
+	while (start<len) {
+		if (src[start]!=' ')
+			break;
+		start++;
+	}
+	end=len-1;
+	while (end>start) {
+		if (src[end]!=' ')
+			break;
+		end--;
+	}
+	for ( ; start<=end; start++) {
+		*dest++=src[start];
+	}
+	*dest='\0';
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Wait until Busy bit is off, or timeout (in ms)
+ * Return last status
+ */
+static uchar ide_wait (int dev, ulong t)
+{
+	ulong delay = 10 * t;		/* poll every 100 us */
+	uchar c;
+
+	while ((c = inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
+		udelay (100);
+		if (delay-- == 0) {
+			break;
+		}
+	}
+	return (c);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_RESET
+extern void ide_set_reset(int idereset);
+
+static void ide_reset (void)
+{
+#if defined(CFG_PB_12V_ENABLE) || defined(CFG_PB_IDE_MOTOR)
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int i;
+
+	curr_device = -1;
+	for (i=0; i<CFG_IDE_MAXBUS; ++i)
+		ide_bus_ok[i] = 0;
+	for (i=0; i<CFG_IDE_MAXDEVICE; ++i)
+		ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+
+	ide_set_reset (1); /* assert reset */
+
+	WATCHDOG_RESET();
+
+#ifdef CFG_PB_12V_ENABLE
+	immr->im_cpm.cp_pbdat &= ~(CFG_PB_12V_ENABLE);	/* 12V Enable output OFF */
+	immr->im_cpm.cp_pbpar &= ~(CFG_PB_12V_ENABLE);
+	immr->im_cpm.cp_pbodr &= ~(CFG_PB_12V_ENABLE);
+	immr->im_cpm.cp_pbdir |=   CFG_PB_12V_ENABLE;
+
+	/* wait 500 ms for the voltage to stabilize
+	 */
+	for (i=0; i<500; ++i) {
+		udelay (1000);
+	}
+
+	immr->im_cpm.cp_pbdat |=   CFG_PB_12V_ENABLE;	/* 12V Enable output ON */
+#endif	/* CFG_PB_12V_ENABLE */
+
+#ifdef CFG_PB_IDE_MOTOR
+	/* configure IDE Motor voltage monitor pin as input */
+	immr->im_cpm.cp_pbpar &= ~(CFG_PB_IDE_MOTOR);
+	immr->im_cpm.cp_pbodr &= ~(CFG_PB_IDE_MOTOR);
+	immr->im_cpm.cp_pbdir &= ~(CFG_PB_IDE_MOTOR);
+
+	/* wait up to 1 s for the motor voltage to stabilize
+	 */
+	for (i=0; i<1000; ++i) {
+		if ((immr->im_cpm.cp_pbdat & CFG_PB_IDE_MOTOR) != 0) {
+			break;
+		}
+		udelay (1000);
+	}
+
+	if (i == 1000) {	/* Timeout */
+		printf ("\nWarning: 5V for IDE Motor missing\n");
+# ifdef CONFIG_STATUS_LED
+#  ifdef STATUS_LED_YELLOW
+		status_led_set  (STATUS_LED_YELLOW, STATUS_LED_ON );
+#  endif
+#  ifdef STATUS_LED_GREEN
+		status_led_set  (STATUS_LED_GREEN,  STATUS_LED_OFF);
+#  endif
+# endif	/* CONFIG_STATUS_LED */
+	}
+#endif	/* CFG_PB_IDE_MOTOR */
+
+	WATCHDOG_RESET();
+
+	/* de-assert RESET signal */
+	ide_set_reset(0);
+
+	/* wait 250 ms */
+	for (i=0; i<250; ++i) {
+		udelay (1000);
+	}
+}
+
+#endif	/* CONFIG_IDE_RESET */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_LED
+
+static	uchar	led_buffer = 0;		/* Buffer for current LED status	*/
+
+static void ide_led (uchar led, uchar status)
+{
+	uchar *led_port = LED_PORT;
+
+	if (status)	{		/* switch LED on	*/
+		led_buffer |=  led;
+	} else {			/* switch LED off	*/
+		led_buffer &= ~led;
+	}
+
+	*led_port = led_buffer;
+}
+
+#endif	/* CONFIG_IDE_LED */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ATAPI
+/****************************************************************************
+ * ATAPI Support
+ */
+
+
+
+#undef	ATAPI_DEBUG
+
+#ifdef	ATAPI_DEBUG
+#define	AT_PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define AT_PRINTF(fmt,args...)
+#endif
+
+/* since ATAPI may use commands with not 4 bytes alligned length
+ * we have our own transfer functions, 2 bytes alligned */
+static void
+output_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (shorts--) {
+		__asm__ volatile ("eieio");
+		*pbuf = *dbuf++;
+	}
+}
+
+static void
+input_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (shorts--) {
+		__asm__ volatile ("eieio");
+		*dbuf++ = *pbuf;
+	}
+}
+
+/*
+ * Wait until (Status & mask) == res, or timeout (in ms)
+ * Return last status
+ * This is used since some ATAPI CD ROMs clears their Busy Bit first
+ * and then they set their DRQ Bit
+ */
+static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res)
+{
+	ulong delay = 10 * t;		/* poll every 100 us */
+	uchar c;
+
+	c = inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */
+	while (((c = inb(dev, ATA_STATUS)) & mask)
+			!= res) {
+		/* break if error occurs (doesn't make sense to wait more) */
+		if((c & ATA_STAT_ERR)==ATA_STAT_ERR)
+			break;
+		udelay (100);
+		if (delay-- == 0) {
+			break;
+		}
+	}
+	return (c);
+}
+
+/*
+ * issue an atapi command
+ */
+unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned char * buffer,int buflen)
+{
+	unsigned char c,err,mask,res;
+	int n;
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+
+	/* Select device
+	 */
+	mask = ATA_STAT_BUSY|ATA_STAT_DRQ;
+	res = 0;
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+	if ((c & mask) != res) {
+		printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c);
+		err=0xFF;
+		goto AI_OUT;
+	}
+	/* write taskfile */
+	outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */
+	outb (device, ATA_CYL_LOW,  (unsigned char)(buflen & 0xFF));
+	outb (device, ATA_CYL_HIGH, (unsigned char)((buflen<<8) & 0xFF));
+	outb (device, ATA_DEV_HD,   ATA_LBA | ATA_DEVICE(device));
+
+	outb (device, ATA_COMMAND,  ATAPI_CMD_PACKET);
+	udelay (50);
+
+	mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+	res = ATA_STAT_DRQ;
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+
+	if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */
+		printf ("ATTAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",device,c);
+		err=0xFF;
+		goto AI_OUT;
+	}
+
+	output_data_shorts (device, (unsigned short *)ccb,ccblen/2); /* write command block */
+ 	/* ATAPI Command written wait for completition */
+	udelay (5000); /* device must set bsy */
+
+	mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+	/* if no data wait for DRQ = 0 BSY = 0
+	 * if data wait for DRQ = 1 BSY = 0 */
+	res=0;
+	if(buflen)
+		res = ATA_STAT_DRQ;
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+	if ((c & mask) != res ) {
+		if (c & ATA_STAT_ERR) {
+			err=(inb(device,ATA_ERROR_REG))>>4;
+			AT_PRINTF("atapi_issue 1 returned sense key %X status %02X\n",err,c);
+		} else {
+			printf ("ATTAPI_ISSUE: (no DRQ) after sending ccb (%x)  status 0x%02x\n", ccb[0],c);
+			err=0xFF;
+		}
+		goto AI_OUT;
+	}
+	n=inb(device, ATA_CYL_HIGH);
+	n<<=8;
+	n+=inb(device, ATA_CYL_LOW);
+	if(n>buflen) {
+		printf("ERROR, transfer bytes %d requested only %d\n",n,buflen);
+		err=0xff;
+		goto AI_OUT;
+	}
+	if((n==0)&&(buflen<0)) {
+		printf("ERROR, transfer bytes %d requested %d\n",n,buflen);
+		err=0xff;
+		goto AI_OUT;
+	}
+	if(n!=buflen) {
+		AT_PRINTF("WARNING, transfer bytes %d not equal with requested %d\n",n,buflen);
+	}
+	if(n!=0) { /* data transfer */
+		AT_PRINTF("ATAPI_ISSUE: %d Bytes to transfer\n",n);
+		 /* we transfer shorts */
+		n>>=1;
+		/* ok now decide if it is an in or output */
+		if ((inb(device, ATA_SECT_CNT)&0x02)==0) {
+			AT_PRINTF("Write to device\n");
+			output_data_shorts(device,(unsigned short *)buffer,n);
+		} else {
+			AT_PRINTF("Read from device @ %p shorts %d\n",buffer,n);
+			input_data_shorts(device,(unsigned short *)buffer,n);
+		}
+	}
+	udelay(5000); /* seems that some CD ROMs need this... */
+	mask = ATA_STAT_BUSY|ATA_STAT_ERR;
+	res=0;
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+		err=(inb(device,ATA_ERROR_REG) >> 4);
+		AT_PRINTF("atapi_issue 2 returned sense key %X status %X\n",err,c);
+	} else {
+		err = 0;
+	}
+AI_OUT:
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+	return (err);
+}
+
+/*
+ * sending the command to atapi_issue. If an status other than good
+ * returns, an request_sense will be issued
+ */
+
+#define ATAPI_DRIVE_NOT_READY 	100
+#define ATAPI_UNIT_ATTN		10
+
+unsigned char atapi_issue_autoreq (int device,
+				   unsigned char* ccb,
+				   int ccblen,
+				   unsigned char *buffer,
+				   int buflen)
+{
+	unsigned char sense_data[18],sense_ccb[12];
+	unsigned char res,key,asc,ascq;
+	int notready,unitattn;
+
+	unitattn=ATAPI_UNIT_ATTN;
+	notready=ATAPI_DRIVE_NOT_READY;
+
+retry:
+	res= atapi_issue(device,ccb,ccblen,buffer,buflen);
+	if (res==0)
+		return (0); /* Ok */
+
+	if (res==0xFF)
+		return (0xFF); /* error */
+
+	AT_PRINTF("(auto_req)atapi_issue returned sense key %X\n",res);
+
+	memset(sense_ccb,0,sizeof(sense_ccb));
+	memset(sense_data,0,sizeof(sense_data));
+	sense_ccb[0]=ATAPI_CMD_REQ_SENSE;
+	sense_ccb[4]=18; /* allocation Legnth */
+
+	res=atapi_issue(device,sense_ccb,12,sense_data,18);
+	key=(sense_data[2]&0xF);
+	asc=(sense_data[12]);
+	ascq=(sense_data[13]);
+
+	AT_PRINTF("ATAPI_CMD_REQ_SENSE returned %x\n",res);
+	AT_PRINTF(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
+		sense_data[0],
+		key,
+		asc,
+		ascq);
+
+	if((key==0))
+		return 0; /* ok device ready */
+
+	if((key==6)|| (asc==0x29) || (asc==0x28)) { /* Unit Attention */
+		if(unitattn-->0) {
+			udelay(200*1000);
+			goto retry;
+		}
+		printf("Unit Attention, tried %d\n",ATAPI_UNIT_ATTN);
+		goto error;
+	}
+	if((asc==0x4) && (ascq==0x1)) { /* not ready, but will be ready soon */
+		if (notready-->0) {
+			udelay(200*1000);
+			goto retry;
+		}
+		printf("Drive not ready, tried %d times\n",ATAPI_DRIVE_NOT_READY);
+		goto error;
+	}
+	if(asc==0x3a) {
+		AT_PRINTF("Media not present\n");
+		goto error;
+	}
+	printf ("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+error:
+	AT_PRINTF ("ERROR Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+	return (0xFF);
+}
+
+
+
+static void	atapi_inquiry(block_dev_desc_t * dev_desc)
+{
+	unsigned char ccb[12]; /* Command descriptor block */
+	unsigned char iobuf[64]; /* temp buf */
+	unsigned char c;
+	int device;
+
+	device=dev_desc->dev;
+	dev_desc->type=DEV_TYPE_UNKNOWN; /* not yet valid */
+	dev_desc->block_read=atapi_read;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+
+	ccb[0]=ATAPI_CMD_INQUIRY;
+	ccb[4]=40; /* allocation Legnth */
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,40);
+
+	AT_PRINTF("ATAPI_CMD_INQUIRY returned %x\n",c);
+	if (c!=0)
+		return;
+
+	/* copy device ident strings */
+	ident_cpy(dev_desc->vendor,&iobuf[8],8);
+	ident_cpy(dev_desc->product,&iobuf[16],16);
+	ident_cpy(dev_desc->revision,&iobuf[32],5);
+
+	dev_desc->lun=0;
+	dev_desc->lba=0;
+	dev_desc->blksz=0;
+	dev_desc->type=iobuf[0] & 0x1f;
+
+	if ((iobuf[1]&0x80)==0x80)
+		dev_desc->removable = 1;
+	else
+		dev_desc->removable = 0;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+	ccb[0]=ATAPI_CMD_START_STOP;
+	ccb[4]=0x03; /* start */
+
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+	AT_PRINTF("ATAPI_CMD_START_STOP returned %x\n",c);
+	if (c!=0)
+		return;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+	AT_PRINTF("ATAPI_CMD_UNIT_TEST_READY returned %x\n",c);
+	if (c!=0)
+		return;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+	ccb[0]=ATAPI_CMD_READ_CAP;
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,8);
+	AT_PRINTF("ATAPI_CMD_READ_CAP returned %x\n",c);
+	if (c!=0)
+		return;
+
+	AT_PRINTF("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n",
+		iobuf[0],iobuf[1],iobuf[2],iobuf[3],
+		iobuf[4],iobuf[5],iobuf[6],iobuf[7]);
+
+	dev_desc->lba  =((unsigned long)iobuf[0]<<24) +
+			((unsigned long)iobuf[1]<<16) +
+			((unsigned long)iobuf[2]<< 8) +
+			((unsigned long)iobuf[3]);
+	dev_desc->blksz=((unsigned long)iobuf[4]<<24) +
+			((unsigned long)iobuf[5]<<16) +
+			((unsigned long)iobuf[6]<< 8) +
+			((unsigned long)iobuf[7]);
+	return;
+}
+
+
+/*
+ * atapi_read:
+ * we transfer only one block per command, since the multiple DRQ per
+ * command is not yet implemented
+ */
+#define ATAPI_READ_MAX_BYTES	2048	/* we read max 2kbytes */
+#define ATAPI_READ_BLOCK_SIZE	2048	/* assuming CD part */
+#define ATAPI_READ_MAX_BLOCK ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE	/* max blocks */
+
+ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+	ulong n = 0;
+	unsigned char ccb[12]; /* Command descriptor block */
+	ulong cnt;
+
+	AT_PRINTF("atapi_read dev %d start %lX, blocks %lX buffer at %lX\n",
+		device, blknr, blkcnt, (ulong)buffer);
+
+	do {
+		if (blkcnt>ATAPI_READ_MAX_BLOCK) {
+			cnt=ATAPI_READ_MAX_BLOCK;
+		} else {
+			cnt=blkcnt;
+		}
+		ccb[0]=ATAPI_CMD_READ_12;
+		ccb[1]=0; /* reserved */
+		ccb[2]=(unsigned char) (blknr>>24) & 0xFF; /* MSB Block */
+		ccb[3]=(unsigned char) (blknr>>16) & 0xFF; /*  */
+		ccb[4]=(unsigned char) (blknr>> 8) & 0xFF;
+		ccb[5]=(unsigned char)  blknr      & 0xFF; /* LSB Block */
+		ccb[6]=(unsigned char) (cnt  >>24) & 0xFF; /* MSB Block count */
+		ccb[7]=(unsigned char) (cnt  >>16) & 0xFF;
+		ccb[8]=(unsigned char) (cnt  >> 8) & 0xFF;
+		ccb[9]=(unsigned char)  cnt	   & 0xFF; /* LSB Block */
+		ccb[10]=0; /* reserved */
+		ccb[11]=0; /* reserved */
+
+		if (atapi_issue_autoreq(device,ccb,12,
+					(unsigned char *)buffer,
+					cnt*ATAPI_READ_BLOCK_SIZE) == 0xFF) {
+			return (n);
+		}
+		n+=cnt;
+		blkcnt-=cnt;
+		blknr+=cnt;
+		buffer+=cnt*(ATAPI_READ_BLOCK_SIZE/4); /* ulong blocksize in ulong */
+	} while (blkcnt > 0);
+	return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CONFIG_ATAPI */
+
+#endif	/* CONFIG_COMMANDS & CFG_CMD_IDE */

+ 578 - 0
common/cmd_immap.c

@@ -0,0 +1,578 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC8xx/MPC8260 Internal Memory Map Functions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <cmd_immap.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_IMMAP) && \
+    (defined(CONFIG_8xx) || defined(CONFIG_8260))
+
+#if defined(CONFIG_8xx)
+#include <asm/8xx_immap.h>
+#include <commproc.h>
+#elif defined(CONFIG_8260)
+#include <asm/immap_8260.h>
+#include <asm/cpm_8260.h>
+#include <asm/iopin_8260.h>
+#endif
+
+static void
+unimplemented ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	printf ("Sorry, but the '%s' command has not been implemented\n",
+		cmdtp->name);
+}
+
+int
+do_siuinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile sysconf8xx_t *sc = &immap->im_siu_conf;
+#elif defined(CONFIG_8260)
+	volatile sysconf8260_t *sc = &immap->im_siu_conf;
+#endif
+
+	printf ("SIUMCR= %08x SYPCR = %08x\n", sc->sc_siumcr, sc->sc_sypcr);
+#if defined(CONFIG_8xx)
+	printf ("SWT   = %08x\n", sc->sc_swt);
+	printf ("SIPEND= %08x SIMASK= %08x\n", sc->sc_sipend, sc->sc_simask);
+	printf ("SIEL  = %08x SIVEC = %08x\n", sc->sc_siel, sc->sc_sivec);
+	printf ("TESR  = %08x SDCR  = %08x\n", sc->sc_tesr, sc->sc_sdcr);
+#elif defined(CONFIG_8260)
+	printf ("BCR   = %08x\n", sc->sc_bcr);
+	printf ("P_ACR =       %02x P_ALRH= %08x P_ALRL= %08x\n",
+		sc->sc_ppc_acr, sc->sc_ppc_alrh, sc->sc_ppc_alrl);
+	printf ("L_ACR =       %02x L_ALRH= %08x L_ALRL= %08x\n",
+		sc->sc_lcl_acr, sc->sc_lcl_alrh, sc->sc_lcl_alrl);
+	printf ("PTESR1= %08x PTESR2= %08x\n", sc->sc_tescr1, sc->sc_tescr2);
+	printf ("LTESR1= %08x LTESR2= %08x\n", sc->sc_ltescr1, sc->sc_ltescr2);
+	printf ("PDTEA = %08x PDTEM =       %02x\n", sc->sc_pdtea, sc->sc_pdtem);
+	printf ("LDTEA = %08x LDTEM =       %02x\n", sc->sc_ldtea, sc->sc_ldtem);
+#endif
+	return 0;
+}
+
+int
+do_memcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	int nbanks = 8;
+#elif defined(CONFIG_8260)
+	volatile memctl8260_t *memctl = &immap->im_memctl;
+	int nbanks = 12;
+#endif
+	volatile uint *p = &memctl->memc_br0;
+	int i;
+
+	for (i = 0; i < nbanks; i++, p += 2) {
+		if (i < 10) {
+			printf ("BR%d   = %08x OR%d   = %08x\n",
+				i, p[0], i, p[1]);
+		} else {
+			printf ("BR%d  = %08x OR%d  = %08x\n",
+				i, p[0], i, p[1]);
+		}
+	}
+
+	printf ("MAR   = %08x", memctl->memc_mar);
+#if defined(CONFIG_8xx)
+	printf (" MCR   = %08x\n", memctl->memc_mcr);
+#elif defined(CONFIG_8260)
+	printf ("\n");
+#endif
+	printf ("MAMR  = %08x MBMR  = %08x",
+		memctl->memc_mamr, memctl->memc_mbmr);
+#if defined(CONFIG_8xx)
+	printf ("\nMSTAT =     %04x\n", memctl->memc_mstat);
+#elif defined(CONFIG_8260)
+	printf (" MCMR  = %08x\n", memctl->memc_mcmr);
+#endif
+	printf ("MPTPR =     %04x MDR   = %08x\n",
+		memctl->memc_mptpr, memctl->memc_mdr);
+#if defined(CONFIG_8260)
+	printf ("PSDMR = %08x LSDMR = %08x\n",
+		memctl->memc_psdmr, memctl->memc_lsdmr);
+	printf ("PURT  =       %02x PSRT  =       %02x\n",
+		memctl->memc_purt, memctl->memc_psrt);
+	printf ("LURT  =       %02x LSRT  =       %02x\n",
+		memctl->memc_lurt, memctl->memc_lsrt);
+	printf ("IMMR  = %08x\n", memctl->memc_immr);
+#endif
+	return 0;
+}
+
+int
+do_sitinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+#ifdef CONFIG_8260
+int
+do_icinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+#endif
+
+int
+do_carinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+static int counter;
+
+static void
+header(void)
+{
+	char *data = "\
+       --------------------------------        --------------------------------\
+       00000000001111111111222222222233        00000000001111111111222222222233\
+       01234567890123456789012345678901        01234567890123456789012345678901\
+       --------------------------------        --------------------------------\
+    ";
+	int i;
+
+	if (counter % 2)
+	putc('\n');
+	counter = 0;
+
+	for (i = 0; i < 4; i++, data += 79)
+		printf("%.79s\n", data);
+}
+
+static void binary (char *label, uint value, int nbits)
+{
+	uint mask = 1 << (nbits - 1);
+	int i, second = (counter++ % 2);
+
+	if (second)
+		putc (' ');
+	puts (label);
+	for (i = 32 + 1; i != nbits; i--)
+		putc (' ');
+
+	while (mask != 0) {
+		if (value & mask)
+			putc ('1');
+		else
+			putc ('0');
+		mask >>= 1;
+	}
+
+	if (second)
+		putc ('\n');
+}
+
+#if defined(CONFIG_8xx)
+#define PA_NBITS	16
+#define PA_NB_ODR	 8
+#define PB_NBITS	18
+#define PB_NB_ODR	16
+#define PC_NBITS	12
+#define PD_NBITS	13
+#elif defined(CONFIG_8260)
+#define PA_NBITS	32
+#define PA_NB_ODR	32
+#define PB_NBITS	28
+#define PB_NB_ODR	28
+#define PC_NBITS	32
+#define PD_NBITS	28
+#endif
+
+int
+do_iopinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile iop8xx_t *iop = &immap->im_ioport;
+	volatile ushort *l, *r;
+#elif defined(CONFIG_8260)
+	volatile iop8260_t *iop = &immap->im_ioport;
+	volatile uint *l, *r;
+#endif
+	volatile uint *R;
+
+	counter = 0;
+	header ();
+
+	/*
+	 * Ports A & B
+	 */
+
+#if defined(CONFIG_8xx)
+	l = &iop->iop_padir;
+	R = &immap->im_cpm.cp_pbdir;
+#elif defined(CONFIG_8260)
+	l = &iop->iop_pdira;
+	R = &iop->iop_pdirb;
+#endif
+	binary ("PA_DIR", *l++, PA_NBITS);
+	binary ("PB_DIR", *R++, PB_NBITS);
+	binary ("PA_PAR", *l++, PA_NBITS);
+	binary ("PB_PAR", *R++, PB_NBITS);
+#if defined(CONFIG_8260)
+	binary ("PA_SOR", *l++, PA_NBITS);
+	binary ("PB_SOR", *R++, PB_NBITS);
+#endif
+	binary ("PA_ODR", *l++, PA_NB_ODR);
+	binary ("PB_ODR", *R++, PB_NB_ODR);
+	binary ("PA_DAT", *l++, PA_NBITS);
+	binary ("PB_DAT", *R++, PB_NBITS);
+
+	header ();
+
+	/*
+	 * Ports C & D
+	 */
+
+#if defined(CONFIG_8xx)
+	l = &iop->iop_pcdir;
+	r = &iop->iop_pddir;
+#elif defined(CONFIG_8260)
+	l = &iop->iop_pdirc;
+	r = &iop->iop_pdird;
+#endif
+	binary ("PC_DIR", *l++, PC_NBITS);
+	binary ("PD_DIR", *r++, PD_NBITS);
+	binary ("PC_PAR", *l++, PC_NBITS);
+	binary ("PD_PAR", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+	binary ("PC_SO ", *l++, PC_NBITS);
+	binary ("      ", 0, 0);
+	r++;
+#elif defined(CONFIG_8260)
+	binary ("PC_SOR", *l++, PC_NBITS);
+	binary ("PD_SOR", *r++, PD_NBITS);
+	binary ("PC_ODR", *l++, PC_NBITS);
+	binary ("PD_ODR", *r++, PD_NBITS);
+#endif
+	binary ("PC_DAT", *l++, PC_NBITS);
+	binary ("PD_DAT", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+	binary ("PC_INT", *l++, PC_NBITS);
+#endif
+
+	header ();
+	return 0;
+}
+
+/*
+ * set the io pins
+ * this needs a clean up for smaller tighter code
+ * use *uint and set the address based on cmd + port
+ */
+int
+do_iopset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+#if defined(CONFIG_8260)
+	uint rcode = 0;
+	static uint port = 0;
+	static uint pin = 0;
+	static uint value = 0;
+	static enum { DIR, PAR, SOR, ODR, DAT } cmd = DAT;
+	iopin_t iopin;
+
+	if (argc != 5) {
+		printf ("iopset PORT PIN CMD VALUE\n");
+		return 1;
+	}
+	port = argv[1][0] - 'A';
+	if (port > 3)
+		port -= 0x20;
+	if (port > 3)
+		rcode = 1;
+	pin = simple_strtol (argv[2], NULL, 10);
+	if (pin > 31)
+		rcode = 1;
+
+
+	switch (argv[3][0]) {
+	case 'd':
+		if (argv[3][1] == 'a')
+			cmd = DAT;
+		else if (argv[3][1] == 'i')
+			cmd = DIR;
+		else
+			rcode = 1;
+		break;
+	case 'p':
+		cmd = PAR;
+		break;
+	case 'o':
+		cmd = ODR;
+		break;
+	case 's':
+		cmd = SOR;
+		break;
+	default:
+		printf ("iopset: unknown command %s\n", argv[3]);
+		rcode = 1;
+	}
+	if (argv[4][0] == '1')
+		value = 1;
+	else if (argv[4][0] == '0')
+		value = 0;
+	else
+		rcode = 1;
+	if (rcode == 0) {
+		iopin.port = port;
+		iopin.pin = pin;
+		switch (cmd) {
+		case DIR:
+			if (value)
+				iopin_set_out (&iopin);
+			else
+				iopin_set_in (&iopin);
+			break;
+		case PAR:
+			if (value)
+				iopin_set_ded (&iopin);
+			else
+				iopin_set_gen (&iopin);
+			break;
+		case SOR:
+			if (value)
+				iopin_set_opt2 (&iopin);
+			else
+				iopin_set_opt1 (&iopin);
+			break;
+		case ODR:
+			if (value)
+				iopin_set_odr (&iopin);
+			else
+				iopin_set_act (&iopin);
+			break;
+		case DAT:
+			if (value)
+				iopin_set_high (&iopin);
+			else
+				iopin_set_low (&iopin);
+			break;
+		}
+
+	}
+	return rcode;
+#else
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+#endif
+}
+
+int
+do_dmainfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_fccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+static void prbrg (int n, uint val)
+{
+	uint extc = (val >> 14) & 3;
+	uint cd = (val & CPM_BRG_CD_MASK) >> 1;
+	uint div16 = (val & CPM_BRG_DIV16) != 0;
+
+#if defined(CONFIG_8xx)
+	DECLARE_GLOBAL_DATA_PTR;
+	ulong clock = gd->cpu_clk;
+#elif defined(CONFIG_8260)
+	DECLARE_GLOBAL_DATA_PTR;
+	ulong clock = gd->brg_clk;
+#endif
+
+	printf ("BRG%d:", n);
+
+	if (val & CPM_BRG_RST)
+		puts (" RESET");
+	else
+		puts ("      ");
+
+	if (val & CPM_BRG_EN)
+		puts ("  ENABLED");
+	else
+		puts (" DISABLED");
+
+	printf (" EXTC=%d", extc);
+
+	if (val & CPM_BRG_ATB)
+		puts (" ATB");
+	else
+		puts ("    ");
+
+	printf (" DIVIDER=%4d", cd);
+	if (extc == 0 && cd != 0) {
+		uint baudrate;
+
+		if (div16)
+			baudrate = (clock / 16) / (cd + 1);
+		else
+			baudrate = clock / (cd + 1);
+
+		printf ("=%6d bps", baudrate);
+	} else {
+		puts ("           ");
+	}
+
+	if (val & CPM_BRG_DIV16)
+		puts (" DIV16");
+	else
+		puts ("      ");
+
+	putc ('\n');
+}
+
+int
+do_brginfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile cpm8xx_t *cp = &immap->im_cpm;
+	volatile uint *p = &cp->cp_brgc1;
+#elif defined(CONFIG_8260)
+	volatile uint *p = &immap->im_brgc1;
+#endif
+	int i = 1;
+
+	while (i <= 4)
+		prbrg (i++, *p++);
+
+#if defined(CONFIG_8260)
+	p = &immap->im_brgc5;
+	while (i <= 8)
+		prbrg (i++, *p++);
+#endif
+	return 0;
+}
+
+int
+do_i2cinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile i2c8xx_t *i2c = &immap->im_i2c;
+	volatile cpm8xx_t *cp = &immap->im_cpm;
+	volatile iic_t *iip = (iic_t *) & cp->cp_dparam[PROFF_IIC];
+#elif defined(CONFIG_8260)
+	volatile i2c8260_t *i2c = &immap->im_i2c;
+	volatile iic_t *iip;
+	uint dpaddr;
+
+	dpaddr = *((unsigned short *) (&immap->im_dprambase[PROFF_I2C_BASE]));
+	if (dpaddr == 0)
+		iip = NULL;
+	else
+		iip = (iic_t *) & immap->im_dprambase[dpaddr];
+#endif
+
+	printf ("I2MOD = %02x I2ADD = %02x\n", i2c->i2c_i2mod, i2c->i2c_i2add);
+	printf ("I2BRG = %02x I2COM = %02x\n", i2c->i2c_i2brg, i2c->i2c_i2com);
+	printf ("I2CER = %02x I2CMR = %02x\n", i2c->i2c_i2cer, i2c->i2c_i2cmr);
+
+	if (iip == NULL)
+		printf ("i2c parameter ram not allocated\n");
+	else {
+		printf ("RBASE = %08x TBASE = %08x\n",
+			iip->iic_rbase, iip->iic_tbase);
+		printf ("RFCR  =       %02x TFCR  =       %02x\n",
+			iip->iic_rfcr, iip->iic_tfcr);
+		printf ("MRBLR =     %04x\n", iip->iic_mrblr);
+		printf ("RSTATE= %08x RDP   = %08x\n",
+			iip->iic_rstate, iip->iic_rdp);
+		printf ("RBPTR =     %04x RBC   =     %04x\n",
+			iip->iic_rbptr, iip->iic_rbc);
+		printf ("RXTMP = %08x\n", iip->iic_rxtmp);
+		printf ("TSTATE= %08x TDP   = %08x\n",
+			iip->iic_tstate, iip->iic_tdp);
+		printf ("TBPTR =     %04x TBC   =     %04x\n",
+			iip->iic_tbptr, iip->iic_tbc);
+		printf ("TXTMP = %08x\n", iip->iic_txtmp);
+	}
+	return 0;
+}
+
+int
+do_sccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_smcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_spiinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_muxinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_siinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_mccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+#endif	/* CFG_CMD_IMMAP && (CONFIG_8xx || CONFIG_8260) */

+ 179 - 0
common/cmd_jffs2.c

@@ -0,0 +1,179 @@
+/*
+ * (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
+ */
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <cmd_autoscript.h>
+#include <s_record.h>
+#include <net.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
+
+#include <jffs2/jffs2.h>
+static int part_num=0;
+
+#ifndef CFG_JFFS_CUSTOM_PART
+
+static struct part_info part;
+
+struct part_info*
+jffs2_part_info(int part_num)
+{
+	extern flash_info_t flash_info[];	/* info for FLASH chips */
+	int i;
+
+	if(part_num==0){
+
+		if(part.usr_priv==(void*)1)
+			return &part;
+
+		memset(&part, 0, sizeof(part));
+
+#if defined(CFG_JFFS2_FIRST_SECTOR)
+		part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR];
+#else
+		part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[0];
+#endif
+
+		/* Figure out flash partition size */
+		for (i = CFG_JFFS2_FIRST_BANK; i < CFG_JFFS2_NUM_BANKS+CFG_JFFS2_FIRST_BANK; i++)
+			part.size += flash_info[i].size;
+
+#if defined(CFG_JFFS2_FIRST_SECTOR) && (CFG_JFFS2_FIRST_SECTOR > 0)
+		part.size -=
+			flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR] -
+			flash_info[CFG_JFFS2_FIRST_BANK].start[0];
+#endif
+
+		/* unused in current jffs2 loader */
+		part.erasesize = 0;
+
+		/* Mark the struct as ready */
+		part.usr_priv=(void*)1;
+
+		return &part;
+	}
+	return 0;
+}
+#endif /* ifndef CFG_JFFS_CUSTOM_PART */
+int
+do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *filename = "pImage";
+	ulong offset = CFG_LOAD_ADDR;
+	int size;
+	struct part_info *part;
+
+	if (argc == 2) {
+		filename = argv[1];
+	}
+	if (argc == 3) {
+		offset = simple_strtoul(argv[1], NULL, 16);
+		filename = argv[2];
+	}
+
+	if (0 != (part=jffs2_part_info(part_num))){
+
+		printf("### JFFS2 loading '%s' to 0x%lx\n", filename, offset);
+		size = jffs2_1pass_load((char *)offset, part, filename);
+
+		if (size > 0) {
+			char buf[10];
+			printf("### JFFS2 load complete: %d bytes loaded to 0x%lx\n",
+				size, offset);
+			sprintf(buf, "%x", size);
+			setenv("filesize", buf);
+		} else {
+			printf("### JFFS2 LOAD ERROR<%x> for %s!\n", size, filename);
+		}
+
+		return !(size > 0);
+	}
+	printf("Active partition not valid\n");
+	return 0;
+}
+
+int
+do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *filename = "/";
+	int ret;
+	struct part_info *part;
+
+	if (argc == 2)
+		filename = argv[1];
+
+	if (0 != (part=jffs2_part_info(part_num))){
+
+		ret = jffs2_1pass_ls(jffs2_part_info(part_num), filename);
+
+		return (ret == 1);
+	}
+	printf("Active partition not valid\n");
+	return 0;
+}
+
+int
+do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int ret;
+	struct part_info *part;
+
+	if (0 != (part=jffs2_part_info(part_num))){
+
+		ret = jffs2_1pass_info(jffs2_part_info(part_num));
+
+		return (ret == 1);
+	}
+	printf("Active partition not valid\n");
+	return 0;
+}
+
+int
+do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int tmp_part;
+
+	if (argc >= 2) {
+		tmp_part = simple_strtoul(argv[1], NULL, 16);
+	}else{
+		printf("Need partition number in argument list\n");
+		return 0;
+
+	}
+
+	if (jffs2_part_info(tmp_part)){
+		printf("Partiton changed to %d\n",tmp_part);
+		part_num=tmp_part;
+		return 0;
+	}
+
+	printf("Partition %d is not valid partiton\n",tmp_part);
+	return 0;
+
+}
+#endif /* CFG_CMD_JFFS2 */

+ 477 - 0
common/cmd_pci.c

@@ -0,0 +1,477 @@
+/*
+ * (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.
+ * Wolfgang Grandegger, DENX Software Engineering, wg@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 <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <command.h>
+#include <cmd_boot.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <cmd_pci.h>
+#include <pci.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCI)
+
+extern int cmd_get_data_size(char* arg, int default_size);
+
+unsigned char	ShortPCIListing = 1;
+
+/*
+ * Follows routines for the output of infos about devices on PCI bus.
+ */
+
+void pci_header_show(pci_dev_t dev);
+void pci_header_show_brief(pci_dev_t dev);
+
+/*
+ * 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 ShortPCIListing)
+{
+	int Device;
+	int Function;
+	unsigned char HeaderType;
+	unsigned short VendorID;
+	pci_dev_t dev;
+
+	printf("Scanning PCI devices on bus %d\n", BusNum);
+
+	if (ShortPCIListing) {
+		printf("BusDevFun  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;
+
+			dev = PCI_BDF(BusNum, Device, Function);
+
+			pci_read_config_word(dev, PCI_VENDOR_ID, &VendorID);
+			if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
+				continue;
+
+			pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
+
+			if (ShortPCIListing)
+			{
+				printf("%02x.%02x.%02x   ", BusNum, Device, Function);
+				pci_header_show_brief(dev);
+			}
+			else
+			{
+				printf("\nFound PCI device %02x.%02x.%02x:\n",
+				       BusNum, Device, Function);
+				pci_header_show(dev);
+			}
+	    }
+    }
+}
+
+char* pci_classes_str(u8 class)
+{
+	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 "
+	};
+
+	if (class < (sizeof pci_classes / sizeof *pci_classes))
+		return pci_classes[(int) class];
+
+	return  "???                    ";
+}
+
+/*
+ * Subroutine:  pci_header_show_brief
+ *
+ * Description: Reads and prints the header of the
+ * 		specified PCI device in short form.
+ *
+ * Inputs:	dev      Bus+Device+Function number
+ *
+ * Return:      None
+ *
+ */
+void pci_header_show_brief(pci_dev_t dev)
+{
+	u16 vendor, device;
+	u8 class, subclass;
+
+	pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
+	pci_read_config_word(dev, PCI_DEVICE_ID, &device);
+	pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
+	pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
+
+	printf("0x%.4x     0x%.4x     %s 0x%.2x\n",
+	       vendor, device,
+	       pci_classes_str(class), subclass);
+}
+
+/*
+ * 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(pci_dev_t dev)
+{
+	u8 _byte, header_type;
+	u16 _word;
+	u32 _dword;
+
+#define PRINT(msg, type, reg) \
+	pci_read_config_##type(dev, reg, &_##type); \
+	printf(msg, _##type)
+
+#define PRINT2(msg, type, reg, func) \
+	pci_read_config_##type(dev, reg, &_##type); \
+	printf(msg, _##type, func(_##type))
+
+	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+	PRINT ("  vendor ID =                   0x%.4x\n", word, PCI_VENDOR_ID);
+	PRINT ("  device ID =                   0x%.4x\n", word, PCI_DEVICE_ID);
+	PRINT ("  command register =            0x%.4x\n", word, PCI_COMMAND);
+	PRINT ("  status register =             0x%.4x\n", word, PCI_STATUS);
+	PRINT ("  revision ID =                 0x%.2x\n", byte, PCI_REVISION_ID);
+	PRINT2("  class code =                  0x%.2x (%s)\n", byte, PCI_CLASS_CODE,
+	       							pci_classes_str);
+	PRINT ("  sub class code =              0x%.2x\n", byte, PCI_CLASS_SUB_CODE);
+	PRINT ("  programming interface =       0x%.2x\n", byte, PCI_CLASS_PROG);
+	PRINT ("  cache line =                  0x%.2x\n", byte, PCI_CACHE_LINE_SIZE);
+	PRINT ("  latency time =                0x%.2x\n", byte, PCI_LATENCY_TIMER);
+	PRINT ("  header type =                 0x%.2x\n", byte, PCI_HEADER_TYPE);
+	PRINT ("  BIST =                        0x%.2x\n", byte, PCI_BIST);
+	PRINT ("  base address 0 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_0);
+	PRINT ("  base address 1 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_1);
+
+	if (header_type & 0x01) {		/* PCI-to-PCI bridge */
+		PRINT ("  primary bus number =          0x%.2x\n", byte, PCI_PRIMARY_BUS);
+		PRINT ("  secondary bus number =        0x%.2x\n", byte, PCI_SECONDARY_BUS);
+		PRINT ("  subordinate bus number =      0x%.2x\n", byte, PCI_SUBORDINATE_BUS);
+		PRINT ("  secondary latency timer =     0x%.2x\n", byte, PCI_SEC_LATENCY_TIMER);
+		PRINT ("  IO base =                     0x%.2x\n", byte, PCI_IO_BASE);
+		PRINT ("  IO limit =                    0x%.2x\n", byte, PCI_IO_LIMIT);
+		PRINT ("  secondary status =            0x%.4x\n", word, PCI_SEC_STATUS);
+		PRINT ("  memory base =                 0x%.4x\n", word, PCI_MEMORY_BASE);
+		PRINT ("  memory limit =                0x%.4x\n", word, PCI_MEMORY_LIMIT);
+		PRINT ("  prefetch memory base =        0x%.4x\n", word, PCI_PREF_MEMORY_BASE);
+		PRINT ("  prefetch memory limit =       0x%.4x\n", word, PCI_PREF_MEMORY_LIMIT);
+		PRINT ("  prefetch memory base upper =  0x%.8x\n", dword, PCI_PREF_BASE_UPPER32);
+		PRINT ("  prefetch memory limit upper = 0x%.8x\n", dword, PCI_PREF_LIMIT_UPPER32);
+		PRINT ("  IO base upper 16 bits =       0x%.4x\n", word, PCI_IO_BASE_UPPER16);
+		PRINT ("  IO limit upper 16 bits =      0x%.4x\n", word, PCI_IO_LIMIT_UPPER16);
+		PRINT ("  expansion ROM base address =  0x%.8x\n", dword, PCI_ROM_ADDRESS1);
+		PRINT ("  interrupt line =              0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+		PRINT ("  interrupt pin =               0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+		PRINT ("  bridge control =              0x%.4x\n", word, PCI_BRIDGE_CONTROL);
+    } else {					/* PCI device */
+		PRINT("  base address 2 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_2);
+		PRINT("  base address 3 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_3);
+		PRINT("  base address 4 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_4);
+		PRINT("  base address 5 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_5);
+		PRINT("  cardBus CIS pointer =         0x%.8x\n", dword, PCI_CARDBUS_CIS);
+		PRINT("  sub system vendor ID =        0x%.4x\n", word, PCI_SUBSYSTEM_VENDOR_ID);
+		PRINT("  sub system ID =               0x%.4x\n", word, PCI_SUBSYSTEM_ID);
+		PRINT("  expansion ROM base address =  0x%.8x\n", dword, PCI_ROM_ADDRESS);
+		PRINT("  interrupt line =              0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+		PRINT("  interrupt pin =               0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+		PRINT("  min Grant =                   0x%.2x\n", byte, PCI_MIN_GNT);
+		PRINT("  max Latency =                 0x%.2x\n", byte, PCI_MAX_LAT);
+    }
+
+#undef PRINT
+#undef PRINT2
+}
+
+/* Convert the "bus.device.function" identifier into a number.
+ */
+static pci_dev_t get_pci_dev(char* name)
+{
+	char cnum[12];
+	int len, i, iold, n;
+	int bdfs[3] = {0,0,0};
+
+	len = strlen(name);
+	if (len > 8)
+		return -1;
+	for (i = 0, iold = 0, n = 0; i < len; i++) {
+		if (name[i] == '.') {
+			memcpy(cnum, &name[iold], i - iold);
+			cnum[i - iold] = '\0';
+			bdfs[n++] = simple_strtoul(cnum, NULL, 16);
+			iold = i + 1;
+		}
+	}
+	strcpy(cnum, &name[iold]);
+	if (n == 0)
+		n = 1;
+	bdfs[n] = simple_strtoul(cnum, NULL, 16);
+	return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
+}
+
+static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
+{
+#define DISP_LINE_LEN	16
+	ulong i, nbytes, linebytes;
+	int rc = 0;
+
+	if (length == 0)
+		length = 0x40 / size; /* Standard PCI configuration space */
+
+	/* Print the lines.
+	 * once, and all accesses are with the specified bus width.
+	 */
+	nbytes = length * size;
+	do {
+		uint	val4;
+		ushort  val2;
+		u_char	val1;
+
+		printf("%08lx:", addr);
+		linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
+		for (i=0; i<linebytes; i+= size) {
+			if (size == 4) {
+				pci_read_config_dword(bdf, addr, &val4);
+				printf(" %08x", val4);
+			} else if (size == 2) {
+				pci_read_config_word(bdf, addr, &val2);
+				printf(" %04x", val2);
+			} else {
+				pci_read_config_byte(bdf, addr, &val1);
+				printf(" %02x", val1);
+			}
+			addr += size;
+		}
+		printf("\n");
+		nbytes -= linebytes;
+		if (ctrlc()) {
+			rc = 1;
+			break;
+		}
+	} while (nbytes > 0);
+
+	return (rc);
+}
+
+static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
+{
+	if (size == 4) {
+		pci_write_config_dword(bdf, addr, value);
+	}
+	else if (size == 2) {
+		ushort val = value & 0xffff;
+		pci_write_config_word(bdf, addr, val);
+	}
+	else {
+		u_char val = value & 0xff;
+		pci_write_config_byte(bdf, addr, val);
+	}
+	return 0;
+}
+
+static int
+pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
+{
+	ulong	i;
+	int	nbytes;
+	extern char console_buffer[];
+	uint	val4;
+	ushort  val2;
+	u_char	val1;
+
+	/* Print the address, followed by value.  Then accept input for
+	 * the next value.  A non-converted value exits.
+	 */
+	do {
+		printf("%08lx:", addr);
+		if (size == 4) {
+			pci_read_config_dword(bdf, addr, &val4);
+			printf(" %08x", val4);
+		}
+		else if (size == 2) {
+			pci_read_config_word(bdf, addr, &val2);
+			printf(" %04x", val2);
+		}
+		else {
+			pci_read_config_byte(bdf, addr, &val1);
+			printf(" %02x", val1);
+		}
+
+		nbytes = readline (" ? ");
+		if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+			/* <CR> pressed as only input, don't modify current
+			 * location and move to next. "-" pressed will go back.
+			 */
+			if (incrflag)
+				addr += nbytes ? -size : size;
+			nbytes = 1;
+#ifdef CONFIG_BOOT_RETRY_TIME
+			reset_cmd_timeout(); /* good enough to not time out */
+#endif
+		}
+#ifdef CONFIG_BOOT_RETRY_TIME
+		else if (nbytes == -2) {
+			break;	/* timed out, exit the command	*/
+		}
+#endif
+		else {
+			char *endp;
+			i = simple_strtoul(console_buffer, &endp, 16);
+			nbytes = endp - console_buffer;
+			if (nbytes) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+				/* good enough to not time out
+				 */
+				reset_cmd_timeout();
+#endif
+				pci_cfg_write (bdf, addr, size, i);
+				if (incrflag)
+					addr += size;
+			}
+		}
+	} while (nbytes);
+
+	return 0;
+}
+
+/* PCI Configuration Space access commands
+ *
+ * Syntax:
+ *	pci display[.b, .w, .l] bus.device.function} [addr] [len]
+ *	pci next[.b, .w, .l] bus.device.function [addr]
+ *      pci modify[.b, .w, .l] bus.device.function [addr]
+ *      pci write[.b, .w, .l] bus.device.function addr value
+ */
+int do_pci (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	ulong addr = 0, value = 0, size = 0;
+	pci_dev_t bdf = 0;
+	char cmd = 's';
+
+	if (argc > 1)
+		cmd = argv[1][0];
+
+	switch (cmd) {
+	case 'd':		/* display */
+	case 'n':		/* next */
+	case 'm':		/* modify */
+	case 'w':		/* write */
+		/* Check for a size specification. */
+		size = cmd_get_data_size(argv[1], 4);
+		if (argc > 3)
+			addr = simple_strtoul(argv[3], NULL, 16);
+		if (argc > 4)
+			value = simple_strtoul(argv[4], NULL, 16);
+	case 'h':		/* header */
+		if (argc < 3)
+			goto usage;
+		if ((bdf = get_pci_dev(argv[2])) == -1)
+			return 1;
+		break;
+	default:		/* scan bus */
+		value = 1; /* short listing */
+		bdf = 0;   /* bus number  */
+		if (argc > 1) {
+			if (argv[argc-1][0] == 'l') {
+				value = 0;
+				argc--;
+			}
+			if (argc > 1)
+				bdf = simple_strtoul(argv[1], NULL, 16);
+		}
+		pciinfo(bdf, value);
+		return 0;
+	}
+
+	switch (argv[1][0]) {
+	case 'h':		/* header */
+		pci_header_show(bdf);
+		return 0;
+	case 'd':		/* display */
+		return pci_cfg_display(bdf, addr, size, value);
+	case 'n':		/* next */
+		if (argc < 4)
+			goto usage;
+		return pci_cfg_modify(bdf, addr, size, value, 0);
+	case 'm':		/* modify */
+		if (argc < 4)
+			goto usage;
+		return pci_cfg_modify(bdf, addr, size, value, 1);
+	case 'w':		/* write */
+		if (argc < 5)
+			goto usage;
+		return pci_cfg_write(bdf, addr, size, value);
+	}
+
+	return 1;
+ usage:
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_PCI) */
+
+#endif /* CONFIG_PCI */

+ 2243 - 0
common/cmd_pcmcia.c

@@ -0,0 +1,2243 @@
+/*
+ * (C) Copyright 2000-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
+ *
+ ********************************************************************
+ *
+ * Lots of code copied from:
+ *
+ * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
+ * (C) 1999-2000 Magnus Damm <damm@bitsmart.com>
+ *
+ * "The ExCA standard specifies that socket controllers should provide
+ * two IO and five memory windows per socket, which can be independently
+ * configured and positioned in the host address space and mapped to
+ * arbitrary segments of card address space. " - David A Hinds. 1999
+ *
+ * This controller does _not_ meet the ExCA standard.
+ *
+ * m8xx pcmcia controller brief info:
+ * + 8 windows (attrib, mem, i/o)
+ * + up to two slots (SLOT_A and SLOT_B)
+ * + inputpins, outputpins, event and mask registers.
+ * - no offset register. sigh.
+ *
+ * Because of the lacking offset register we must map the whole card.
+ * We assign each memory window PCMCIA_MEM_WIN_SIZE address space.
+ * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO
+ * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE.
+ * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE.
+ * They are maximum 64KByte each...
+ */
+
+/* #define DEBUG	1	*/
+
+/*
+ * PCMCIA support
+ */
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <pcmcia.h>
+#include <cmd_pcmcia.h>
+#if defined(CONFIG_IDE_8xx_PCCARD) && defined(CONFIG_8xx)
+#include <mpc8xx.h>
+#endif
+#if defined(CONFIG_LWMON)
+#include <i2c.h>
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) || \
+    ((CONFIG_COMMANDS & CFG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD))
+
+int pcmcia_on (void);
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int  pcmcia_off (void);
+static int  hardware_disable(int slot);
+#endif
+static int  hardware_enable (int slot);
+static int  voltage_set(int slot, int vcc, int vpp);
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_funcid (int func);
+static void print_fixed  (volatile uchar *p);
+static int  identify     (volatile uchar *p);
+static int  check_ide_device (void);
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+static u_int m8xx_get_graycode(u_int size);
+#if 0
+static u_int m8xx_get_speed(u_int ns, u_int is_io);
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/* look up table for pgcrx registers */
+
+static u_int *pcmcia_pgcrx[2] = {
+	&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcra,
+	&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcrb,
+};
+
+#define PCMCIA_PGCRX(slot)	(*pcmcia_pgcrx[slot])
+
+const char *indent = "\t   ";
+
+/* ------------------------------------------------------------------------- */
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+
+int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int rcode = 0;
+
+	if (argc != 2) {
+		printf ("Usage: pinit {on | off}\n");
+		return 1;
+	}
+	if (strcmp(argv[1],"on") == 0) {
+	     	rcode = pcmcia_on ();
+	} else if (strcmp(argv[1],"off") == 0) {
+		rcode = pcmcia_off ();
+	} else {
+		printf ("Usage: pinit {on | off}\n");
+		return 1;
+	}
+
+	return rcode;
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_LWMON)
+# define  CFG_PCMCIA_TIMING	(PCMCIA_SHT(9) | PCMCIA_SST(3) | PCMCIA_SL(12))
+#else
+# define  CFG_PCMCIA_TIMING	(PCMCIA_SHT(2) | PCMCIA_SST(4) | PCMCIA_SL(9))
+#endif
+
+int pcmcia_on (void)
+{
+	int i;
+	u_long reg, base;
+	pcmcia_win_t *win;
+
+	debug ("Enable PCMCIA " PCMCIA_SLOT_MSG "\n");
+
+	/* intialize the fixed memory windows */
+	win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
+	base = CFG_PCMCIA_MEM_ADDR;
+
+	if((reg = m8xx_get_graycode(CFG_PCMCIA_MEM_SIZE)) == -1) {
+		printf ("Cannot set window size to 0x%08x\n",
+			CFG_PCMCIA_MEM_SIZE);
+		return (1);
+	}
+
+	for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
+		win->br = base;
+
+		switch (i) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+		case 0:	{	/* map attribute memory */
+			win->or = (	PCMCIA_BSIZE_64M
+				|	PCMCIA_PPS_8
+				|	PCMCIA_PRS_ATTR
+				|	PCMCIA_SLOT_x
+				|	PCMCIA_PV
+				|	CFG_PCMCIA_TIMING );
+			break;
+		    }
+
+		case 1: {	/* map I/O window for data reg */
+			win->or = (	PCMCIA_BSIZE_1K
+				|	PCMCIA_PPS_16
+				|	PCMCIA_PRS_IO
+				|	PCMCIA_SLOT_x
+				|	PCMCIA_PV
+				|	CFG_PCMCIA_TIMING );
+			break;
+		    }
+
+		case 2: {	/* map I/O window for command/ctrl reg block */
+			win->or = (	PCMCIA_BSIZE_1K
+				|	PCMCIA_PPS_8
+				|	PCMCIA_PRS_IO
+				|	PCMCIA_SLOT_x
+				|	PCMCIA_PV
+				|	CFG_PCMCIA_TIMING );
+			break;
+		    }
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+		default:	/* set to not valid */
+			win->or = 0;
+			break;
+		}
+
+		debug ("MemWin %d: PBR 0x%08lX  POR %08lX\n",
+			i, win->br, win->or);
+		base += CFG_PCMCIA_MEM_SIZE;
+		++win;
+	}
+
+	/* turn off voltage */
+	if (voltage_set(_slot_, 0, 0))
+		return (1);
+
+	/* Enable external hardware */
+	if (hardware_enable(_slot_))
+		return (1);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	if (check_ide_device())
+		return (1);
+#endif
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+
+static int pcmcia_off (void)
+{
+	int i;
+	pcmcia_win_t *win;
+
+	printf ("Disable PCMCIA " PCMCIA_SLOT_MSG "\n");
+
+	/* clear interrupt state, and disable interrupts */
+	((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pscr =  PCMCIA_MASK(_slot_);
+	((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* turn off interrupt and disable CxOE */
+	PCMCIA_PGCRX(_slot_) = __MY_PCMCIA_GCRX_CXOE;
+
+	/* turn off memory windows */
+	win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
+
+	for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
+		/* disable memory window */
+		win->or = 0;
+		++win;
+	}
+
+	/* turn off voltage */
+	voltage_set(_slot_, 0, 0);
+
+	/* disable external hardware */
+	printf ("Shutdown and Poweroff " PCMCIA_SLOT_MSG "\n");
+	hardware_disable(_slot_);
+	return 0;
+}
+
+#endif	/* CFG_CMD_PCMCIA */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#define	MAX_TUPEL_SZ	512
+#define MAX_FEATURES	4
+
+static int check_ide_device (void)
+{
+	volatile uchar *ident = NULL;
+	volatile uchar *feature_p[MAX_FEATURES];
+	volatile uchar *p, *start;
+	int n_features = 0;
+	uchar func_id = ~0;
+	uchar code, len;
+	ushort config_base = 0;
+	int found = 0;
+	int i;
+
+	debug ("PCMCIA MEM: %08X\n", CFG_PCMCIA_MEM_ADDR);
+
+	start = p = (volatile uchar *) CFG_PCMCIA_MEM_ADDR;
+
+	while ((p - start) < MAX_TUPEL_SZ) {
+
+		code = *p; p += 2;
+
+		if (code == 0xFF) { /* End of chain */
+			break;
+		}
+
+		len = *p; p += 2;
+#if defined(DEBUG) && (DEBUG > 1)
+		{ volatile uchar *q = p;
+			printf ("\nTuple code %02x  length %d\n\tData:",
+				code, len);
+
+			for (i = 0; i < len; ++i) {
+				printf (" %02x", *q);
+				q+= 2;
+			}
+		}
+#endif	/* DEBUG */
+		switch (code) {
+		case CISTPL_VERS_1:
+			ident = p + 4;
+			break;
+		case CISTPL_FUNCID:
+			/* Fix for broken SanDisk which may have 0x80 bit set */
+			func_id = *p & 0x7F;
+			break;
+		case CISTPL_FUNCE:
+			if (n_features < MAX_FEATURES)
+				feature_p[n_features++] = p;
+			break;
+		case CISTPL_CONFIG:
+			config_base = (*(p+6) << 8) + (*(p+4));
+			debug ("\n## Config_base = %04x ###\n", config_base);
+		default:
+			break;
+		}
+		p += 2 * len;
+	}
+
+	found = identify (ident);
+
+	if (func_id != ((uchar)~0)) {
+		print_funcid (func_id);
+
+		if (func_id == CISTPL_FUNCID_FIXED)
+			found = 1;
+		else
+			return (1);	/* no disk drive */
+	}
+
+	for (i=0; i<n_features; ++i) {
+		print_fixed (feature_p[i]);
+	}
+
+	if (!found) {
+		printf ("unknown card type\n");
+		return (1);
+	}
+
+	/* set I/O area in config reg -> only valid for ARGOSY D5!!! */
+	*((uchar *)(CFG_PCMCIA_MEM_ADDR + config_base)) = 1;
+
+	return (0);
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------------- */
+/* board specific stuff:							*/
+/* voltage_set(), hardware_enable() and hardware_disable()			*/
+/* ---------------------------------------------------------------------------- */
+
+/* ---------------------------------------------------------------------------- */
+/* RPX Boards from Embedded Planet						*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
+
+/* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks.
+ * SYPCR is write once only, therefore must the slowest memory be faster
+ * than the bus monitor or we will get a machine check due to the bus timeout.
+ */
+
+#define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE"
+
+#undef PCMCIA_BMT_LIMIT
+#define PCMCIA_BMT_LIMIT (6*8)
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	u_long reg = 0;
+
+	switch(vcc) {
+	case 0: break;
+	case 33: reg |= BCSR1_PCVCTL4; break;
+	case 50: reg |= BCSR1_PCVCTL5; break;
+	default: return 1;
+	}
+
+	switch(vpp) {
+	case 0: break;
+	case 33:
+	case 50:
+		if(vcc == vpp)
+			reg |= BCSR1_PCVCTL6;
+		else
+			return 1;
+		break;
+	case 120:
+		reg |= BCSR1_PCVCTL7;
+	default: return 1;
+	}
+
+	if(vcc == 120)
+	   return 1;
+
+	/* first, turn off all power */
+
+	*((uint *)RPX_CSR_ADDR) &= ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5
+				     | BCSR1_PCVCTL6 | BCSR1_PCVCTL7);
+
+	/* enable new powersettings */
+
+	*((uint *)RPX_CSR_ADDR) |= reg;
+
+	return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+static int hardware_enable (int slot)
+{
+	return 0;	/* No hardware to enable */
+}
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	return 0;	/* No hardware to disable */
+}
+#endif	/* CFG_CMD_PCMCIA */
+#endif	/* CONFIG_RPXCLASSIC */
+
+/* ---------------------------------------------------------------------------- */
+/* (F)ADS Boards from Motorola							*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_ADS) || defined(CONFIG_FADS)
+
+#ifdef CONFIG_ADS
+#define PCMCIA_BOARD_MSG "ADS"
+#define PCMCIA_GLITCHY_CD  /* My ADS board needs this */
+#else
+#define PCMCIA_BOARD_MSG "FADS"
+#endif
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	u_long reg = 0;
+
+	switch(vpp) {
+	case 0: reg = 0; break;
+	case 50: reg = 1; break;
+	case 120: reg = 2; break;
+	default: return 1;
+	}
+
+	switch(vcc) {
+	case 0: reg = 0; break;
+#ifdef CONFIG_ADS
+	case 50: reg = BCSR1_PCCVCCON; break;
+#endif
+#ifdef CONFIG_FADS
+	case 33: reg = BCSR1_PCCVCC0 | BCSR1_PCCVCC1; break;
+	case 50: reg = BCSR1_PCCVCC1; break;
+#endif
+	default: return 1;
+	}
+
+	/* first, turn off all power */
+
+#ifdef CONFIG_ADS
+	*((uint *)BCSR1) |= BCSR1_PCCVCCON;
+#endif
+#ifdef CONFIG_FADS
+	*((uint *)BCSR1) &= ~(BCSR1_PCCVCC0 | BCSR1_PCCVCC1);
+#endif
+	*((uint *)BCSR1) &= ~BCSR1_PCCVPP_MASK;
+
+	/* enable new powersettings */
+
+#ifdef CONFIG_ADS
+	*((uint *)BCSR1) &= ~reg;
+#endif
+#ifdef CONFIG_FADS
+	*((uint *)BCSR1) |= reg;
+#endif
+
+ 	*((uint *)BCSR1) |= reg << 20;
+
+	return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+
+static int hardware_enable(int slot)
+{
+	*((uint *)BCSR1) &= ~BCSR1_PCCEN;
+	return 0;
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	*((uint *)BCSR1) &= ~BCSR1_PCCEN;
+	return 0;
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+#endif	/* (F)ADS */
+
+/* ---------------------------------------------------------------------------- */
+/* TQM8xxL Boards by TQ Components						*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_TQM8xxL)
+
+#define PCMCIA_BOARD_MSG "TQM8xxL"
+
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, mask;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable
+	 */
+	immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
+	immap->im_ioport.iop_pcso  &= ~(0x0002 | 0x0004);
+	/* remove all power */
+
+	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	reg  = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+	if ((reg & mask) == mask) {
+		immap->im_ioport.iop_pcdat |= 0x0004;
+		puts (" 5.0V card found: ");
+	} else {
+		immap->im_ioport.iop_pcdat |= 0x0002;
+		puts (" 3.3V card found: ");
+	}
+	immap->im_ioport.iop_pcdir |=  (0x0002 | 0x0004);
+#if 0
+	/*  VCC switch error flag, PCMCIA slot INPACK_ pin */
+	cp->cp_pbdir &= ~(0x0020 | 0x0010);
+	cp->cp_pbpar &= ~(0x0020 | 0x0010);
+	udelay(500000);
+#endif
+	udelay(1000);
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* remove all power */
+	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn off all power
+	 */
+	debug ("PCMCIA power OFF\n");
+	immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
+	immap->im_ioport.iop_pcso  &= ~(0x0002 | 0x0004);
+	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+	reg = 0;
+	switch(vcc) {
+	case  0: 		break;
+	case 33: reg |= 0x0002;	break;
+	case 50: reg |= 0x0004;	break;
+	default: 		goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	immap->im_ioport.iop_pcdat |= reg;
+	immap->im_ioport.iop_pcdir |=  (0x0002 | 0x0004);
+	if (reg) {
+		debug ("PCMCIA powered at %sV\n",
+			(reg&0x0004) ? "5.0" : "3.3");
+	} else {
+		debug ("PCMCIA powered down\n");
+	}
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+#endif	/* TQM8xxL */
+
+
+/* ---------------------------------------------------------------------------- */
+/* LWMON Board									*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_LWMON)
+
+#define PCMCIA_BOARD_MSG "LWMON"
+
+/* #define's for MAX1604 Power Switch */
+#define MAX1604_OP_SUS		0x80
+#define MAX1604_VCCBON		0x40
+#define MAX1604_VCC_35		0x20
+#define MAX1604_VCCBHIZ		0x10
+#define MAX1604_VPPBON		0x08
+#define MAX1604_VPPBPBPGM	0x04
+#define MAX1604_VPPBHIZ		0x02
+/* reserved			0x01	*/
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, mask;
+	uchar val;
+
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	/* Switch on PCMCIA port in PIC register 0x60 */
+	reg = pic_read  (0x60);
+	debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+	reg &= ~0x10;
+	/* reg |=  0x08; Vpp not needed */
+	pic_write (0x60, reg);
+#ifdef DEBUG
+	reg = pic_read  (0x60);
+	printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+#endif
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	reg  = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+	if ((reg & mask) == mask) {
+		val = 0;		/* VCCB3/5 = 0 ==> use Vx = 5.0 V */
+		puts (" 5.0V card found: ");
+	} else {
+		val = MAX1604_VCC_35;	/* VCCB3/5 = 1 ==> use Vy = 3.3 V */
+		puts (" 3.3V card found: ");
+	}
+
+	/*  switch VCC on */
+	val |=  MAX1604_OP_SUS | MAX1604_VCCBON;
+	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+	udelay(500000);
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+	uchar val;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* remove all power, put output in high impedance state */
+	val  = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
+	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	/* Switch off PCMCIA port in PIC register 0x60 */
+	reg = pic_read  (0x60);
+	debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+	reg |=  0x10;
+	reg &= ~0x08;
+	pic_write (0x60, reg);
+#ifdef DEBUG
+	reg = pic_read  (0x60);
+	printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+#endif
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+	uchar val;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Turn off all power (switch to high impedance)
+	 */
+	debug ("PCMCIA power OFF\n");
+	val  = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
+	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+	val = 0;
+	switch(vcc) {
+	case  0: 			break;
+	case 33: val = MAX1604_VCC_35;	break;
+	case 50: 			break;
+	default: 			goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+	if (val) {
+		debug ("PCMCIA powered at %sV\n",
+			(val & MAX1604_VCC_35) ? "3.3" : "5.0");
+	} else {
+		debug ("PCMCIA powered down\n");
+	}
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+#endif	/* LWMON */
+
+/* ---------------------------------------------------------------------------- */
+/* GTH board by Corelatus AB                                                    */
+/* ---------------------------------------------------------------------------- */
+#if defined(CONFIG_GTH)
+
+#define PCMCIA_BOARD_MSG "GTH COMPACT FLASH"
+
+static int voltage_set(int slot, int vcc, int vpp)
+{  /* Do nothing */
+  return 0;
+}
+
+static int hardware_enable (int slot)
+{
+  volatile immap_t	*immap;
+  volatile cpm8xx_t	*cp;
+  volatile pcmconf8xx_t	*pcmp;
+  volatile sysconf8xx_t	*sysp;
+  uint reg, mask;
+
+  debug ("hardware_enable: GTH Slot %c\n", 'A'+slot);
+
+  immap = (immap_t *)CFG_IMMR;
+  sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+  pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+  cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+  /* clear interrupt state, and disable interrupts */
+  pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+  pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+  /* disable interrupts & DMA */
+  PCMCIA_PGCRX(_slot_) = 0;
+
+  /*
+   * Disable PCMCIA buffers (isolate the interface)
+   * and assert RESET signal
+   */
+  debug ("Disable PCMCIA buffers and assert RESET\n");
+  reg  =  PCMCIA_PGCRX(_slot_);
+  reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+  reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+  PCMCIA_PGCRX(_slot_) = reg;
+  udelay(500);
+
+  /*
+   * Make sure there is a card in the slot, then configure the interface.
+   */
+  udelay(10000);
+  debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+  if (pcmp->pcmc_pipr & 0x98000000) {
+    printf ("   No Card found\n");
+    return (1);
+  }
+
+  mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+  reg  = pcmp->pcmc_pipr;
+  debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+
+  debug ("Enable PCMCIA buffers and stop RESET\n");
+  reg  =  PCMCIA_PGCRX(_slot_);
+  reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+  reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+  PCMCIA_PGCRX(_slot_) = reg;
+
+  udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+  debug ("# hardware_enable done\n");
+
+  return 0;
+}
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	return 0;	/* No hardware to disable */
+}
+#endif	/* CFG_CMD_PCMCIA */
+#endif	/* CONFIG_GTH */
+
+/* ---------------------------------------------------------------------------- */
+/* ICU862 Boards by Cambridge Broadband Ltd.					*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_ICU862)
+
+#define PCMCIA_BOARD_MSG "ICU862"
+
+static void cfg_port_B (void);
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, pipr, mask;
+	int i;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/* Configure Port B for TPS2205 PC-Card Power-Interface Switch */
+	cfg_port_B ();
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	pipr = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		pipr,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+
+	reg  = cp->cp_pbdat;
+	if ((pipr & mask) == mask) {
+		reg |=  (TPS2205_VPP_PGM | TPS2205_VPP_VCC |	/* VAVPP => Hi-Z */
+			 TPS2205_VCC3);				/* 3V off	*/
+		reg &= ~(TPS2205_VCC5);				/* 5V on	*/
+		puts (" 5.0V card found: ");
+	} else {
+		reg |=  (TPS2205_VPP_PGM | TPS2205_VPP_VCC |	/* VAVPP => Hi-Z */
+			 TPS2205_VCC5);				/* 5V off	*/
+		reg &= ~(TPS2205_VCC3);				/* 3V on	*/
+		puts (" 3.3V card found: ");
+	}
+
+	debug ("\nPB DAT: %08x -> 3.3V %s 5.0V %s VPP_PGM %s VPP_VCC %s\n",
+		reg,
+		(reg & TPS2205_VCC3)    ? "off" : "on",
+		(reg & TPS2205_VCC5)    ? "off" : "on",
+		(reg & TPS2205_VPP_PGM) ? "off" : "on",
+		(reg & TPS2205_VPP_VCC) ? "off" : "on" );
+
+	cp->cp_pbdat = reg;
+
+	/*  Wait 500 ms; use this to check for over-current */
+	for (i=0; i<5000; ++i) {
+		if ((cp->cp_pbdat & TPS2205_OC) == 0) {
+			printf ("   *** Overcurrent - Safety shutdown ***\n");
+			cp->cp_pbdat &= ~(TPS2205_SHDN);
+			return (1);
+		}
+		udelay (100);
+	}
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* Shut down */
+	cp->cp_pbdat &= ~(TPS2205_SHDN);
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn all power pins to Hi-Z
+	 */
+	debug ("PCMCIA power OFF\n");
+	cfg_port_B ();	/* Enables switch, but all in Hi-Z */
+
+	reg  = cp->cp_pbdat;
+
+	switch(vcc) {
+	case  0: 			break;	/* Switch off		*/
+	case 33: reg &= ~TPS2205_VCC3;	break;	/* Switch on 3.3V	*/
+	case 50: reg &= ~TPS2205_VCC5;	break;	/* Switch on 5.0V	*/
+	default: 			goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	cp->cp_pbdat = reg;
+
+#ifdef DEBUG
+    {
+	char *s;
+
+	if ((reg & TPS2205_VCC3) == 0) {
+		s = "at 3.3V";
+	} else if ((reg & TPS2205_VCC5) == 0) {
+		s = "at 5.0V";
+	} else {
+		s = "down";
+	}
+	printf ("PCMCIA powered %s\n", s);
+    }
+#endif
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+static void cfg_port_B (void)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	uint reg;
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure Port B for TPS2205 PC-Card Power-Interface Switch
+	 *
+	 * Switch off all voltages, assert shutdown
+	 */
+	reg  = cp->cp_pbdat;
+	reg |=  (TPS2205_VPP_PGM | TPS2205_VPP_VCC |	/* VAVPP => Hi-Z */
+		 TPS2205_VCC3    | TPS2205_VCC5    |	/* VAVCC => Hi-Z */
+		 TPS2205_SHDN);				/* enable switch */
+	cp->cp_pbdat = reg;
+
+	cp->cp_pbpar &= ~(TPS2205_INPUTS | TPS2205_OUTPUTS);
+
+	reg = cp->cp_pbdir & ~(TPS2205_INPUTS);
+	cp->cp_pbdir = reg | TPS2205_OUTPUTS;
+
+	debug ("Set Port B: PAR: %08x DIR: %08x DAT: %08x\n",
+		cp->cp_pbpar, cp->cp_pbdir, cp->cp_pbdat);
+}
+
+#endif	/* ICU862 */
+
+
+/* ---------------------------------------------------------------------------- */
+/* C2MON Boards by TTTech Computertechnik AG					*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_C2MON)
+
+#define PCMCIA_BOARD_MSG "C2MON"
+
+static void cfg_ports (void);
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, pipr, mask;
+	ushort sreg;
+	int i;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/* Configure Ports for TPS2211A PC-Card Power-Interface Switch */
+	cfg_ports ();
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	pipr = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		pipr,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+
+	sreg = immap->im_ioport.iop_pcdat;
+	if ((pipr & mask) == mask) {
+		sreg |=  (TPS2211_VPPD0 | TPS2211_VPPD1 |	/* VAVPP => Hi-Z */
+			  TPS2211_VCCD1);			/* 5V on	*/
+		sreg &= ~(TPS2211_VCCD0);			/* 3V off	*/
+		puts (" 5.0V card found: ");
+	} else {
+		sreg |=  (TPS2211_VPPD0 | TPS2211_VPPD1 |	/* VAVPP => Hi-Z */
+			  TPS2211_VCCD0);			/* 3V on	*/
+		sreg &= ~(TPS2211_VCCD1);			/* 5V off	*/
+		puts (" 3.3V card found: ");
+	}
+
+	debug ("\nPC DAT: %04x -> 3.3V %s 5.0V %s\n",
+		sreg,
+		( (sreg & TPS2211_VCCD0) && !(sreg & TPS2211_VCCD1)) ? "on" : "off",
+		(!(sreg & TPS2211_VCCD0) &&  (sreg & TPS2211_VCCD1)) ? "on" : "off"
+	);
+
+	immap->im_ioport.iop_pcdat = sreg;
+
+	/*  Wait 500 ms; use this to check for over-current */
+	for (i=0; i<5000; ++i) {
+		if ((cp->cp_pbdat & TPS2211_OC) == 0) {
+		    printf ("   *** Overcurrent - Safety shutdown ***\n");
+		    immap->im_ioport.iop_pcdat &= ~(TPS2211_VCCD0|TPS2211_VCCD1);
+		    return (1);
+		}
+		udelay (100);
+	}
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	/* ALl voltages off / Hi-Z */
+	immap->im_ioport.iop_pcdat |= (TPS2211_VPPD0 | TPS2211_VPPD1 |
+				       TPS2211_VCCD0 | TPS2211_VCCD1 );
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+	ushort sreg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn all power pins to Hi-Z
+	 */
+	debug ("PCMCIA power OFF\n");
+	cfg_ports ();	/* Enables switch, but all in Hi-Z */
+
+	sreg  = immap->im_ioport.iop_pcdat;
+	sreg |= TPS2211_VPPD0 | TPS2211_VPPD1;		/* VAVPP always Hi-Z */
+
+	switch(vcc) {
+	case  0: 			break;	/* Switch off		*/
+	case 33: sreg |=  TPS2211_VCCD0;	/* Switch on 3.3V	*/
+		 sreg &= ~TPS2211_VCCD1;
+		 			break;
+	case 50: sreg &= ~TPS2211_VCCD0;	/* Switch on 5.0V	*/
+		 sreg |=  TPS2211_VCCD1;
+		 			break;
+	default: 			goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	immap->im_ioport.iop_pcdat = sreg;
+
+#ifdef DEBUG
+    {
+	char *s;
+
+	if ((sreg & TPS2211_VCCD0) && !(sreg & TPS2211_VCCD1)) {
+		s = "at 3.3V";
+	} else if (!(sreg & TPS2211_VCCD0) &&  (sreg & TPS2211_VCCD1)) {
+		s = "at 5.0V";
+	} else {
+		s = "down";
+	}
+	printf ("PCMCIA powered %s\n", s);
+    }
+#endif
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+static void cfg_ports (void)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	ushort sreg;
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure Port C for TPS2211 PC-Card Power-Interface Switch
+	 *
+	 * Switch off all voltages, assert shutdown
+	 */
+	sreg = immap->im_ioport.iop_pcdat;
+	sreg |=  (TPS2211_VPPD0 | TPS2211_VPPD1);	/* VAVPP => Hi-Z */
+	sreg &= ~(TPS2211_VCCD0 | TPS2211_VCCD1);	/* 3V and 5V off */
+	immap->im_ioport.iop_pcdat = sreg;
+
+	immap->im_ioport.iop_pcpar &= ~(TPS2211_OUTPUTS);
+	immap->im_ioport.iop_pcdir |=   TPS2211_OUTPUTS;
+
+	debug ("Set Port C: PAR:     %04x DIR:     %04x DAT:     %04x\n",
+		immap->im_ioport.iop_pcpar,
+		immap->im_ioport.iop_pcdir,
+		immap->im_ioport.iop_pcdat);
+
+	/*
+	 * Configure Port B for TPS2211 PC-Card Power-Interface Switch
+	 *
+	 * Over-Current Input only
+	 */
+	cp->cp_pbpar &= ~(TPS2211_INPUTS);
+	cp->cp_pbdir &= ~(TPS2211_INPUTS);
+
+	debug ("Set Port B: PAR: %08x DIR: %08x DAT: %08x\n",
+		cp->cp_pbpar, cp->cp_pbdir, cp->cp_pbdat);
+}
+
+#endif	/* C2MON */
+
+/* ----------------------------------------------------------------------------
+   MBX board from Morotola
+   ---------------------------------------------------------------------------- */
+
+#if defined( CONFIG_MBX )
+#include <../board/mbx8xx/csr.h>
+
+/* A lot of this has been taken from the RPX code in this file it works from me.
+   I have added the voltage selection for the MBX board. */
+
+/* MBX voltage bit in control register #2 */
+#define CR2_VPP12       ((uchar)0x10)
+#define CR2_VPPVDD      ((uchar)0x20)
+#define CR2_VDD5        ((uchar)0x40)
+#define CR2_VDD3        ((uchar)0x80)
+
+#define PCMCIA_BOARD_MSG "MBX860"
+
+static int voltage_set (int slot, int vcc, int vpp)
+{
+	uchar reg = 0;
+
+	debug ("voltage_set: PCMCIA_BOARD_MSG Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		 'A' + slot, vcc / 10, vcc % 10, vpp / 10, vcc % 10);
+
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= CR2_VDD3;
+		break;
+	case 50:
+		reg |= CR2_VDD5;
+		break;
+	default:
+		return 1;
+	}
+
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp) {
+			reg |= CR2_VPPVDD;
+		} else {
+			return 1;
+		}
+		break;
+	case 120:
+		reg |= CR2_VPP12;
+		break;
+	default:
+		return 1;
+	}
+
+	/* first, turn off all power */
+	MBX_CSR2 &= ~(CR2_VDDSEL | CR2_VPPSEL);
+
+	/* enable new powersettings */
+	MBX_CSR2 |= reg;
+	debug ("MBX_CSR2 read = 0x%02x\n", MBX_CSR2);
+
+	return (0);
+}
+
+static int hardware_enable (int slot)
+{
+	volatile immap_t *immap;
+	volatile cpm8xx_t *cp;
+	volatile pcmconf8xx_t *pcmp;
+	volatile sysconf8xx_t *sysp;
+	uint reg, mask;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n",
+				  'A' + slot);
+
+	udelay (10000);
+
+	immap = (immap_t *) CFG_IMMR;
+	sysp = (sysconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_siu_conf));
+	pcmp = (pcmconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_pcmcia));
+	cp = (cpm8xx_t *) (&(((immap_t *) CFG_IMMR)->im_cpm));
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr = PCMCIA_MASK (_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK (_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX (_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg = PCMCIA_PGCRX (_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;	/* active low  */
+	PCMCIA_PGCRX (_slot_) = reg;
+	udelay (500);
+
+	/* remove all power */
+	voltage_set (slot, 0, 0);
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay (10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n", __LINE__, __FUNCTION__,
+		  &(pcmp->pcmc_pipr), pcmp->pcmc_pipr);
+
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1 (_slot_) | PCMCIA_VS2 (_slot_);
+	reg = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n", reg,
+		  (reg & PCMCIA_VS1 (slot)) ? "n" : "ff",
+		  (reg & PCMCIA_VS2 (slot)) ? "n" : "ff");
+
+	if ((reg & mask) == mask) {
+		voltage_set (_slot_, 50, 0);
+		printf (" 5.0V card found: ");
+	} else {
+		voltage_set (_slot_, 33, 0);
+		printf (" 3.3V card found: ");
+	}
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg = PCMCIA_PGCRX (_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;	/* active low  */
+	PCMCIA_PGCRX (_slot_) = reg;
+
+	udelay (250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable (int slot)
+{
+	return 0;	/* No hardware to disable */
+}
+#endif /* CFG_CMD_PCMCIA */
+#endif /* CONFIG_MBX */
+/* ---------------------------------------------------------------------------- */
+/* R360MPI Board								*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_R360MPI)
+
+#define PCMCIA_BOARD_MSG "R360MPI"
+
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, mask;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Ports A, B & C pins for
+	 * 5 Volts Enable and 3 Volts enable
+	 */
+	immap->im_ioport.iop_pcpar &= ~(0x0400);
+	immap->im_ioport.iop_pcso  &= ~(0x0400);/*
+	immap->im_ioport.iop_pcdir |= 0x0400;*/
+
+	immap->im_ioport.iop_papar &= ~(0x0200);/*
+	immap->im_ioport.iop_padir |= 0x0200;*/
+#if 0
+	immap->im_ioport.iop_pbpar &= ~(0xC000);
+	immap->im_ioport.iop_pbdir &= ~(0xC000);
+#endif
+	/* remove all power */
+
+	immap->im_ioport.iop_pcdat |= 0x0400;
+	immap->im_ioport.iop_padat |= 0x0200;
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	reg  = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+	if ((reg & mask) == mask) {
+		immap->im_ioport.iop_pcdat &= ~(0x4000);
+		puts (" 5.0V card found: ");
+	} else {
+		immap->im_ioport.iop_padat &= ~(0x0002);
+		puts (" 3.3V card found: ");
+	}
+	immap->im_ioport.iop_pcdir |= 0x0400;
+	immap->im_ioport.iop_padir |= 0x0200;
+#if 0
+	/*  VCC switch error flag, PCMCIA slot INPACK_ pin */
+	cp->cp_pbdir &= ~(0x0020 | 0x0010);
+	cp->cp_pbpar &= ~(0x0020 | 0x0010);
+	udelay(500000);
+#endif
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* remove all power */
+	immap->im_ioport.iop_pcdat |= 0x0400;
+	immap->im_ioport.iop_padat |= 0x0200;
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Ports A & C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn off all power
+	 */
+	debug ("PCMCIA power OFF\n");
+	immap->im_ioport.iop_pcpar &= ~(0x0400);
+	immap->im_ioport.iop_pcso  &= ~(0x0400);/*
+	immap->im_ioport.iop_pcdir |= 0x0400;*/
+
+	immap->im_ioport.iop_papar &= ~(0x0200);/*
+	immap->im_ioport.iop_padir |= 0x0200;*/
+
+	immap->im_ioport.iop_pcdat |= 0x0400;
+	immap->im_ioport.iop_padat |= 0x0200;
+
+	reg = 0;
+	switch(vcc) {
+	case  0: 		break;
+	case 33: reg |= 0x0200;	break;
+	case 50: reg |= 0x0400;	break;
+	default: 		goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	if (reg & 0x0200)
+		immap->im_ioport.iop_pcdat &= !reg;
+	if (reg & 0x0400)
+		immap->im_ioport.iop_padat &= !reg;
+	immap->im_ioport.iop_pcdir |=  0x0200;
+	immap->im_ioport.iop_padir |=  0x0400;
+	if (reg) {
+		debug ("PCMCIA powered at %sV\n",
+			(reg&0x0400) ? "5.0" : "3.3");
+	} else {
+		debug ("PCMCIA powered down\n");
+	}
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+#endif	/* R360MPI */
+
+
+/* ---------------------------------------------------------------------------- */
+/* End of Board Specific Stuff							*/
+/* ---------------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------------- */
+/* MPC8xx Specific Stuff - should go to MPC8xx directory			*/
+/* ---------------------------------------------------------------------------- */
+
+/*
+ * Search this table to see if the windowsize is
+ * supported...
+ */
+
+#define M8XX_SIZES_NO 32
+
+static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] =
+{ 0x00000001, 0x00000002, 0x00000008, 0x00000004,
+  0x00000080, 0x00000040, 0x00000010, 0x00000020,
+  0x00008000, 0x00004000, 0x00001000, 0x00002000,
+  0x00000100, 0x00000200, 0x00000800, 0x00000400,
+
+  0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+  0x01000000, 0x02000000, 0xffffffff, 0x04000000,
+  0x00010000, 0x00020000, 0x00080000, 0x00040000,
+  0x00800000, 0x00400000, 0x00100000, 0x00200000 };
+
+
+/* ---------------------------------------------------------------------------- */
+
+static u_int m8xx_get_graycode(u_int size)
+{
+	u_int k;
+
+	for (k = 0; k < M8XX_SIZES_NO; k++) {
+		if(m8xx_size_to_gray[k] == size)
+			break;
+	}
+
+	if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
+		k = -1;
+
+	return k;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if 0
+static u_int m8xx_get_speed(u_int ns, u_int is_io)
+{
+	u_int reg, clocks, psst, psl, psht;
+
+	if(!ns) {
+
+		/*
+		 * We get called with IO maps setup to 0ns
+		 * if not specified by the user.
+		 * They should be 255ns.
+		 */
+
+		if(is_io)
+			ns = 255;
+		else
+			ns = 100;  /* fast memory if 0 */
+	}
+
+	/*
+	 * In PSST, PSL, PSHT fields we tell the controller
+	 * timing parameters in CLKOUT clock cycles.
+	 * CLKOUT is the same as GCLK2_50.
+	 */
+
+/* how we want to adjust the timing - in percent */
+
+#define ADJ 180 /* 80 % longer accesstime - to be sure */
+
+	clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000;
+	clocks = (clocks * ADJ) / (100*1000);
+
+	if(clocks >= PCMCIA_BMT_LIMIT) {
+		DEBUG(0, "Max access time limit reached\n");
+		clocks = PCMCIA_BMT_LIMIT-1;
+	}
+
+	psst = clocks / 7;          /* setup time */
+	psht = clocks / 7;          /* hold time */
+	psl  = (clocks * 5) / 7;    /* strobe length */
+
+	psst += clocks - (psst + psht + psl);
+
+	reg =  psst << 12;
+	reg |= psl  << 7;
+	reg |= psht << 16;
+
+	return reg;
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_funcid (int func)
+{
+	puts (indent);
+	switch (func) {
+	case CISTPL_FUNCID_MULTI:
+		puts (" Multi-Function");
+		break;
+	case CISTPL_FUNCID_MEMORY:
+		puts (" Memory");
+		break;
+	case CISTPL_FUNCID_SERIAL:
+		puts (" Serial Port");
+		break;
+	case CISTPL_FUNCID_PARALLEL:
+		puts (" Parallel Port");
+		break;
+	case CISTPL_FUNCID_FIXED:
+		puts (" Fixed Disk");
+		break;
+	case CISTPL_FUNCID_VIDEO:
+		puts (" Video Adapter");
+		break;
+	case CISTPL_FUNCID_NETWORK:
+		puts (" Network Adapter");
+		break;
+	case CISTPL_FUNCID_AIMS:
+		puts (" AIMS Card");
+		break;
+	case CISTPL_FUNCID_SCSI:
+		puts (" SCSI Adapter");
+		break;
+	default:
+		puts (" Unknown");
+		break;
+	}
+	puts (" Card\n");
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_fixed (volatile uchar *p)
+{
+	if (p == NULL)
+		return;
+
+	puts(indent);
+
+	switch (*p) {
+	case CISTPL_FUNCE_IDE_IFACE:
+	    {   uchar iface = *(p+2);
+
+		puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+		puts (" interface ");
+		break;
+	    }
+	case CISTPL_FUNCE_IDE_MASTER:
+	case CISTPL_FUNCE_IDE_SLAVE:
+	    {   uchar f1 = *(p+2);
+		uchar f2 = *(p+4);
+
+		puts ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+		if (f1 & CISTPL_IDE_UNIQUE)
+			puts (" [unique]");
+
+		puts ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+		if (f2 & CISTPL_IDE_HAS_SLEEP)
+			puts (" [sleep]");
+
+		if (f2 & CISTPL_IDE_HAS_STANDBY)
+			puts (" [standby]");
+
+		if (f2 & CISTPL_IDE_HAS_IDLE)
+			puts (" [idle]");
+
+		if (f2 & CISTPL_IDE_LOW_POWER)
+			puts (" [low power]");
+
+		if (f2 & CISTPL_IDE_REG_INHIBIT)
+			puts (" [reg inhibit]");
+
+		if (f2 & CISTPL_IDE_HAS_INDEX)
+			puts (" [index]");
+
+		if (f2 & CISTPL_IDE_IOIS16)
+			puts (" [IOis16]");
+
+		break;
+	    }
+	}
+	putc ('\n');
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#define MAX_IDENT_CHARS		64
+#define	MAX_IDENT_FIELDS	4
+
+static uchar *known_cards[] = {
+	"ARGOSY PnPIDE D5",
+	NULL
+};
+
+static int identify  (volatile uchar *p)
+{
+	uchar id_str[MAX_IDENT_CHARS];
+	uchar data;
+	uchar *t;
+	uchar **card;
+	int i, done;
+
+	if (p == NULL)
+		return (0);	/* Don't know */
+
+	t = id_str;
+	done =0;
+
+	for (i=0; i<=4 && !done; ++i, p+=2) {
+		while ((data = *p) != '\0') {
+			if (data == 0xFF) {
+				done = 1;
+				break;
+			}
+			*t++ = data;
+			if (t == &id_str[MAX_IDENT_CHARS-1]) {
+				done = 1;
+				break;
+			}
+			p += 2;
+		}
+		if (!done)
+			*t++ = ' ';
+	}
+	*t = '\0';
+	while (--t > id_str) {
+		if (*t == ' ')
+			*t = '\0';
+		else
+			break;
+	}
+	puts (id_str);
+	putc ('\n');
+
+	for (card=known_cards; *card; ++card) {
+		debug ("## Compare against \"%s\"\n", *card);
+		if (strcmp(*card, id_str) == 0) {	/* found! */
+			debug ("## CARD FOUND ##\n");
+			return (1);
+		}
+	}
+
+	return (0);	/* don't know */
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CFG_CMD_PCMCIA || (CFG_CMD_IDE && CONFIG_IDE_8xx_PCCARD) */

+ 377 - 0
common/env_flash.c

@@ -0,0 +1,377 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.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
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH) /* Environment is in Flash */
+
+#include <command.h>
+#include <environment.h>
+#include <cmd_nvedit.h>
+#include <linux/stddef.h>
+
+#if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_FLASH)) == (CFG_CMD_ENV|CFG_CMD_FLASH))
+#define CMD_SAVEENV
+#elif defined(CFG_ENV_ADDR_REDUND)
+#error Cannot use CFG_ENV_ADDR_REDUND without CFG_CMD_ENV & CFG_CMD_FLASH
+#endif
+
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE) && \
+    defined(CFG_ENV_ADDR_REDUND)
+#error CFG_ENV_ADDR_REDUND should not be used when CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
+#endif
+
+#if defined(CFG_ENV_SIZE_REDUND) && (CFG_ENV_SIZE_REDUND < CFG_ENV_SIZE)
+#error CFG_ENV_SIZE_REDUND should not be less then CFG_ENV_SIZE
+#endif
+
+#ifdef CONFIG_INFERNO
+# ifdef CFG_ENV_ADDR_REDUND
+#error CFG_ENV_ADDR_REDUND is not implemented for CONFIG_INFERNO
+# endif
+#endif
+
+char * env_name_spec = "Flash";
+
+#ifdef ENV_IS_EMBEDDED
+
+extern uchar environment[];
+env_t *env_ptr = (env_t *)(&environment[0]);
+
+#ifdef CMD_SAVEENV
+/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
+static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+#else /* ! ENV_IS_EMBEDDED */
+
+env_t *env_ptr = (env_t *)CFG_ENV_ADDR;
+#ifdef CMD_SAVEENV
+static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+#endif /* ENV_IS_EMBEDDED */
+
+#ifdef CFG_ENV_ADDR_REDUND
+static env_t *flash_addr_new = (env_t *)CFG_ENV_ADDR_REDUND;
+
+static ulong end_addr = CFG_ENV_ADDR + CFG_ENV_SIZE - 1;
+static ulong end_addr_new = CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1;
+
+static uchar active_flag = 1;
+static uchar obsolete_flag = 0;
+#endif
+
+extern uchar default_environment[];
+extern int default_environment_size;
+
+
+uchar env_get_char_spec (int index)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	return ( *((uchar *)(gd->env_addr + index)) );
+}
+
+#ifdef CFG_ENV_ADDR_REDUND
+
+int  env_init(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int crc1_ok =
+		(crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc);
+	int crc2_ok =
+		(crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc);
+
+	uchar flag1 = flash_addr->flags;
+	uchar flag2 = flash_addr_new->flags;
+
+	ulong addr_default = (ulong)&default_environment[0];
+	ulong addr1 = (ulong)&(flash_addr->data);
+	ulong addr2 = (ulong)&(flash_addr_new->data);
+
+	if (crc1_ok && ! crc2_ok)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 1;
+	}
+	else if (! crc1_ok && crc2_ok)
+	{
+		gd->env_addr  = addr2;
+		gd->env_valid = 1;
+	}
+	else if (! crc1_ok && ! crc2_ok)
+	{
+		gd->env_addr  = addr_default;
+		gd->env_valid = 0;
+	}
+	else if (flag1 == active_flag && flag2 == obsolete_flag)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 1;
+	}
+	else if (flag1 == obsolete_flag && flag2 == active_flag)
+	{
+		gd->env_addr  = addr2;
+		gd->env_valid = 1;
+	}
+	else if (flag1 == flag2)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 2;
+	}
+	else if (flag1 == 0xFF)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 2;
+	}
+	else if (flag2 == 0xFF)
+	{
+		gd->env_addr  = addr2;
+		gd->env_valid = 2;
+	}
+
+	return (0);
+}
+
+#ifdef CMD_SAVEENV
+int saveenv(void)
+{
+	int rc = 1;
+
+	debug ("Protect off %08lX ... %08lX\n",
+		(ulong)flash_addr, end_addr);
+
+	if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {
+		goto Done;
+	}
+
+	debug ("Protect off %08lX ... %08lX\n",
+		(ulong)flash_addr_new, end_addr_new);
+
+	if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {
+		goto Done;
+	}
+
+	puts ("Erasing Flash...");
+	debug (" %08lX ... %08lX ...",
+		(ulong)flash_addr_new, end_addr_new);
+
+	if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {
+		goto Done;
+	}
+
+	puts ("Writing to Flash... ");
+	debug (" %08lX ... %08lX ...",
+		(ulong)&(flash_addr_new->data),
+		sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
+	if (flash_write(env_ptr->data,
+	                (ulong)&(flash_addr_new->data),
+			sizeof(env_ptr->data)) ||
+
+	    flash_write((char *)&(env_ptr->crc),
+	                (ulong)&(flash_addr_new->crc),
+			sizeof(env_ptr->crc)) ||
+
+	    flash_write((char *)&obsolete_flag,
+	                (ulong)&(flash_addr->flags),
+			sizeof(flash_addr->flags)) ||
+
+	    flash_write((char *)&active_flag,
+	                (ulong)&(flash_addr_new->flags),
+			sizeof(flash_addr_new->flags)))
+	{
+		flash_perror (rc);
+		goto Done;
+	}
+	puts ("done\n");
+
+	{
+		env_t * etmp = flash_addr;
+		ulong ltmp = end_addr;
+
+		flash_addr = flash_addr_new;
+		flash_addr_new = etmp;
+
+		end_addr = end_addr_new;
+		end_addr_new = ltmp;
+	}
+
+	rc = 0;
+Done:
+
+	/* try to re-protect */
+	(void) flash_sect_protect (1, (ulong)flash_addr, end_addr);
+	(void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+
+	return rc;
+}
+#endif /* CMD_SAVEENV */
+
+#else /* ! CFG_ENV_ADDR_REDUND */
+
+int  env_init(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+		gd->env_addr  = (ulong)&(env_ptr->data);
+		gd->env_valid = 1;
+	} else {
+		gd->env_addr  = (ulong)&default_environment[0];
+		gd->env_valid = 0;
+	}
+
+	return (0);
+}
+
+#ifdef CMD_SAVEENV
+
+int saveenv(void)
+{
+	int	len, rc;
+	ulong	end_addr;
+	ulong	flash_sect_addr;
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
+	ulong	flash_offset;
+	uchar	env_buffer[CFG_ENV_SECT_SIZE];
+#else
+	uchar *env_buffer = (char *)env_ptr;
+#endif	/* CFG_ENV_SECT_SIZE */
+	int rcode = 0;
+
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
+
+	flash_offset    = ((ulong)flash_addr) & (CFG_ENV_SECT_SIZE-1);
+	flash_sect_addr = ((ulong)flash_addr) & ~(CFG_ENV_SECT_SIZE-1);
+
+	debug ( "copy old content: "
+		"sect_addr: %08lX  env_addr: %08lX  offset: %08lX\n",
+		flash_sect_addr, (ulong)flash_addr, flash_offset);
+
+	/* copy old contents to temporary buffer */
+	memcpy (env_buffer, (void *)flash_sect_addr, CFG_ENV_SECT_SIZE);
+
+	/* copy current environment to temporary buffer */
+	memcpy ((uchar *)((unsigned long)env_buffer + flash_offset),
+		env_ptr,
+		CFG_ENV_SIZE);
+
+	len	 = CFG_ENV_SECT_SIZE;
+#else
+	flash_sect_addr = (ulong)flash_addr;
+	len	 = CFG_ENV_SIZE;
+#endif	/* CFG_ENV_SECT_SIZE */
+
+#ifndef CONFIG_INFERNO
+	end_addr = flash_sect_addr + len - 1;
+#else
+	/* this is the last sector, and the size is hardcoded here */
+	/* otherwise we will get stack problems on loading 128 KB environment */
+	end_addr = flash_sect_addr + 0x20000 - 1;
+#endif
+
+	debug ("Protect off %08lX ... %08lX\n",
+		(ulong)flash_sect_addr, end_addr);
+
+	if (flash_sect_protect (0, flash_sect_addr, end_addr))
+		return 1;
+
+	puts ("Erasing Flash...");
+	if (flash_sect_erase (flash_sect_addr, end_addr))
+		return 1;
+
+	puts ("Writing to Flash... ");
+	rc = flash_write(env_buffer, flash_sect_addr, len);
+	if (rc != 0) {
+		flash_perror (rc);
+		rcode = 1;
+	} else {
+		puts ("done\n");
+	}
+
+	/* try to re-protect */
+	(void) flash_sect_protect (1, flash_sect_addr, end_addr);
+	return rcode;
+}
+
+#endif /* CMD_SAVEENV */
+
+#endif /* CFG_ENV_ADDR_REDUND */
+
+void env_relocate_spec (void)
+{
+#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
+#ifdef CFG_ENV_ADDR_REDUND
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->env_addr != (ulong)&(flash_addr->data))
+	{
+		env_t * etmp = flash_addr;
+		ulong ltmp = end_addr;
+
+		flash_addr = flash_addr_new;
+		flash_addr_new = etmp;
+
+		end_addr = end_addr_new;
+		end_addr_new = ltmp;
+	}
+
+	if (flash_addr_new->flags != obsolete_flag &&
+	    crc32(0, flash_addr_new->data, ENV_SIZE) ==
+	    flash_addr_new->crc)
+	{
+		gd->env_valid = 2;
+		flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
+		flash_write((char *)&obsolete_flag,
+                    	    (ulong)&(flash_addr_new->flags),
+	        	    sizeof(flash_addr_new->flags));
+		flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+	}
+
+	if (flash_addr->flags != active_flag &&
+	    (flash_addr->flags & active_flag) == active_flag)
+	{
+		gd->env_valid = 2;
+		flash_sect_protect (0, (ulong)flash_addr, end_addr);
+		flash_write((char *)&active_flag,
+                    	    (ulong)&(flash_addr->flags),
+	        	    sizeof(flash_addr->flags));
+		flash_sect_protect (1, (ulong)flash_addr, end_addr);
+	}
+
+	if (gd->env_valid == 2)
+		puts ("*** Warning - some problems detected "
+		      "reading environment; recovered successfully\n\n");
+#endif /* CFG_ENV_ADDR_REDUND */
+	memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE);
+#endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */
+}
+
+#endif /* CFG_ENV_IS_IN_FLASH) */

+ 138 - 0
common/env_nvram.c

@@ -0,0 +1,138 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.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
+ */
+
+/*
+ * 09-18-2001 Andreas Heppel, Sysgo RTS GmbH <aheppel@sysgo.de>
+ *
+ * It might not be possible in all cases to use 'memcpy()' to copy
+ * the environment to NVRAM, as the NVRAM might not be mapped into
+ * the memory space. (I.e. this is the case for the BAB750). In those
+ * cases it might be possible to access the NVRAM using a different
+ * method. For example, the RTC on the BAB750 is accessible in IO
+ * space using its address and data registers. To enable usage of
+ * NVRAM in those cases I invented the functions 'nvram_read()' and
+ * 'nvram_write()', which will be activated upon the configuration
+ * #define CFG_NVRAM_ACCESS_ROUTINE. Note, that those functions are
+ * strongly dependent on the used HW, and must be redefined for each
+ * board that wants to use them.
+ */
+
+#include <common.h>
+
+#ifdef CFG_ENV_IS_IN_NVRAM /* Environment is in NVRAM */
+
+#include <command.h>
+#include <environment.h>
+#include <cmd_nvedit.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+extern void *nvram_read(void *dest, const long src, size_t count);
+extern void nvram_write(long dest, const void *src, size_t count);
+env_t *env_ptr = NULL;
+#else
+env_t *env_ptr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+char * env_name_spec = "NVRAM";
+
+extern uchar default_environment[];
+extern int default_environment_size;
+
+extern uchar (*env_get_char)(int);
+extern uchar env_get_char_memory (int index);
+
+
+uchar env_get_char_spec (int index)
+{
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+	uchar c;
+
+	nvram_read(&c, CFG_ENV_ADDR+index, 1);
+
+	return c;
+#else
+	DECLARE_GLOBAL_DATA_PTR;
+
+	return *((uchar *)(gd->env_addr + index));
+#endif
+}
+
+void env_relocate_spec (void)
+{
+#if defined(CFG_NVRAM_ACCESS_ROUTINE)
+	nvram_read(env_ptr, CFG_ENV_ADDR, CFG_ENV_SIZE);
+#else
+	memcpy (env_ptr, (void*)CFG_ENV_ADDR, CFG_ENV_SIZE);
+#endif
+}
+
+int saveenv (void)
+{
+	int rcode = 0;
+
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+	nvram_write(CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE);
+#else
+	if (memcpy ((char *)CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE) == NULL)
+		    rcode = 1 ;
+#endif
+	return rcode;
+}
+
+
+/************************************************************************
+ * Initialize Environment use
+ *
+ * We are still running from ROM, so data use is limited
+ */
+int env_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CFG_NVRAM_ACCESS_ROUTINE)
+	ulong crc;
+	uchar data[ENV_SIZE];
+	nvram_read (&crc, CFG_ENV_ADDR, sizeof(ulong));
+	nvram_read (data, CFG_ENV_ADDR+sizeof(ulong), ENV_SIZE);
+
+	if (crc32(0, data, ENV_SIZE) == crc) {
+		gd->env_addr  = (ulong)CFG_ENV_ADDR + sizeof(long);
+#else
+	if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+		gd->env_addr  = (ulong)&(env_ptr->data);
+#endif
+		gd->env_valid = 1;
+	} else {
+		gd->env_addr  = (ulong)&default_environment[0];
+		gd->env_valid = 0;
+	}
+
+	return (0);
+}
+
+#endif /* CFG_ENV_IS_IN_NVRAM */

+ 198 - 0
common/environment.c

@@ -0,0 +1,198 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen,  Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <environment.h>
+
+/*
+ * Handle HOSTS that have prepended
+ * crap on symbol names, not TARGETS.
+ */
+#if defined(__APPLE__)
+/* Leading underscore on symbols */
+#  define SYM_CHAR "_"
+#else /* No leading character on symbols */
+#  define SYM_CHAR
+#endif
+
+/*
+ * Generate embedded environment table
+ * inside U-Boot image, if needed.
+ */
+#if defined(ENV_IS_EMBEDDED)
+/*
+ * Only put the environment in it's own section when we are building
+ * U-Boot proper.  The host based program "tools/envcrc" does not need
+ * a seperate section.  Note that ENV_CRC is only defined when building
+ * U-Boot itself.
+ */
+#if (defined(CONFIG_FADS)	|| \
+     defined(CONFIG_HYMOD)	|| \
+     defined(CONFIG_ICU862)	|| \
+     defined(CONFIG_R360MPI)	|| \
+     defined(CONFIG_TQM8xxL)	|| \
+     defined(CONFIG_RRVISION)	|| \
+     defined(CONFIG_TRAB)   )	&& \
+     defined(ENV_CRC) /* Environment embedded in U-Boot .ppcenv section */
+/* XXX - This only works with GNU C */
+#  define __PPCENV__ __attribute__ ((section(".ppcenv")))
+#  define __PPCTEXT__ __attribute__ ((section(".text")))
+
+#elif defined(USE_HOSTCC) /* Native for 'tools/envcrc' */
+#  define __PPCENV__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+#  define __PPCTEXT__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+
+#else /* Environment is embedded in U-Boot's .text section */
+/* XXX - This only works with GNU C */
+#  define __PPCENV__ __attribute__ ((section(".text")))
+#  define __PPCTEXT__ __attribute__ ((section(".text")))
+#endif
+
+/*
+ * Macros to generate global absolutes.
+ */
+#define GEN_SYMNAME(str) SYM_CHAR #str
+#define GEN_VALUE(str) #str
+#define GEN_ABS(name, value) \
+		asm (".globl " GEN_SYMNAME(name)); \
+		asm (GEN_SYMNAME(name) " = " GEN_VALUE(value))
+
+/*
+ * Macros to transform values
+ * into environment strings.
+ */
+#define XMK_STR(x)	#x
+#define MK_STR(x)	XMK_STR(x)
+
+/*
+ * Check to see if we are building with a
+ * computed CRC.  Otherwise define it as ~0.
+ */
+#if !defined(ENV_CRC)
+#  define ENV_CRC	~0
+#endif
+
+env_t environment __PPCENV__ = {
+	ENV_CRC,	/* CRC Sum */
+#ifdef CFG_REDUNDAND_ENVIRONMENT
+	1,		/* Flags: valid */
+#endif
+	{
+#if defined(CONFIG_BOOTARGS)
+	"bootargs="	CONFIG_BOOTARGS			"\0"
+#endif
+#if defined(CONFIG_BOOTCOMMAND)
+	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
+#endif
+#if defined(CONFIG_RAMBOOTCOMMAND)
+	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
+#endif
+#if defined(CONFIG_NFSBOOTCOMMAND)
+	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
+#endif
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+	"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
+#endif
+#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
+	"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
+#endif
+#ifdef	CONFIG_LOADS_ECHO
+	"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
+#endif
+#ifdef	CONFIG_ETHADDR
+	"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH1ADDR
+	"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH2ADDR
+	"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETHPRIME
+	"ethprime="	CONFIG_ETHPRIME			"\0"
+#endif
+#ifdef	CONFIG_IPADDR
+	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
+#endif
+#ifdef	CONFIG_SERVERIP
+	"serverip="	MK_STR(CONFIG_SERVERIP)		"\0"
+#endif
+#ifdef	CFG_AUTOLOAD
+	"autoload="	CFG_AUTOLOAD			"\0"
+#endif
+#ifdef	CONFIG_ROOTPATH
+	"rootpath="	MK_STR(CONFIG_ROOTPATH)		"\0"
+#endif
+#ifdef	CONFIG_GATEWAYIP
+	"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
+#endif
+#ifdef	CONFIG_NETMASK
+	"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
+#endif
+#ifdef	CONFIG_HOSTNAME
+	"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
+#endif
+#ifdef	CONFIG_BOOTFILE
+	"bootfile="	MK_STR(CONFIG_BOOTFILE)		"\0"
+#endif
+#ifdef	CONFIG_LOADADDR
+	"loadaddr="	MK_STR(CONFIG_LOADADDR)		"\0"
+#endif
+#ifdef	CONFIG_PREBOOT
+	"preboot="	CONFIG_PREBOOT			"\0"
+#endif
+#ifdef	CONFIG_CLOCKS_IN_MHZ
+	"clocks_in_mhz=" "1"				"\0"
+#endif
+#ifdef  CONFIG_EXTRA_ENV_SETTINGS
+	CONFIG_EXTRA_ENV_SETTINGS
+#endif
+	"\0"		/* Term. env_t.data with 2 NULLs */
+	}
+};
+#ifdef CFG_ENV_ADDR_REDUND
+env_t redundand_environment __PPCENV__ = {
+	0,		/* CRC Sum: invalid */
+	0,		/* Flags:   invalid */
+	{
+	"\0"
+	}
+};
+#endif	/* CFG_ENV_ADDR_REDUND */
+
+/*
+ * These will end up in the .text section
+ * if the environment strings are embedded
+ * in the image.  When this is used for
+ * tools/envcrc, they are placed in the
+ * .data/.sdata section.
+ *
+ */
+unsigned long env_size __PPCTEXT__ = sizeof(env_t);
+
+/*
+ * Add in absolutes.
+ */
+GEN_ABS(env_offset, CFG_ENV_OFFSET);
+
+#endif /* ENV_IS_EMBEDDED */

+ 817 - 0
common/main.c

@@ -0,0 +1,817 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <cmd_nvedit.h>
+#include <cmd_bootm.h>
+#include <malloc.h>
+#if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
+#include <cmd_boot.h>		/* for do_reset() prototype */
+#endif
+
+#ifdef CFG_HUSH_PARSER
+#include <hush.h>
+#endif
+
+#define MAX_DELAY_STOP_STR 32
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
+static int parse_line (char *, char *[]);
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+static int abortboot(int);
+#endif
+
+#undef DEBUG_PARSER
+
+char        console_buffer[CFG_CBSIZE];		/* console I/O buffer	*/
+
+static char erase_seq[] = "\b \b";		/* erase sequence	*/
+static char   tab_seq[] = "        ";		/* used to expand TABs	*/
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+static uint64_t endtime = 0;  /* must be set, default is instant timeout */
+static int      retry_time = -1; /* -1 so can call readline before main_loop */
+#endif
+
+#define	endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
+
+#ifndef CONFIG_BOOT_RETRY_MIN
+#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
+#endif
+
+#ifdef CONFIG_MODEM_SUPPORT
+int do_mdm_init = 0;
+extern void mdm_init(void); /* defined in board.c */
+#endif
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
+ * returns: 0 -  no key string, allow autoboot
+ *          1 - got key string, abort
+ */
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+# if defined(CONFIG_AUTOBOOT_KEYED)
+static __inline__ int abortboot(int bootdelay)
+{
+	int abort = 0;
+	uint64_t etime = endtick(bootdelay);
+	struct
+	{
+		char* str;
+		u_int len;
+		int retry;
+	}
+	delaykey [] =
+	{
+		{ str: getenv ("bootdelaykey"),  retry: 1 },
+		{ str: getenv ("bootdelaykey2"), retry: 1 },
+		{ str: getenv ("bootstopkey"),   retry: 0 },
+		{ str: getenv ("bootstopkey2"),  retry: 0 },
+	};
+
+	char presskey [MAX_DELAY_STOP_STR];
+	u_int presskey_len = 0;
+	u_int presskey_max = 0;
+	u_int i;
+
+#  ifdef CONFIG_AUTOBOOT_PROMPT
+	printf (CONFIG_AUTOBOOT_PROMPT, bootdelay);
+#  endif
+
+#  ifdef CONFIG_AUTOBOOT_DELAY_STR
+	if (delaykey[0].str == NULL)
+		delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
+#  endif
+#  ifdef CONFIG_AUTOBOOT_DELAY_STR2
+	if (delaykey[1].str == NULL)
+		delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
+#  endif
+#  ifdef CONFIG_AUTOBOOT_STOP_STR
+	if (delaykey[2].str == NULL)
+		delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
+#  endif
+#  ifdef CONFIG_AUTOBOOT_STOP_STR2
+	if (delaykey[3].str == NULL)
+		delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
+#  endif
+
+	for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+		delaykey[i].len = delaykey[i].str == NULL ?
+				    0 : strlen (delaykey[i].str);
+		delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
+				    MAX_DELAY_STOP_STR : delaykey[i].len;
+
+		presskey_max = presskey_max > delaykey[i].len ?
+				    presskey_max : delaykey[i].len;
+
+#  if DEBUG_BOOTKEYS
+		printf("%s key:<%s>\n",
+		       delaykey[i].retry ? "delay" : "stop",
+		       delaykey[i].str ? delaykey[i].str : "NULL");
+#  endif
+	}
+
+	/* In order to keep up with incoming data, check timeout only
+	 * when catch up.
+	 */
+	while (!abort && get_ticks() <= etime) {
+		for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+			if (delaykey[i].len > 0 &&
+			    presskey_len >= delaykey[i].len &&
+			    memcmp (presskey + presskey_len - delaykey[i].len,
+		        	    delaykey[i].str,
+				    delaykey[i].len) == 0) {
+#  if DEBUG_BOOTKEYS
+				printf("got %skey\n",
+				       delaykey[i].retry ? "delay" : "stop");
+#  endif
+
+#  ifdef CONFIG_BOOT_RETRY_TIME
+				/* don't retry auto boot */
+				if (! delaykey[i].retry)
+					retry_time = -1;
+#  endif
+				abort = 1;
+			}
+		}
+
+		if (tstc()) {
+			if (presskey_len < presskey_max) {
+				presskey [presskey_len ++] = getc();
+			}
+			else {
+				for (i = 0; i < presskey_max - 1; i ++)
+					presskey [i] = presskey [i + 1];
+
+				presskey [i] = getc();
+			}
+		}
+	}
+#  if DEBUG_BOOTKEYS
+	if (!abort)
+		printf("key timeout\n");
+#  endif
+
+	return abort;
+}
+
+# else	/* !defined(CONFIG_AUTOBOOT_KEYED) */
+
+static __inline__ int abortboot(int bootdelay)
+{
+	int abort = 0;
+
+	printf("Hit any key to stop autoboot: %2d ", bootdelay);
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+        /*
+         * Check if key already pressed
+         * Don't check if bootdelay < 0
+         */
+	if (bootdelay >= 0) {
+		if (tstc()) {	/* we got a key press	*/
+			(void) getc();  /* consume input	*/
+			printf ("\b\b\b 0\n");
+			return 1; 	/* don't auto boot	*/
+		}
+        }
+#endif
+
+	while (bootdelay > 0) {
+		int i;
+
+		--bootdelay;
+		/* delay 100 * 10ms */
+		for (i=0; !abort && i<100; ++i) {
+			if (tstc()) {	/* we got a key press	*/
+				abort  = 1;	/* don't auto boot	*/
+				bootdelay = 0;	/* no more delay	*/
+				(void) getc();  /* consume input	*/
+				break;
+			}
+			udelay (10000);
+		}
+
+		printf ("\b\b\b%2d ", bootdelay);
+	}
+
+	putc ('\n');
+
+	return abort;
+}
+# endif	/* CONFIG_AUTOBOOT_KEYED */
+#endif	/* CONFIG_BOOTDELAY >= 0  */
+
+/****************************************************************************/
+
+void main_loop (void)
+{
+#ifndef CFG_HUSH_PARSER
+	static char lastcommand[CFG_CBSIZE] = { 0, };
+	int len;
+	int rc = 1;
+	int flag;
+#endif
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+	char *s;
+	int bootdelay;
+#endif
+#ifdef CONFIG_PREBOOT
+	char *p;
+#endif
+
+#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
+	ulong bmp = 0;		/* default bitmap */
+	extern int trab_vfd (ulong bitmap);
+
+#ifdef CONFIG_MODEM_SUPPORT
+	if (do_mdm_init)
+		bmp = 1;	/* alternate bitmap */
+#endif
+	trab_vfd (bmp);
+#endif	/* CONFIG_VFD && VFD_TEST_LOGO */
+
+#ifdef CONFIG_MODEM_SUPPORT
+	debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
+	if (do_mdm_init) {
+		uchar *str = strdup(getenv("mdm_cmd"));
+		setenv ("preboot", str);  /* set or delete definition */
+		if (str != NULL)
+			free (str);
+		mdm_init(); /* wait for modem connection */
+	}
+#endif  /* CONFIG_MODEM_SUPPORT */
+
+#ifdef CFG_HUSH_PARSER
+	u_boot_hush_start ();
+#endif
+
+#ifdef CONFIG_PREBOOT
+	if ((p = getenv ("preboot")) != NULL) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+		int prev = disable_ctrlc(1);	/* disable Control C checking */
+# endif
+
+# ifndef CFG_HUSH_PARSER
+		run_command (p, 0);
+# else
+		parse_string_outer(p, FLAG_PARSE_SEMICOLON |
+				    FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+		disable_ctrlc(prev);	/* restore Control C checking */
+# endif
+	}
+#endif /* CONFIG_PREBOOT */
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+	s = getenv ("bootdelay");
+	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+
+#if 0
+	printf ("### main_loop entered:\n\n");
+#endif
+
+# ifdef CONFIG_BOOT_RETRY_TIME
+	s = getenv ("bootretry");
+	if (s != NULL)
+		retry_time = (int)simple_strtoul(s, NULL, 10);
+	else
+		retry_time =  CONFIG_BOOT_RETRY_TIME;
+	if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
+		retry_time = CONFIG_BOOT_RETRY_MIN;
+# endif	/* CONFIG_BOOT_RETRY_TIME */
+
+	s = getenv ("bootcmd");
+	if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+		int prev = disable_ctrlc(1);	/* disable Control C checking */
+# endif
+
+# ifndef CFG_HUSH_PARSER
+		run_command (s, 0);
+# else
+		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
+				    FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+		disable_ctrlc(prev);	/* restore Control C checking */
+# endif
+	}
+#endif	/* CONFIG_BOOTDELAY */
+
+	/*
+	 * Main Loop for Monitor Command Processing
+	 */
+#ifdef CFG_HUSH_PARSER
+	parse_file_outer();
+	/* This point is never reached */
+	for (;;);
+#else
+	for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+		if (rc >= 0) {
+			/* Saw enough of a valid command to
+			 * restart the timeout.
+			 */
+			reset_cmd_timeout();
+		}
+#endif
+		len = readline (CFG_PROMPT);
+
+		flag = 0;	/* assume no special flags for now */
+		if (len > 0)
+			strcpy (lastcommand, console_buffer);
+		else if (len == 0)
+			flag |= CMD_FLAG_REPEAT;
+#ifdef CONFIG_BOOT_RETRY_TIME
+		else if (len == -2) {
+			/* -2 means timed out, retry autoboot
+			 */
+			printf("\nTimed out waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+			/* Reinit board to run initialization code again */
+			do_reset (NULL, 0, 0, NULL);
+# else
+			return;		/* retry autoboot */
+# endif
+		}
+#endif
+
+		if (len == -1)
+			printf ("<INTERRUPT>\n");
+		else
+			rc = run_command (lastcommand, flag);
+
+		if (rc <= 0) {
+			/* invalid command or not repeatable, forget it */
+			lastcommand[0] = 0;
+		}
+	}
+#endif /*CFG_HUSH_PARSER*/
+}
+
+/***************************************************************************
+ * reset command line timeout to retry_time seconds
+ */
+#ifdef CONFIG_BOOT_RETRY_TIME
+void reset_cmd_timeout(void)
+{
+	endtime = endtick(retry_time);
+}
+#endif
+
+/****************************************************************************/
+
+/*
+ * Prompt for input and read a line.
+ * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
+ * time out when time goes past endtime (timebase time in ticks).
+ * Return:	number of read characters
+ *		-1 if break
+ *		-2 if timed out
+ */
+int readline (const char *const prompt)
+{
+	char   *p = console_buffer;
+	int	n = 0;				/* buffer index		*/
+	int	plen = 0;			/* prompt length	*/
+	int	col;				/* output column cnt	*/
+	char	c;
+
+	/* print prompt */
+	if (prompt) {
+		plen = strlen (prompt);
+		puts (prompt);
+	}
+	col = plen;
+
+	for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+		while (!tstc()) {	/* while no incoming data */
+			if (retry_time >= 0 && get_ticks() > endtime)
+				return (-2);	/* timed out */
+		}
+#endif
+		WATCHDOG_RESET();		/* Trigger watchdog, if needed */
+
+#ifdef CONFIG_SHOW_ACTIVITY
+		while (!tstc()) {
+			extern void show_activity(int arg);
+			show_activity(0);
+		}
+#endif
+		c = getc();
+
+		/*
+		 * Special character handling
+		 */
+		switch (c) {
+		case '\r':				/* Enter		*/
+		case '\n':
+			*p = '\0';
+			puts ("\r\n");
+			return (p - console_buffer);
+
+		case 0x03:				/* ^C - break		*/
+			console_buffer[0] = '\0';	/* discard input */
+			return (-1);
+
+		case 0x15:				/* ^U - erase line	*/
+			while (col > plen) {
+				puts (erase_seq);
+				--col;
+			}
+			p = console_buffer;
+			n = 0;
+			continue;
+
+		case 0x17:				/* ^W - erase word 	*/
+			p=delete_char(console_buffer, p, &col, &n, plen);
+			while ((n > 0) && (*p != ' ')) {
+				p=delete_char(console_buffer, p, &col, &n, plen);
+			}
+			continue;
+
+		case 0x08:				/* ^H  - backspace	*/
+		case 0x7F:				/* DEL - backspace	*/
+			p=delete_char(console_buffer, p, &col, &n, plen);
+			continue;
+
+		default:
+			/*
+			 * Must be a normal character then
+			 */
+			if (n < CFG_CBSIZE-2) {
+				if (c == '\t') {	/* expand TABs		*/
+					puts (tab_seq+(col&07));
+					col += 8 - (col&07);
+				} else {
+					++col;		/* echo input		*/
+					putc (c);
+				}
+				*p++ = c;
+				++n;
+			} else {			/* Buffer full		*/
+				putc ('\a');
+			}
+		}
+	}
+}
+
+/****************************************************************************/
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+	char *s;
+
+	if (*np == 0) {
+		return (p);
+	}
+
+	if (*(--p) == '\t') {			/* will retype the whole line	*/
+		while (*colp > plen) {
+			puts (erase_seq);
+			(*colp)--;
+		}
+		for (s=buffer; s<p; ++s) {
+			if (*s == '\t') {
+				puts (tab_seq+((*colp) & 07));
+				*colp += 8 - ((*colp) & 07);
+			} else {
+				++(*colp);
+				putc (*s);
+			}
+		}
+	} else {
+		puts (erase_seq);
+		(*colp)--;
+	}
+	(*np)--;
+	return (p);
+}
+
+/****************************************************************************/
+
+int parse_line (char *line, char *argv[])
+{
+	int nargs = 0;
+
+#ifdef DEBUG_PARSER
+	printf ("parse_line: \"%s\"\n", line);
+#endif
+	while (nargs < CFG_MAXARGS) {
+
+		/* skip any white space */
+		while ((*line == ' ') || (*line == '\t')) {
+			++line;
+		}
+
+		if (*line == '\0') {	/* end of line, no more args	*/
+			argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+		printf ("parse_line: nargs=%d\n", nargs);
+#endif
+			return (nargs);
+		}
+
+		argv[nargs++] = line;	/* begin of argument string	*/
+
+		/* find end of string */
+		while (*line && (*line != ' ') && (*line != '\t')) {
+			++line;
+		}
+
+		if (*line == '\0') {	/* end of line, no more args	*/
+			argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+		printf ("parse_line: nargs=%d\n", nargs);
+#endif
+			return (nargs);
+		}
+
+		*line++ = '\0';		/* terminate current arg	 */
+	}
+
+	printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
+
+#ifdef DEBUG_PARSER
+	printf ("parse_line: nargs=%d\n", nargs);
+#endif
+	return (nargs);
+}
+
+/****************************************************************************/
+
+static void process_macros (const char *input, char *output)
+{
+	char c, prev;
+	const char *varname_start = NULL;
+	int inputcnt  = strlen (input);
+	int outputcnt = CFG_CBSIZE;
+	int state = 0;	/* 0 = waiting for '$'	*/
+			/* 1 = waiting for '('	*/
+			/* 2 = waiting for ')'	*/
+
+#ifdef DEBUG_PARSER
+	char *output_start = output;
+
+	printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
+#endif
+
+	prev = '\0';			/* previous character	*/
+
+	while (inputcnt && outputcnt) {
+	    c = *input++;
+	    inputcnt--;
+
+	    /* remove one level of escape characters */
+	    if ((c == '\\') && (prev != '\\')) {
+		if (inputcnt-- == 0)
+			break;
+		prev = c;
+	    	c = *input++;
+	    }
+
+	    switch (state) {
+	    case 0:			/* Waiting for (unescaped) $	*/
+		if ((c == '$') && (prev != '\\')) {
+			state++;
+		} else {
+			*(output++) = c;
+			outputcnt--;
+		}
+		break;
+	    case 1:			/* Waiting for (	*/
+		if (c == '(') {
+			state++;
+			varname_start = input;
+		} else {
+			state = 0;
+			*(output++) = '$';
+			outputcnt--;
+
+			if (outputcnt) {
+				*(output++) = c;
+				outputcnt--;
+			}
+		}
+		break;
+	    case 2:			/* Waiting for )	*/
+		if (c == ')') {
+			int i;
+			char envname[CFG_CBSIZE], *envval;
+			int envcnt = input-varname_start-1; /* Varname # of chars */
+
+			/* Get the varname */
+			for (i = 0; i < envcnt; i++) {
+				envname[i] = varname_start[i];
+			}
+			envname[i] = 0;
+
+			/* Get its value */
+			envval = getenv (envname);
+
+			/* Copy into the line if it exists */
+			if (envval != NULL)
+				while ((*envval) && outputcnt) {
+					*(output++) = *(envval++);
+					outputcnt--;
+				}
+			/* Look for another '$' */
+			state = 0;
+		}
+		break;
+	    }
+
+	    prev = c;
+	}
+
+	if (outputcnt)
+		*output = 0;
+
+#ifdef DEBUG_PARSER
+	printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
+		strlen(output_start), output_start);
+#endif
+}
+
+/****************************************************************************
+ * returns:
+ *	1  - command executed, repeatable
+ *	0  - command executed but not repeatable, interrupted commands are
+ *	     always considered not repeatable
+ *	-1 - not executed (unrecognized, bootd recursion or too many args)
+ *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
+ *           considered unrecognized)
+ *
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from getenv(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ */
+
+int run_command (const char *cmd, int flag)
+{
+	cmd_tbl_t *cmdtp;
+	char cmdbuf[CFG_CBSIZE];	/* working copy of cmd		*/
+	char *token;			/* start of token in cmdbuf	*/
+	char *sep;			/* end of token (separator) in cmdbuf */
+	char finaltoken[CFG_CBSIZE];
+	char *str = cmdbuf;
+	char *argv[CFG_MAXARGS + 1];	/* NULL terminated	*/
+	int argc;
+	int repeatable = 1;
+
+#ifdef DEBUG_PARSER
+	printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
+	puts (cmd ? cmd : "NULL");	/* use puts - string may be loooong */
+	puts ("\"\n");
+#endif
+
+	clear_ctrlc();		/* forget any previous Control C */
+
+	if (!cmd || !*cmd) {
+		return -1;	/* empty command */
+	}
+
+	if (strlen(cmd) >= CFG_CBSIZE) {
+		puts ("## Command too long!\n");
+		return -1;
+	}
+
+	strcpy (cmdbuf, cmd);
+
+	/* Process separators and check for invalid
+	 * repeatable commands
+	 */
+
+#ifdef DEBUG_PARSER
+	printf ("[PROCESS_SEPARATORS] %s\n", cmd);
+#endif
+	while (*str) {
+
+		/*
+		 * Find separator, or string end
+		 * Allow simple escape of ';' by writing "\;"
+		 */
+		for (sep = str; *sep; sep++) {
+			if ((*sep == ';') &&	/* separator		*/
+			    ( sep != str) &&	/* past string start	*/
+			    (*(sep-1) != '\\'))	/* and NOT escaped	*/
+				break;
+		}
+
+		/*
+		 * Limit the token to data between separators
+		 */
+		token = str;
+		if (*sep) {
+			str = sep + 1;	/* start of command for next pass */
+			*sep = '\0';
+		}
+		else
+			str = sep;	/* no more commands for next pass */
+#ifdef DEBUG_PARSER
+		printf ("token: \"%s\"\n", token);
+#endif
+
+		/* find macros in this token and replace them */
+		process_macros (token, finaltoken);
+
+		/* Extract arguments */
+		argc = parse_line (finaltoken, argv);
+
+		/* Look up command in command table */
+		if ((cmdtp = find_cmd(argv[0])) == NULL) {
+			printf ("Unknown command '%s' - try 'help'\n", argv[0]);
+			return -1;	/* give up after bad command */
+		}
+
+		/* found - check max args */
+		if (argc > cmdtp->maxargs) {
+			printf ("Usage:\n%s\n", cmdtp->usage);
+			return -1;
+		}
+
+#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
+		/* avoid "bootd" recursion */
+		if (cmdtp->cmd == do_bootd) {
+#ifdef DEBUG_PARSER
+			printf ("[%s]\n", finaltoken);
+#endif
+			if (flag & CMD_FLAG_BOOTD) {
+				printf ("'bootd' recursion detected\n");
+				return -1;
+			}
+			else
+				flag |= CMD_FLAG_BOOTD;
+		}
+#endif	/* CFG_CMD_BOOTD */
+
+		/* OK - call function to do the command */
+		if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
+			return (-1);
+		}
+
+		repeatable &= cmdtp->repeatable;
+
+		/* Did the user stop this? */
+		if (had_ctrlc ())
+			return 0;	/* if stopped then not repeatable */
+	}
+
+	return repeatable;
+}
+
+/****************************************************************************/
+
+#if (CONFIG_COMMANDS & CFG_CMD_RUN)
+int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int i;
+	int rcode = 1;
+
+	if (argc < 2) {
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	for (i=1; i<argc; ++i) {
+#ifndef CFG_HUSH_PARSER
+	    if (run_command (getenv (argv[i]), flag) != -1) ++rcode;
+#else
+   	    if (parse_string_outer(getenv (argv[i]),
+		    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) == 0) ++rcode;
+#endif
+	}
+	return ((rcode == i) ? 0 : 1);
+}
+#endif

+ 172 - 0
common/miiphyutil.c

@@ -0,0 +1,172 @@
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This provides a bit-banged interface to the ethernet MII management
+ * channel.
+ */
+
+#include <common.h>
+#include <miiphy.h>
+
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+
+/*****************************************************************************
+ *
+ * Read the OUI, manufacture's model number, and revision number.
+ *
+ * OUI:     22 bits (unsigned int)
+ * Model:    6 bits (unsigned char)
+ * Revision: 4 bits (unsigned char)
+ *
+ * Returns:
+ *   0 on success
+ */
+int miiphy_info (unsigned char addr,
+		 unsigned int *oui,
+		 unsigned char *model, unsigned char *rev)
+{
+	unsigned int reg = 0;
+
+	/*
+	 * Trick: we are reading two 16 registers into a 32 bit variable
+	 * so we do a 16 read into the high order bits of the variable (big
+	 * endian, you know), shift it down 16 bits, and the read the rest.
+	 */
+	if (miiphy_read (addr, PHY_PHYIDR2, (unsigned short *) &reg) != 0) {
+#ifdef DEBUG
+		printf ("PHY ID register 2 read failed\n");
+#endif
+		return (-1);
+	}
+	reg >>= 16;
+
+#ifdef DEBUG
+	printf ("PHY_PHYIDR2 @ 0x%x = 0x%04x\n", addr, reg);
+#endif
+	if (reg == 0xFFFF) {
+		/* No physical device present at this address */
+		return (-1);
+	}
+
+	if (miiphy_read (addr, PHY_PHYIDR1, (unsigned short *) &reg) != 0) {
+#ifdef DEBUG
+		printf ("PHY ID register 1 read failed\n");
+#endif
+		return (-1);
+	}
+#ifdef DEBUG
+	printf ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
+#endif
+	*oui   =                 ( reg >> 10);
+	*model = (unsigned char) ((reg >>  4) & 0x0000003F);
+	*rev   = (unsigned char) ( reg        & 0x0000000F);
+	return (0);
+}
+
+
+/*****************************************************************************
+ *
+ * Reset the PHY.
+ * Returns:
+ *   0 on success
+ */
+int miiphy_reset (unsigned char addr)
+{
+	unsigned short reg;
+	int loop_cnt;
+
+	if (miiphy_write (addr, PHY_BMCR, 0x8000) != 0) {
+#ifdef DEBUG
+		printf ("PHY reset failed\n");
+#endif
+		return (-1);
+	}
+
+	/*
+	 * Poll the control register for the reset bit to go to 0 (it is
+	 * auto-clearing).  This should happen within 0.5 seconds per the
+	 * IEEE spec.
+	 */
+	loop_cnt = 0;
+	reg = 0x8000;
+	while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) {
+		if (miiphy_read (addr, PHY_BMCR, &reg) != 0) {
+#     ifdef DEBUG
+			printf ("PHY status read failed\n");
+#     endif
+			return (-1);
+		}
+	}
+	if ((reg & 0x8000) == 0) {
+		return (0);
+	} else {
+		printf ("PHY reset timed out\n");
+		return (-1);
+	}
+	return (0);
+}
+
+
+/*****************************************************************************
+ *
+ * Determine the ethernet speed (10/100).
+ */
+int miiphy_speed (unsigned char addr)
+{
+	unsigned short reg;
+
+	if (miiphy_read (addr, PHY_ANLPAR, &reg)) {
+		printf ("PHY speed1 read failed, assuming 10bT\n");
+		return (_10BASET);
+	}
+
+	if ((reg & PHY_ANLPAR_100) != 0) {
+		return (_100BASET);
+	} else {
+		return (_10BASET);
+	}
+}
+
+
+/*****************************************************************************
+ *
+ * Determine full/half duplex.
+ */
+int miiphy_duplex (unsigned char addr)
+{
+	unsigned short reg;
+
+	if (miiphy_read (addr, PHY_ANLPAR, &reg)) {
+		printf ("PHY duplex read failed, assuming half duplex\n");
+		return (HALF);
+	}
+
+	if ((reg & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) {
+		return (FULL);
+	} else {
+		return (HALF);
+	}
+}
+
+#endif /* CONFIG_MII || (CONFIG_COMMANDS & CFG_CMD_MII) */

+ 416 - 0
common/soft_i2c.c

@@ -0,0 +1,416 @@
+/*
+ * (C) Copyright 2001, 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
+ *
+ * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
+ * vanbaren@cideas.com.  It was heavily influenced by LiMon, written by
+ * Neil Russell.
+ */
+
+#include <common.h>
+#ifdef	CONFIG_MPC8260			/* only valid for MPC8260 */
+#include <ioports.h>
+#endif
+#include <i2c.h>
+
+#if defined(CONFIG_SOFT_I2C)
+
+/* #define	DEBUG_I2C	*/
+
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#define RETRIES		0
+
+
+#define I2C_ACK		0		/* PD_SDA level to ack a byte */
+#define I2C_NOACK	1		/* PD_SDA level to noack a byte */
+
+
+#ifdef DEBUG_I2C
+#define PRINTD(fmt,args...)	do {	\
+	DECLARE_GLOBAL_DATA_PTR;	\
+	if (gd->have_console)		\
+		printf (fmt ,##args);	\
+	} while (0)
+#else
+#define PRINTD(fmt,args...)
+#endif
+
+/*-----------------------------------------------------------------------
+ * Local functions
+ */
+static void  send_reset	(void);
+static void  send_start	(void);
+static void  send_stop	(void);
+static void  send_ack	(int);
+static int   write_byte	(uchar byte);
+static uchar read_byte	(int);
+
+
+/*-----------------------------------------------------------------------
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state.  Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void send_reset(void)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int j;
+
+	I2C_ACTIVE;
+	I2C_SDA(1);
+	for(j = 0; j < 9; j++) {
+		I2C_SCL(0);
+		I2C_DELAY;
+		I2C_DELAY;
+		I2C_SCL(1);
+		I2C_DELAY;
+		I2C_DELAY;
+	}
+	send_stop();
+	I2C_TRISTATE;
+}
+
+/*-----------------------------------------------------------------------
+ * START: High -> Low on SDA while SCL is High
+ */
+static void send_start(void)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+	I2C_DELAY;
+	I2C_SDA(1);
+	I2C_ACTIVE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_SDA(0);
+	I2C_DELAY;
+}
+
+/*-----------------------------------------------------------------------
+ * STOP: Low -> High on SDA while SCL is High
+ */
+static void send_stop(void)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+	I2C_SCL(0);
+	I2C_DELAY;
+	I2C_SDA(0);
+	I2C_ACTIVE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_SDA(1);
+	I2C_DELAY;
+	I2C_TRISTATE;
+}
+
+
+/*-----------------------------------------------------------------------
+ * ack should be I2C_ACK or I2C_NOACK
+ */
+static void send_ack(int ack)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+	I2C_ACTIVE;
+	I2C_SCL(0);
+	I2C_DELAY;
+
+	I2C_SDA(ack);
+
+	I2C_ACTIVE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_DELAY;
+	I2C_SCL(0);
+	I2C_DELAY;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Send 8 bits and look for an acknowledgement.
+ */
+static int write_byte(uchar data)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int j;
+	int nack;
+
+	I2C_ACTIVE;
+	for(j = 0; j < 8; j++) {
+		I2C_SCL(0);
+		I2C_DELAY;
+		I2C_SDA(data & 0x80);
+		I2C_DELAY;
+		I2C_SCL(1);
+		I2C_DELAY;
+		I2C_DELAY;
+
+		data <<= 1;
+	}
+
+	/*
+	 * Look for an <ACK>(negative logic) and return it.
+	 */
+	I2C_SCL(0);
+	I2C_DELAY;
+	I2C_SDA(1);
+	I2C_TRISTATE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_DELAY;
+	nack = I2C_READ;
+	I2C_SCL(0);
+	I2C_DELAY;
+	I2C_ACTIVE;
+
+	return(nack);	/* not a nack is an ack */
+}
+
+
+/*-----------------------------------------------------------------------
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar read_byte(int ack)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int  data;
+	int  j;
+
+	/*
+	 * Read 8 bits, MSB first.
+	 */
+	I2C_TRISTATE;
+	data = 0;
+	for(j = 0; j < 8; j++) {
+		I2C_SCL(0);
+		I2C_DELAY;
+		I2C_SCL(1);
+		I2C_DELAY;
+		data <<= 1;
+		data |= I2C_READ;
+		I2C_DELAY;
+	}
+	send_ack(ack);
+
+	return(data);
+}
+
+/*=====================================================================*/
+/*                         Public Functions                            */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+void i2c_init (int speed, int slaveaddr)
+{
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+#ifdef	I2C_INIT
+	I2C_INIT;
+#endif
+	/*
+         * WARNING: Do NOT save speed in a static variable: if the
+         * I2C routines are called before RAM is initialized (to read
+         * the DIMM SPD, for instance), RAM won't be usable and your
+         * system will crash.
+	 */
+	send_reset ();
+}
+
+/*-----------------------------------------------------------------------
+ * Probe to see if a chip is present.  Also good for checking for the
+ * completion of EEPROM writes since the chip stops responding until
+ * the write completes (typically 10mSec).
+ */
+int i2c_probe(uchar addr)
+{
+	int rc;
+
+	send_start();
+	rc = write_byte ((addr << 1) | 1);
+	send_stop();
+
+	return (rc ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------------
+ * Read bytes
+ */
+int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	int shift;
+	PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
+		chip, addr, alen, buffer, len);
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+	/*
+	 * EEPROM chips that implement "address overflow" are ones
+	 * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+	 * address and the extra bits end up in the "chip address"
+	 * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+	 * four 256 byte chips.
+	 *
+	 * Note that we consider the length of the address field to
+	 * still be one byte because the extra address bits are
+	 * hidden in the chip address.
+	 */
+	chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+
+	PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
+		chip, addr);
+#endif
+
+	/*
+	 * Do the addressing portion of a write cycle to set the
+	 * chip's address pointer.  If the address length is zero,
+	 * don't do the normal write cycle to set the address pointer,
+	 * there is no address pointer in this chip.
+	 */
+	send_start();
+	if(alen > 0) {
+		if(write_byte(chip << 1)) {	/* write cycle */
+			send_stop();
+			PRINTD("i2c_read, no chip responded %02X\n", chip);
+			return(1);
+		}
+		shift = (alen-1) * 8;
+		while(alen-- > 0) {
+			if(write_byte(addr >> shift)) {
+				PRINTD("i2c_read, address not <ACK>ed\n");
+				return(1);
+			}
+			shift -= 8;
+		}
+		send_stop();	/* reportedly some chips need a full stop */
+		send_start();
+	}
+	/*
+	 * Send the chip address again, this time for a read cycle.
+	 * Then read the data.  On the last byte, we do a NACK instead
+	 * of an ACK(len == 0) to terminate the read.
+	 */
+	write_byte((chip << 1) | 1);	/* read cycle */
+	while(len-- > 0) {
+		*buffer++ = read_byte(len == 0);
+	}
+	send_stop();
+	return(0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write bytes
+ */
+int  i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	int shift, failures = 0;
+
+	PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
+		chip, addr, alen, buffer, len);
+
+	send_start();
+	if(write_byte(chip << 1)) {	/* write cycle */
+		send_stop();
+		PRINTD("i2c_write, no chip responded %02X\n", chip);
+		return(1);
+	}
+	shift = (alen-1) * 8;
+	while(alen-- > 0) {
+		if(write_byte(addr >> shift)) {
+			PRINTD("i2c_write, address not <ACK>ed\n");
+			return(1);
+		}
+		shift -= 8;
+	}
+
+	while(len-- > 0) {
+		if(write_byte(*buffer++)) {
+			failures++;
+		}
+	}
+	send_stop();
+	return(failures);
+}
+
+/*-----------------------------------------------------------------------
+ * Read a register
+ */
+uchar i2c_reg_read(uchar i2c_addr, uchar reg)
+{
+	char buf;
+
+	i2c_read(i2c_addr, reg, 1, &buf, 1);
+
+	return(buf);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a register
+ */
+void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
+{
+	i2c_write(i2c_addr, reg, 1, &val, 1);
+}
+
+
+#endif	/* CONFIG_SOFT_I2C */

+ 43 - 0
cpu/arm720t/Makefile

@@ -0,0 +1,43 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= lib$(CPU).a
+
+START	= start.o
+OBJS	= serial.o interrupts.o cpu.o
+
+all:	.depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################

+ 265 - 0
cpu/arm720t/interrupts.c

@@ -0,0 +1,265 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <clps7111.h>
+
+#include <asm/proc-armv/ptrace.h>
+
+extern void reset_cpu(ulong addr);
+
+/* we always count down the max. */
+#define TIMER_LOAD_VAL 0xffff
+
+/* macro to read the 16 bit timer */
+#define READ_TIMER (IO_TC1D & 0xffff)
+
+#ifdef CONFIG_USE_IRQ
+/* enable IRQ/FIQ interrupts */
+void enable_interrupts (void)
+{
+	unsigned long temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "bic %0, %0, #0x80\n"
+			     "msr cpsr_c, %0"
+			     : "=r" (temp)
+			     :
+			     : "memory");
+}
+
+
+/*
+ * disable IRQ/FIQ interrupts
+ * returns true if interrupts had been enabled before we disabled them
+ */
+int disable_interrupts (void)
+{
+	unsigned long old,temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "orr %1, %0, #0x80\n"
+			     "msr cpsr_c, %1"
+			     : "=r" (old), "=r" (temp)
+			     :
+			     : "memory");
+	return (old & 0x80) == 0;
+}
+#else
+void enable_interrupts (void)
+{
+	return;
+}
+int disable_interrupts (void)
+{
+	return 0;
+}
+#endif
+
+
+
+void bad_mode (void)
+{
+	panic ("Resetting CPU ...\n");
+	reset_cpu (0);
+}
+
+void show_regs (struct pt_regs *regs)
+{
+	unsigned long flags;
+	const char *processor_modes[] =
+			{ "USER_26", "FIQ_26", "IRQ_26", "SVC_26", "UK4_26", "UK5_26",
+"UK6_26", "UK7_26",
+		"UK8_26", "UK9_26", "UK10_26", "UK11_26", "UK12_26", "UK13_26",
+				"UK14_26", "UK15_26",
+		"USER_32", "FIQ_32", "IRQ_32", "SVC_32", "UK4_32", "UK5_32",
+				"UK6_32", "ABT_32",
+		"UK8_32", "UK9_32", "UK10_32", "UND_32", "UK12_32", "UK13_32",
+				"UK14_32", "SYS_32"
+	};
+
+	flags = condition_codes (regs);
+
+	printf ("pc : [<%08lx>]    lr : [<%08lx>]\n"
+			"sp : %08lx  ip : %08lx  fp : %08lx\n",
+			instruction_pointer (regs),
+			regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
+	printf ("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
+			regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
+	printf ("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+			regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
+	printf ("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+			regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
+	printf ("Flags: %c%c%c%c",
+			flags & CC_N_BIT ? 'N' : 'n',
+			flags & CC_Z_BIT ? 'Z' : 'z',
+			flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
+	printf ("  IRQs %s  FIQs %s  Mode %s%s\n",
+			interrupts_enabled (regs) ? "on" : "off",
+			fast_interrupts_enabled (regs) ? "on" : "off",
+			processor_modes[processor_mode (regs)],
+			thumb_mode (regs) ? " (T)" : "");
+}
+
+void do_undefined_instruction (struct pt_regs *pt_regs)
+{
+	printf ("undefined instruction\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_software_interrupt (struct pt_regs *pt_regs)
+{
+	printf ("software interrupt\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_prefetch_abort (struct pt_regs *pt_regs)
+{
+	printf ("prefetch abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_data_abort (struct pt_regs *pt_regs)
+{
+	printf ("data abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_not_used (struct pt_regs *pt_regs)
+{
+	printf ("not used\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_fiq (struct pt_regs *pt_regs)
+{
+	printf ("fast interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_irq (struct pt_regs *pt_regs)
+{
+	printf ("interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+static ulong timestamp;
+static ulong lastdec;
+
+int interrupt_init (void)
+{
+	/* disable all interrupts */
+	IO_INTMR1 = 0;
+
+	/* operate timer 1 in prescale mode */
+	IO_SYSCON1 |= SYSCON1_TC1M;
+
+	/* select 2kHz clock source for timer 1 */
+	IO_SYSCON1 &= ~SYSCON1_TC1S;
+
+	/* set timer 1 counter */
+	lastdec = IO_TC1D = TIMER_LOAD_VAL;
+	timestamp = 0;
+
+	return (0);
+}
+
+/*
+ * timer without interrupts
+ */
+
+void reset_timer (void)
+{
+	reset_timer_masked ();
+}
+
+ulong get_timer (ulong base)
+{
+	return get_timer_masked () - base;
+}
+
+void set_timer (ulong t)
+{
+	timestamp = t;
+}
+
+void udelay (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= CFG_HZ;
+	tmo /= 1000;
+
+	tmo += get_timer (0);
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}
+
+void reset_timer_masked (void)
+{
+	/* reset time */
+	lastdec = READ_TIMER;
+	timestamp = 0;
+}
+
+ulong get_timer_masked (void)
+{
+	ulong now = READ_TIMER;
+
+	if (lastdec >= now) {
+		/* normal mode */
+		timestamp += lastdec - now;
+	} else {
+		/* we have an overflow ... */
+		timestamp += lastdec + TIMER_LOAD_VAL - now;
+	}
+	lastdec = now;
+
+	return timestamp;
+}
+
+void udelay_masked (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= CFG_HZ;
+	tmo /= 1000;
+
+	reset_timer_masked ();
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}

+ 43 - 0
cpu/arm920t/Makefile

@@ -0,0 +1,43 @@
+#
+# (C) Copyright 2000, 2001, 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$(CPU).a
+
+START	= start.o
+OBJS	= serial.o interrupts.o cpu.o speed.o
+
+all:	.depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################

+ 304 - 0
cpu/arm920t/interrupts.c

@@ -0,0 +1,304 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <arm920t.h>
+#if defined(CONFIG_S3C2400)
+#include <s3c2400.h>
+#elif defined(CONFIG_S3C2410)
+#include <s3c2410.h>
+#endif
+
+#include <asm/proc-armv/ptrace.h>
+
+extern void reset_cpu(ulong addr);
+int timer_load_val = 0;
+
+/* macro to read the 16 bit timer */
+#define READ_TIMER (rTCNTO4 & 0xffff)
+
+#ifdef CONFIG_USE_IRQ
+/* enable IRQ interrupts */
+void enable_interrupts (void)
+{
+	unsigned long temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "bic %0, %0, #0x80\n"
+			     "msr cpsr_c, %0"
+			     : "=r" (temp)
+			     :
+			     : "memory");
+}
+
+
+/*
+ * disable IRQ/FIQ interrupts
+ * returns true if interrupts had been enabled before we disabled them
+ */
+int disable_interrupts (void)
+{
+	unsigned long old,temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "orr %1, %0, #0xc0\n"
+			     "msr cpsr_c, %1"
+			     : "=r" (old), "=r" (temp)
+			     :
+			     : "memory");
+	return (old & 0x80) == 0;
+}
+#else
+void enable_interrupts (void)
+{
+	return;
+}
+int disable_interrupts (void)
+{
+	return 0;
+}
+#endif
+
+
+
+void bad_mode (void)
+{
+	panic ("Resetting CPU ...\n");
+	reset_cpu (0);
+}
+
+void show_regs (struct pt_regs *regs)
+{
+	unsigned long flags;
+	const char *processor_modes[] = {
+	"USER_26",	"FIQ_26",	"IRQ_26",	"SVC_26",
+	"UK4_26",	"UK5_26",	"UK6_26",	"UK7_26",
+	"UK8_26",	"UK9_26",	"UK10_26",	"UK11_26",
+	"UK12_26",	"UK13_26",	"UK14_26",	"UK15_26",
+	"USER_32",	"FIQ_32",	"IRQ_32",	"SVC_32",
+	"UK4_32",	"UK5_32",	"UK6_32",	"ABT_32",
+	"UK8_32",	"UK9_32",	"UK10_32",	"UND_32",
+	"UK12_32",	"UK13_32",	"UK14_32",	"SYS_32",
+	};
+
+	flags = condition_codes (regs);
+
+	printf ("pc : [<%08lx>]    lr : [<%08lx>]\n"
+		"sp : %08lx  ip : %08lx  fp : %08lx\n",
+		instruction_pointer (regs),
+		regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
+	printf ("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
+		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
+	printf ("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
+	printf ("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
+	printf ("Flags: %c%c%c%c",
+		flags & CC_N_BIT ? 'N' : 'n',
+		flags & CC_Z_BIT ? 'Z' : 'z',
+		flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
+	printf ("  IRQs %s  FIQs %s  Mode %s%s\n",
+		interrupts_enabled (regs) ? "on" : "off",
+		fast_interrupts_enabled (regs) ? "on" : "off",
+		processor_modes[processor_mode (regs)],
+		thumb_mode (regs) ? " (T)" : "");
+}
+
+void do_undefined_instruction (struct pt_regs *pt_regs)
+{
+	printf ("undefined instruction\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_software_interrupt (struct pt_regs *pt_regs)
+{
+	printf ("software interrupt\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_prefetch_abort (struct pt_regs *pt_regs)
+{
+	printf ("prefetch abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_data_abort (struct pt_regs *pt_regs)
+{
+	printf ("data abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_not_used (struct pt_regs *pt_regs)
+{
+	printf ("not used\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_fiq (struct pt_regs *pt_regs)
+{
+	printf ("fast interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_irq (struct pt_regs *pt_regs)
+{
+	printf ("interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+static ulong timestamp;
+static ulong lastdec;
+
+int interrupt_init (void)
+{
+	/* use PWM Timer 4 because it has no output */
+	/* prescaler for Timer 4 is 16 */
+	rTCFG0 = 0x0f00;
+	if (timer_load_val == 0)
+	{
+		/*
+		 * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
+		 * (default) and prescaler = 16. Should be 10390
+		 * @33.25MHz and 15625 @ 50 MHz
+		 */
+		timer_load_val = get_PCLK()/(2 * 16 * 100);
+	}
+	/* load value for 10 ms timeout */
+	lastdec = rTCNTB4 = timer_load_val;
+	/* auto load, manual update of Timer 4 */
+	rTCON = 0x600000;
+	/* auto load, start Timer 4 */
+	rTCON = 0x500000;
+	timestamp = 0;
+
+	return (0);
+}
+
+/*
+ * timer without interrupts
+ */
+
+void reset_timer (void)
+{
+	reset_timer_masked ();
+}
+
+ulong get_timer (ulong base)
+{
+	return get_timer_masked () - base;
+}
+
+void set_timer (ulong t)
+{
+	timestamp = t;
+}
+
+void udelay (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= (timer_load_val * 100);
+	tmo /= 1000;
+
+	tmo += get_timer (0);
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}
+
+void reset_timer_masked (void)
+{
+	/* reset time */
+	lastdec = READ_TIMER;
+	timestamp = 0;
+}
+
+ulong get_timer_masked (void)
+{
+	ulong now = READ_TIMER;
+
+	if (lastdec >= now) {
+		/* normal mode */
+		timestamp += lastdec - now;
+	} else {
+		/* we have an overflow ... */
+		timestamp += lastdec + timer_load_val - now;
+	}
+	lastdec = now;
+
+	return timestamp;
+}
+
+void udelay_masked (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= (timer_load_val * 100);
+	tmo /= 1000;
+
+	reset_timer_masked ();
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk (void)
+{
+	ulong tbclk;
+
+#if defined(CONFIG_SMDK2400) || defined(CONFIG_TRAB)
+	tbclk = timer_load_val * 100;
+#elif defined(CONFIG_SMDK2410)
+	tbclk = CFG_HZ;
+#endif
+
+	return tbclk;
+}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác