summaryrefslogtreecommitdiff
path: root/cpu/ppc4xx
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/ppc4xx')
-rwxr-xr-xcpu/ppc4xx/405gp_pci.c553
-rwxr-xr-xcpu/ppc4xx/4xx_enet.c1564
-rwxr-xr-xcpu/ppc4xx/Makefile50
-rwxr-xr-xcpu/ppc4xx/bedbug_405.c308
-rwxr-xr-xcpu/ppc4xx/commproc.c69
-rwxr-xr-xcpu/ppc4xx/config.mk26
-rwxr-xr-xcpu/ppc4xx/cpu.c371
-rwxr-xr-xcpu/ppc4xx/cpu_init.c268
-rwxr-xr-xcpu/ppc4xx/dcr.S198
-rwxr-xr-xcpu/ppc4xx/i2c.c445
-rwxr-xr-xcpu/ppc4xx/interrupts.c571
-rwxr-xr-xcpu/ppc4xx/kgdb.S78
-rwxr-xr-xcpu/ppc4xx/miiphy.c260
-rwxr-xr-xcpu/ppc4xx/resetvec.S12
-rwxr-xr-xcpu/ppc4xx/sdram.c178
-rwxr-xr-xcpu/ppc4xx/serial.c1064
-rwxr-xr-xcpu/ppc4xx/spd_sdram.c1831
-rwxr-xr-xcpu/ppc4xx/speed.c568
-rwxr-xr-xcpu/ppc4xx/start.S1687
-rwxr-xr-xcpu/ppc4xx/traps.c290
-rwxr-xr-xcpu/ppc4xx/usb_ohci.c1642
-rwxr-xr-xcpu/ppc4xx/usb_ohci.h410
-rwxr-xr-xcpu/ppc4xx/usbdev.c214
-rwxr-xr-xcpu/ppc4xx/usbdev.h31
-rwxr-xr-xcpu/ppc4xx/vecnum.h129
25 files changed, 12817 insertions, 0 deletions
diff --git a/cpu/ppc4xx/405gp_pci.c b/cpu/ppc4xx/405gp_pci.c
new file mode 100755
index 0000000..64431ab
--- /dev/null
+++ b/cpu/ppc4xx/405gp_pci.c
@@ -0,0 +1,553 @@
+/*-----------------------------------------------------------------------------+
+ *
+ * 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
+ *-----------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------+
+ *
+ * File Name: 405gp_pci.c
+ *
+ * Function: Initialization code for the 405GP PCI Configuration regs.
+ *
+ * Author: Mark Game
+ *
+ * Change Activity-
+ *
+ * Date Description of Change BY
+ * --------- --------------------- ---
+ * 09-Sep-98 Created MCG
+ * 02-Nov-98 Removed External arbiter selected message JWB
+ * 27-Nov-98 Zero out PTMBAR2 and disable in PTM2MS JWB
+ * 04-Jan-99 Zero out other unused PMM and PTM regs. Change bus scan MCG
+ * from (0 to n) to (1 to n).
+ * 17-May-99 Port to Walnut JWB
+ * 17-Jun-99 Updated for VGA support JWB
+ * 21-Jun-99 Updated to allow SRAM region to be a target from PCI bus JWB
+ * 19-Jul-99 Updated for 405GP pass 1 errata #26 (Low PCI subsequent MCG
+ * target latency timer values are not supported).
+ * Should be fixed in pass 2.
+ * 09-Sep-99 Removed use of PTM2 since the SRAM region no longer needs JWB
+ * to be a PCI target. Zero out PTMBAR2 and disable in PTM2MS.
+ * 10-Dec-99 Updated PCI_Write_CFG_Reg for pass2 errata #6 JWB
+ * 11-Jan-00 Ensure PMMxMAs disabled before setting PMMxLAs. This is not
+ * really required after a reset since PMMxMAs are already
+ * disabled but is a good practice nonetheless. JWB
+ * 12-Jun-01 stefan.roese@esd-electronics.com
+ * - PCI host/adapter handling reworked
+ * 09-Jul-01 stefan.roese@esd-electronics.com
+ * - PCI host now configures from device 0 (not 1) to max_dev,
+ * (host configures itself)
+ * - On CPCI-405 pci base address and size is generated from
+ * SDRAM and FLASH size (CFG regs not used anymore)
+ * - Some minor changes for CPCI-405-A (adapter version)
+ * 14-Sep-01 stefan.roese@esd-electronics.com
+ * - CONFIG_PCI_SCAN_SHOW added to print pci devices upon startup
+ * 28-Sep-01 stefan.roese@esd-electronics.com
+ * - Changed pci master configuration for linux compatibility
+ * (no need for bios_fixup() anymore)
+ * 26-Feb-02 stefan.roese@esd-electronics.com
+ * - Bug fixed in pci configuration (Andrew May)
+ * - Removed pci class code init for CPCI405 board
+ * 15-May-02 stefan.roese@esd-electronics.com
+ * - New vga device handling
+ * 29-May-02 stefan.roese@esd-electronics.com
+ * - PCI class code init added (if defined)
+ *----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <command.h>
+#if !defined(CONFIG_440)
+#include <405gp_pci.h>
+#endif
+#include <asm/processor.h>
+#include <pci.h>
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
+
+#ifdef CONFIG_PCI
+
+/*#define DEBUG*/
+
+/*-----------------------------------------------------------------------------+
+ * pci_init. Initializes the 405GP PCI Configuration regs.
+ *-----------------------------------------------------------------------------*/
+void pci_405gp_init(struct pci_controller *hose)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ int i, reg_num = 0;
+ bd_t *bd = gd->bd;
+
+ unsigned short temp_short;
+ unsigned long ptmpcila[2] = {CFG_PCI_PTM1PCI, CFG_PCI_PTM2PCI};
+#if defined(CONFIG_CPCI405) || defined(CONFIG_PMC405)
+ unsigned long ptmla[2] = {bd->bi_memstart, bd->bi_flashstart};
+ unsigned long ptmms[2] = {~(bd->bi_memsize - 1) | 1, ~(bd->bi_flashsize - 1) | 1};
+ char *ptmla_str, *ptmms_str;
+#else
+ unsigned long ptmla[2] = {CFG_PCI_PTM1LA, CFG_PCI_PTM2LA};
+ unsigned long ptmms[2] = {CFG_PCI_PTM1MS, CFG_PCI_PTM2MS};
+#endif
+#if defined(CONFIG_PIP405) || defined (CONFIG_MIP405)
+ unsigned long pmmla[3] = {0x80000000, 0xA0000000, 0};
+ unsigned long pmmma[3] = {0xE0000001, 0xE0000001, 0};
+ unsigned long pmmpcila[3] = {0x80000000, 0x00000000, 0};
+ unsigned long pmmpciha[3] = {0x00000000, 0x00000000, 0};
+#else
+ unsigned long pmmla[3] = {0x80000000, 0,0};
+ unsigned long pmmma[3] = {0xC0000001, 0,0};
+ unsigned long pmmpcila[3] = {0x80000000, 0,0};
+ unsigned long pmmpciha[3] = {0x00000000, 0,0};
+#endif
+#ifdef CONFIG_PCI_PNP
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+ char *s;
+#endif
+#endif
+
+#if defined(CONFIG_CPCI405) || defined(CONFIG_PMC405)
+ ptmla_str = getenv("ptm1la");
+ ptmms_str = getenv("ptm1ms");
+ if(NULL != ptmla_str && NULL != ptmms_str ) {
+ ptmla[0] = simple_strtoul (ptmla_str, NULL, 16);
+ ptmms[0] = simple_strtoul (ptmms_str, NULL, 16);
+ }
+
+ ptmla_str = getenv("ptm2la");
+ ptmms_str = getenv("ptm2ms");
+ if(NULL != ptmla_str && NULL != ptmms_str ) {
+ ptmla[1] = simple_strtoul (ptmla_str, NULL, 16);
+ ptmms[1] = simple_strtoul (ptmms_str, NULL, 16);
+ }
+#endif
+
+ /*
+ * Register the hose
+ */
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* ISA/PCI I/O space */
+ pci_set_region(hose->regions + reg_num++,
+ MIN_PCI_PCI_IOADDR,
+ MIN_PLB_PCI_IOADDR,
+ 0x10000,
+ PCI_REGION_IO);
+
+ /* PCI I/O space */
+ pci_set_region(hose->regions + reg_num++,
+ 0x00800000,
+ 0xe8800000,
+ 0x03800000,
+ PCI_REGION_IO);
+
+ reg_num = 2;
+
+ /* Memory spaces */
+ for (i=0; i<2; i++)
+ if (ptmms[i] & 1)
+ {
+ if (!i) hose->pci_fb = hose->regions + reg_num;
+
+ pci_set_region(hose->regions + reg_num++,
+ ptmpcila[i], ptmla[i],
+ ~(ptmms[i] & 0xfffff000) + 1,
+ PCI_REGION_MEM |
+ PCI_REGION_MEMORY);
+ }
+
+ /* PCI memory spaces */
+ for (i=0; i<3; i++)
+ if (pmmma[i] & 1)
+ {
+ pci_set_region(hose->regions + reg_num++,
+ pmmpcila[i], pmmla[i],
+ ~(pmmma[i] & 0xfffff000) + 1,
+ PCI_REGION_MEM);
+ }
+
+ hose->region_count = reg_num;
+
+ pci_setup_indirect(hose,
+ PCICFGADR,
+ PCICFGDATA);
+
+ if (hose->pci_fb)
+ pciauto_region_init(hose->pci_fb);
+
+ pci_register_hose(hose);
+
+ /*--------------------------------------------------------------------------+
+ * 405GP PCI Master configuration.
+ * Map one 512 MB range of PLB/processor addresses to PCI memory space.
+ * PLB address 0x80000000-0xBFFFFFFF ==> PCI address 0x80000000-0xBFFFFFFF
+ * Use byte reversed out routines to handle endianess.
+ *--------------------------------------------------------------------------*/
+ out32r(PMM0MA, (pmmma[0]&~0x1)); /* disable, configure PMMxLA, PMMxPCILA first */
+ out32r(PMM0LA, pmmla[0]);
+ out32r(PMM0PCILA, pmmpcila[0]);
+ out32r(PMM0PCIHA, pmmpciha[0]);
+ out32r(PMM0MA, pmmma[0]);
+
+ /*--------------------------------------------------------------------------+
+ * PMM1 is not used. Initialize them to zero.
+ *--------------------------------------------------------------------------*/
+ out32r(PMM1MA, (pmmma[1]&~0x1));
+ out32r(PMM1LA, pmmla[1]);
+ out32r(PMM1PCILA, pmmpcila[1]);
+ out32r(PMM1PCIHA, pmmpciha[1]);
+ out32r(PMM1MA, pmmma[1]);
+
+ /*--------------------------------------------------------------------------+
+ * PMM2 is not used. Initialize them to zero.
+ *--------------------------------------------------------------------------*/
+ out32r(PMM2MA, (pmmma[2]&~0x1));
+ out32r(PMM2LA, pmmla[2]);
+ out32r(PMM2PCILA, pmmpcila[2]);
+ out32r(PMM2PCIHA, pmmpciha[2]);
+ out32r(PMM2MA, pmmma[2]);
+
+ /*--------------------------------------------------------------------------+
+ * 405GP PCI Target configuration. (PTM1)
+ * Note: PTM1MS is hardwire enabled but we set the enable bit anyway.
+ *--------------------------------------------------------------------------*/
+ out32r(PTM1LA, ptmla[0]); /* insert address */
+ out32r(PTM1MS, ptmms[0]); /* insert size, enable bit is 1 */
+ pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_1, ptmpcila[0]);
+
+ /*--------------------------------------------------------------------------+
+ * 405GP PCI Target configuration. (PTM2)
+ *--------------------------------------------------------------------------*/
+ out32r(PTM2LA, ptmla[1]); /* insert address */
+ pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, ptmpcila[1]);
+
+ if (ptmms[1] == 0)
+ {
+ out32r(PTM2MS, 0x00000001); /* set enable bit */
+ pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, 0x00000000);
+ out32r(PTM2MS, 0x00000000); /* disable */
+ }
+ else
+ {
+ out32r(PTM2MS, ptmms[1]); /* insert size, enable bit is 1 */
+ }
+
+ /*
+ * Insert Subsystem Vendor and Device ID
+ */
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_VENDOR_ID, CFG_PCI_SUBSYS_VENDORID);
+#ifdef CONFIG_CPCI405
+ if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID);
+ else
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID2);
+#else
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID);
+#endif
+
+ /*
+ * Insert Class-code
+ */
+#ifdef CFG_PCI_CLASSCODE
+ pci_write_config_word(PCIDEVID_405GP, PCI_CLASS_SUB_CODE, CFG_PCI_CLASSCODE);
+#endif /* CFG_PCI_CLASSCODE */
+
+ /*--------------------------------------------------------------------------+
+ * If PCI speed = 66Mhz, set 66Mhz capable bit.
+ *--------------------------------------------------------------------------*/
+ if (bd->bi_pci_busfreq >= 66000000) {
+ pci_read_config_word(PCIDEVID_405GP, PCI_STATUS, &temp_short);
+ pci_write_config_word(PCIDEVID_405GP,PCI_STATUS,(temp_short|PCI_STATUS_66MHZ));
+ }
+
+#if (CONFIG_PCI_HOST != PCI_HOST_ADAPTER)
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+ if ((mfdcr(strap) & PSR_PCI_ARBIT_EN) ||
+ (((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
+#endif
+ {
+ /*--------------------------------------------------------------------------+
+ * Write the 405GP PCI Configuration regs.
+ * Enable 405GP to be a master on the PCI bus (PMM).
+ * Enable 405GP to act as a PCI memory target (PTM).
+ *--------------------------------------------------------------------------*/
+ pci_read_config_word(PCIDEVID_405GP, PCI_COMMAND, &temp_short);
+ pci_write_config_word(PCIDEVID_405GP, PCI_COMMAND, temp_short |
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ }
+#endif
+
+#if defined(CONFIG_405EP) /* on ppc405ep vendor id is not set */
+ pci_write_config_word(PCIDEVID_405GP, PCI_VENDOR_ID, 0x1014); /* IBM */
+#endif
+
+ /*
+ * Set HCE bit (Host Configuration Enabled)
+ */
+ pci_read_config_word(PCIDEVID_405GP, PCIBRDGOPT2, &temp_short);
+ pci_write_config_word(PCIDEVID_405GP, PCIBRDGOPT2, (temp_short | 0x0001));
+
+#ifdef CONFIG_PCI_PNP
+ /*--------------------------------------------------------------------------+
+ * Scan the PCI bus and configure devices found.
+ *--------------------------------------------------------------------------*/
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+ if ((mfdcr(strap) & PSR_PCI_ARBIT_EN) ||
+ (((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
+#endif
+ {
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+
+ hose->last_busno = pci_hose_scan(hose);
+ }
+#endif /* CONFIG_PCI_PNP */
+
+}
+
+/*
+ * drivers/pci.c skips every host bridge but the 405GP since it could
+ * be set as an Adapter.
+ *
+ * I (Andrew May) don't know what we should do here, but I don't want
+ * the auto setup of a PCI device disabling what is done pci_405gp_init
+ * as has happened before.
+ */
+void pci_405gp_setup_bridge(struct pci_controller *hose, pci_dev_t dev,
+ struct pci_config_table *entry)
+{
+#ifdef DEBUG
+ printf("405gp_setup_bridge\n");
+#endif
+}
+
+/*
+ *
+ */
+
+void pci_405gp_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+ unsigned char int_line = 0xff;
+
+ /*
+ * Write pci interrupt line register (cpci405 specific)
+ */
+ switch (PCI_DEV(dev) & 0x03)
+ {
+ case 0:
+ int_line = 27 + 2;
+ break;
+ case 1:
+ int_line = 27 + 3;
+ break;
+ case 2:
+ int_line = 27 + 0;
+ break;
+ case 3:
+ int_line = 27 + 1;
+ break;
+ }
+
+ pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line);
+}
+
+void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev,
+ struct pci_config_table *entry)
+{
+ unsigned int cmdstat = 0;
+
+ pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io);
+
+ /* always enable io space on vga boards */
+ pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+ cmdstat |= PCI_COMMAND_IO;
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
+}
+
+#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405))
+
+/*
+ *As is these functs get called out of flash Not a horrible
+ *thing, but something to keep in mind. (no statics?)
+ */
+static struct pci_config_table pci_405gp_config_table[] = {
+/*if VendID is 0 it terminates the table search (ie Walnut)*/
+#ifdef CFG_PCI_SUBSYS_VENDORID
+ {CFG_PCI_SUBSYS_VENDORID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_bridge},
+#endif
+ {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},
+
+ { }
+};
+
+static struct pci_controller hose = {
+ fixup_irq: pci_405gp_fixup_irq,
+ config_table: pci_405gp_config_table,
+};
+
+void pci_init_board(void)
+{
+ /*we want the ptrs to RAM not flash (ie don't use init list)*/
+ hose.fixup_irq = pci_405gp_fixup_irq;
+ hose.config_table = pci_405gp_config_table;
+ pci_405gp_init(&hose);
+}
+
+#endif
+
+#endif /* CONFIG_PCI */
+
+#endif /* CONFIG_405GP */
+
+/*-----------------------------------------------------------------------------+
+ * CONFIG_440
+ *-----------------------------------------------------------------------------*/
+#if defined(CONFIG_440) && defined(CONFIG_PCI)
+
+static struct pci_controller ppc440_hose = {0};
+
+
+void pci_440_init (struct pci_controller *hose)
+{
+ int reg_num = 0;
+
+#ifndef CONFIG_DISABLE_PISE_TEST
+ /*--------------------------------------------------------------------------+
+ * The PCI initialization sequence enable bit must be set ... if not abort
+ * pci setup since updating the bit requires chip reset.
+ *--------------------------------------------------------------------------*/
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+ unsigned long strap;
+
+ mfsdr(sdr_sdstp1,strap);
+ if ((strap & SDR0_SDSTP1_PISE_MASK) == 0) {
+ printf("PCI: SDR0_STRP1[PISE] not set.\n");
+ printf("PCI: Configuration aborted.\n");
+ return;
+ }
+#elif defined(CONFIG_440GP)
+ unsigned long strap;
+
+ strap = mfdcr(cpc0_strp1);
+ if ((strap & CPC0_STRP1_PISE_MASK) == 0) {
+ printf("PCI: CPC0_STRP1[PISE] not set.\n");
+ printf("PCI: Configuration aborted.\n");
+ return;
+ }
+#endif
+#endif /* CONFIG_DISABLE_PISE_TEST */
+
+ /*--------------------------------------------------------------------------+
+ * PCI controller init
+ *--------------------------------------------------------------------------*/
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ pci_set_region(hose->regions + reg_num++,
+ 0x00000000,
+ PCIX0_IOBASE,
+ 0x10000,
+ PCI_REGION_IO);
+
+ pci_set_region(hose->regions + reg_num++,
+ CFG_PCI_TARGBASE,
+ CFG_PCI_MEMBASE,
+ 0x10000000,
+ PCI_REGION_MEM );
+ hose->region_count = reg_num;
+
+ pci_setup_indirect(hose, PCIX0_CFGADR, PCIX0_CFGDATA);
+
+#if defined(CFG_PCI_PRE_INIT)
+ /* Let board change/modify hose & do initial checks */
+ if (pci_pre_init (hose) == 0) {
+ printf("PCI: Board-specific initialization failed.\n");
+ printf("PCI: Configuration aborted.\n");
+ return;
+ }
+#endif
+
+ pci_register_hose( hose );
+
+ /*--------------------------------------------------------------------------+
+ * PCI target init
+ *--------------------------------------------------------------------------*/
+#if defined(CFG_PCI_TARGET_INIT)
+ pci_target_init(hose); /* Let board setup pci target */
+#else
+ out16r( PCIX0_SBSYSVID, CFG_PCI_SUBSYS_VENDORID );
+ out16r( PCIX0_SBSYSID, CFG_PCI_SUBSYS_ID );
+ out16r( PCIX0_CLS, 0x00060000 ); /* Bridge, host bridge */
+#endif
+
+#if defined(CONFIG_440GX)
+ out32r( PCIX0_BRDGOPT1, 0x04000060 ); /* PLB Rq pri highest */
+ out32r( PCIX0_BRDGOPT2, in32(PCIX0_BRDGOPT2) | 0x83 ); /* Enable host config, clear Timeout, ensure int src1 */
+#elif defined(PCIX0_BRDGOPT1)
+ out32r( PCIX0_BRDGOPT1, 0x10000060 ); /* PLB Rq pri highest */
+ out32r( PCIX0_BRDGOPT2, in32(PCIX0_BRDGOPT2) | 1 ); /* Enable host config */
+#endif
+
+ /*--------------------------------------------------------------------------+
+ * PCI master init: default is one 256MB region for PCI memory:
+ * 0x3_00000000 - 0x3_0FFFFFFF ==> CFG_PCI_MEMBASE
+ *--------------------------------------------------------------------------*/
+#if defined(CFG_PCI_MASTER_INIT)
+ pci_master_init(hose); /* Let board setup pci master */
+#else
+ out32r( PCIX0_POM0SA, 0 ); /* disable */
+ out32r( PCIX0_POM1SA, 0 ); /* disable */
+ out32r( PCIX0_POM2SA, 0 ); /* disable */
+ out32r( PCIX0_POM0LAL, 0x00000000 );
+ out32r( PCIX0_POM0LAH, 0x00000003 );
+ out32r( PCIX0_POM0PCIAL, CFG_PCI_MEMBASE );
+ out32r( PCIX0_POM0PCIAH, 0x00000000 );
+ out32r( PCIX0_POM0SA, 0xf0000001 ); /* 256MB, enabled */
+ out32r( PCIX0_STS, in32r( PCIX0_STS ) & ~0x0000fff8 );
+#endif
+
+ /*--------------------------------------------------------------------------+
+ * PCI host configuration -- we don't make any assumptions here ... the
+ * _board_must_indicate_ what to do -- there's just too many runtime
+ * scenarios in environments like cPCI, PPMC, etc. to make a determination
+ * based on hard-coded values or state of arbiter enable.
+ *--------------------------------------------------------------------------*/
+ if (is_pci_host(hose)) {
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+#if !defined(CONFIG_440EP) && !defined(CONFIG_440GR)
+ out16r( PCIX0_CMD, in16r( PCIX0_CMD ) | PCI_COMMAND_MASTER);
+#endif
+ hose->last_busno = pci_hose_scan(hose);
+ }
+}
+
+
+void pci_init_board(void)
+{
+ pci_440_init (&ppc440_hose);
+}
+
+#endif /* CONFIG_440 & CONFIG_PCI */
diff --git a/cpu/ppc4xx/4xx_enet.c b/cpu/ppc4xx/4xx_enet.c
new file mode 100755
index 0000000..86dc2d0
--- /dev/null
+++ b/cpu/ppc4xx/4xx_enet.c
@@ -0,0 +1,1564 @@
+/*-----------------------------------------------------------------------------+
+ *
+ * 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
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------+
+ *
+ * File Name: enetemac.c
+ *
+ * Function: Device driver for the ethernet EMAC3 macro on the 405GP.
+ *
+ * Author: Mark Wisner
+ *
+ * Change Activity-
+ *
+ * Date Description of Change BY
+ * --------- --------------------- ---
+ * 05-May-99 Created MKW
+ * 27-Jun-99 Clean up JWB
+ * 16-Jul-99 Added MAL error recovery and better IP packet handling MKW
+ * 29-Jul-99 Added Full duplex support MKW
+ * 06-Aug-99 Changed names for Mal CR reg MKW
+ * 23-Aug-99 Turned off SYE when running at 10Mbs MKW
+ * 24-Aug-99 Marked descriptor empty after call_xlc MKW
+ * 07-Sep-99 Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16 MCG
+ * to avoid chaining maximum sized packets. Push starting
+ * RX descriptor address up to the next cache line boundary.
+ * 16-Jan-00 Added support for booting with IP of 0x0 MKW
+ * 15-Mar-00 Updated enetInit() to enable broadcast addresses in the
+ * EMAC_RXM register. JWB
+ * 12-Mar-01 anne-sophie.harnois@nextream.fr
+ * - Variables are compatible with those already defined in
+ * include/net.h
+ * - Receive buffer descriptor ring is used to send buffers
+ * to the user
+ * - Info print about send/received/handled packet number if
+ * INFO_405_ENET is set
+ * 17-Apr-01 stefan.roese@esd-electronics.com
+ * - MAL reset in "eth_halt" included
+ * - Enet speed and duplex output now in one line
+ * 08-May-01 stefan.roese@esd-electronics.com
+ * - MAL error handling added (eth_init called again)
+ * 13-Nov-01 stefan.roese@esd-electronics.com
+ * - Set IST bit in EMAC_M1 reg upon 100MBit or full duplex
+ * 04-Jan-02 stefan.roese@esd-electronics.com
+ * - Wait for PHY auto negotiation to complete added
+ * 06-Feb-02 stefan.roese@esd-electronics.com
+ * - Bug fixed in waiting for auto negotiation to complete
+ * 26-Feb-02 stefan.roese@esd-electronics.com
+ * - rx and tx buffer descriptors now allocated (no fixed address
+ * used anymore)
+ * 17-Jun-02 stefan.roese@esd-electronics.com
+ * - MAL error debug printf 'M' removed (rx de interrupt may
+ * occur upon many incoming packets with only 4 rx buffers).
+ *-----------------------------------------------------------------------------*
+ * 17-Nov-03 travis.sawyer@sandburst.com
+ * - ported from 405gp_enet.c to utilized upto 4 EMAC ports
+ * in the 440GX. This port should work with the 440GP
+ * (2 EMACs) also
+ * 15-Aug-05 sr@denx.de
+ * - merged 405gp_enet.c and 440gx_enet.c to generic 4xx_enet.c
+ now handling all 4xx cpu's.
+ *-----------------------------------------------------------------------------*/
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <asm/processor.h>
+#include <commproc.h>
+#include <ppc4xx.h>
+#include <ppc4xx_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include "vecnum.h"
+
+/*
+ * Only compile for platform with AMCC EMAC ethernet controller and
+ * network support enabled.
+ * Remark: CONFIG_405 describes Xilinx PPC405 FPGA without EMAC controller!
+ */
+#if (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_405) && !defined(CONFIG_IOP480)
+
+#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_NET_MULTI)
+#error "CONFIG_NET_MULTI has to be defined for NetConsole"
+#endif
+
+#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */
+#define PHY_AUTONEGOTIATE_TIMEOUT 4000 /* 4000 ms autonegotiate timeout */
+
+/* Ethernet Transmit and Receive Buffers */
+/* AS.HARNOIS
+ * In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from
+ * PKTSIZE and PKTSIZE_ALIGN (include/net.h)
+ */
+#define ENET_MAX_MTU PKTSIZE
+#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN
+
+/*-----------------------------------------------------------------------------+
+ * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
+ * Interrupt Controller).
+ *-----------------------------------------------------------------------------*/
+#define MAL_UIC_ERR ( UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)
+#define MAL_UIC_DEF (UIC_MAL_RXEOB | MAL_UIC_ERR)
+#define EMAC_UIC_DEF UIC_ENET
+#define EMAC_UIC_DEF1 UIC_ENET1
+#define SEL_UIC_DEF(p) (p ? UIC_ENET1 : UIC_ENET )
+
+#undef INFO_4XX_ENET
+
+#define BI_PHYMODE_NONE 0
+#define BI_PHYMODE_ZMII 1
+#define BI_PHYMODE_RGMII 2
+
+
+/*-----------------------------------------------------------------------------+
+ * Global variables. TX and RX descriptors and buffers.
+ *-----------------------------------------------------------------------------*/
+/* IER globals */
+static uint32_t mal_ier;
+
+#if !defined(CONFIG_NET_MULTI)
+struct eth_device *emac0_dev = NULL;
+#endif
+
+/*
+ * Get count of EMAC devices (doesn't have to be the max. possible number
+ * supported by the cpu)
+ */
+#if defined(CONFIG_HAS_ETH3)
+#define LAST_EMAC_NUM 4
+#elif defined(CONFIG_HAS_ETH2)
+#define LAST_EMAC_NUM 3
+#elif defined(CONFIG_HAS_ETH1)
+#define LAST_EMAC_NUM 2
+#else
+#define LAST_EMAC_NUM 1
+#endif
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes and externals.
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (struct eth_device *dev, unsigned long malisr);
+
+int enetInt (struct eth_device *dev);
+static void mal_err (struct eth_device *dev, unsigned long isr,
+ unsigned long uic, unsigned long maldef,
+ unsigned long mal_errr);
+static void emac_err (struct eth_device *dev, unsigned long isr);
+
+extern int phy_setup_aneg (char *devname, unsigned char addr);
+extern int emac4xx_miiphy_read (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value);
+extern int emac4xx_miiphy_write (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value);
+
+/*-----------------------------------------------------------------------------+
+| ppc_4xx_eth_halt
+| Disable MAL channel, and EMACn
++-----------------------------------------------------------------------------*/
+static void ppc_4xx_eth_halt (struct eth_device *dev)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+ uint32_t failsafe = 10000;
+
+ out32 (EMAC_IER + hw_p->hw_addr, 0x00000000); /* disable emac interrupts */
+
+ /* 1st reset MAL channel */
+ /* Note: writing a 0 to a channel has no effect */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (maltxcarr, (MAL_CR_MMSR >> (hw_p->devnum * 2)));
+#else
+ mtdcr (maltxcarr, (MAL_CR_MMSR >> hw_p->devnum));
+#endif
+ mtdcr (malrxcarr, (MAL_CR_MMSR >> hw_p->devnum));
+
+ /* wait for reset */
+ while (mfdcr (malrxcasr) & (MAL_CR_MMSR >> hw_p->devnum)) {
+ udelay (1000); /* Delay 1 MS so as not to hammer the register */
+ failsafe--;
+ if (failsafe == 0)
+ break;
+ }
+
+ /* EMAC RESET */
+ out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
+
+#ifndef CONFIG_NETCONSOLE
+ hw_p->print_speed = 1; /* print speed message again next time */
+#endif
+
+ return;
+}
+
+#if defined (CONFIG_440GX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ unsigned long pfc1;
+ unsigned long zmiifer;
+ unsigned long rmiifer;
+
+ mfsdr(sdr_pfc1, pfc1);
+ pfc1 = SDR0_PFC1_EPS_DECODE(pfc1);
+
+ zmiifer = 0;
+ rmiifer = 0;
+
+ switch (pfc1) {
+ case 1:
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ case 2:
+ zmiifer = ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer = ZMII_FER_SMII << ZMII_FER_V(1);
+ zmiifer = ZMII_FER_SMII << ZMII_FER_V(2);
+ zmiifer = ZMII_FER_SMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ case 3:
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 4:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 5:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 6:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ break;
+ case 0:
+ default:
+ zmiifer = ZMII_FER_MII << ZMII_FER_V(devnum);
+ rmiifer = 0x0;
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ }
+
+ /* Ensure we setup mdio for this devnum and ONLY this devnum */
+ zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
+
+ out32 (ZMII_FER, zmiifer);
+ out32 (RGMII_FER, rmiifer);
+
+ return ((int)pfc1);
+
+}
+#endif
+
+static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
+{
+ int i, j;
+ unsigned long reg = 0;
+ unsigned long msr;
+ unsigned long speed;
+ unsigned long duplex;
+ unsigned long failsafe;
+ unsigned mode_reg;
+ unsigned short devnum;
+ unsigned short reg_short;
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+ sys_info_t sysinfo;
+#if defined(CONFIG_440GX)
+ int ethgroup = -1;
+#endif
+#endif
+
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ /* before doing anything, figure out if we have a MAC address */
+ /* if not, bail */
+ if (memcmp (dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) {
+ printf("ERROR: ethaddr not set!\n");
+ return -1;
+ }
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+ /* Need to get the OPB frequency so we can access the PHY */
+ get_sys_info (&sysinfo);
+#endif
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE)); /* disable interrupts */
+
+ devnum = hw_p->devnum;
+
+#ifdef INFO_4XX_ENET
+ /* AS.HARNOIS
+ * We should have :
+ * hw_p->stats.pkts_handled <= hw_p->stats.pkts_rx <= hw_p->stats.pkts_handled+PKTBUFSRX
+ * In the most cases hw_p->stats.pkts_handled = hw_p->stats.pkts_rx, but it
+ * is possible that new packets (without relationship with
+ * current transfer) have got the time to arrived before
+ * netloop calls eth_halt
+ */
+ printf ("About preceeding transfer (eth%d):\n"
+ "- Sent packet number %d\n"
+ "- Received packet number %d\n"
+ "- Handled packet number %d\n",
+ hw_p->devnum,
+ hw_p->stats.pkts_tx,
+ hw_p->stats.pkts_rx, hw_p->stats.pkts_handled);
+
+ hw_p->stats.pkts_tx = 0;
+ hw_p->stats.pkts_rx = 0;
+ hw_p->stats.pkts_handled = 0;
+#endif
+
+ hw_p->tx_err_index = 0; /* Transmit Error Index for tx_err_log */
+ hw_p->rx_err_index = 0; /* Receive Error Index for rx_err_log */
+
+ hw_p->rx_slot = 0; /* MAL Receive Slot */
+ hw_p->rx_i_index = 0; /* Receive Interrupt Queue Index */
+ hw_p->rx_u_index = 0; /* Receive User Queue Index */
+
+ hw_p->tx_slot = 0; /* MAL Transmit Slot */
+ hw_p->tx_i_index = 0; /* Transmit Interrupt Queue Index */
+ hw_p->tx_u_index = 0; /* Transmit User Queue Index */
+
+#if defined(CONFIG_440) && !defined(CONFIG_440SP)
+ /* set RMII mode */
+ /* NOTE: 440GX spec states that mode is mutually exclusive */
+ /* NOTE: Therefore, disable all other EMACS, since we handle */
+ /* NOTE: only one emac at a time */
+ reg = 0;
+ out32 (ZMII_FER, 0);
+ udelay (100);
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ out32 (ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
+#elif defined(CONFIG_440GX)
+ ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
+#elif defined(CONFIG_440GP)
+ /* set RMII mode */
+ out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0);
+#else
+ if ((devnum == 0) || (devnum == 1)) {
+ out32 (ZMII_FER, (ZMII_FER_SMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
+ }
+ else { /* ((devnum == 2) || (devnum == 3)) */
+ out32 (ZMII_FER, ZMII_FER_MDI << ZMII_FER_V (devnum));
+ out32 (RGMII_FER, ((RGMII_FER_RGMII << RGMII_FER_V (2)) |
+ (RGMII_FER_RGMII << RGMII_FER_V (3))));
+ }
+#endif
+
+ out32 (ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
+
+ __asm__ volatile ("eieio");
+
+ /* reset emac so we have access to the phy */
+
+ out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
+ __asm__ volatile ("eieio");
+
+ failsafe = 1000;
+ while ((in32 (EMAC_M0 + hw_p->hw_addr) & (EMAC_M0_SRST)) && failsafe) {
+ udelay (1000);
+ failsafe--;
+ }
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+ /* Whack the M1 register */
+ mode_reg = 0x0;
+ mode_reg &= ~0x00000038;
+ if (sysinfo.freqOPB <= 50000000);
+ else if (sysinfo.freqOPB <= 66666667)
+ mode_reg |= EMAC_M1_OBCI_66;
+ else if (sysinfo.freqOPB <= 83333333)
+ mode_reg |= EMAC_M1_OBCI_83;
+ else if (sysinfo.freqOPB <= 100000000)
+ mode_reg |= EMAC_M1_OBCI_100;
+ else
+ mode_reg |= EMAC_M1_OBCI_GT100;
+
+ out32 (EMAC_M1 + hw_p->hw_addr, mode_reg);
+#endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */
+
+ /* wait for PHY to complete auto negotiation */
+ reg_short = 0;
+#ifndef CONFIG_CS8952_PHY
+ switch (devnum) {
+ case 0:
+ reg = CONFIG_PHY_ADDR;
+ break;
+#if defined (CONFIG_PHY1_ADDR)
+ case 1:
+ reg = CONFIG_PHY1_ADDR;
+ break;
+#endif
+#if defined (CONFIG_440GX)
+ case 2:
+ reg = CONFIG_PHY2_ADDR;
+ break;
+ case 3:
+ reg = CONFIG_PHY3_ADDR;
+ break;
+#endif
+ default:
+ reg = CONFIG_PHY_ADDR;
+ break;
+ }
+
+ bis->bi_phynum[devnum] = reg;
+
+#if defined(CONFIG_PHY_RESET)
+ /*
+ * Reset the phy, only if its the first time through
+ * otherwise, just check the speeds & feeds
+ */
+ if (hw_p->first_init == 0) {
+ miiphy_reset (dev->name, reg);
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+#if defined(CONFIG_CIS8201_PHY)
+ /*
+ * Cicada 8201 PHY needs to have an extended register whacked
+ * for RGMII mode.
+ */
+ if ( ((devnum == 2) || (devnum ==3)) && (4 == ethgroup) ) {
+#if defined(CONFIG_CIS8201_SHORT_ETCH)
+ miiphy_write (dev->name, reg, 23, 0x1300);
+#else
+ miiphy_write (dev->name, reg, 23, 0x1000);
+#endif
+ /*
+ * Vitesse VSC8201/Cicada CIS8201 errata:
+ * Interoperability problem with Intel 82547EI phys
+ * This work around (provided by Vitesse) changes
+ * the default timer convergence from 8ms to 12ms
+ */
+ miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+ miiphy_write (dev->name, reg, 0x08, 0x0200);
+ miiphy_write (dev->name, reg, 0x1f, 0x52b5);
+ miiphy_write (dev->name, reg, 0x02, 0x0004);
+ miiphy_write (dev->name, reg, 0x01, 0x0671);
+ miiphy_write (dev->name, reg, 0x00, 0x8fae);
+ miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+ miiphy_write (dev->name, reg, 0x08, 0x0000);
+ miiphy_write (dev->name, reg, 0x1f, 0x0000);
+ /* end Vitesse/Cicada errata */
+ }
+#endif
+#endif
+ /* Start/Restart autonegotiation */
+ phy_setup_aneg (dev->name, reg);
+ udelay (1000);
+ }
+#endif /* defined(CONFIG_PHY_RESET) */
+
+ miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);
+
+ /*
+ * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
+ */
+ if ((reg_short & PHY_BMSR_AUTN_ABLE)
+ && !(reg_short & PHY_BMSR_AUTN_COMP)) {
+ puts ("Waiting for PHY auto negotiation to complete");
+ i = 0;
+ while (!(reg_short & PHY_BMSR_AUTN_COMP)) {
+ /*
+ * Timeout reached ?
+ */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts (" TIMEOUT !\n");
+ break;
+ }
+
+ if ((i++ % 1000) == 0) {
+ putc ('.');
+ }
+ udelay (1000); /* 1 ms */
+ miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);
+
+ }
+ puts (" done\n");
+ udelay (500000); /* another 500 ms (results in faster booting) */
+ }
+#endif /* #ifndef CONFIG_CS8952_PHY */
+
+ speed = miiphy_speed (dev->name, reg);
+ duplex = miiphy_duplex (dev->name, reg);
+
+ if (hw_p->print_speed) {
+ hw_p->print_speed = 0;
+ printf ("ENET Speed is %d Mbps - %s duplex connection\n",
+ (int) speed, (duplex == HALF) ? "HALF" : "FULL");
+ }
+
+#if defined(CONFIG_440) && !defined(CONFIG_440SP)
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mfsdr(sdr_mfr, reg);
+ if (speed == 100) {
+ reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M;
+ } else {
+ reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M;
+ }
+ mtsdr(sdr_mfr, reg);
+#endif
+
+ /* Set ZMII/RGMII speed according to the phy link speed */
+ reg = in32 (ZMII_SSR);
+ if ( (speed == 100) || (speed == 1000) )
+ out32 (ZMII_SSR, reg | (ZMII_SSR_SP << ZMII_SSR_V (devnum)));
+ else
+ out32 (ZMII_SSR, reg & (~(ZMII_SSR_SP << ZMII_SSR_V (devnum))));
+
+ if ((devnum == 2) || (devnum == 3)) {
+ if (speed == 1000)
+ reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V (devnum));
+ else if (speed == 100)
+ reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V (devnum));
+ else
+ reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum));
+
+ out32 (RGMII_SSR, reg);
+ }
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
+
+ /* set the Mal configuration reg */
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+ mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA |
+ MAL_CR_PLBLT_DEFAULT | MAL_CR_EOPIE | 0x00330000);
+#else
+ mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+ /* Errata 1.12: MAL_1 -- Disable MAL bursting */
+ if (get_pvr() == PVR_440GP_RB) {
+ mtdcr (malmcr, mfdcr(malmcr) & ~MAL_CR_PLBB);
+ }
+#endif
+
+ /* Free "old" buffers */
+ if (hw_p->alloc_tx_buf)
+ free (hw_p->alloc_tx_buf);
+ if (hw_p->alloc_rx_buf)
+ free (hw_p->alloc_rx_buf);
+
+ /*
+ * Malloc MAL buffer desciptors, make sure they are
+ * aligned on cache line boundary size
+ * (401/403/IOP480 = 16, 405 = 32)
+ * and doesn't cross cache block boundaries.
+ */
+ hw_p->alloc_tx_buf =
+ (mal_desc_t *) malloc ((sizeof (mal_desc_t) * NUM_TX_BUFF) +
+ ((2 * CFG_CACHELINE_SIZE) - 2));
+ if (NULL == hw_p->alloc_tx_buf)
+ return -1;
+ if (((int) hw_p->alloc_tx_buf & CACHELINE_MASK) != 0) {
+ hw_p->tx =
+ (mal_desc_t *) ((int) hw_p->alloc_tx_buf +
+ CFG_CACHELINE_SIZE -
+ ((int) hw_p->
+ alloc_tx_buf & CACHELINE_MASK));
+ } else {
+ hw_p->tx = hw_p->alloc_tx_buf;
+ }
+
+ hw_p->alloc_rx_buf =
+ (mal_desc_t *) malloc ((sizeof (mal_desc_t) * NUM_RX_BUFF) +
+ ((2 * CFG_CACHELINE_SIZE) - 2));
+ if (NULL == hw_p->alloc_rx_buf) {
+ free(hw_p->alloc_tx_buf);
+ hw_p->alloc_tx_buf = NULL;
+ return -1;
+ }
+
+ if (((int) hw_p->alloc_rx_buf & CACHELINE_MASK) != 0) {
+ hw_p->rx =
+ (mal_desc_t *) ((int) hw_p->alloc_rx_buf +
+ CFG_CACHELINE_SIZE -
+ ((int) hw_p->
+ alloc_rx_buf & CACHELINE_MASK));
+ } else {
+ hw_p->rx = hw_p->alloc_rx_buf;
+ }
+
+ for (i = 0; i < NUM_TX_BUFF; i++) {
+ hw_p->tx[i].ctrl = 0;
+ hw_p->tx[i].data_len = 0;
+ if (hw_p->first_init == 0) {
+ hw_p->txbuf_ptr =
+ (char *) malloc (ENET_MAX_MTU_ALIGNED);
+ if (NULL == hw_p->txbuf_ptr) {
+ free(hw_p->alloc_rx_buf);
+ free(hw_p->alloc_tx_buf);
+ hw_p->alloc_rx_buf = NULL;
+ hw_p->alloc_tx_buf = NULL;
+ for(j = 0; j < i; j++) {
+ free(hw_p->tx[i].data_ptr);
+ hw_p->tx[i].data_ptr = NULL;
+ }
+ }
+ }
+ hw_p->tx[i].data_ptr = hw_p->txbuf_ptr;
+ if ((NUM_TX_BUFF - 1) == i)
+ hw_p->tx[i].ctrl |= MAL_TX_CTRL_WRAP;
+ hw_p->tx_run[i] = -1;
+#if 0
+ printf ("TX_BUFF %d @ 0x%08lx\n", i,
+ (ulong) hw_p->tx[i].data_ptr);
+#endif
+ }
+
+ for (i = 0; i < NUM_RX_BUFF; i++) {
+ hw_p->rx[i].ctrl = 0;
+ hw_p->rx[i].data_len = 0;
+ /* rx[i].data_ptr = (char *) &rx_buff[i]; */
+ hw_p->rx[i].data_ptr = (char *) NetRxPackets[i];
+ if ((NUM_RX_BUFF - 1) == i)
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_WRAP;
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
+ hw_p->rx_ready[i] = -1;
+#if 0
+ printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);
+#endif
+ }
+
+ reg = 0x00000000;
+
+ reg |= dev->enetaddr[0]; /* set high address */
+ reg = reg << 8;
+ reg |= dev->enetaddr[1];
+
+ out32 (EMAC_IAH + hw_p->hw_addr, reg);
+
+ reg = 0x00000000;
+ reg |= dev->enetaddr[2]; /* set low address */
+ reg = reg << 8;
+ reg |= dev->enetaddr[3];
+ reg = reg << 8;
+ reg |= dev->enetaddr[4];
+ reg = reg << 8;
+ reg |= dev->enetaddr[5];
+
+ out32 (EMAC_IAL + hw_p->hw_addr, reg);
+
+ switch (devnum) {
+ case 1:
+ /* setup MAL tx & rx channel pointers */
+#if defined (CONFIG_405EP) || defined (CONFIG_440EP) || defined (CONFIG_440GR)
+ mtdcr (maltxctp2r, hw_p->tx);
+#else
+ mtdcr (maltxctp1r, hw_p->tx);
+#endif
+#if defined(CONFIG_440)
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+#endif
+ mtdcr (malrxctp1r, hw_p->rx);
+ /* set RX buffer size */
+ mtdcr (malrcbs1, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+#if defined (CONFIG_440GX)
+ case 2:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+ mtdcr (maltxctp2r, hw_p->tx);
+ mtdcr (malrxctp2r, hw_p->rx);
+ /* set RX buffer size */
+ mtdcr (malrcbs2, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ case 3:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (maltxctp3r, hw_p->tx);
+ mtdcr (malrxbattr, 0x0);
+ mtdcr (malrxctp3r, hw_p->rx);
+ /* set RX buffer size */
+ mtdcr (malrcbs3, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+#endif /* CONFIG_440GX */
+ case 0:
+ default:
+ /* setup MAL tx & rx channel pointers */
+#if defined(CONFIG_440)
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+#endif
+ mtdcr (maltxctp0r, hw_p->tx);
+ mtdcr (malrxctp0r, hw_p->rx);
+ /* set RX buffer size */
+ mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ }
+
+ /* Enable MAL transmit and receive channels */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (maltxcasr, (MAL_TXRX_CASR >> (hw_p->devnum*2)));
+#else
+ mtdcr (maltxcasr, (MAL_TXRX_CASR >> hw_p->devnum));
+#endif
+ mtdcr (malrxcasr, (MAL_TXRX_CASR >> hw_p->devnum));
+
+ /* set transmit enable & receive enable */
+ out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_TXE | EMAC_M0_RXE);
+
+ /* set receive fifo to 4k and tx fifo to 2k */
+ mode_reg = in32 (EMAC_M1 + hw_p->hw_addr);
+ mode_reg |= EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
+
+ /* set speed */
+ if (speed == _1000BASET) {
+#if defined(CONFIG_440SP)
+#define SDR0_PFC1_EM_1000 0x00200000
+ unsigned long pfc1;
+ mfsdr (sdr_pfc1, pfc1);
+ pfc1 |= SDR0_PFC1_EM_1000;
+ mtsdr (sdr_pfc1, pfc1);
+#endif
+ mode_reg = mode_reg | EMAC_M1_MF_1000MBPS | EMAC_M1_IST;
+ } else if (speed == _100BASET)
+ mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
+ else
+ mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */
+ if (duplex == FULL)
+ mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST;
+
+ out32 (EMAC_M1 + hw_p->hw_addr, mode_reg);
+
+ /* Enable broadcast and indvidual address */
+ /* TBS: enabling runts as some misbehaved nics will send runts */
+ out32 (EMAC_RXM + hw_p->hw_addr, EMAC_RMR_BAE | EMAC_RMR_IAE);
+
+ /* we probably need to set the tx mode1 reg? maybe at tx time */
+
+ /* set transmit request threshold register */
+ out32 (EMAC_TRTR + hw_p->hw_addr, 0x18000000); /* 256 byte threshold */
+
+ /* set receive low/high water mark register */
+#if defined(CONFIG_440)
+ /* 440GP has a 64 byte burst length */
+ out32 (EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x80009000);
+#else
+ /* 405s have a 16 byte burst length */
+ out32 (EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x0f002000);
+#endif /* defined(CONFIG_440) */
+ out32 (EMAC_TXM1 + hw_p->hw_addr, 0xf8640000);
+
+ /* Set fifo limit entry in tx mode 0 */
+ out32 (EMAC_TXM0 + hw_p->hw_addr, 0x00000003);
+ /* Frame gap set */
+ out32 (EMAC_I_FRAME_GAP_REG + hw_p->hw_addr, 0x00000008);
+
+ /* Set EMAC IER */
+ hw_p->emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE;
+ if (speed == _100BASET)
+ hw_p->emac_ier = hw_p->emac_ier | EMAC_ISR_SYE;
+
+ out32 (EMAC_ISR + hw_p->hw_addr, 0xffffffff); /* clear pending interrupts */
+ out32 (EMAC_IER + hw_p->hw_addr, hw_p->emac_ier);
+
+ if (hw_p->first_init == 0) {
+ /*
+ * Connect interrupt service routines
+ */
+ irq_install_handler (VECNUM_ETH0 + (hw_p->devnum * 2),
+ (interrupt_handler_t *) enetInt, dev);
+ }
+
+ mtmsr (msr); /* enable interrupts again */
+
+ hw_p->bis = bis;
+ hw_p->first_init = 1;
+
+ return (1);
+}
+
+
+static int ppc_4xx_eth_send (struct eth_device *dev, volatile void *ptr,
+ int len)
+{
+ struct enet_frame *ef_ptr;
+ ulong time_start, time_now;
+ unsigned long temp_txm0;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ ef_ptr = (struct enet_frame *) ptr;
+
+ /*-----------------------------------------------------------------------+
+ * Copy in our address into the frame.
+ *-----------------------------------------------------------------------*/
+ (void) memcpy (ef_ptr->source_addr, dev->enetaddr, ENET_ADDR_LENGTH);
+
+ /*-----------------------------------------------------------------------+
+ * If frame is too long or too short, modify length.
+ *-----------------------------------------------------------------------*/
+ /* TBS: where does the fragment go???? */
+ if (len > ENET_MAX_MTU)
+ len = ENET_MAX_MTU;
+
+ /* memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */
+ memcpy ((void *) hw_p->txbuf_ptr, (const void *) ptr, len);
+
+ /*-----------------------------------------------------------------------+
+ * set TX Buffer busy, and send it
+ *-----------------------------------------------------------------------*/
+ hw_p->tx[hw_p->tx_slot].ctrl = (MAL_TX_CTRL_LAST |
+ EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP) &
+ ~(EMAC_TX_CTRL_ISA | EMAC_TX_CTRL_RSA);
+ if ((NUM_TX_BUFF - 1) == hw_p->tx_slot)
+ hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_WRAP;
+
+ hw_p->tx[hw_p->tx_slot].data_len = (short) len;
+ hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_READY;
+
+ __asm__ volatile ("eieio");
+
+ out32 (EMAC_TXM0 + hw_p->hw_addr,
+ in32 (EMAC_TXM0 + hw_p->hw_addr) | EMAC_TXM0_GNP0);
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_tx++;
+#endif
+
+ /*-----------------------------------------------------------------------+
+ * poll unitl the packet is sent and then make sure it is OK
+ *-----------------------------------------------------------------------*/
+ time_start = get_timer (0);
+ while (1) {
+ temp_txm0 = in32 (EMAC_TXM0 + hw_p->hw_addr);
+ /* loop until either TINT turns on or 3 seconds elapse */
+ if ((temp_txm0 & EMAC_TXM0_GNP0) != 0) {
+ /* transmit is done, so now check for errors
+ * If there is an error, an interrupt should
+ * happen when we return
+ */
+ time_now = get_timer (0);
+ if ((time_now - time_start) > 3000) {
+ return (-1);
+ }
+ } else {
+ return (len);
+ }
+ }
+}
+
+
+#if defined (CONFIG_440)
+
+#if defined(CONFIG_440SP)
+/*
+ * Hack: On 440SP all enet irq sources are located on UIC1
+ * Needs some cleanup. --sr
+ */
+#define UIC0MSR uic1msr
+#define UIC0SR uic1sr
+#else
+#define UIC0MSR uic0msr
+#define UIC0SR uic0sr
+#endif
+
+int enetInt (struct eth_device *dev)
+{
+ int serviced;
+ int rc = -1; /* default to not us */
+ unsigned long mal_isr;
+ unsigned long emac_isr = 0;
+ unsigned long mal_rx_eob;
+ unsigned long my_uic0msr, my_uic1msr;
+
+#if defined(CONFIG_440GX)
+ unsigned long my_uic2msr;
+#endif
+ EMAC_4XX_HW_PST hw_p;
+
+ /*
+ * Because the mal is generic, we need to get the current
+ * eth device
+ */
+#if defined(CONFIG_NET_MULTI)
+ dev = eth_get_dev();
+#else
+ dev = emac0_dev;
+#endif
+
+ hw_p = dev->priv;
+
+ /* enter loop that stays in interrupt code until nothing to service */
+ do {
+ serviced = 0;
+
+ my_uic0msr = mfdcr (UIC0MSR);
+ my_uic1msr = mfdcr (uic1msr);
+#if defined(CONFIG_440GX)
+ my_uic2msr = mfdcr (uic2msr);
+#endif
+ if (!(my_uic0msr & (UIC_MRE | UIC_MTE))
+ && !(my_uic1msr & (UIC_ETH0 | UIC_ETH1 | UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ /* not for us */
+ return (rc);
+ }
+#if defined (CONFIG_440GX)
+ if (!(my_uic0msr & (UIC_MRE | UIC_MTE))
+ && !(my_uic2msr & (UIC_ETH2 | UIC_ETH3))) {
+ /* not for us */
+ return (rc);
+ }
+#endif
+ /* get and clear controller status interrupts */
+ /* look at Mal and EMAC interrupts */
+ if ((my_uic0msr & (UIC_MRE | UIC_MTE))
+ || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ /* we have a MAL interrupt */
+ mal_isr = mfdcr (malesr);
+ /* look for mal error */
+ if (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE)) {
+ mal_err (dev, mal_isr, my_uic0msr,
+ MAL_UIC_DEF, MAL_UIC_ERR);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+
+ /* port by port dispatch of emac interrupts */
+ if (hw_p->devnum == 0) {
+ if (UIC_ETH0 & my_uic1msr) { /* look for EMAC errors */
+ emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
+ if ((hw_p->emac_ier & emac_isr) != 0) {
+ emac_err (dev, emac_isr);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if ((hw_p->emac_ier & emac_isr)
+ || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ mtdcr (UIC0SR, UIC_MRE | UIC_MTE); /* Clear */
+ mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+ return (rc); /* we had errors so get out */
+ }
+ }
+
+#if !defined(CONFIG_440SP)
+ if (hw_p->devnum == 1) {
+ if (UIC_ETH1 & my_uic1msr) { /* look for EMAC errors */
+ emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
+ if ((hw_p->emac_ier & emac_isr) != 0) {
+ emac_err (dev, emac_isr);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if ((hw_p->emac_ier & emac_isr)
+ || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ mtdcr (UIC0SR, UIC_MRE | UIC_MTE); /* Clear */
+ mtdcr (uic1sr, UIC_ETH1 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+ return (rc); /* we had errors so get out */
+ }
+ }
+#if defined (CONFIG_440GX)
+ if (hw_p->devnum == 2) {
+ if (UIC_ETH2 & my_uic2msr) { /* look for EMAC errors */
+ emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
+ if ((hw_p->emac_ier & emac_isr) != 0) {
+ emac_err (dev, emac_isr);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if ((hw_p->emac_ier & emac_isr)
+ || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ mtdcr (UIC0SR, UIC_MRE | UIC_MTE); /* Clear */
+ mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+ mtdcr (uic2sr, UIC_ETH2);
+ return (rc); /* we had errors so get out */
+ }
+ }
+
+ if (hw_p->devnum == 3) {
+ if (UIC_ETH3 & my_uic2msr) { /* look for EMAC errors */
+ emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
+ if ((hw_p->emac_ier & emac_isr) != 0) {
+ emac_err (dev, emac_isr);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if ((hw_p->emac_ier & emac_isr)
+ || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ mtdcr (UIC0SR, UIC_MRE | UIC_MTE); /* Clear */
+ mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+ mtdcr (uic2sr, UIC_ETH3);
+ return (rc); /* we had errors so get out */
+ }
+ }
+#endif /* CONFIG_440GX */
+#endif /* !CONFIG_440SP */
+
+ /* handle MAX TX EOB interrupt from a tx */
+ if (my_uic0msr & UIC_MTE) {
+ mal_rx_eob = mfdcr (maltxeobisr);
+ mtdcr (maltxeobisr, mal_rx_eob);
+ mtdcr (UIC0SR, UIC_MTE);
+ }
+ /* handle MAL RX EOB interupt from a receive */
+ /* check for EOB on valid channels */
+ if (my_uic0msr & UIC_MRE) {
+ mal_rx_eob = mfdcr (malrxeobisr);
+ if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */
+ /* clear EOB
+ mtdcr(malrxeobisr, mal_rx_eob); */
+ enet_rcv (dev, emac_isr);
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+ }
+
+ mtdcr (UIC0SR, UIC_MRE); /* Clear */
+ mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+ switch (hw_p->devnum) {
+ case 0:
+ mtdcr (uic1sr, UIC_ETH0);
+ break;
+ case 1:
+ mtdcr (uic1sr, UIC_ETH1);
+ break;
+#if defined (CONFIG_440GX)
+ case 2:
+ mtdcr (uic2sr, UIC_ETH2);
+ break;
+ case 3:
+ mtdcr (uic2sr, UIC_ETH3);
+ break;
+#endif /* CONFIG_440GX */
+ default:
+ break;
+ }
+ } while (serviced);
+
+ return (rc);
+}
+
+#else /* CONFIG_440 */
+
+int enetInt (struct eth_device *dev)
+{
+ int serviced;
+ int rc = -1; /* default to not us */
+ unsigned long mal_isr;
+ unsigned long emac_isr = 0;
+ unsigned long mal_rx_eob;
+ unsigned long my_uicmsr;
+
+ EMAC_4XX_HW_PST hw_p;
+
+ /*
+ * Because the mal is generic, we need to get the current
+ * eth device
+ */
+#if defined(CONFIG_NET_MULTI)
+ dev = eth_get_dev();
+#else
+ dev = emac0_dev;
+#endif
+
+ hw_p = dev->priv;
+
+ /* enter loop that stays in interrupt code until nothing to service */
+ do {
+ serviced = 0;
+
+ my_uicmsr = mfdcr (uicmsr);
+
+ if ((my_uicmsr & (MAL_UIC_DEF | EMAC_UIC_DEF)) == 0) { /* not for us */
+ return (rc);
+ }
+ /* get and clear controller status interrupts */
+ /* look at Mal and EMAC interrupts */
+ if ((MAL_UIC_DEF & my_uicmsr) != 0) { /* we have a MAL interrupt */
+ mal_isr = mfdcr (malesr);
+ /* look for mal error */
+ if ((my_uicmsr & MAL_UIC_ERR) != 0) {
+ mal_err (dev, mal_isr, my_uicmsr, MAL_UIC_DEF, MAL_UIC_ERR);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+
+ /* port by port dispatch of emac interrupts */
+
+ if ((SEL_UIC_DEF(hw_p->devnum) & my_uicmsr) != 0) { /* look for EMAC errors */
+ emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
+ if ((hw_p->emac_ier & emac_isr) != 0) {
+ emac_err (dev, emac_isr);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if (((hw_p->emac_ier & emac_isr) != 0) || ((MAL_UIC_ERR & my_uicmsr) != 0)) {
+ mtdcr (uicsr, MAL_UIC_DEF | SEL_UIC_DEF(hw_p->devnum)); /* Clear */
+ return (rc); /* we had errors so get out */
+ }
+
+ /* handle MAX TX EOB interrupt from a tx */
+ if (my_uicmsr & UIC_MAL_TXEOB) {
+ mal_rx_eob = mfdcr (maltxeobisr);
+ mtdcr (maltxeobisr, mal_rx_eob);
+ mtdcr (uicsr, UIC_MAL_TXEOB);
+ }
+ /* handle MAL RX EOB interupt from a receive */
+ /* check for EOB on valid channels */
+ if (my_uicmsr & UIC_MAL_RXEOB)
+ {
+ mal_rx_eob = mfdcr (malrxeobisr);
+ if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */
+ /* clear EOB
+ mtdcr(malrxeobisr, mal_rx_eob); */
+ enet_rcv (dev, emac_isr);
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ mtdcr (uicsr, MAL_UIC_DEF|EMAC_UIC_DEF|EMAC_UIC_DEF1); /* Clear */
+ }
+ while (serviced);
+
+ return (rc);
+}
+
+#endif /* CONFIG_440 */
+
+/*-----------------------------------------------------------------------------+
+ * MAL Error Routine
+ *-----------------------------------------------------------------------------*/
+static void mal_err (struct eth_device *dev, unsigned long isr,
+ unsigned long uic, unsigned long maldef,
+ unsigned long mal_errr)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ mtdcr (malesr, isr); /* clear interrupt */
+
+ /* clear DE interrupt */
+ mtdcr (maltxdeir, 0xC0000000);
+ mtdcr (malrxdeir, 0x80000000);
+
+#ifdef INFO_4XX_ENET
+ printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n", isr, uic, maldef, mal_errr);
+#endif
+
+ eth_init (hw_p->bis); /* start again... */
+}
+
+/*-----------------------------------------------------------------------------+
+ * EMAC Error Routine
+ *-----------------------------------------------------------------------------*/
+static void emac_err (struct eth_device *dev, unsigned long isr)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ printf ("EMAC%d error occured.... ISR = %lx\n", hw_p->devnum, isr);
+ out32 (EMAC_ISR + hw_p->hw_addr, isr);
+}
+
+/*-----------------------------------------------------------------------------+
+ * enet_rcv() handles the ethernet receive data
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (struct eth_device *dev, unsigned long malisr)
+{
+ struct enet_frame *ef_ptr;
+ unsigned long data_len;
+ unsigned long rx_eob_isr;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ int handled = 0;
+ int i;
+ int loop_count = 0;
+
+ rx_eob_isr = mfdcr (malrxeobisr);
+ if ((0x80000000 >> hw_p->devnum) & rx_eob_isr) {
+ /* clear EOB */
+ mtdcr (malrxeobisr, rx_eob_isr);
+
+ /* EMAC RX done */
+ while (1) { /* do all */
+ i = hw_p->rx_slot;
+
+ if ((MAL_RX_CTRL_EMPTY & hw_p->rx[i].ctrl)
+ || (loop_count >= NUM_RX_BUFF))
+ break;
+ loop_count++;
+ hw_p->rx_slot++;
+ if (NUM_RX_BUFF == hw_p->rx_slot)
+ hw_p->rx_slot = 0;
+ handled++;
+ data_len = (unsigned long) hw_p->rx[i].data_len; /* Get len */
+ if (data_len) {
+ if (data_len > ENET_MAX_MTU) /* Check len */
+ data_len = 0;
+ else {
+ if (EMAC_RX_ERRORS & hw_p->rx[i].ctrl) { /* Check Errors */
+ data_len = 0;
+ hw_p->stats.rx_err_log[hw_p->
+ rx_err_index]
+ = hw_p->rx[i].ctrl;
+ hw_p->rx_err_index++;
+ if (hw_p->rx_err_index ==
+ MAX_ERR_LOG)
+ hw_p->rx_err_index =
+ 0;
+ } /* emac_erros */
+ } /* data_len < max mtu */
+ } /* if data_len */
+ if (!data_len) { /* no data */
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY; /* Free Recv Buffer */
+
+ hw_p->stats.data_len_err++; /* Error at Rx */
+ }
+
+ /* !data_len */
+ /* AS.HARNOIS */
+ /* Check if user has already eaten buffer */
+ /* if not => ERROR */
+ else if (hw_p->rx_ready[hw_p->rx_i_index] != -1) {
+ if (hw_p->is_receiving)
+ printf ("ERROR : Receive buffers are full!\n");
+ break;
+ } else {
+ hw_p->stats.rx_frames++;
+ hw_p->stats.rx += data_len;
+ ef_ptr = (struct enet_frame *) hw_p->rx[i].
+ data_ptr;
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_rx++;
+#endif
+ /* AS.HARNOIS
+ * use ring buffer
+ */
+ hw_p->rx_ready[hw_p->rx_i_index] = i;
+ hw_p->rx_i_index++;
+ if (NUM_RX_BUFF == hw_p->rx_i_index)
+ hw_p->rx_i_index = 0;
+
+ /* AS.HARNOIS
+ * free receive buffer only when
+ * buffer has been handled (eth_rx)
+ rx[i].ctrl |= MAL_RX_CTRL_EMPTY;
+ */
+ } /* if data_len */
+ } /* while */
+ } /* if EMACK_RXCHL */
+}
+
+
+static int ppc_4xx_eth_rx (struct eth_device *dev)
+{
+ int length;
+ int user_index;
+ unsigned long msr;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ hw_p->is_receiving = 1; /* tell driver */
+
+ for (;;) {
+ /* AS.HARNOIS
+ * use ring buffer and
+ * get index from rx buffer desciptor queue
+ */
+ user_index = hw_p->rx_ready[hw_p->rx_u_index];
+ if (user_index == -1) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE));
+
+ length = hw_p->rx[user_index].data_len;
+
+ /* Pass the packet up to the protocol layers. */
+ /* NetReceive(NetRxPackets[rxIdx], length - 4); */
+ /* NetReceive(NetRxPackets[i], length); */
+ NetReceive (NetRxPackets[user_index], length - 4);
+ /* Free Recv Buffer */
+ hw_p->rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
+ /* Free rx buffer descriptor queue */
+ hw_p->rx_ready[hw_p->rx_u_index] = -1;
+ hw_p->rx_u_index++;
+ if (NUM_RX_BUFF == hw_p->rx_u_index)
+ hw_p->rx_u_index = 0;
+
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_handled++;
+#endif
+
+ mtmsr (msr); /* Enable IRQ's */
+ }
+
+ hw_p->is_receiving = 0; /* tell driver */
+
+ return length;
+}
+
+int ppc_4xx_eth_initialize (bd_t * bis)
+{
+ static int virgin = 0;
+ struct eth_device *dev;
+ int eth_num = 0;
+ EMAC_4XX_HW_PST hw = NULL;
+
+#if defined(CONFIG_440GX)
+ unsigned long pfc1;
+
+ mfsdr (sdr_pfc1, pfc1);
+ pfc1 &= ~(0x01e00000);
+ pfc1 |= 0x01200000;
+ mtsdr (sdr_pfc1, pfc1);
+#endif
+ /* set phy num and mode */
+ bis->bi_phynum[0] = CONFIG_PHY_ADDR;
+#if defined(CONFIG_PHY1_ADDR)
+ bis->bi_phynum[1] = CONFIG_PHY1_ADDR;
+#endif
+#if defined(CONFIG_440GX)
+ bis->bi_phynum[2] = CONFIG_PHY2_ADDR;
+ bis->bi_phynum[3] = CONFIG_PHY3_ADDR;
+ bis->bi_phymode[0] = 0;
+ bis->bi_phymode[1] = 0;
+ bis->bi_phymode[2] = 2;
+ bis->bi_phymode[3] = 2;
+
+#if defined (CONFIG_440GX)
+ ppc_4xx_eth_setup_bridge(0, bis);
+#endif
+#endif
+
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+
+ /* See if we can actually bring up the interface, otherwise, skip it */
+ switch (eth_num) {
+ default: /* fall through */
+ case 0:
+ if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) {
+ bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+ continue;
+ }
+ break;
+#ifdef CONFIG_HAS_ETH1
+ case 1:
+ if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) {
+ bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+ continue;
+ }
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH2
+ case 2:
+ if (memcmp (bis->bi_enet2addr, "\0\0\0\0\0\0", 6) == 0) {
+ bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+ continue;
+ }
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH3
+ case 3:
+ if (memcmp (bis->bi_enet3addr, "\0\0\0\0\0\0", 6) == 0) {
+ bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+ continue;
+ }
+ break;
+#endif
+ }
+
+ /* Allocate device structure */
+ dev = (struct eth_device *) malloc (sizeof (*dev));
+ if (dev == NULL) {
+ printf ("ppc_4xx_eth_initialize: "
+ "Cannot allocate eth_device %d\n", eth_num);
+ return (-1);
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ /* Allocate our private use data */
+ hw = (EMAC_4XX_HW_PST) malloc (sizeof (*hw));
+ if (hw == NULL) {
+ printf ("ppc_4xx_eth_initialize: "
+ "Cannot allocate private hw data for eth_device %d",
+ eth_num);
+ free (dev);
+ return (-1);
+ }
+ memset(hw, 0, sizeof(*hw));
+
+ switch (eth_num) {
+ default: /* fall through */
+ case 0:
+ hw->hw_addr = 0;
+ memcpy (dev->enetaddr, bis->bi_enetaddr, 6);
+ break;
+#ifdef CONFIG_HAS_ETH1
+ case 1:
+ hw->hw_addr = 0x100;
+ memcpy (dev->enetaddr, bis->bi_enet1addr, 6);
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH2
+ case 2:
+ hw->hw_addr = 0x400;
+ memcpy (dev->enetaddr, bis->bi_enet2addr, 6);
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH3
+ case 3:
+ hw->hw_addr = 0x600;
+ memcpy (dev->enetaddr, bis->bi_enet3addr, 6);
+ break;
+#endif
+ }
+
+ hw->devnum = eth_num;
+ hw->print_speed = 1;
+
+ sprintf (dev->name, "ppc_4xx_eth%d", eth_num);
+ dev->priv = (void *) hw;
+ dev->init = ppc_4xx_eth_init;
+ dev->halt = ppc_4xx_eth_halt;
+ dev->send = ppc_4xx_eth_send;
+ dev->recv = ppc_4xx_eth_rx;
+
+ if (0 == virgin) {
+ /* set the MAL IER ??? names may change with new spec ??? */
+ mal_ier =
+ MAL_IER_DE | MAL_IER_NE | MAL_IER_TE |
+ MAL_IER_OPBE | MAL_IER_PLBE;
+ mtdcr (malesr, 0xffffffff); /* clear pending interrupts */
+ mtdcr (maltxdeir, 0xffffffff); /* clear pending interrupts */
+ mtdcr (malrxdeir, 0xffffffff); /* clear pending interrupts */
+ mtdcr (malier, mal_ier);
+
+ /* install MAL interrupt handler */
+ irq_install_handler (VECNUM_MS,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MTE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MRE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_TXDE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_RXDE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ virgin = 1;
+ }
+
+#if defined(CONFIG_NET_MULTI)
+ eth_register (dev);
+#else
+ emac0_dev = dev;
+#endif
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+ miiphy_register (dev->name,
+ emac4xx_miiphy_read, emac4xx_miiphy_write);
+#endif
+
+ } /* end for each supported device */
+ return (1);
+}
+
+
+#if !defined(CONFIG_NET_MULTI)
+void eth_halt (void) {
+ if (emac0_dev) {
+ ppc_4xx_eth_halt(emac0_dev);
+ free(emac0_dev);
+ emac0_dev = NULL;
+ }
+}
+
+int eth_init (bd_t *bis)
+{
+ ppc_4xx_eth_initialize(bis);
+ if (emac0_dev) {
+ return ppc_4xx_eth_init(emac0_dev, bis);
+ } else {
+ printf("ERROR: ethaddr not set!\n");
+ return -1;
+ }
+}
+
+int eth_send(volatile void *packet, int length)
+{
+ return (ppc_4xx_eth_send(emac0_dev, packet, length));
+}
+
+int eth_rx(void)
+{
+ return (ppc_4xx_eth_rx(emac0_dev));
+}
+
+int emac4xx_miiphy_initialize (bd_t * bis)
+{
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+ miiphy_register ("ppc_4xx_eth0",
+ emac4xx_miiphy_read, emac4xx_miiphy_write);
+#endif
+
+ return 0;
+}
+#endif /* !defined(CONFIG_NET_MULTI) */
+
+#endif /* #if (CONFIG_COMMANDS & CFG_CMD_NET) */
diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile
new file mode 100755
index 0000000..c563457
--- /dev/null
+++ b/cpu/ppc4xx/Makefile
@@ -0,0 +1,50 @@
+#
+# (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 resetvec.o kgdb.o
+AOBJS = dcr.o
+COBJS = 405gp_pci.o 4xx_enet.o \
+ bedbug_405.o commproc.o \
+ cpu.o cpu_init.o i2c.o interrupts.o \
+ miiphy.o sdram.o serial.o \
+ spd_sdram.o speed.o traps.o usb_ohci.o usbdev.o
+
+OBJS = $(AOBJS) $(COBJS)
+
+all: .depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend: Makefile $(START:.o=.S) $(AOBJS:.o=.S) $(COBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(START:.o=.S) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/ppc4xx/bedbug_405.c b/cpu/ppc4xx/bedbug_405.c
new file mode 100755
index 0000000..a3c2119
--- /dev/null
+++ b/cpu/ppc4xx/bedbug_405.c
@@ -0,0 +1,308 @@
+/*
+ * Bedbug Functions specific to the PPC405 chip
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/type.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) && defined(CONFIG_4xx)
+
+#define MAX_BREAK_POINTS 4
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug405_init __P ((void));
+void bedbug405_do_break __P ((cmd_tbl_t *, int, int, char *[]));
+void bedbug405_break_isr __P ((struct pt_regs *));
+int bedbug405_find_empty __P ((void));
+int bedbug405_set __P ((int, unsigned long));
+int bedbug405_clear __P ((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the AMCC PPC405. Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug405_init (void)
+{
+ int i;
+
+ /* -------------------------------------------------- */
+
+ bug_ctx.hw_debug_enabled = 0;
+ bug_ctx.stopped = 0;
+ bug_ctx.current_bp = 0;
+ bug_ctx.regs = NULL;
+
+ bug_ctx.do_break = bedbug405_do_break;
+ bug_ctx.break_isr = bedbug405_break_isr;
+ bug_ctx.find_empty = bedbug405_find_empty;
+ bug_ctx.set = bedbug405_set;
+ bug_ctx.clear = bedbug405_clear;
+
+ for (i = 1; i <= MAX_BREAK_POINTS; ++i)
+ (*bug_ctx.clear) (i);
+
+ puts ("BEDBUG:ready\n");
+ return;
+} /* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show one of the hardware breakpoints for the 405. The "off"
+ * string will disable a specific breakpoint. The "show" string will
+ * display the current breakpoints. Otherwise an address will set a
+ * breakpoint at that address. Setting a breakpoint uses the CPU-specific
+ * set routine which will assign a breakpoint number.
+ * ====================================================================== */
+
+void bedbug405_do_break (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ long addr = 0; /* Address to break at */
+ int which_bp; /* Breakpoint number */
+
+ /* -------------------------------------------------- */
+
+ if (argc < 2) {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return;
+ }
+
+ /* Turn off a breakpoint */
+
+ if (strcmp (argv[1], "off") == 0) {
+ if (bug_ctx.hw_debug_enabled == 0) {
+ printf ("No breakpoints enabled\n");
+ return;
+ }
+
+ which_bp = simple_strtoul (argv[2], NULL, 10);
+
+ if (bug_ctx.clear)
+ (*bug_ctx.clear) (which_bp);
+
+ printf ("Breakpoint %d removed\n", which_bp);
+ return;
+ }
+
+ /* Show a list of breakpoints */
+
+ if (strcmp (argv[1], "show") == 0) {
+ for (which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp) {
+
+ switch (which_bp) {
+ case 1:
+ addr = GET_IAC1 ();
+ break;
+ case 2:
+ addr = GET_IAC2 ();
+ break;
+ case 3:
+ addr = GET_IAC3 ();
+ break;
+ case 4:
+ addr = GET_IAC4 ();
+ break;
+ }
+
+ printf ("Breakpoint [%d]: ", which_bp);
+ if (addr == 0)
+ printf ("NOT SET\n");
+ else
+ disppc ((unsigned char *) addr, 0, 1, bedbug_puts,
+ F_RADHEX);
+ }
+ return;
+ }
+
+ /* Set a breakpoint at the address */
+
+ if (!isdigit (argv[1][0])) {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return;
+ }
+
+ addr = simple_strtoul (argv[1], NULL, 16) & 0xfffffffc;
+
+ if ((bug_ctx.set) && (which_bp = (*bug_ctx.set) (0, addr)) > 0) {
+ printf ("Breakpoint [%d]: ", which_bp);
+ disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
+ }
+
+ return;
+} /* bedbug405_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint. First determine which breakpoint was hit by
+ * looking at the DeBug Status Register (DBSR), clear the breakpoint
+ * and enter a mini main loop. Stay in the loop until the stopped flag
+ * in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug405_break_isr (struct pt_regs *regs)
+{
+ unsigned long dbsr_val; /* Value of the DBSR */
+ unsigned long addr = 0; /* Address stopped at */
+
+ /* -------------------------------------------------- */
+
+ dbsr_val = GET_DBSR ();
+
+ if (dbsr_val & DBSR_IA1) {
+ bug_ctx.current_bp = 1;
+ addr = GET_IAC1 ();
+ SET_DBSR (DBSR_IA1); /* Write a 1 to clear */
+ } else if (dbsr_val & DBSR_IA2) {
+ bug_ctx.current_bp = 2;
+ addr = GET_IAC2 ();
+ SET_DBSR (DBSR_IA2); /* Write a 1 to clear */
+ } else if (dbsr_val & DBSR_IA3) {
+ bug_ctx.current_bp = 3;
+ addr = GET_IAC3 ();
+ SET_DBSR (DBSR_IA3); /* Write a 1 to clear */
+ } else if (dbsr_val & DBSR_IA4) {
+ bug_ctx.current_bp = 4;
+ addr = GET_IAC4 ();
+ SET_DBSR (DBSR_IA4); /* Write a 1 to clear */
+ }
+
+ bedbug_main_loop (addr, regs);
+ return;
+} /* bedbug405_break_isr */
+
+
+
+/* ======================================================================
+ * Look through all of the hardware breakpoints available to see if one
+ * is unused.
+ * ====================================================================== */
+
+int bedbug405_find_empty (void)
+{
+ /* -------------------------------------------------- */
+
+ if (GET_IAC1 () == 0)
+ return 1;
+
+ if (GET_IAC2 () == 0)
+ return 2;
+
+ if (GET_IAC3 () == 0)
+ return 3;
+
+ if (GET_IAC4 () == 0)
+ return 4;
+
+ return 0;
+} /* bedbug405_find_empty */
+
+
+
+/* ======================================================================
+ * Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
+ * number, otherwise reassign the given breakpoint. If hardware debugging
+ * is not enabled, then turn it on via the MSR and DBCR0. Set the break
+ * address in the appropriate IACx register and enable proper address
+ * beakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug405_set (int which_bp, unsigned long addr)
+{
+ /* -------------------------------------------------- */
+
+ /* Only look if which_bp == 0, else use which_bp */
+ if ((bug_ctx.find_empty) && (!which_bp) &&
+ (which_bp = (*bug_ctx.find_empty) ()) == 0) {
+ printf ("All breakpoints in use\n");
+ return 0;
+ }
+
+ if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
+ printf ("Invalid break point # %d\n", which_bp);
+ return 0;
+ }
+
+ if (!bug_ctx.hw_debug_enabled) {
+ SET_MSR (GET_MSR () | 0x200); /* set MSR[ DE ] */
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IDM);
+ bug_ctx.hw_debug_enabled = 1;
+ }
+
+ switch (which_bp) {
+ case 1:
+ SET_IAC1 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA1);
+ break;
+
+ case 2:
+ SET_IAC2 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA2);
+ break;
+
+ case 3:
+ SET_IAC3 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA3);
+ break;
+
+ case 4:
+ SET_IAC4 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA4);
+ break;
+ }
+
+ return which_bp;
+} /* bedbug405_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the appropriate IACx register
+ * to zero and claring the instruction address breakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug405_clear (int which_bp)
+{
+ /* -------------------------------------------------- */
+
+ if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
+ printf ("Invalid break point # (%d)\n", which_bp);
+ return -1;
+ }
+
+ switch (which_bp) {
+ case 1:
+ SET_IAC1 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA1);
+ break;
+
+ case 2:
+ SET_IAC2 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA2);
+ break;
+
+ case 3:
+ SET_IAC3 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA3);
+ break;
+
+ case 4:
+ SET_IAC4 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA4);
+ break;
+ }
+
+ return 0;
+} /* bedbug405_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/cpu/ppc4xx/commproc.c b/cpu/ppc4xx/commproc.c
new file mode 100755
index 0000000..68aab5b
--- /dev/null
+++ b/cpu/ppc4xx/commproc.c
@@ -0,0 +1,69 @@
+/*
+ * (C) Copyright 2000-2004
+ * 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
+ *
+ *
+ * Atapted for ppc4XX by Denis Peter
+ */
+
+#include <common.h>
+#include <commproc.h>
+
+
+#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
+
+void post_word_store (ulong a)
+{
+ volatile void *save_addr = (volatile void *)(CFG_OCM_DATA_ADDR + CFG_POST_WORD_ADDR);
+ *(volatile ulong *) save_addr = a;
+}
+
+ulong post_word_load (void)
+{
+ volatile void *save_addr = (volatile void *)(CFG_OCM_DATA_ADDR + CFG_POST_WORD_ADDR);
+ return *(volatile ulong *) save_addr;
+}
+
+#endif /* CONFIG_POST || CONFIG_LOGBUFFER*/
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+void bootcount_store (ulong a)
+{
+ volatile ulong *save_addr =
+ (volatile ulong *)(CFG_OCM_DATA_ADDR + CFG_BOOTCOUNT_ADDR);
+
+ save_addr[0] = a;
+ save_addr[1] = BOOTCOUNT_MAGIC;
+}
+
+ulong bootcount_load (void)
+{
+ volatile ulong *save_addr =
+ (volatile ulong *)(CFG_OCM_DATA_ADDR + CFG_BOOTCOUNT_ADDR);
+
+ if (save_addr[1] != BOOTCOUNT_MAGIC)
+ return 0;
+ else
+ return save_addr[0];
+}
+
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/cpu/ppc4xx/config.mk b/cpu/ppc4xx/config.mk
new file mode 100755
index 0000000..119e061
--- /dev/null
+++ b/cpu/ppc4xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (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
+#
+
+PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -fno-strict-aliasing
+
+PLATFORM_CPPFLAGS += -DCONFIG_4xx -ffixed-r2 -ffixed-r29 -mstring -Wa,-m405 -mcpu=405 -msoft-float
diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c
new file mode 100755
index 0000000..a26533c
--- /dev/null
+++ b/cpu/ppc4xx/cpu.c
@@ -0,0 +1,371 @@
+/*
+ * (C) Copyright 2000-2003
+ * 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
+ */
+
+/*
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <ppc4xx.h>
+
+
+#if defined(CONFIG_440)
+#define FREQ_EBC (sys_info.freqEPB)
+#else
+#define FREQ_EBC (sys_info.freqPLB / sys_info.pllExtBusDiv)
+#endif
+
+#if defined(CONFIG_405GP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+
+#define PCI_ASYNC
+
+int pci_async_enabled(void)
+{
+#if defined(CONFIG_405GP)
+ return (mfdcr(strap) & PSR_PCI_ASYNC_EN);
+#endif
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ unsigned long val;
+
+ mfsdr(sdr_sdstp1, val);
+ return (val & SDR0_SDSTP1_PAME_MASK);
+#endif
+}
+#endif
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_IOP480) && !defined(CONFIG_405)
+int pci_arbiter_enabled(void)
+{
+#if defined(CONFIG_405GP)
+ return (mfdcr(strap) & PSR_PCI_ARBIT_EN);
+#endif
+
+#if defined(CONFIG_405EP)
+ return (mfdcr(cpc0_pci) & CPC0_PCI_ARBIT_EN);
+#endif
+
+#if defined(CONFIG_440GP)
+ return (mfdcr(cpc0_strp1) & CPC0_STRP1_PAE_MASK);
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SP)
+ unsigned long val;
+
+ mfsdr(sdr_sdstp1, val);
+ return (val & SDR0_SDSTP1_PAE_MASK);
+#endif
+}
+#endif
+
+#if defined(CONFIG_405EP)|| defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440GX) || defined(CONFIG_440SP)
+
+#define I2C_BOOTROM
+
+int i2c_bootrom_enabled(void)
+{
+#if defined(CONFIG_405EP)
+ return (mfdcr(cpc0_boot) & CPC0_BOOT_SEP);
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SP)
+ unsigned long val;
+
+ mfsdr(sdr_sdcs, val);
+ return (val & SDR0_SDCS_SDD);
+#endif
+}
+#endif
+
+
+#if defined(CONFIG_440)
+static int do_chip_reset(unsigned long sys0, unsigned long sys1);
+#endif
+
+
+int checkcpu (void)
+{
+#if !defined(CONFIG_405) /* not used on Xilinx 405 FPGA implementations */
+ DECLARE_GLOBAL_DATA_PTR;
+ uint pvr = get_pvr();
+ ulong clock = gd->cpu_clk;
+ char buf[32];
+
+#if !defined(CONFIG_IOP480)
+ sys_info_t sys_info;
+
+ puts ("CPU: ");
+
+ get_sys_info(&sys_info);
+
+ puts("AMCC PowerPC 4");
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP)
+ puts("05");
+#endif
+#if defined(CONFIG_440)
+ puts("40");
+#endif
+
+ switch (pvr) {
+ case PVR_405GP_RB:
+ puts("GP Rev. B");
+ break;
+
+ case PVR_405GP_RC:
+ puts("GP Rev. C");
+ break;
+
+ case PVR_405GP_RD:
+ puts("GP Rev. D");
+ break;
+
+#ifdef CONFIG_405GP
+ case PVR_405GP_RE: /* 405GP rev E and 405CR rev C have same PVR */
+ puts("GP Rev. E");
+ break;
+#endif
+
+ case PVR_405CR_RA:
+ puts("CR Rev. A");
+ break;
+
+ case PVR_405CR_RB:
+ puts("CR Rev. B");
+ break;
+
+#ifdef CONFIG_405CR
+ case PVR_405CR_RC: /* 405GP rev E and 405CR rev C have same PVR */
+ puts("CR Rev. C");
+ break;
+#endif
+
+ case PVR_405GPR_RB:
+ puts("GPr Rev. B");
+ break;
+
+ case PVR_405EP_RB:
+ puts("EP Rev. B");
+ break;
+
+#if defined(CONFIG_440)
+ case PVR_440GP_RB:
+ puts("GP Rev. B");
+ /* See errata 1.12: CHIP_4 */
+ if ((mfdcr(cpc0_sys0) != mfdcr(cpc0_strp0)) ||
+ (mfdcr(cpc0_sys1) != mfdcr(cpc0_strp1)) ){
+ puts ( "\n\t CPC0_SYSx DCRs corrupted. "
+ "Resetting chip ...\n");
+ udelay( 1000 * 1000 ); /* Give time for serial buf to clear */
+ do_chip_reset ( mfdcr(cpc0_strp0),
+ mfdcr(cpc0_strp1) );
+ }
+ break;
+
+ case PVR_440GP_RC:
+ puts("GP Rev. C");
+ break;
+
+ case PVR_440GX_RA:
+ puts("GX Rev. A");
+ break;
+
+ case PVR_440GX_RB:
+ puts("GX Rev. B");
+ break;
+
+ case PVR_440GX_RC:
+ puts("GX Rev. C");
+ break;
+
+ case PVR_440GX_RF:
+ puts("GX Rev. F");
+ break;
+
+ case PVR_440EP_RA:
+ puts("EP Rev. A");
+ break;
+
+#ifdef CONFIG_440EP
+ case PVR_440EP_RB: /* 440EP rev B and 440GR rev A have same PVR */
+ puts("EP Rev. B");
+ break;
+#endif /* CONFIG_440EP */
+
+#ifdef CONFIG_440GR
+ case PVR_440GR_RA: /* 440EP rev B and 440GR rev A have same PVR */
+ puts("GR Rev. A");
+ break;
+#endif /* CONFIG_440GR */
+#endif /* CONFIG_440 */
+
+ case PVR_440SP_RA:
+ puts("SP Rev. A");
+ break;
+
+ case PVR_440SP_RB:
+ puts("SP Rev. B");
+ break;
+
+ default:
+ printf (" UNKNOWN (PVR=%08x)", pvr);
+ break;
+ }
+
+ printf (" at %s MHz (PLB=%lu, OPB=%lu, EBC=%lu MHz)\n", strmhz(buf, clock),
+ sys_info.freqPLB / 1000000,
+ sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,
+ FREQ_EBC / 1000000);
+
+#if defined(I2C_BOOTROM)
+ printf (" I2C boot EEPROM %sabled\n", i2c_bootrom_enabled() ? "en" : "dis");
+#endif
+
+#if defined(CONFIG_PCI)
+ printf (" Internal PCI arbiter %sabled", pci_arbiter_enabled() ? "en" : "dis");
+#endif
+
+#if defined(PCI_ASYNC)
+ if (pci_async_enabled()) {
+ printf (", PCI async ext clock used");
+ } else {
+ printf (", PCI sync clock at %lu MHz",
+ sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
+ }
+#endif
+
+#if defined(CONFIG_PCI)
+ putc('\n');
+#endif
+
+#if defined(CONFIG_405EP)
+ printf (" 16 kB I-Cache 16 kB D-Cache");
+#elif defined(CONFIG_440)
+ printf (" 32 kB I-Cache 32 kB D-Cache");
+#else
+ printf (" 16 kB I-Cache %d kB D-Cache",
+ ((pvr | 0x00000001) == PVR_405GPR_RB) ? 16 : 8);
+#endif
+#endif /* !defined(CONFIG_IOP480) */
+
+#if defined(CONFIG_IOP480)
+ printf ("PLX IOP480 (PVR=%08x)", pvr);
+ printf (" at %s MHz:", strmhz(buf, clock));
+ printf (" %u kB I-Cache", 4);
+ printf (" %u kB D-Cache", 2);
+#endif
+
+#endif /* !defined(CONFIG_405) */
+
+ putc ('\n');
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+#if defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE)
+ /*give reset to BCSR*/
+ *(unsigned char*)(CFG_BCSR_BASE | 0x06) = 0x09;
+
+#else
+
+ /*
+ * Initiate system reset in debug control register DBCR
+ */
+ __asm__ __volatile__("lis 3, 0x3000" ::: "r3");
+#if defined(CONFIG_440)
+ __asm__ __volatile__("mtspr 0x134, 3");
+#else
+ __asm__ __volatile__("mtspr 0x3f2, 3");
+#endif
+
+#endif/* defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE)*/
+ return 1;
+}
+
+#if defined(CONFIG_440)
+static int do_chip_reset (unsigned long sys0, unsigned long sys1)
+{
+ /* Changes to cpc0_sys0 and cpc0_sys1 require chip
+ * reset.
+ */
+ mtdcr (cntrl0, mfdcr (cntrl0) | 0x80000000); /* Set SWE */
+ mtdcr (cpc0_sys0, sys0);
+ mtdcr (cpc0_sys1, sys1);
+ mtdcr (cntrl0, mfdcr (cntrl0) & ~0x80000000); /* Clr SWE */
+ mtspr (dbcr0, 0x20000000); /* Reset the chip */
+
+ return 1;
+}
+#endif
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long get_tbclk (void)
+{
+#if !defined(CONFIG_IOP480)
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ return (sys_info.freqProcessor);
+#else
+ return (66000000);
+#endif
+
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void
+watchdog_reset(void)
+{
+ int re_enable = disable_interrupts();
+ reset_4xx_watchdog();
+ if (re_enable) enable_interrupts();
+}
+
+void
+reset_4xx_watchdog(void)
+{
+ /*
+ * Clear TSR(WIS) bit
+ */
+ mtspr(tsr, 0x40000000);
+}
+#endif /* CONFIG_WATCHDOG */
diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c
new file mode 100755
index 0000000..79cfba3
--- /dev/null
+++ b/cpu/ppc4xx/cpu_init.c
@@ -0,0 +1,268 @@
+/*
+ * (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 <ppc4xx_enet.h>
+#include <asm/processor.h>
+#include <ppc4xx.h>
+
+
+#define mtebc(reg, data) mtdcr(ebccfga,reg);mtdcr(ebccfgd,data)
+
+#ifdef CFG_INIT_DCACHE_CS
+# if (CFG_INIT_DCACHE_CS == 0)
+# define PBxAP pb0ap
+# define PBxCR pb0cr
+# if (defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR))
+# define PBxAP_VAL CFG_EBC_PB0AP
+# define PBxCR_VAL CFG_EBC_PB0CR
+# endif
+# endif
+# if (CFG_INIT_DCACHE_CS == 1)
+# define PBxAP pb1ap
+# define PBxCR pb1cr
+# if (defined(CFG_EBC_PB1AP) && defined(CFG_EBC_PB1CR))
+# define PBxAP_VAL CFG_EBC_PB1AP
+# define PBxCR_VAL CFG_EBC_PB1CR
+# endif
+# endif
+# if (CFG_INIT_DCACHE_CS == 2)
+# define PBxAP pb2ap
+# define PBxCR pb2cr
+# if (defined(CFG_EBC_PB2AP) && defined(CFG_EBC_PB2CR))
+# define PBxAP_VAL CFG_EBC_PB2AP
+# define PBxCR_VAL CFG_EBC_PB2CR
+# endif
+# endif
+# if (CFG_INIT_DCACHE_CS == 3)
+# define PBxAP pb3ap
+# define PBxCR pb3cr
+# if (defined(CFG_EBC_PB3AP) && defined(CFG_EBC_PB3CR))
+# define PBxAP_VAL CFG_EBC_PB3AP
+# define PBxCR_VAL CFG_EBC_PB3CR
+# endif
+# endif
+# if (CFG_INIT_DCACHE_CS == 4)
+# define PBxAP pb4ap
+# define PBxCR pb4cr
+# if (defined(CFG_EBC_PB4AP) && defined(CFG_EBC_PB4CR))
+# define PBxAP_VAL CFG_EBC_PB4AP
+# define PBxCR_VAL CFG_EBC_PB4CR
+# endif
+# endif
+# if (CFG_INIT_DCACHE_CS == 5)
+# define PBxAP pb5ap
+# define PBxCR pb5cr
+# if (defined(CFG_EBC_PB5AP) && defined(CFG_EBC_PB5CR))
+# define PBxAP_VAL CFG_EBC_PB5AP
+# define PBxCR_VAL CFG_EBC_PB5CR
+# endif
+# endif
+# if (CFG_INIT_DCACHE_CS == 6)
+# define PBxAP pb6ap
+# define PBxCR pb6cr
+# if (defined(CFG_EBC_PB6AP) && defined(CFG_EBC_PB6CR))
+# define PBxAP_VAL CFG_EBC_PB6AP
+# define PBxCR_VAL CFG_EBC_PB6CR
+# endif
+# endif
+# if (CFG_INIT_DCACHE_CS == 7)
+# define PBxAP pb7ap
+# define PBxCR pb7cr
+# if (defined(CFG_EBC_PB7AP) && defined(CFG_EBC_PB7CR))
+# define PBxAP_VAL CFG_EBC_PB7AP
+# define PBxCR_VAL CFG_EBC_PB7CR
+# endif
+# endif
+#endif /* CFG_INIT_DCACHE_CS */
+
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers
+ */
+void
+cpu_init_f (void)
+{
+#if defined(CONFIG_405EP)
+ /*
+ * GPIO0 setup (select GPIO or alternate function)
+ */
+ out32(GPIO0_OSRH, CFG_GPIO0_OSRH); /* output select */
+ out32(GPIO0_OSRL, CFG_GPIO0_OSRL);
+ out32(GPIO0_ISR1H, CFG_GPIO0_ISR1H); /* input select */
+ out32(GPIO0_ISR1L, CFG_GPIO0_ISR1L);
+ out32(GPIO0_TSRH, CFG_GPIO0_TSRH); /* three-state select */
+ out32(GPIO0_TSRL, CFG_GPIO0_TSRL);
+ out32(GPIO0_TCR, CFG_GPIO0_TCR); /* enable output driver for outputs */
+
+ /*
+ * Set EMAC noise filter bits
+ */
+ mtdcr(cpc0_epctl, CPC0_EPRCSR_E0NFE | CPC0_EPRCSR_E1NFE);
+#endif /* CONFIG_405EP */
+
+ /*
+ * External Bus Controller (EBC) Setup
+ */
+#if (defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR))
+ /*
+ * Move the next instructions into icache, since these modify the flash
+ * we are running from!
+ */
+ asm volatile(" bl 0f" ::: "lr");
+ asm volatile("0: mflr 3" ::: "r3");
+ asm volatile(" addi 4, 0, 14" ::: "r4");
+ asm volatile(" mtctr 4" ::: "ctr");
+ asm volatile("1: icbt 0, 3");
+ asm volatile(" addi 3, 3, 32" ::: "r3");
+ asm volatile(" bdnz 1b" ::: "ctr", "cr0");
+ asm volatile(" addis 3, 0, 0x0" ::: "r3");
+ asm volatile(" ori 3, 3, 0xA000" ::: "r3");
+ asm volatile(" mtctr 3" ::: "ctr");
+ asm volatile("2: bdnz 2b" ::: "ctr", "cr0");
+
+ mtebc(pb0ap, CFG_EBC_PB0AP);
+ mtebc(pb0cr, CFG_EBC_PB0CR);
+#endif
+
+#if (defined(CFG_EBC_PB1AP) && defined(CFG_EBC_PB1CR) && !(CFG_INIT_DCACHE_CS == 1))
+ mtebc(pb1ap, CFG_EBC_PB1AP);
+ mtebc(pb1cr, CFG_EBC_PB1CR);
+#endif
+
+#if (defined(CFG_EBC_PB2AP) && defined(CFG_EBC_PB2CR) && !(CFG_INIT_DCACHE_CS == 2))
+ mtebc(pb2ap, CFG_EBC_PB2AP);
+ mtebc(pb2cr, CFG_EBC_PB2CR);
+#endif
+
+#if (defined(CFG_EBC_PB3AP) && defined(CFG_EBC_PB3CR) && !(CFG_INIT_DCACHE_CS == 3))
+ mtebc(pb3ap, CFG_EBC_PB3AP);
+ mtebc(pb3cr, CFG_EBC_PB3CR);
+#endif
+
+#if (defined(CFG_EBC_PB4AP) && defined(CFG_EBC_PB4CR) && !(CFG_INIT_DCACHE_CS == 4))
+ mtebc(pb4ap, CFG_EBC_PB4AP);
+ mtebc(pb4cr, CFG_EBC_PB4CR);
+#endif
+
+#if (defined(CFG_EBC_PB5AP) && defined(CFG_EBC_PB5CR) && !(CFG_INIT_DCACHE_CS == 5))
+ mtebc(pb5ap, CFG_EBC_PB5AP);
+ mtebc(pb5cr, CFG_EBC_PB5CR);
+#endif
+
+#if (defined(CFG_EBC_PB6AP) && defined(CFG_EBC_PB6CR) && !(CFG_INIT_DCACHE_CS == 6))
+ mtebc(pb6ap, CFG_EBC_PB6AP);
+ mtebc(pb6cr, CFG_EBC_PB6CR);
+#endif
+
+#if (defined(CFG_EBC_PB7AP) && defined(CFG_EBC_PB7CR) && !(CFG_INIT_DCACHE_CS == 7))
+ mtebc(pb7ap, CFG_EBC_PB7AP);
+ mtebc(pb7cr, CFG_EBC_PB7CR);
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+ unsigned long val;
+
+ val = mfspr(tcr);
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ val |= 0xb8000000; /* generate system reset after 1.34 seconds */
+#else
+ val |= 0xf0000000; /* generate system reset after 2.684 seconds */
+#endif
+ mtspr(tcr, val);
+
+ val = mfspr(tsr);
+ val |= 0x80000000; /* enable watchdog timer */
+ mtspr(tsr, val);
+
+ reset_4xx_watchdog();
+#endif /* CONFIG_WATCHDOG */
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
+ DECLARE_GLOBAL_DATA_PTR;
+
+ bd_t *bd = gd->bd;
+ unsigned long reg;
+#if defined(CONFIG_405GP)
+ uint pvr = get_pvr();
+#endif
+
+#ifdef CFG_INIT_DCACHE_CS
+ /*
+ * Flush and invalidate dcache, then disable CS for temporary stack.
+ * Afterwards, this CS can be used for other purposes
+ */
+ dcache_disable(); /* flush and invalidate dcache */
+ mtebc(PBxAP, 0);
+ mtebc(PBxCR, 0); /* disable CS for temporary stack */
+
+#if (defined(PBxAP_VAL) && defined(PBxCR_VAL))
+ /*
+ * Write new value into CS register
+ */
+ mtebc(PBxAP, PBxAP_VAL);
+ mtebc(PBxCR, PBxCR_VAL);
+#endif
+#endif /* CFG_INIT_DCACHE_CS */
+
+ /*
+ * Write Ethernetaddress into on-chip register
+ */
+ reg = 0x00000000;
+ reg |= bd->bi_enetaddr[0]; /* set high address */
+ reg = reg << 8;
+ reg |= bd->bi_enetaddr[1];
+ out32 (EMAC_IAH, reg);
+
+ reg = 0x00000000;
+ reg |= bd->bi_enetaddr[2]; /* set low address */
+ reg = reg << 8;
+ reg |= bd->bi_enetaddr[3];
+ reg = reg << 8;
+ reg |= bd->bi_enetaddr[4];
+ reg = reg << 8;
+ reg |= bd->bi_enetaddr[5];
+ out32 (EMAC_IAL, reg);
+
+#if defined(CONFIG_405GP)
+ /*
+ * Set edge conditioning circuitry on PPC405GPr
+ * for compatibility to existing PPC405GP designs.
+ */
+ if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
+ mtdcr(ecr, 0x60606000);
+ }
+#endif /* defined(CONFIG_405GP) */
+#endif /* defined(CONFIG_405GP) || defined(CONFIG_405EP) */
+ return (0);
+}
diff --git a/cpu/ppc4xx/dcr.S b/cpu/ppc4xx/dcr.S
new file mode 100755
index 0000000..7102364
--- /dev/null
+++ b/cpu/ppc4xx/dcr.S
@@ -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>
+
+#if defined(CONFIG_4xx) && defined(CFG_CMD_SETGETDCR)
+
+#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>
+
+#define _ASMLANGUAGE
+
+/*****************************************************************************
+ *
+ * XXX - DANGER
+ * These routines make use of self modifying code. DO NOT CALL THEM
+ * UNTIL THEY ARE RELOCATED TO RAM. Additionally, I do not
+ * recommend them for use in anything other than an interactive
+ * debugging environment. This is mainly due to performance reasons.
+ *
+ ****************************************************************************/
+
+/*
+ * static void _create_MFDCR(unsigned short dcrn)
+ *
+ * Builds a 'mfdcr' instruction for get_dcr
+ * function.
+ */
+ .section ".text"
+ .align 2
+ .type _create_MFDCR,@function
+_create_MFDCR:
+ /*
+ * Build up a 'mfdcr' instruction formatted as follows:
+ *
+ * OPCD | RT | DCRF | XO | CR |
+ * ---------------|--------------|--------------|----|
+ * 0 5 | 6 10 | 11 20 | 21 30 | 31 |
+ * | | DCRN | | |
+ * 31 | %r3 | (5..9|0..4) | 323 | 0 |
+ *
+ * Where:
+ * OPCD = opcode - 31
+ * RT = destination register - %r3 return register
+ * DCRF = DCRN # with upper and lower halves swapped
+ * XO = extended opcode - 323
+ * CR = CR[CR0] NOT undefined - 0
+ */
+ rlwinm r0, r3, 27, 27, 31 /* OPCD = 31 */
+ rlwinm r3, r3, 5, 22, 26
+ or r3, r3, r0
+ slwi r3, r3, 10
+ oris r3, r3, 0x3e30 /* RT = %r3 */
+ ori r3, r3, 323 /* XO = 323 */
+ slwi r3, r3, 1 /* CR = 0 */
+
+ mflr r4
+ stw r3, 0(r4) /* Store instr in get_dcr() */
+ dcbst r0, r4 /* Make sure val is written out */
+ sync /* Wait for write to complete */
+ icbi r0, r4 /* Make sure old instr is dumped */
+ isync /* Wait for icbi to complete */
+
+ blr
+.Lfe1: .size _create_MFDCR,.Lfe1-_create_MFDCR
+/* end _create_MFDCR() */
+
+/*
+ * static void _create_MTDCR(unsigned short dcrn, unsigned long value)
+ *
+ * Builds a 'mtdcr' instruction for set_dcr
+ * function.
+ */
+ .section ".text"
+ .align 2
+ .type _create_MTDCR,@function
+_create_MTDCR:
+ /*
+ * Build up a 'mtdcr' instruction formatted as follows:
+ *
+ * OPCD | RS | DCRF | XO | CR |
+ * ---------------|--------------|--------------|----|
+ * 0 5 | 6 10 | 11 20 | 21 30 | 31 |
+ * | | DCRN | | |
+ * 31 | %r3 | (5..9|0..4) | 451 | 0 |
+ *
+ * Where:
+ * OPCD = opcode - 31
+ * RS = source register - %r4
+ * DCRF = dest. DCRN # with upper and lower halves swapped
+ * XO = extended opcode - 451
+ * CR = CR[CR0] NOT undefined - 0
+ */
+ rlwinm r0, r3, 27, 27, 31 /* OPCD = 31 */
+ rlwinm r3, r3, 5, 22, 26
+ or r3, r3, r0
+ slwi r3, r3, 10
+ oris r3, r3, 0x3e40 /* RS = %r4 */
+ ori r3, r3, 451 /* XO = 451 */
+ slwi r3, r3, 1 /* CR = 0 */
+
+ mflr r5
+ stw r3, 0(r5) /* Store instr in set_dcr() */
+ dcbst r0, r5 /* Make sure val is written out */
+ sync /* Wait for write to complete */
+ icbi r0, r5 /* Make sure old instr is dumped */
+ isync /* Wait for icbi to complete */
+
+ blr
+.Lfe2: .size _create_MTDCR,.Lfe2-_create_MTDCR
+/* end _create_MTDCR() */
+
+
+/*
+ * unsigned long get_dcr(unsigned short dcrn)
+ *
+ * Return a given DCR's value.
+ */
+ /* */
+ /* XXX - This is self modifying code, hence */
+ /* it is in the data section. */
+ /* */
+ .section ".data"
+ .align 2
+ .globl get_dcr
+ .type get_dcr,@function
+get_dcr:
+ mflr r0 /* Get link register */
+ stwu r1, -32(r1) /* Save back chain and move SP */
+ stw r0, +36(r1) /* Save link register */
+
+ bl _create_MFDCR /* Build following instruction */
+ /* XXX - we build this instuction up on the fly. */
+ .long 0 /* Get DCR's value */
+
+ lwz r0, +36(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +32 /* Remove frame from stack */
+ blr /* Return to calling function */
+.Lfe3: .size get_dcr,.Lfe3-get_dcr
+/* end get_dcr() */
+
+
+/*
+ * unsigned void set_dcr(unsigned short dcrn, unsigned long value)
+ *
+ * Return a given DCR's value.
+ */
+ /*
+ * XXX - This is self modifying code, hence
+ * it is in the data section.
+ */
+ .section ".data"
+ .align 2
+ .globl set_dcr
+ .type set_dcr,@function
+set_dcr:
+ mflr r0 /* Get link register */
+ stwu r1, -32(r1) /* Save back chain and move SP */
+ stw r0, +36(r1) /* Save link register */
+
+ bl _create_MTDCR /* Build following instruction */
+ /* XXX - we build this instuction up on the fly. */
+ .long 0 /* Set DCR's value */
+
+ lwz r0, +36(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +32 /* Remove frame from stack */
+ blr /* Return to calling function */
+.Lfe4: .size set_dcr,.Lfe4-set_dcr
+/* end set_dcr() */
+#endif /* CONFIG_4xx & CFG_CMD_SETGETDCR */
diff --git a/cpu/ppc4xx/i2c.c b/cpu/ppc4xx/i2c.c
new file mode 100755
index 0000000..be94b57
--- /dev/null
+++ b/cpu/ppc4xx/i2c.c
@@ -0,0 +1,445 @@
+/*****************************************************************************/
+/* I2C Bus interface initialisation and I2C Commands */
+/* for PPC405GP */
+/* Author : AS HARNOIS */
+/* Date : 13.Dec.00 */
+/*****************************************************************************/
+
+#include <common.h>
+#include <ppc4xx.h>
+#if defined(CONFIG_440)
+# include <440_i2c.h>
+#else
+# include <405gp_i2c.h>
+#endif
+#include <i2c.h>
+
+#ifdef CONFIG_HARD_I2C
+
+#define IIC_OK 0
+#define IIC_NOK 1
+#define IIC_NOK_LA 2 /* Lost arbitration */
+#define IIC_NOK_ICT 3 /* Incomplete transfer */
+#define IIC_NOK_XFRA 4 /* Transfer aborted */
+#define IIC_NOK_DATA 5 /* No data in buffer */
+#define IIC_NOK_TOUT 6 /* Transfer timeout */
+
+#define IIC_TIMEOUT 1 /* 1 seconde */
+
+
+static void _i2c_bus_reset (void)
+{
+ int i, status;
+
+ /* Reset status register */
+ /* write 1 in SCMP and IRQA to clear these fields */
+ out8 (IIC_STS, 0x0A);
+
+ /* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
+ out8 (IIC_EXTSTS, 0x8F);
+ __asm__ volatile ("eieio");
+
+ /*
+ * Get current state, reset bus
+ * only if no transfers are pending.
+ */
+ i = 10;
+ do {
+ /* Get status */
+ status = in8 (IIC_STS);
+ udelay (500); /* 500us */
+ i--;
+ } while ((status & IIC_STS_PT) && (i > 0));
+ /* Soft reset controller */
+ status = in8 (IIC_XTCNTLSS);
+ out8 (IIC_XTCNTLSS, (status | IIC_XTCNTLSS_SRST));
+ __asm__ volatile ("eieio");
+
+ /* make sure where in initial state, data hi, clock hi */
+ out8 (IIC_DIRECTCNTL, 0xC);
+ for (i = 0; i < 10; i++) {
+ if ((in8 (IIC_DIRECTCNTL) & 0x3) != 0x3) {
+ /* clock until we get to known state */
+ out8 (IIC_DIRECTCNTL, 0x8); /* clock lo */
+ udelay (100); /* 100us */
+ out8 (IIC_DIRECTCNTL, 0xC); /* clock hi */
+ udelay (100); /* 100us */
+ } else {
+ break;
+ }
+ }
+ /* send start condition */
+ out8 (IIC_DIRECTCNTL, 0x4);
+ udelay (1000); /* 1ms */
+ /* send stop condition */
+ out8 (IIC_DIRECTCNTL, 0xC);
+ udelay (1000); /* 1ms */
+ /* Unreset controller */
+ out8 (IIC_XTCNTLSS, (status & ~IIC_XTCNTLSS_SRST));
+ udelay (1000); /* 1ms */
+}
+
+void i2c_init (int speed, int slaveadd)
+{
+ sys_info_t sysInfo;
+ unsigned long freqOPB;
+ int val, divisor;
+
+#ifdef CFG_I2C_INIT_BOARD
+ /* call board specific i2c bus reset routine before accessing the */
+ /* environment, which might be in a chip on that bus. For details */
+ /* about this problem see doc/I2C_Edge_Conditions. */
+ i2c_init_board();
+#endif
+
+ /* Handle possible failed I2C state */
+ /* FIXME: put this into i2c_init_board()? */
+ _i2c_bus_reset ();
+
+ /* clear lo master address */
+ out8 (IIC_LMADR, 0);
+
+ /* clear hi master address */
+ out8 (IIC_HMADR, 0);
+
+ /* clear lo slave address */
+ out8 (IIC_LSADR, 0);
+
+ /* clear hi slave address */
+ out8 (IIC_HSADR, 0);
+
+ /* Clock divide Register */
+ /* get OPB frequency */
+ get_sys_info (&sysInfo);
+ freqOPB = sysInfo.freqPLB / sysInfo.pllOpbDiv;
+ /* set divisor according to freqOPB */
+ divisor = (freqOPB - 1) / 10000000;
+ if (divisor == 0)
+ divisor = 1;
+ out8 (IIC_CLKDIV, divisor);
+
+ /* no interrupts */
+ out8 (IIC_INTRMSK, 0);
+
+ /* clear transfer count */
+ out8 (IIC_XFRCNT, 0);
+
+ /* clear extended control & stat */
+ /* write 1 in SRC SRS SWC SWS to clear these fields */
+ out8 (IIC_XTCNTLSS, 0xF0);
+
+ /* Mode Control Register
+ Flush Slave/Master data buffer */
+ out8 (IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
+ __asm__ volatile ("eieio");
+
+
+ val = in8(IIC_MDCNTL);
+ __asm__ volatile ("eieio");
+
+ /* Ignore General Call, slave transfers are ignored,
+ disable interrupts, exit unknown bus state, enable hold
+ SCL
+ 100kHz normaly or FastMode for 400kHz and above
+ */
+
+ val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL;
+ if( speed >= 400000 ){
+ val |= IIC_MDCNTL_FSM;
+ }
+ out8 (IIC_MDCNTL, val);
+
+ /* clear control reg */
+ out8 (IIC_CNTL, 0x00);
+ __asm__ volatile ("eieio");
+
+}
+
+/*
+ This code tries to use the features of the 405GP i2c
+ controller. It will transfer up to 4 bytes in one pass
+ on the loop. It only does out8(lbz) to the buffer when it
+ is possible to do out16(lhz) transfers.
+
+ cmd_type is 0 for write 1 for read.
+
+ addr_len can take any value from 0-255, it is only limited
+ by the char, we could make it larger if needed. If it is
+ 0 we skip the address write cycle.
+
+ Typical case is a Write of an addr followd by a Read. The
+ IBM FAQ does not cover this. On the last byte of the write
+ we don't set the creg CHT bit, and on the first bytes of the
+ read we set the RPST bit.
+
+ It does not support address only transfers, there must be
+ a data part. If you want to write the address yourself, put
+ it in the data pointer.
+
+ It does not support transfer to/from address 0.
+
+ It does not check XFRCNT.
+*/
+static
+int i2c_transfer(unsigned char cmd_type,
+ unsigned char chip,
+ unsigned char addr[],
+ unsigned char addr_len,
+ unsigned char data[],
+ unsigned short data_len )
+{
+ unsigned char* ptr;
+ int reading;
+ int tran,cnt;
+ int result;
+ int status;
+ int i;
+ uchar creg;
+
+ if( data == 0 || data_len == 0 ){
+ /*Don't support data transfer of no length or to address 0*/
+ printf( "i2c_transfer: bad call\n" );
+ return IIC_NOK;
+ }
+ if( addr && addr_len ){
+ ptr = addr;
+ cnt = addr_len;
+ reading = 0;
+ }else{
+ ptr = data;
+ cnt = data_len;
+ reading = cmd_type;
+ }
+
+ /*Clear Stop Complete Bit*/
+ out8(IIC_STS,IIC_STS_SCMP);
+ /* Check init */
+ i=10;
+ do {
+ /* Get status */
+ status = in8(IIC_STS);
+ __asm__ volatile("eieio");
+ i--;
+ } while ((status & IIC_STS_PT) && (i>0));
+
+ if (status & IIC_STS_PT) {
+ result = IIC_NOK_TOUT;
+ return(result);
+ }
+ /*flush the Master/Slave Databuffers*/
+ out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB));
+ /*need to wait 4 OPB clocks? code below should take that long*/
+
+ /* 7-bit adressing */
+ out8(IIC_HMADR,0);
+ out8(IIC_LMADR, chip);
+ __asm__ volatile("eieio");
+
+ tran = 0;
+ result = IIC_OK;
+ creg = 0;
+
+ while ( tran != cnt && (result == IIC_OK)) {
+ int bc,j;
+
+ /* Control register =
+ Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start,
+ Transfer is a sequence of transfers
+ */
+ creg |= IIC_CNTL_PT;
+
+ bc = (cnt - tran) > 4 ? 4 :
+ cnt - tran;
+ creg |= (bc-1)<<4;
+ /* if the real cmd type is write continue trans*/
+ if ( (!cmd_type && (ptr == addr)) || ((tran+bc) != cnt) )
+ creg |= IIC_CNTL_CHT;
+
+ if (reading)
+ creg |= IIC_CNTL_READ;
+ else {
+ for(j=0; j<bc; j++) {
+ /* Set buffer */
+ out8(IIC_MDBUF,ptr[tran+j]);
+ __asm__ volatile("eieio");
+ }
+ }
+ out8(IIC_CNTL, creg );
+ __asm__ volatile("eieio");
+
+ /* Transfer is in progress
+ we have to wait for upto 5 bytes of data
+ 1 byte chip address+r/w bit then bc bytes
+ of data.
+ udelay(10) is 1 bit time at 100khz
+ Doubled for slop. 20 is too small.
+ */
+ i=2*5*8;
+ do {
+ /* Get status */
+ status = in8(IIC_STS);
+ __asm__ volatile("eieio");
+ udelay (10);
+ i--;
+ } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR)
+ && (i>0));
+
+ if (status & IIC_STS_ERR) {
+ result = IIC_NOK;
+ status = in8 (IIC_EXTSTS);
+ /* Lost arbitration? */
+ if (status & IIC_EXTSTS_LA)
+ result = IIC_NOK_LA;
+ /* Incomplete transfer? */
+ if (status & IIC_EXTSTS_ICT)
+ result = IIC_NOK_ICT;
+ /* Transfer aborted? */
+ if (status & IIC_EXTSTS_XFRA)
+ result = IIC_NOK_XFRA;
+ } else if ( status & IIC_STS_PT) {
+ result = IIC_NOK_TOUT;
+ }
+ /* Command is reading => get buffer */
+ if ((reading) && (result == IIC_OK)) {
+ /* Are there data in buffer */
+ if (status & IIC_STS_MDBS) {
+ /*
+ even if we have data we have to wait 4OPB clocks
+ for it to hit the front of the FIFO, after that
+ we can just read. We should check XFCNT here and
+ if the FIFO is full there is no need to wait.
+ */
+ udelay (1);
+ for(j=0;j<bc;j++) {
+ ptr[tran+j] = in8(IIC_MDBUF);
+ __asm__ volatile("eieio");
+ }
+ } else
+ result = IIC_NOK_DATA;
+ }
+ creg = 0;
+ tran+=bc;
+ if( ptr == addr && tran == cnt ) {
+ ptr = data;
+ cnt = data_len;
+ tran = 0;
+ reading = cmd_type;
+ if( reading )
+ creg = IIC_CNTL_RPST;
+ }
+ }
+ return (result);
+}
+
+int i2c_probe (uchar chip)
+{
+ uchar buf[1];
+
+ buf[0] = 0;
+
+ /*
+ * What is needed is to send the chip address and verify that the
+ * address was <ACK>ed (i.e. there was a chip at that address which
+ * drove the data line low).
+ */
+ return(i2c_transfer (1, chip << 1, 0,0, buf, 1) != 0);
+}
+
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+ uchar xaddr[4];
+ int ret;
+ DECLARE_GLOBAL_DATA_PTR;
+
+ if ( alen > 4 ) {
+ printf ("I2C read: addr len %d not supported\n", alen);
+ return 1;
+ }
+
+ if ( alen > 0 ) {
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+ }
+
+
+#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.
+ */
+ if( alen > 0 )
+ chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+ if( (ret = i2c_transfer( 1, chip<<1, &xaddr[4-alen], alen, buffer, len )) != 0) {
+ if (gd->have_console)
+ printf( "I2c read: failed %d\n", ret);
+ return 1;
+ }
+ return 0;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+ uchar xaddr[4];
+
+ if ( alen > 4 ) {
+ printf ("I2C write: addr len %d not supported\n", alen);
+ return 1;
+
+ }
+ if ( alen > 0 ) {
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+ }
+
+#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.
+ */
+ if( alen > 0 )
+ chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+ return (i2c_transfer( 0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0);
+}
+
+/*-----------------------------------------------------------------------
+ * Read a register
+ */
+uchar i2c_reg_read(uchar i2c_addr, uchar reg)
+{
+ uchar 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_HARD_I2C */
diff --git a/cpu/ppc4xx/interrupts.c b/cpu/ppc4xx/interrupts.c
new file mode 100755
index 0000000..1d8dc7c
--- /dev/null
+++ b/cpu/ppc4xx/interrupts.c
@@ -0,0 +1,571 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 (440GX port)
+ * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.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 <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include "vecnum.h"
+
+/****************************************************************************/
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ int count;
+};
+
+static struct irq_action irq_vecs[32];
+
+#if defined(CONFIG_440)
+static struct irq_action irq_vecs1[32]; /* For UIC1 */
+
+void uic1_interrupt( void * parms); /* UIC1 handler */
+
+#if defined(CONFIG_440GX)
+static struct irq_action irq_vecs2[32]; /* For UIC2 */
+
+void uic0_interrupt( void * parms); /* UIC0 handler */
+void uic2_interrupt( void * parms); /* UIC2 handler */
+#endif /* CONFIG_440GX */
+
+#endif /* CONFIG_440 */
+
+/****************************************************************************/
+#if defined(CONFIG_440)
+
+/* SPRN changed in 440 */
+static __inline__ void set_evpr(unsigned long val)
+{
+ asm volatile("mtspr 0x03f,%0" : : "r" (val));
+}
+
+#else /* !defined(CONFIG_440) */
+
+static __inline__ void set_pit(unsigned long val)
+{
+ asm volatile("mtpit %0" : : "r" (val));
+}
+
+
+static __inline__ void set_tcr(unsigned long val)
+{
+ asm volatile("mttcr %0" : : "r" (val));
+}
+
+
+static __inline__ void set_evpr(unsigned long val)
+{
+ asm volatile("mtevpr %0" : : "r" (val));
+}
+#endif /* defined(CONFIG_440 */
+
+/****************************************************************************/
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ int vec;
+ unsigned long val;
+
+ /* decrementer is automatically reloaded */
+ *decrementer_count = 0;
+
+ /*
+ * Mark all irqs as free
+ */
+ for (vec=0; vec<32; vec++) {
+ irq_vecs[vec].handler = NULL;
+ irq_vecs[vec].arg = NULL;
+ irq_vecs[vec].count = 0;
+#if defined(CONFIG_440)
+ irq_vecs1[vec].handler = NULL;
+ irq_vecs1[vec].arg = NULL;
+ irq_vecs1[vec].count = 0;
+#if defined(CONFIG_440GX)
+ irq_vecs2[vec].handler = NULL;
+ irq_vecs2[vec].arg = NULL;
+ irq_vecs2[vec].count = 0;
+#endif /* CONFIG_440GX */
+#endif
+ }
+
+#ifdef CONFIG_4xx
+ /*
+ * Init PIT
+ */
+#if defined(CONFIG_440)
+ val = mfspr( tcr );
+ val &= (~0x04400000); /* clear DIS & ARE */
+ mtspr( tcr, val );
+ mtspr( dec, 0 ); /* Prevent exception after TSR clear*/
+ mtspr( decar, 0 ); /* clear reload */
+ mtspr( tsr, 0x08000000 ); /* clear DEC status */
+ val = gd->bd->bi_intfreq/1000; /* 1 msec */
+ mtspr( decar, val ); /* Set auto-reload value */
+ mtspr( dec, val ); /* Set inital val */
+#else
+ set_pit(gd->bd->bi_intfreq / 1000);
+#endif
+#endif /* CONFIG_4xx */
+
+#ifdef CONFIG_ADCIOP
+ /*
+ * Init PIT
+ */
+ set_pit(66000);
+#endif
+
+ /*
+ * Enable PIT
+ */
+ val = mfspr(tcr);
+ val |= 0x04400000;
+ mtspr(tcr, val);
+
+ /*
+ * Set EVPR to 0
+ */
+ set_evpr(0x00000000);
+
+#if defined(CONFIG_440)
+#if !defined(CONFIG_440GX)
+ /* Install the UIC1 handlers */
+ irq_install_handler(VECNUM_UIC1NC, uic1_interrupt, 0);
+ irq_install_handler(VECNUM_UIC1C, uic1_interrupt, 0);
+#endif
+#endif
+
+#if defined(CONFIG_440GX)
+ /* Take the GX out of compatibility mode
+ * Travis Sawyer, 9 Mar 2004
+ * NOTE: 440gx user manual inconsistency here
+ * Compatibility mode and Ethernet Clock select are not
+ * correct in the manual
+ */
+ mfsdr(sdr_mfr, val);
+ val &= ~0x10000000;
+ mtsdr(sdr_mfr,val);
+
+ /* Enable UIC interrupts via UIC Base Enable Register */
+ mtdcr(uicb0sr, UICB0_ALL);
+ mtdcr(uicb0er, 0x54000000);
+ /* None are critical */
+ mtdcr(uicb0cr, 0);
+#endif
+
+ return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+#if defined(CONFIG_440GX)
+void external_interrupt(struct pt_regs *regs)
+{
+ ulong uic_msr;
+
+ /*
+ * Read masked interrupt status register to determine interrupt source
+ */
+ /* 440 GX uses base uic register */
+ uic_msr = mfdcr(uicb0msr);
+
+ if ( (UICB0_UIC0CI & uic_msr) || (UICB0_UIC0NCI & uic_msr) )
+ uic0_interrupt(0);
+
+ if ( (UICB0_UIC1CI & uic_msr) || (UICB0_UIC1NCI & uic_msr) )
+ uic1_interrupt(0);
+
+ if ( (UICB0_UIC2CI & uic_msr) || (UICB0_UIC2NCI & uic_msr) )
+ uic2_interrupt(0);
+
+ mtdcr(uicb0sr, uic_msr);
+
+ return;
+
+} /* external_interrupt CONFIG_440GX */
+
+#else
+
+void external_interrupt(struct pt_regs *regs)
+{
+ ulong uic_msr;
+ ulong msr_shift;
+ int vec;
+
+ /*
+ * Read masked interrupt status register to determine interrupt source
+ */
+ uic_msr = mfdcr(uicmsr);
+ msr_shift = uic_msr;
+ vec = 0;
+
+ while (msr_shift != 0) {
+ if (msr_shift & 0x80000000) {
+ /*
+ * Increment irq counter (for debug purpose only)
+ */
+ irq_vecs[vec].count++;
+
+ if (irq_vecs[vec].handler != NULL) {
+ /* call isr */
+ (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
+ } else {
+ mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
+ printf ("Masking bogus interrupt vector 0x%x\n", vec);
+ }
+
+ /*
+ * After servicing the interrupt, we have to remove the status indicator.
+ */
+ mtdcr(uicsr, (0x80000000 >> vec));
+ }
+
+ /*
+ * Shift msr to next position and increment vector
+ */
+ msr_shift <<= 1;
+ vec++;
+ }
+}
+#endif
+
+#if defined(CONFIG_440GX)
+/* Handler for UIC0 interrupt */
+void uic0_interrupt( void * parms)
+{
+ ulong uic_msr;
+ ulong msr_shift;
+ int vec;
+
+ /*
+ * Read masked interrupt status register to determine interrupt source
+ */
+ uic_msr = mfdcr(uicmsr);
+ msr_shift = uic_msr;
+ vec = 0;
+
+ while (msr_shift != 0) {
+ if (msr_shift & 0x80000000) {
+ /*
+ * Increment irq counter (for debug purpose only)
+ */
+ irq_vecs[vec].count++;
+
+ if (irq_vecs[vec].handler != NULL) {
+ /* call isr */
+ (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
+ } else {
+ mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
+ printf ("Masking bogus interrupt vector (uic0) 0x%x\n", vec);
+ }
+
+ /*
+ * After servicing the interrupt, we have to remove the status indicator.
+ */
+ mtdcr(uicsr, (0x80000000 >> vec));
+ }
+
+ /*
+ * Shift msr to next position and increment vector
+ */
+ msr_shift <<= 1;
+ vec++;
+ }
+}
+
+#endif /* CONFIG_440GX */
+
+#if defined(CONFIG_440)
+/* Handler for UIC1 interrupt */
+void uic1_interrupt( void * parms)
+{
+ ulong uic1_msr;
+ ulong msr_shift;
+ int vec;
+
+ /*
+ * Read masked interrupt status register to determine interrupt source
+ */
+ uic1_msr = mfdcr(uic1msr);
+ msr_shift = uic1_msr;
+ vec = 0;
+
+ while (msr_shift != 0) {
+ if (msr_shift & 0x80000000) {
+ /*
+ * Increment irq counter (for debug purpose only)
+ */
+ irq_vecs1[vec].count++;
+
+ if (irq_vecs1[vec].handler != NULL) {
+ /* call isr */
+ (*irq_vecs1[vec].handler)(irq_vecs1[vec].arg);
+ } else {
+ mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> vec));
+ printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
+ }
+
+ /*
+ * After servicing the interrupt, we have to remove the status indicator.
+ */
+ mtdcr(uic1sr, (0x80000000 >> vec));
+ }
+
+ /*
+ * Shift msr to next position and increment vector
+ */
+ msr_shift <<= 1;
+ vec++;
+ }
+}
+#endif /* defined(CONFIG_440) */
+
+#if defined(CONFIG_440GX)
+/* Handler for UIC1 interrupt */
+void uic2_interrupt( void * parms)
+{
+ ulong uic2_msr;
+ ulong msr_shift;
+ int vec;
+
+ /*
+ * Read masked interrupt status register to determine interrupt source
+ */
+ uic2_msr = mfdcr(uic2msr);
+ msr_shift = uic2_msr;
+ vec = 0;
+
+ while (msr_shift != 0) {
+ if (msr_shift & 0x80000000) {
+ /*
+ * Increment irq counter (for debug purpose only)
+ */
+ irq_vecs2[vec].count++;
+
+ if (irq_vecs2[vec].handler != NULL) {
+ /* call isr */
+ (*irq_vecs2[vec].handler)(irq_vecs2[vec].arg);
+ } else {
+ mtdcr(uic2er, mfdcr(uic2er) & ~(0x80000000 >> vec));
+ printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
+ }
+
+ /*
+ * After servicing the interrupt, we have to remove the status indicator.
+ */
+ mtdcr(uic2sr, (0x80000000 >> vec));
+ }
+
+ /*
+ * Shift msr to next position and increment vector
+ */
+ msr_shift <<= 1;
+ vec++;
+ }
+}
+#endif /* defined(CONFIG_440GX) */
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
+{
+ struct irq_action *irqa = irq_vecs;
+ int i = vec;
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_440GX)
+ if ((vec > 31) && (vec < 64)) {
+ i = vec - 32;
+ irqa = irq_vecs1;
+ } else if (vec > 63) {
+ i = vec - 64;
+ irqa = irq_vecs2;
+ }
+#else /* CONFIG_440GX */
+ if (vec > 31) {
+ i = vec - 32;
+ irqa = irq_vecs1;
+ }
+#endif /* CONFIG_440GX */
+#endif /* CONFIG_440 */
+
+ /*
+ * print warning when replacing with a different irq vector
+ */
+ if ((irqa[i].handler != NULL) && (irqa[i].handler != handler)) {
+ printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
+ vec, (uint) handler, (uint) irqa[i].handler);
+ }
+ irqa[i].handler = handler;
+ irqa[i].arg = arg;
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_440GX)
+ if ((vec > 31) && (vec < 64))
+ mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
+ else if (vec > 63)
+ mtdcr (uic2er, mfdcr (uic2er) | (0x80000000 >> i));
+ else
+#endif /* CONFIG_440GX */
+ if (vec > 31)
+ mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
+ else
+#endif
+ mtdcr (uicer, mfdcr (uicer) | (0x80000000 >> i));
+#if 0
+ printf ("Install interrupt for vector %d ==> %p\n", vec, handler);
+#endif
+}
+
+void irq_free_handler (int vec)
+{
+ struct irq_action *irqa = irq_vecs;
+ int i = vec;
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_440GX)
+ if ((vec > 31) && (vec < 64)) {
+ irqa = irq_vecs1;
+ i = vec - 32;
+ } else if (vec > 63) {
+ irqa = irq_vecs2;
+ i = vec - 64;
+ }
+#endif /* CONFIG_440GX */
+ if (vec > 31) {
+ irqa = irq_vecs1;
+ i = vec - 32;
+ }
+#endif
+
+#if 0
+ printf ("Free interrupt for vector %d ==> %p\n",
+ vec, irq_vecs[vec].handler);
+#endif
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_440GX)
+ if ((vec > 31) && (vec < 64))
+ mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
+ else if (vec > 63)
+ mtdcr (uic2er, mfdcr (uic2er) & ~(0x80000000 >> i));
+ else
+#endif /* CONFIG_440GX */
+ if (vec > 31)
+ mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
+ else
+#endif
+ mtdcr (uicer, mfdcr (uicer) & ~(0x80000000 >> i));
+
+ irqa[i].handler = NULL;
+ irqa[i].arg = NULL;
+}
+
+/****************************************************************************/
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+/****************************************************************************/
+
+#if (CONFIG_COMMANDS & CFG_CMD_IRQ)
+
+/*******************************************************************************
+ *
+ * irqinfo - print information about PCI devices
+ *
+ */
+int
+do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int vec;
+
+ printf ("\nInterrupt-Information:\n");
+#if defined(CONFIG_440)
+ printf ("\nUIC 0\n");
+#endif
+ printf ("Nr Routine Arg Count\n");
+
+ for (vec=0; vec<32; vec++) {
+ if (irq_vecs[vec].handler != NULL) {
+ printf ("%02d %08lx %08lx %d\n",
+ vec,
+ (ulong)irq_vecs[vec].handler,
+ (ulong)irq_vecs[vec].arg,
+ irq_vecs[vec].count);
+ }
+ }
+
+#if defined(CONFIG_440)
+ printf ("\nUIC 1\n");
+ printf ("Nr Routine Arg Count\n");
+
+ for (vec=0; vec<32; vec++) {
+ if (irq_vecs1[vec].handler != NULL)
+ printf ("%02d %08lx %08lx %d\n",
+ vec+31, (ulong)irq_vecs1[vec].handler,
+ (ulong)irq_vecs1[vec].arg, irq_vecs1[vec].count);
+ }
+ printf("\n");
+#endif
+
+#if defined(CONFIG_440GX)
+ printf ("\nUIC 2\n");
+ printf ("Nr Routine Arg Count\n");
+
+ for (vec=0; vec<32; vec++) {
+ if (irq_vecs2[vec].handler != NULL)
+ printf ("%02d %08lx %08lx %d\n",
+ vec+63, (ulong)irq_vecs2[vec].handler,
+ (ulong)irq_vecs2[vec].arg, irq_vecs2[vec].count);
+ }
+ printf("\n");
+#endif
+
+ return 0;
+}
+#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */
diff --git a/cpu/ppc4xx/kgdb.S b/cpu/ppc4xx/kgdb.S
new file mode 100755
index 0000000..be28340
--- /dev/null
+++ b/cpu/ppc4xx/kgdb.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * 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 <command.h>
+#include <ppc4xx.h>
+#include <version.h>
+
+#define CONFIG_405GP 1 /* needed for Linux kernel header files */
+#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>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ /*
+ * cache flushing routines for kgdb
+ */
+
+ .globl kgdb_flush_cache_all
+kgdb_flush_cache_all:
+ /* icache */
+ iccci r0,r0 /* iccci invalidates the entire I cache */
+ /* dcache */
+ addi r6,0,0x0000 /* clear GPR 6 */
+ addi r7,r0, 128 /* do loop for # of dcache lines */
+ /* NOTE: dccci invalidates both */
+ mtctr r7 /* ways in the D cache */
+..dcloop:
+ dccci 0,r6 /* invalidate line */
+ addi r6,r6, 32 /* bump to next line */
+ bdnz ..dcloop
+ blr
+
+ .globl kgdb_flush_cache_range
+kgdb_flush_cache_range:
+ li r5,CFG_CACHELINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,CFG_CACHELINE_SHIFT
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CFG_CACHELINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CFG_CACHELINE_SIZE
+ bdnz 2b
+ SYNC
+ blr
+
+#endif /* CFG_CMD_KGDB */
diff --git a/cpu/ppc4xx/miiphy.c b/cpu/ppc4xx/miiphy.c
new file mode 100755
index 0000000..f26f2a2
--- /dev/null
+++ b/cpu/ppc4xx/miiphy.c
@@ -0,0 +1,260 @@
+/*-----------------------------------------------------------------------------+
+ |
+ | 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
+ +-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------+
+ |
+ | File Name: miiphy.c
+ |
+ | Function: This module has utilities for accessing the MII PHY through
+ | the EMAC3 macro.
+ |
+ | Author: Mark Wisner
+ |
+ | Change Activity-
+ |
+ | Date Description of Change BY
+ | --------- --------------------- ---
+ | 05-May-99 Created MKW
+ | 01-Jul-99 Changed clock setting of sta_reg from 66Mhz to 50Mhz to
+ | better match OPB speed. Also modified delay times. JWB
+ | 29-Jul-99 Added Full duplex support MKW
+ | 24-Aug-99 Removed printf from dp83843_duplex() JWB
+ | 19-Jul-00 Ported to esd cpci405 sr
+ | 23-Dec-03 Ported from miiphy.c to 440GX Travis Sawyer TBS
+ | <travis.sawyer@sandburst.com>
+ |
+ +-----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <asm/processor.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include <ppc4xx_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+
+
+/***********************************************************/
+/* Dump out to the screen PHY regs */
+/***********************************************************/
+
+void miiphy_dump (char *devname, unsigned char addr)
+{
+ unsigned long i;
+ unsigned short data;
+
+
+ for (i = 0; i < 0x1A; i++) {
+ if (miiphy_read (devname, addr, i, &data)) {
+ printf ("read error for reg %lx\n", i);
+ return;
+ }
+ printf ("Phy reg %lx ==> %4x\n", i, data);
+
+ /* jump to the next set of regs */
+ if (i == 0x07)
+ i = 0x0f;
+
+ } /* end for loop */
+} /* end dump */
+
+
+/***********************************************************/
+/* (Re)start autonegotiation */
+/***********************************************************/
+int phy_setup_aneg (char *devname, unsigned char addr)
+{
+ unsigned short ctl, adv;
+
+ /* Setup standard advertise */
+ miiphy_read (devname, addr, PHY_ANAR, &adv);
+ adv |= (PHY_ANLPAR_ACK | PHY_ANLPAR_RF | PHY_ANLPAR_T4 |
+ PHY_ANLPAR_TXFD | PHY_ANLPAR_TX | PHY_ANLPAR_10FD |
+ PHY_ANLPAR_10);
+ miiphy_write (devname, addr, PHY_ANAR, adv);
+
+ /* Start/Restart aneg */
+ miiphy_read (devname, addr, PHY_BMCR, &ctl);
+ ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+ miiphy_write (devname, addr, PHY_BMCR, ctl);
+
+ return 0;
+}
+
+
+/***********************************************************/
+/* read a phy reg and return the value with a rc */
+/***********************************************************/
+unsigned int miiphy_getemac_offset (void)
+{
+#if (defined(CONFIG_440) && !defined(CONFIG_440SP)) && defined(CONFIG_NET_MULTI)
+ unsigned long zmii;
+ unsigned long eoffset;
+
+ /* Need to find out which mdi port we're using */
+ zmii = in32 (ZMII_FER);
+
+ if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0))) {
+ /* using port 0 */
+ eoffset = 0;
+ } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1))) {
+ /* using port 1 */
+ eoffset = 0x100;
+ } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2))) {
+ /* using port 2 */
+ eoffset = 0x400;
+ } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3))) {
+ /* using port 3 */
+ eoffset = 0x600;
+ } else {
+ /* None of the mdi ports are enabled! */
+ /* enable port 0 */
+ zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
+ out32 (ZMII_FER, zmii);
+ eoffset = 0;
+ /* need to soft reset port 0 */
+ zmii = in32 (EMAC_M0);
+ zmii |= EMAC_M0_SRST;
+ out32 (EMAC_M0, zmii);
+ }
+
+ return (eoffset);
+#else
+ return 0;
+#endif
+}
+
+
+int emac4xx_miiphy_read (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ unsigned long sta_reg; /* STA scratch area */
+ unsigned long i;
+ unsigned long emac_reg;
+
+
+ emac_reg = miiphy_getemac_offset ();
+ /* see if it is ready for 1000 nsec */
+ i = 0;
+
+ /* see if it is ready for sec */
+ while ((in32 (EMAC_STACR + emac_reg) & EMAC_STACR_OC) == 0) {
+ udelay (7);
+ if (i > 5) {
+#if 0
+ printf ("read err 1\n");
+#endif
+ return -1;
+ }
+ i++;
+ }
+ sta_reg = reg; /* reg address */
+ /* set clock (50Mhz) and read flags */
+#if defined(CONFIG_440GX)
+ sta_reg |= EMAC_STACR_READ;
+#else
+ sta_reg = (sta_reg | EMAC_STACR_READ) & ~EMAC_STACR_CLK_100MHZ;
+#endif
+
+#if defined(CONFIG_PHY_CLK_FREQ) && !defined(CONFIG_440GX)
+ sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
+#endif
+ sta_reg = sta_reg | (addr << 5); /* Phy address */
+
+ out32 (EMAC_STACR + emac_reg, sta_reg);
+#if 0 /* test-only */
+ printf ("a2: write: EMAC_STACR=0x%0x\n", sta_reg); /* test-only */
+#endif
+
+ sta_reg = in32 (EMAC_STACR + emac_reg);
+ i = 0;
+ while ((sta_reg & EMAC_STACR_OC) == 0) {
+ udelay (7);
+ if (i > 5) {
+ return -1;
+ }
+ i++;
+ sta_reg = in32 (EMAC_STACR + emac_reg);
+ }
+ if ((sta_reg & EMAC_STACR_PHYE) != 0) {
+ return -1;
+ }
+
+ *value = *(short *) (&sta_reg);
+ return 0;
+
+
+} /* phy_read */
+
+
+/***********************************************************/
+/* write a phy reg and return the value with a rc */
+/***********************************************************/
+
+int emac4xx_miiphy_write (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ unsigned long sta_reg; /* STA scratch area */
+ unsigned long i;
+ unsigned long emac_reg;
+
+ emac_reg = miiphy_getemac_offset ();
+ /* see if it is ready for 1000 nsec */
+ i = 0;
+
+ while ((in32 (EMAC_STACR + emac_reg) & EMAC_STACR_OC) == 0) {
+ if (i > 5)
+ return -1;
+ udelay (7);
+ i++;
+ }
+ sta_reg = 0;
+ sta_reg = reg; /* reg address */
+ /* set clock (50Mhz) and read flags */
+#if defined(CONFIG_440GX)
+ sta_reg |= EMAC_STACR_WRITE;
+#else
+ sta_reg = (sta_reg | EMAC_STACR_WRITE) & ~EMAC_STACR_CLK_100MHZ;
+#endif
+
+#if defined(CONFIG_PHY_CLK_FREQ) && !defined(CONFIG_440GX)
+ sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ; /* Set clock frequency (PLB freq. dependend) */
+#endif
+ sta_reg = sta_reg | ((unsigned long) addr << 5); /* Phy address */
+ memcpy (&sta_reg, &value, 2); /* put in data */
+
+ out32 (EMAC_STACR + emac_reg, sta_reg);
+
+ /* wait for completion */
+ i = 0;
+ sta_reg = in32 (EMAC_STACR + emac_reg);
+ while ((sta_reg & EMAC_STACR_OC) == 0) {
+ udelay (7);
+ if (i > 5)
+ return -1;
+ i++;
+ sta_reg = in32 (EMAC_STACR + emac_reg);
+ }
+
+ if ((sta_reg & EMAC_STACR_PHYE) != 0)
+ return -1;
+ return 0;
+
+} /* phy_write */
diff --git a/cpu/ppc4xx/resetvec.S b/cpu/ppc4xx/resetvec.S
new file mode 100755
index 0000000..b3308bd
--- /dev/null
+++ b/cpu/ppc4xx/resetvec.S
@@ -0,0 +1,12 @@
+/* Copyright MontaVista Software Incorporated, 2000 */
+#include <config.h>
+ .section .resetvec,"ax"
+#if defined(CONFIG_440)
+ b _start_440
+#else
+#if defined(CONFIG_BOOT_PCI) && defined(CONFIG_MIP405)
+ b _start_pci
+#else
+ b _start
+#endif
+#endif
diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c
new file mode 100755
index 0000000..e9548cd
--- /dev/null
+++ b/cpu/ppc4xx/sdram.c
@@ -0,0 +1,178 @@
+/*
+ * (C) Copyright 2005
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2002-2004
+ * 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>
+
+
+#ifdef CONFIG_SDRAM_BANK0
+
+
+#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data)
+
+
+struct sdram_conf_s {
+ unsigned long size;
+ unsigned long reg;
+};
+
+typedef struct sdram_conf_s sdram_conf_t;
+
+#ifndef CFG_SDRAM_TABLE
+sdram_conf_t mb0cf[] = {
+ {(128 << 20), 0x000A4001}, /* (0-128MB) Address Mode 3, 13x10(4) */
+ {(64 << 20), 0x00084001}, /* (0-64MB) Address Mode 3, 13x9(4) */
+ {(32 << 20), 0x00062001}, /* (0-32MB) Address Mode 2, 12x9(4) */
+ {(16 << 20), 0x00046001}, /* (0-16MB) Address Mode 4, 12x8(4) */
+ {(4 << 20), 0x00008001}, /* (0-4MB) Address Mode 5, 11x8(2) */
+};
+#else
+sdram_conf_t mb0cf[] = CFG_SDRAM_TABLE;
+#endif
+
+#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0]))
+
+
+#ifndef CONFIG_440
+
+/*
+ * Autodetect onboard SDRAM on 405 platforms
+ */
+void sdram_init(void)
+{
+ ulong sdtr1;
+ ulong rtr;
+ int i;
+
+ /*
+ * Support for 100MHz and 133MHz SDRAM
+ */
+ if (get_bus_freq(0) > 100000000) {
+ /*
+ * 133 MHz SDRAM
+ */
+ sdtr1 = 0x01074015;
+ rtr = 0x07f00000;
+ } else {
+ /*
+ * default: 100 MHz SDRAM
+ */
+ sdtr1 = 0x0086400d;
+ rtr = 0x05f00000;
+ }
+
+ for (i=0; i<N_MB0CF; i++) {
+ /*
+ * Disable memory controller.
+ */
+ mtsdram0(mem_mcopt1, 0x00000000);
+
+ /*
+ * Set MB0CF for bank 0.
+ */
+ mtsdram0(mem_mb0cf, mb0cf[i].reg);
+ mtsdram0(mem_sdtr1, sdtr1);
+ mtsdram0(mem_rtr, rtr);
+
+ udelay(200);
+
+ /*
+ * Set memory controller options reg, MCOPT1.
+ * Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
+ * read/prefetch.
+ */
+ mtsdram0(mem_mcopt1, 0x80800000);
+
+ udelay(10000);
+
+ if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
+ /*
+ * OK, size detected -> all done
+ */
+ return;
+ }
+ }
+}
+
+#else /* CONFIG_440 */
+
+/*
+ * Autodetect onboard DDR SDRAM on 440 platforms
+ *
+ * NOTE: Some of the hardcoded values are hardware dependant,
+ * so this should be extended for other future boards
+ * using this routine!
+ */
+long int initdram(int board_type)
+{
+ int i;
+
+ for (i=0; i<N_MB0CF; i++) {
+ /*
+ * Disable memory controller.
+ */
+ mtsdram(mem_cfg0, 0x00000000);
+
+ /*
+ * 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 */
+
+ /*
+ * Following for CAS Latency = 2.5 @ 133 MHz PLB
+ */
+ mtsdram(mem_b0cr, mb0cf[i].reg);
+ mtsdram(mem_tr0, 0x41094012);
+ mtsdram(mem_tr1, 0x80800800); /* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/
+ mtsdram(mem_rtr, 0x7e000000); /* Interval 15.20µs @ 133MHz 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 */
+ udelay(10000);
+
+ if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
+ /*
+ * OK, size detected -> all done
+ */
+ return mb0cf[i].size;
+ }
+ }
+
+ return 0; /* nothing found ! */
+}
+
+#endif /* CONFIG_440 */
+
+#endif /* CONFIG_SDRAM_BANK0 */
diff --git a/cpu/ppc4xx/serial.c b/cpu/ppc4xx/serial.c
new file mode 100755
index 0000000..e7f6bcb
--- /dev/null
+++ b/cpu/ppc4xx/serial.c
@@ -0,0 +1,1064 @@
+/*
+ * (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
+ */
+/*------------------------------------------------------------------------------+ */
+/*
+ * 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
+ */
+/*------------------------------------------------------------------------------- */
+/*
+ * Travis Sawyer 15 September 2004
+ * Added CONFIG_SERIAL_MULTI support
+ */
+#include <common.h>
+#include <commproc.h>
+#include <asm/processor.h>
+#include <watchdog.h>
+#include "vecnum.h"
+
+#ifdef CONFIG_SERIAL_MULTI
+#include <serial.h>
+#endif
+
+#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
+#include <malloc.h>
+#endif
+
+/*****************************************************************************/
+#ifdef CONFIG_IOP480
+
+#define SPU_BASE 0x40000000
+
+#define spu_LineStat_rc 0x00 /* Line Status Register (Read/Clear) */
+#define spu_LineStat_w 0x04 /* Line Status Register (Set) */
+#define spu_Handshk_rc 0x08 /* Handshake Status Register (Read/Clear) */
+#define spu_Handshk_w 0x0c /* Handshake Status Register (Set) */
+#define spu_BRateDivh 0x10 /* Baud rate divisor high */
+#define spu_BRateDivl 0x14 /* Baud rate divisor low */
+#define spu_CtlReg 0x18 /* Control Register */
+#define spu_RxCmd 0x1c /* Rx Command Register */
+#define spu_TxCmd 0x20 /* Tx Command Register */
+#define spu_RxBuff 0x24 /* Rx data buffer */
+#define spu_TxBuff 0x24 /* Tx data buffer */
+
+/*-----------------------------------------------------------------------------+
+ | Line Status Register.
+ +-----------------------------------------------------------------------------*/
+#define asyncLSRport1 0x40000000
+#define asyncLSRport1set 0x40000004
+#define asyncLSRDataReady 0x80
+#define asyncLSRFramingError 0x40
+#define asyncLSROverrunError 0x20
+#define asyncLSRParityError 0x10
+#define asyncLSRBreakInterrupt 0x08
+#define asyncLSRTxHoldEmpty 0x04
+#define asyncLSRTxShiftEmpty 0x02
+
+/*-----------------------------------------------------------------------------+
+ | Handshake Status Register.
+ +-----------------------------------------------------------------------------*/
+#define asyncHSRport1 0x40000008
+#define asyncHSRport1set 0x4000000c
+#define asyncHSRDsr 0x80
+#define asyncLSRCts 0x40
+
+/*-----------------------------------------------------------------------------+
+ | Control Register.
+ +-----------------------------------------------------------------------------*/
+#define asyncCRport1 0x40000018
+#define asyncCRNormal 0x00
+#define asyncCRLoopback 0x40
+#define asyncCRAutoEcho 0x80
+#define asyncCRDtr 0x20
+#define asyncCRRts 0x10
+#define asyncCRWordLength7 0x00
+#define asyncCRWordLength8 0x08
+#define asyncCRParityDisable 0x00
+#define asyncCRParityEnable 0x04
+#define asyncCREvenParity 0x00
+#define asyncCROddParity 0x02
+#define asyncCRStopBitsOne 0x00
+#define asyncCRStopBitsTwo 0x01
+#define asyncCRDisableDtrRts 0x00
+
+/*-----------------------------------------------------------------------------+
+ | Receiver Command Register.
+ +-----------------------------------------------------------------------------*/
+#define asyncRCRport1 0x4000001c
+#define asyncRCRDisable 0x00
+#define asyncRCREnable 0x80
+#define asyncRCRIntDisable 0x00
+#define asyncRCRIntEnabled 0x20
+#define asyncRCRDMACh2 0x40
+#define asyncRCRDMACh3 0x60
+#define asyncRCRErrorInt 0x10
+#define asyncRCRPauseEnable 0x08
+
+/*-----------------------------------------------------------------------------+
+ | Transmitter Command Register.
+ +-----------------------------------------------------------------------------*/
+#define asyncTCRport1 0x40000020
+#define asyncTCRDisable 0x00
+#define asyncTCREnable 0x80
+#define asyncTCRIntDisable 0x00
+#define asyncTCRIntEnabled 0x20
+#define asyncTCRDMACh2 0x40
+#define asyncTCRDMACh3 0x60
+#define asyncTCRTxEmpty 0x10
+#define asyncTCRErrorInt 0x08
+#define asyncTCRStopPause 0x04
+#define asyncTCRBreakGen 0x02
+
+/*-----------------------------------------------------------------------------+
+ | Miscellanies defines.
+ +-----------------------------------------------------------------------------*/
+#define asyncTxBufferport1 0x40000024
+#define asyncRxBufferport1 0x40000024
+#define asyncDLABLsbport1 0x40000014
+#define asyncDLABMsbport1 0x40000010
+#define asyncXOFFchar 0x13
+#define asyncXONchar 0x11
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+int serial_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ volatile char val;
+ unsigned short br_reg;
+
+ br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1);
+
+ /*
+ * Init onboard UART
+ */
+ out8 (SPU_BASE + spu_LineStat_rc, 0x78); /* Clear all bits in Line Status Reg */
+ out8 (SPU_BASE + spu_BRateDivl, (br_reg & 0x00ff)); /* Set baud rate divisor... */
+ out8 (SPU_BASE + spu_BRateDivh, ((br_reg & 0xff00) >> 8)); /* ... */
+ out8 (SPU_BASE + spu_CtlReg, 0x08); /* Set 8 bits, no parity and 1 stop bit */
+ out8 (SPU_BASE + spu_RxCmd, 0xb0); /* Enable Rx */
+ out8 (SPU_BASE + spu_TxCmd, 0x9c); /* Enable Tx */
+ out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */
+ val = in8 (SPU_BASE + spu_RxBuff); /* Dummy read, to clear receiver */
+
+ return (0);
+}
+
+void serial_setbrg (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ unsigned short br_reg;
+
+ br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1);
+
+ out8 (SPU_BASE + spu_BRateDivl, (br_reg & 0x00ff)); /* Set baud rate divisor... */
+ out8 (SPU_BASE + spu_BRateDivh, ((br_reg & 0xff00) >> 8)); /* ... */
+}
+
+void serial_putc (const char c)
+{
+ if (c == '\n')
+ serial_putc ('\r');
+
+ /* load status from handshake register */
+ if (in8 (SPU_BASE + spu_Handshk_rc) != 00)
+ out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */
+
+ out8 (SPU_BASE + spu_TxBuff, c); /* Put char */
+
+ while ((in8 (SPU_BASE + spu_LineStat_rc) & 04) != 04) {
+ if (in8 (SPU_BASE + spu_Handshk_rc) != 00)
+ out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */
+ }
+}
+
+void serial_puts (const char *s)
+{
+ while (*s) {
+ serial_putc (*s++);
+ }
+}
+
+int serial_getc ()
+{
+ unsigned char status = 0;
+
+ while (1) {
+ status = in8 (asyncLSRport1);
+ if ((status & asyncLSRDataReady) != 0x0) {
+ break;
+ }
+ if ((status & ( asyncLSRFramingError |
+ asyncLSROverrunError |
+ asyncLSRParityError |
+ asyncLSRBreakInterrupt )) != 0) {
+ (void) out8 (asyncLSRport1,
+ asyncLSRFramingError |
+ asyncLSROverrunError |
+ asyncLSRParityError |
+ asyncLSRBreakInterrupt );
+ }
+ }
+ return (0x000000ff & (int) in8 (asyncRxBufferport1));
+}
+
+int serial_tstc ()
+{
+ unsigned char status;
+
+ status = in8 (asyncLSRport1);
+ if ((status & asyncLSRDataReady) != 0x0) {
+ return (1);
+ }
+ if ((status & ( asyncLSRFramingError |
+ asyncLSROverrunError |
+ asyncLSRParityError |
+ asyncLSRBreakInterrupt )) != 0) {
+ (void) out8 (asyncLSRport1,
+ asyncLSRFramingError |
+ asyncLSROverrunError |
+ asyncLSRParityError |
+ asyncLSRBreakInterrupt);
+ }
+ return 0;
+}
+
+#endif /* CONFIG_IOP480 */
+
+/*****************************************************************************/
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405EP)
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000300
+#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000400
+#else
+#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000200
+#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000300
+#endif
+
+#if defined(CONFIG_440SP)
+#define UART2_BASE CFG_PERIPHERAL_BASE + 0x00000600
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SP)
+#define CR0_MASK 0xdfffffff
+#define CR0_EXTCLK_ENA 0x00800000
+#define CR0_UDIV_POS 0
+#else
+#define CR0_MASK 0x3fff0000
+#define CR0_EXTCLK_ENA 0x00600000
+#define CR0_UDIV_POS 16
+#endif /* CONFIG_440GX */
+#elif defined(CONFIG_405EP)
+#define UART0_BASE 0xef600300
+#define UART1_BASE 0xef600400
+#define UCR0_MASK 0x0000007f
+#define UCR1_MASK 0x00007f00
+#define UCR0_UDIV_POS 0
+#define UCR1_UDIV_POS 8
+#define UDIV_MAX 127
+#else /* CONFIG_405GP || CONFIG_405CR */
+#define UART0_BASE 0xef600300
+#define UART1_BASE 0xef600400
+#define CR0_MASK 0x00001fff
+#define CR0_EXTCLK_ENA 0x000000c0
+#define CR0_UDIV_POS 1
+#define UDIV_MAX 32
+#endif
+
+/* using serial port 0 or 1 as U-Boot console ? */
+#if defined(CONFIG_UART1_CONSOLE)
+#define ACTING_UART0_BASE UART1_BASE
+#define ACTING_UART1_BASE UART0_BASE
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SP)
+#define UART0_SDR sdr_uart1
+#define UART1_SDR sdr_uart0
+#endif /* CONFIG_440GX */
+#else
+#define ACTING_UART0_BASE UART0_BASE
+#define ACTING_UART1_BASE UART1_BASE
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SP)
+#define UART0_SDR sdr_uart0
+#define UART1_SDR sdr_uart1
+#endif /* CONFIG_440GX */
+#endif
+
+#if defined(CONFIG_405EP) && defined(CFG_EXT_SERIAL_CLOCK)
+#error "External serial clock not supported on AMCC PPC405EP!"
+#endif
+
+#define UART_RBR 0x00
+#define UART_THR 0x00
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/*-----------------------------------------------------------------------------+
+ | Line Status Register.
+ +-----------------------------------------------------------------------------*/
+/*#define asyncLSRport1 ACTING_UART0_BASE+0x05 */
+#define asyncLSRDataReady1 0x01
+#define asyncLSROverrunError1 0x02
+#define asyncLSRParityError1 0x04
+#define asyncLSRFramingError1 0x08
+#define asyncLSRBreakInterrupt1 0x10
+#define asyncLSRTxHoldEmpty1 0x20
+#define asyncLSRTxShiftEmpty1 0x40
+#define asyncLSRRxFifoError1 0x80
+
+/*-----------------------------------------------------------------------------+
+ | Miscellanies defines.
+ +-----------------------------------------------------------------------------*/
+/*#define asyncTxBufferport1 ACTING_UART0_BASE+0x00 */
+/*#define asyncRxBufferport1 ACTING_UART0_BASE+0x00 */
+
+#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
+/*-----------------------------------------------------------------------------+
+ | Fifo
+ +-----------------------------------------------------------------------------*/
+typedef struct {
+ char *rx_buffer;
+ ulong rx_put;
+ ulong rx_get;
+} serial_buffer_t;
+
+volatile static serial_buffer_t buf_info;
+#endif
+
+#if defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLOCK)
+static void serial_divs (int baudrate, unsigned long *pudiv,
+ unsigned short *pbdiv )
+{
+ sys_info_t sysinfo;
+ unsigned long div; /* total divisor udiv * bdiv */
+ unsigned long umin; /* minimum udiv */
+ unsigned short diff; /* smallest diff */
+ unsigned long udiv; /* best udiv */
+
+ unsigned short idiff; /* current diff */
+ unsigned short ibdiv; /* current bdiv */
+ unsigned long i;
+ unsigned long est; /* current estimate */
+
+ get_sys_info( &sysinfo );
+
+ udiv = 32; /* Assume lowest possible serial clk */
+ div = sysinfo.freqPLB/(16*baudrate); /* total divisor */
+ umin = sysinfo.pllOpbDiv<<1; /* 2 x OPB divisor */
+ diff = 32; /* highest possible */
+
+ /* i is the test udiv value -- start with the largest
+ * possible (32) to minimize serial clock and constrain
+ * search to umin.
+ */
+ for( i = 32; i > umin; i-- ){
+ ibdiv = div/i;
+ est = i * ibdiv;
+ idiff = (est > div) ? (est-div) : (div-est);
+ if( idiff == 0 ){
+ udiv = i;
+ break; /* can't do better */
+ }
+ else if( idiff < diff ){
+ udiv = i; /* best so far */
+ diff = idiff; /* update lowest diff*/
+ }
+ }
+
+ *pudiv = udiv;
+ *pbdiv = div/udiv;
+
+}
+#endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK */
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_init_dev (unsigned long dev_base)
+#else
+int serial_init(void)
+#endif
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ unsigned long reg;
+ unsigned long udiv;
+ unsigned short bdiv;
+ volatile char val;
+#ifdef CFG_EXT_SERIAL_CLOCK
+ unsigned long tmp;
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+#if defined(CONFIG_SERIAL_MULTI)
+ if (UART0_BASE == dev_base) {
+ mfsdr(UART0_SDR,reg);
+ reg &= ~CR0_MASK;
+ } else {
+ mfsdr(UART1_SDR,reg);
+ reg &= ~CR0_MASK;
+ }
+#else
+ mfsdr(UART0_SDR,reg);
+ reg &= ~CR0_MASK;
+#endif
+#else
+ reg = mfdcr(cntrl0) & ~CR0_MASK;
+#endif /* CONFIG_440GX */
+#ifdef CFG_EXT_SERIAL_CLOCK
+ reg |= CR0_EXTCLK_ENA;
+ udiv = 1;
+ tmp = gd->baudrate * 16;
+ bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
+#else
+ /* For 440, the cpu clock is on divider chain A, UART on divider
+ * chain B ... so cpu clock is irrelevant. Get the "optimized"
+ * values that are subject to the 1/2 opb clock constraint
+ */
+ serial_divs (gd->baudrate, &udiv, &bdiv);
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SP)
+ reg |= udiv << CR0_UDIV_POS; /* set the UART divisor */
+#if defined(CONFIG_SERIAL_MULTI)
+ if (UART0_BASE == dev_base) {
+ mtsdr (UART0_SDR,reg);
+ } else {
+ mtsdr (UART1_SDR,reg);
+ }
+#else
+ mtsdr (UART0_SDR,reg);
+#endif
+#else
+ reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
+ mtdcr (cntrl0, reg);
+#endif
+
+#if defined(CONFIG_SERIAL_MULTI)
+ out8 (dev_base + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (dev_base + UART_DLL, bdiv); /* set baudrate divisor */
+ out8 (dev_base + UART_DLM, bdiv >> 8);/* set baudrate divisor */
+ out8 (dev_base + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+ out8 (dev_base + UART_FCR, 0x00); /* disable FIFO */
+ out8 (dev_base + UART_MCR, 0x00); /* no modem control DTR RTS */
+ val = in8 (dev_base + UART_LSR); /* clear line status */
+ val = in8 (dev_base + UART_RBR); /* read receive buffer */
+ out8 (dev_base + UART_SCR, 0x00); /* set scratchpad */
+ out8 (dev_base + UART_IER, 0x00); /* set interrupt enable reg */
+#else
+ out8 (ACTING_UART0_BASE + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (ACTING_UART0_BASE + UART_DLL, bdiv); /* set baudrate divisor */
+ out8 (ACTING_UART0_BASE + UART_DLM, bdiv >> 8);/* set baudrate divisor */
+ out8 (ACTING_UART0_BASE + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+ out8 (ACTING_UART0_BASE + UART_FCR, 0x00); /* disable FIFO */
+ out8 (ACTING_UART0_BASE + UART_MCR, 0x00); /* no modem control DTR RTS */
+ val = in8 (ACTING_UART0_BASE + UART_LSR); /* clear line status */
+ val = in8 (ACTING_UART0_BASE + UART_RBR); /* read receive buffer */
+ out8 (ACTING_UART0_BASE + UART_SCR, 0x00); /* set scratchpad */
+ out8 (ACTING_UART0_BASE + UART_IER, 0x00); /* set interrupt enable reg */
+#endif
+ return (0);
+}
+
+#else /* !defined(CONFIG_440) */
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_init_dev (unsigned long dev_base)
+#else
+int serial_init (void)
+#endif
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ unsigned long reg;
+ unsigned long tmp;
+ unsigned long clk;
+ unsigned long udiv;
+ unsigned short bdiv;
+ volatile char val;
+
+#ifdef CONFIG_405EP
+ reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
+ clk = gd->cpu_clk;
+ tmp = CFG_BASE_BAUD * 16;
+ udiv = (clk + tmp / 2) / tmp;
+ if (udiv > UDIV_MAX) /* max. n bits for udiv */
+ udiv = UDIV_MAX;
+ reg |= (udiv) << UCR0_UDIV_POS; /* set the UART divisor */
+ reg |= (udiv) << UCR1_UDIV_POS; /* set the UART divisor */
+ mtdcr (cpc0_ucr, reg);
+#else /* CONFIG_405EP */
+ reg = mfdcr(cntrl0) & ~CR0_MASK;
+#ifdef CFG_EXT_SERIAL_CLOCK
+ clk = CFG_EXT_SERIAL_CLOCK;
+ udiv = 1;
+ reg |= CR0_EXTCLK_ENA;
+#else
+ clk = gd->cpu_clk;
+#ifdef CFG_405_UART_ERRATA_59
+ udiv = 31; /* Errata 59: stuck at 31 */
+#else
+ tmp = CFG_BASE_BAUD * 16;
+ udiv = (clk + tmp / 2) / tmp;
+ if (udiv > UDIV_MAX) /* max. n bits for udiv */
+ udiv = UDIV_MAX;
+#endif
+#endif
+ reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
+ mtdcr (cntrl0, reg);
+#endif /* CONFIG_405EP */
+
+ tmp = gd->baudrate * udiv * 16;
+ bdiv = (clk + tmp / 2) / tmp;
+
+#if defined(CONFIG_SERIAL_MULTI)
+ out8 (dev_base + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (dev_base + UART_DLL, bdiv); /* set baudrate divisor */
+ out8 (dev_base + UART_DLM, bdiv >> 8);/* set baudrate divisor */
+ out8 (dev_base + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+ out8 (dev_base + UART_FCR, 0x00); /* disable FIFO */
+ out8 (dev_base + UART_MCR, 0x00); /* no modem control DTR RTS */
+ val = in8 (dev_base + UART_LSR); /* clear line status */
+ val = in8 (dev_base + UART_RBR); /* read receive buffer */
+ out8 (dev_base + UART_SCR, 0x00); /* set scratchpad */
+ out8 (dev_base + UART_IER, 0x00); /* set interrupt enable reg */
+#else
+ out8 (ACTING_UART0_BASE + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (ACTING_UART0_BASE + UART_DLL, bdiv); /* set baudrate divisor */
+ out8 (ACTING_UART0_BASE + UART_DLM, bdiv >> 8);/* set baudrate divisor */
+ out8 (ACTING_UART0_BASE + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+ out8 (ACTING_UART0_BASE + UART_FCR, 0x00); /* disable FIFO */
+ out8 (ACTING_UART0_BASE + UART_MCR, 0x00); /* no modem control DTR RTS */
+ val = in8 (ACTING_UART0_BASE + UART_LSR); /* clear line status */
+ val = in8 (ACTING_UART0_BASE + UART_RBR); /* read receive buffer */
+ out8 (ACTING_UART0_BASE + UART_SCR, 0x00); /* set scratchpad */
+ out8 (ACTING_UART0_BASE + UART_IER, 0x00); /* set interrupt enable reg */
+#endif
+ return (0);
+}
+
+#endif /* if defined(CONFIG_440) */
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_setbrg_dev (unsigned long dev_base)
+#else
+void serial_setbrg (void)
+#endif
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ unsigned long tmp;
+ unsigned long clk;
+ unsigned long udiv;
+ unsigned short bdiv;
+
+#ifdef CFG_EXT_SERIAL_CLOCK
+ clk = CFG_EXT_SERIAL_CLOCK;
+#else
+ clk = gd->cpu_clk;
+#endif
+
+#ifdef CONFIG_405EP
+ udiv = ((mfdcr (cpc0_ucr) & UCR0_MASK) >> UCR0_UDIV_POS);
+#else
+ udiv = ((mfdcr (cntrl0) & 0x3e) >> 1) + 1;
+#endif /* CONFIG_405EP */
+ tmp = gd->baudrate * udiv * 16;
+ bdiv = (clk + tmp / 2) / tmp;
+
+#if defined(CONFIG_SERIAL_MULTI)
+ out8 (dev_base + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (dev_base + UART_DLL, bdiv); /* set baudrate divisor */
+ out8 (dev_base + UART_DLM, bdiv >> 8);/* set baudrate divisor */
+ out8 (dev_base + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+#else
+ out8 (ACTING_UART0_BASE + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (ACTING_UART0_BASE + UART_DLL, bdiv); /* set baudrate divisor */
+ out8 (ACTING_UART0_BASE + UART_DLM, bdiv >> 8);/* set baudrate divisor */
+ out8 (ACTING_UART0_BASE + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+#endif
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_putc_dev (unsigned long dev_base, const char c)
+#else
+void serial_putc (const char c)
+#endif
+{
+ int i;
+
+ if (c == '\n')
+#if defined(CONFIG_SERIAL_MULTI)
+ serial_putc_dev (dev_base, '\r');
+#else
+ serial_putc ('\r');
+#endif
+
+ /* check THRE bit, wait for transmiter available */
+ for (i = 1; i < 3500; i++) {
+#if defined(CONFIG_SERIAL_MULTI)
+ if ((in8 (dev_base + UART_LSR) & 0x20) == 0x20)
+#else
+ if ((in8 (ACTING_UART0_BASE + UART_LSR) & 0x20) == 0x20)
+#endif
+ break;
+ udelay (100);
+ }
+#if defined(CONFIG_SERIAL_MULTI)
+ out8 (dev_base + UART_THR, c); /* put character out */
+#else
+ out8 (ACTING_UART0_BASE + UART_THR, c); /* put character out */
+#endif
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_puts_dev (unsigned long dev_base, const char *s)
+#else
+void serial_puts (const char *s)
+#endif
+{
+ while (*s) {
+#if defined(CONFIG_SERIAL_MULTI)
+ serial_putc_dev (dev_base, *s++);
+#else
+ serial_putc (*s++);
+#endif
+ }
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_getc_dev (unsigned long dev_base)
+#else
+int serial_getc (void)
+#endif
+{
+ unsigned char status = 0;
+
+ while (1) {
+#if defined(CONFIG_HW_WATCHDOG)
+ WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */
+#endif /* CONFIG_HW_WATCHDOG */
+#if defined(CONFIG_SERIAL_MULTI)
+ status = in8 (dev_base + UART_LSR);
+#else
+ status = in8 (ACTING_UART0_BASE + UART_LSR);
+#endif
+ if ((status & asyncLSRDataReady1) != 0x0) {
+ break;
+ }
+ if ((status & ( asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1 )) != 0) {
+#if defined(CONFIG_SERIAL_MULTI)
+ out8 (dev_base + UART_LSR,
+#else
+ out8 (ACTING_UART0_BASE + UART_LSR,
+#endif
+ asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1);
+ }
+ }
+#if defined(CONFIG_SERIAL_MULTI)
+ return (0x000000ff & (int) in8 (dev_base));
+#else
+ return (0x000000ff & (int) in8 (ACTING_UART0_BASE));
+#endif
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_tstc_dev (unsigned long dev_base)
+#else
+int serial_tstc (void)
+#endif
+{
+ unsigned char status;
+
+#if defined(CONFIG_SERIAL_MULTI)
+ status = in8 (dev_base + UART_LSR);
+#else
+ status = in8 (ACTING_UART0_BASE + UART_LSR);
+#endif
+ if ((status & asyncLSRDataReady1) != 0x0) {
+ return (1);
+ }
+ if ((status & ( asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1 )) != 0) {
+#if defined(CONFIG_SERIAL_MULTI)
+ out8 (dev_base + UART_LSR,
+#else
+ out8 (ACTING_UART0_BASE + UART_LSR,
+#endif
+ asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
+
+void serial_isr (void *arg)
+{
+ int space;
+ int c;
+ const int rx_get = buf_info.rx_get;
+ int rx_put = buf_info.rx_put;
+
+ if (rx_get <= rx_put) {
+ space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
+ } else {
+ space = rx_get - rx_put;
+ }
+ while (serial_tstc_dev (ACTING_UART0_BASE)) {
+ c = serial_getc_dev (ACTING_UART0_BASE);
+ if (space) {
+ buf_info.rx_buffer[rx_put++] = c;
+ space--;
+ }
+ if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
+ rx_put = 0;
+ if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
+ /* Stop flow by setting RTS inactive */
+ out8 (ACTING_UART0_BASE + UART_MCR,
+ in8 (ACTING_UART0_BASE + UART_MCR) & (0xFF ^ 0x02));
+ }
+ }
+ buf_info.rx_put = rx_put;
+}
+
+void serial_buffered_init (void)
+{
+ serial_puts ("Switching to interrupt driven serial input mode.\n");
+ buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
+ buf_info.rx_put = 0;
+ buf_info.rx_get = 0;
+
+ if (in8 (ACTING_UART0_BASE + UART_MSR) & 0x10) {
+ serial_puts ("Check CTS signal present on serial port: OK.\n");
+ } else {
+ serial_puts ("WARNING: CTS signal not present on serial port.\n");
+ }
+
+ irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ ,
+ serial_isr /*interrupt_handler_t *handler */ ,
+ (void *) &buf_info /*void *arg */ );
+
+ /* Enable "RX Data Available" Interrupt on UART */
+ /* out8(ACTING_UART0_BASE + UART_IER, in8(ACTING_UART0_BASE + UART_IER) |0x01); */
+ out8 (ACTING_UART0_BASE + UART_IER, 0x01);
+ /* Set DTR active */
+ out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x01);
+ /* Start flow by setting RTS active */
+ out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
+ /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
+ out8 (ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1);
+}
+
+void serial_buffered_putc (const char c)
+{
+ /* Wait for CTS */
+#if defined(CONFIG_HW_WATCHDOG)
+ while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10))
+ WATCHDOG_RESET ();
+#else
+ while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10));
+#endif
+ serial_putc (c);
+}
+
+void serial_buffered_puts (const char *s)
+{
+ serial_puts (s);
+}
+
+int serial_buffered_getc (void)
+{
+ int space;
+ int c;
+ int rx_get = buf_info.rx_get;
+ int rx_put;
+
+#if defined(CONFIG_HW_WATCHDOG)
+ while (rx_get == buf_info.rx_put)
+ WATCHDOG_RESET ();
+#else
+ while (rx_get == buf_info.rx_put);
+#endif
+ c = buf_info.rx_buffer[rx_get++];
+ if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
+ rx_get = 0;
+ buf_info.rx_get = rx_get;
+
+ rx_put = buf_info.rx_put;
+ if (rx_get <= rx_put) {
+ space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
+ } else {
+ space = rx_get - rx_put;
+ }
+ if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
+ /* Start flow by setting RTS active */
+ out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
+ }
+
+ return c;
+}
+
+int serial_buffered_tstc (void)
+{
+ return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
+}
+
+#endif /* CONFIG_SERIAL_SOFTWARE_FIFO */
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+/*
+ AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
+ number 0 or number 1
+ - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
+ configuration has been already done
+ - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
+ configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
+*/
+#if (CONFIG_KGDB_SER_INDEX & 2)
+void kgdb_serial_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ volatile char val;
+ unsigned short br_reg;
+
+ get_clocks ();
+ br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) +
+ 5) / 10;
+ /*
+ * Init onboard 16550 UART
+ */
+ out8 (ACTING_UART1_BASE + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set divisor for 9600 baud */
+ out8 (ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8)); /* set divisor for 9600 baud */
+ out8 (ACTING_UART1_BASE + UART_LCR, 0x03); /* line control 8 bits no parity */
+ out8 (ACTING_UART1_BASE + UART_FCR, 0x00); /* disable FIFO */
+ out8 (ACTING_UART1_BASE + UART_MCR, 0x00); /* no modem control DTR RTS */
+ val = in8 (ACTING_UART1_BASE + UART_LSR); /* clear line status */
+ val = in8 (ACTING_UART1_BASE + UART_RBR); /* read receive buffer */
+ out8 (ACTING_UART1_BASE + UART_SCR, 0x00); /* set scratchpad */
+ out8 (ACTING_UART1_BASE + UART_IER, 0x00); /* set interrupt enable reg */
+}
+
+void putDebugChar (const char c)
+{
+ if (c == '\n')
+ serial_putc ('\r');
+
+ out8 (ACTING_UART1_BASE + UART_THR, c); /* put character out */
+
+ /* check THRE bit, wait for transfer done */
+ while ((in8 (ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
+}
+
+void putDebugStr (const char *s)
+{
+ while (*s) {
+ serial_putc (*s++);
+ }
+}
+
+int getDebugChar (void)
+{
+ unsigned char status = 0;
+
+ while (1) {
+ status = in8 (ACTING_UART1_BASE + UART_LSR);
+ if ((status & asyncLSRDataReady1) != 0x0) {
+ break;
+ }
+ if ((status & ( asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1 )) != 0) {
+ out8 (ACTING_UART1_BASE + UART_LSR,
+ asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1);
+ }
+ }
+ return (0x000000ff & (int) in8 (ACTING_UART1_BASE));
+}
+
+void kgdb_interruptible (int yes)
+{
+ return;
+}
+
+#else /* ! (CONFIG_KGDB_SER_INDEX & 2) */
+
+void kgdb_serial_init (void)
+{
+ serial_printf ("[on serial] ");
+}
+
+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 /* (CONFIG_KGDB_SER_INDEX & 2) */
+#endif /* CFG_CMD_KGDB */
+
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial0_init(void)
+{
+ return (serial_init_dev(UART0_BASE));
+}
+
+int serial1_init(void)
+{
+ return (serial_init_dev(UART1_BASE));
+}
+void serial0_setbrg (void)
+{
+ serial_setbrg_dev(UART0_BASE);
+}
+void serial1_setbrg (void)
+{
+ serial_setbrg_dev(UART1_BASE);
+}
+
+void serial0_putc(const char c)
+{
+ serial_putc_dev(UART0_BASE,c);
+}
+
+void serial1_putc(const char c)
+{
+ serial_putc_dev(UART1_BASE, c);
+}
+void serial0_puts(const char *s)
+{
+ serial_puts_dev(UART0_BASE, s);
+}
+
+void serial1_puts(const char *s)
+{
+ serial_puts_dev(UART1_BASE, s);
+}
+
+int serial0_getc(void)
+{
+ return(serial_getc_dev(UART0_BASE));
+}
+
+int serial1_getc(void)
+{
+ return(serial_getc_dev(UART1_BASE));
+}
+int serial0_tstc(void)
+{
+ return (serial_tstc_dev(UART0_BASE));
+}
+
+int serial1_tstc(void)
+{
+ return (serial_tstc_dev(UART1_BASE));
+}
+
+struct serial_device serial0_device =
+{
+ "serial0",
+ "UART0",
+ serial0_init,
+ serial0_setbrg,
+ serial0_getc,
+ serial0_tstc,
+ serial0_putc,
+ serial0_puts,
+};
+
+struct serial_device serial1_device =
+{
+ "serial1",
+ "UART1",
+ serial1_init,
+ serial1_setbrg,
+ serial1_getc,
+ serial1_tstc,
+ serial1_putc,
+ serial1_puts,
+};
+#endif /* CONFIG_SERIAL_MULTI */
+
+#endif /* CONFIG_405GP || CONFIG_405CR */
diff --git a/cpu/ppc4xx/spd_sdram.c b/cpu/ppc4xx/spd_sdram.c
new file mode 100755
index 0000000..ebd5f39
--- /dev/null
+++ b/cpu/ppc4xx/spd_sdram.c
@@ -0,0 +1,1831 @@
+/*
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
+ *
+ * Based on code by:
+ *
+ * Kenneth Johansson ,Ericsson AB.
+ * kenneth.johansson@etx.ericsson.se
+ *
+ * hacked up by bill hunter. fixed so we could run before
+ * serial_init and console_init. previous version avoided this by
+ * running out of cache memory during serial/console init, then running
+ * this code later.
+ *
+ * (C) Copyright 2002
+ * Jun Gu, Artesyn Technology, jung@artesyncp.com
+ * Support for AMCC 440 based on OpenBIOS draminit.c from IBM.
+ *
+ * (C) Copyright 2005
+ * Stefan Roese, DENX Software Engineering, sr@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 <asm/processor.h>
+#include <i2c.h>
+#include <ppc4xx.h>
+
+#ifdef CONFIG_SPD_EEPROM
+
+/*
+ * Set default values
+ */
+#ifndef CFG_I2C_SPEED
+#define CFG_I2C_SPEED 50000
+#endif
+
+#ifndef CFG_I2C_SLAVE
+#define CFG_I2C_SLAVE 0xFE
+#endif
+
+#define ONE_BILLION 1000000000
+
+#ifndef CONFIG_440 /* for 405 WALNUT/SYCAMORE/BUBINGA boards */
+
+#define SDRAM0_CFG_DCE 0x80000000
+#define SDRAM0_CFG_SRE 0x40000000
+#define SDRAM0_CFG_PME 0x20000000
+#define SDRAM0_CFG_MEMCHK 0x10000000
+#define SDRAM0_CFG_REGEN 0x08000000
+#define SDRAM0_CFG_ECCDD 0x00400000
+#define SDRAM0_CFG_EMDULR 0x00200000
+#define SDRAM0_CFG_DRW_SHIFT (31-6)
+#define SDRAM0_CFG_BRPF_SHIFT (31-8)
+
+#define SDRAM0_TR_CASL_SHIFT (31-8)
+#define SDRAM0_TR_PTA_SHIFT (31-13)
+#define SDRAM0_TR_CTP_SHIFT (31-15)
+#define SDRAM0_TR_LDF_SHIFT (31-17)
+#define SDRAM0_TR_RFTA_SHIFT (31-29)
+#define SDRAM0_TR_RCD_SHIFT (31-31)
+
+#define SDRAM0_RTR_SHIFT (31-15)
+#define SDRAM0_ECCCFG_SHIFT (31-11)
+
+/* SDRAM0_CFG enable macro */
+#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT )
+
+#define SDRAM0_BXCR_SZ_MASK 0x000e0000
+#define SDRAM0_BXCR_AM_MASK 0x0000e000
+
+#define SDRAM0_BXCR_SZ_SHIFT (31-14)
+#define SDRAM0_BXCR_AM_SHIFT (31-18)
+
+#define SDRAM0_BXCR_SZ(x) ( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) )
+#define SDRAM0_BXCR_AM(x) ( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) )
+
+#ifdef CONFIG_SPDDRAM_SILENT
+# define SPD_ERR(x) do { return 0; } while (0)
+#else
+# define SPD_ERR(x) do { printf(x); return(0); } while (0)
+#endif
+
+#define sdram_HZ_to_ns(hertz) (1000000000/(hertz))
+
+/* function prototypes */
+int spd_read(uint addr);
+
+
+/*
+ * This function is reading data from the DIMM module EEPROM over the SPD bus
+ * and uses that to program the sdram controller.
+ *
+ * This works on boards that has the same schematics that the AMCC walnut has.
+ *
+ * Input: null for default I2C spd functions or a pointer to a custom function
+ * returning spd_data.
+ */
+
+long int spd_sdram(int(read_spd)(uint addr))
+{
+ int tmp,row,col;
+ int total_size,bank_size,bank_code;
+ int ecc_on;
+ int mode;
+ int bank_cnt;
+
+ int sdram0_pmit=0x07c00000;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ int sdram0_besr0=-1;
+ int sdram0_besr1=-1;
+ int sdram0_eccesr=-1;
+#endif
+ int sdram0_ecccfg;
+
+ int sdram0_rtr=0;
+ int sdram0_tr=0;
+
+ int sdram0_b0cr;
+ int sdram0_b1cr;
+ int sdram0_b2cr;
+ int sdram0_b3cr;
+
+ int sdram0_cfg=0;
+
+ int t_rp;
+ int t_rcd;
+ int t_ras;
+ int t_rc;
+ int min_cas;
+
+ PPC405_SYS_INFO sys_info;
+ unsigned long bus_period_x_10;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+ bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+ if (read_spd == 0){
+ read_spd=spd_read;
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+ i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ }
+
+ /* Make shure we are using SDRAM */
+ if (read_spd(2) != 0x04) {
+ SPD_ERR("SDRAM - non SDRAM memory module found\n");
+ }
+
+ /* ------------------------------------------------------------------
+ * configure memory timing register
+ *
+ * data from DIMM:
+ * 27 IN Row Precharge Time ( t RP)
+ * 29 MIN RAS to CAS Delay ( t RCD)
+ * 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS
+ * -------------------------------------------------------------------*/
+
+ /*
+ * first figure out which cas latency mode to use
+ * use the min supported mode
+ */
+
+ tmp = read_spd(127) & 0x6;
+ if (tmp == 0x02) { /* only cas = 2 supported */
+ min_cas = 2;
+/* t_ck = read_spd(9); */
+/* t_ac = read_spd(10); */
+ } else if (tmp == 0x04) { /* only cas = 3 supported */
+ min_cas = 3;
+/* t_ck = read_spd(9); */
+/* t_ac = read_spd(10); */
+ } else if (tmp == 0x06) { /* 2,3 supported, so use 2 */
+ min_cas = 2;
+/* t_ck = read_spd(23); */
+/* t_ac = read_spd(24); */
+ } else {
+ SPD_ERR("SDRAM - unsupported CAS latency \n");
+ }
+
+ /* get some timing values, t_rp,t_rcd,t_ras,t_rc
+ */
+ t_rp = read_spd(27);
+ t_rcd = read_spd(29);
+ t_ras = read_spd(30);
+ t_rc = t_ras + t_rp;
+
+ /* The following timing calcs subtract 1 before deviding.
+ * this has effect of using ceiling instead of floor rounding,
+ * and also subtracting 1 to convert number to reg value
+ */
+ /* set up CASL */
+ sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT;
+ /* set up PTA */
+ sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT;
+ /* set up CTP */
+ tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3;
+ if (tmp < 1)
+ tmp = 1;
+ sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT;
+ /* set LDF = 2 cycles, reg value = 1 */
+ sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT;
+ /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */
+ tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3;
+ if (tmp < 0)
+ tmp = 0;
+ if (tmp > 6)
+ tmp = 6;
+ sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT;
+ /* set RCD = t_rcd/bus_period*/
+ sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ;
+
+
+ /*------------------------------------------------------------------
+ * configure RTR register
+ * -------------------------------------------------------------------*/
+ row = read_spd(3);
+ col = read_spd(4);
+ tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */
+ switch (tmp) {
+ case 0x00:
+ tmp = 15625;
+ break;
+ case 0x01:
+ tmp = 15625 / 4;
+ break;
+ case 0x02:
+ tmp = 15625 / 2;
+ break;
+ case 0x03:
+ tmp = 15625 * 2;
+ break;
+ case 0x04:
+ tmp = 15625 * 4;
+ break;
+ case 0x05:
+ tmp = 15625 * 8;
+ break;
+ default:
+ SPD_ERR("SDRAM - Bad refresh period \n");
+ }
+ /* convert from nsec to bus cycles */
+ tmp = (tmp * 10) / bus_period_x_10;
+ sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT;
+
+ /*------------------------------------------------------------------
+ * determine the number of banks used
+ * -------------------------------------------------------------------*/
+ /* byte 7:6 is module data width */
+ if (read_spd(7) != 0)
+ SPD_ERR("SDRAM - unsupported module width\n");
+ tmp = read_spd(6);
+ if (tmp < 32)
+ SPD_ERR("SDRAM - unsupported module width\n");
+ else if (tmp < 64)
+ bank_cnt = 1; /* one bank per sdram side */
+ else if (tmp < 73)
+ bank_cnt = 2; /* need two banks per side */
+ else if (tmp < 161)
+ bank_cnt = 4; /* need four banks per side */
+ else
+ SPD_ERR("SDRAM - unsupported module width\n");
+
+ /* byte 5 is the module row count (refered to as dimm "sides") */
+ tmp = read_spd(5);
+ if (tmp == 1)
+ ;
+ else if (tmp==2)
+ bank_cnt *= 2;
+ else if (tmp==4)
+ bank_cnt *= 4;
+ else
+ bank_cnt = 8; /* 8 is an error code */
+
+ if (bank_cnt > 4) /* we only have 4 banks to work with */
+ SPD_ERR("SDRAM - unsupported module rows for this width\n");
+
+ /* now check for ECC ability of module. We only support ECC
+ * on 32 bit wide devices with 8 bit ECC.
+ */
+ if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) {
+ sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT;
+ ecc_on = 1;
+ } else {
+ sdram0_ecccfg = 0;
+ ecc_on = 0;
+ }
+
+ /*------------------------------------------------------------------
+ * calculate total size
+ * -------------------------------------------------------------------*/
+ /* calculate total size and do sanity check */
+ tmp = read_spd(31);
+ total_size = 1 << 22; /* total_size = 4MB */
+ /* now multiply 4M by the smallest device row density */
+ /* note that we don't support asymetric rows */
+ while (((tmp & 0x0001) == 0) && (tmp != 0)) {
+ total_size = total_size << 1;
+ tmp = tmp >> 1;
+ }
+ total_size *= read_spd(5); /* mult by module rows (dimm sides) */
+
+ /*------------------------------------------------------------------
+ * map rows * cols * banks to a mode
+ * -------------------------------------------------------------------*/
+
+ switch (row) {
+ case 11:
+ switch (col) {
+ case 8:
+ mode=4; /* mode 5 */
+ break;
+ case 9:
+ case 10:
+ mode=0; /* mode 1 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ case 12:
+ switch (col) {
+ case 8:
+ mode=3; /* mode 4 */
+ break;
+ case 9:
+ case 10:
+ mode=1; /* mode 2 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ case 13:
+ switch (col) {
+ case 8:
+ mode=5; /* mode 6 */
+ break;
+ case 9:
+ case 10:
+ if (read_spd(17) == 2)
+ mode = 6; /* mode 7 */
+ else
+ mode = 2; /* mode 3 */
+ break;
+ case 11:
+ mode = 2; /* mode 3 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+
+ /*------------------------------------------------------------------
+ * using the calculated values, compute the bank
+ * config register values.
+ * -------------------------------------------------------------------*/
+ sdram0_b1cr = 0;
+ sdram0_b2cr = 0;
+ sdram0_b3cr = 0;
+
+ /* compute the size of each bank */
+ bank_size = total_size / bank_cnt;
+ /* convert bank size to bank size code for ppc4xx
+ by takeing log2(bank_size) - 22 */
+ tmp = bank_size; /* start with tmp = bank_size */
+ bank_code = 0; /* and bank_code = 0 */
+ while (tmp > 1) { /* this takes log2 of tmp */
+ bank_code++; /* and stores result in bank_code */
+ tmp = tmp >> 1;
+ } /* bank_code is now log2(bank_size) */
+ bank_code -= 22; /* subtract 22 to get the code */
+
+ tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1;
+ sdram0_b0cr = (bank_size * 0) | tmp;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ if (bank_cnt > 1)
+ sdram0_b2cr = (bank_size * 1) | tmp;
+ if (bank_cnt > 2)
+ sdram0_b1cr = (bank_size * 2) | tmp;
+ if (bank_cnt > 3)
+ sdram0_b3cr = (bank_size * 3) | tmp;
+#else
+ /* PPC405EP chip only supports two SDRAM banks */
+ if (bank_cnt > 1)
+ sdram0_b1cr = (bank_size * 1) | tmp;
+ if (bank_cnt > 2)
+ total_size = 2 * bank_size;
+#endif
+
+ /*
+ * enable sdram controller DCE=1
+ * enable burst read prefetch to 32 bytes BRPF=2
+ * leave other functions off
+ */
+
+ /*------------------------------------------------------------------
+ * now that we've done our calculations, we are ready to
+ * program all the registers.
+ * -------------------------------------------------------------------*/
+
+#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data)
+ /* disable memcontroller so updates work */
+ mtsdram0( mem_mcopt1, 0 );
+
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ mtsdram0( mem_besra , sdram0_besr0 );
+ mtsdram0( mem_besrb , sdram0_besr1 );
+ mtsdram0( mem_ecccf , sdram0_ecccfg );
+ mtsdram0( mem_eccerr, sdram0_eccesr );
+#endif
+ mtsdram0( mem_rtr , sdram0_rtr );
+ mtsdram0( mem_pmit , sdram0_pmit );
+ mtsdram0( mem_mb0cf , sdram0_b0cr );
+ mtsdram0( mem_mb1cf , sdram0_b1cr );
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ mtsdram0( mem_mb2cf , sdram0_b2cr );
+ mtsdram0( mem_mb3cf , sdram0_b3cr );
+#endif
+ mtsdram0( mem_sdtr1 , sdram0_tr );
+
+ /* SDRAM have a power on delay, 500 micro should do */
+ udelay(500);
+ sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR;
+ if (ecc_on)
+ sdram0_cfg |= SDRAM0_CFG_MEMCHK;
+ mtsdram0(mem_mcopt1, sdram0_cfg);
+
+ return (total_size);
+}
+
+int spd_read(uint addr)
+{
+ uchar data[2];
+
+ if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0)
+ return (int)data[0];
+ else
+ return 0;
+}
+
+#else /* CONFIG_440 */
+
+/*-----------------------------------------------------------------------------
+ | Memory Controller Options 0
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_CFG0_DCEN 0x80000000 /* SDRAM Controller Enable */
+#define SDRAM_CFG0_MCHK_MASK 0x30000000 /* Memory data errchecking mask */
+#define SDRAM_CFG0_MCHK_NON 0x00000000 /* No ECC generation */
+#define SDRAM_CFG0_MCHK_GEN 0x20000000 /* ECC generation */
+#define SDRAM_CFG0_MCHK_CHK 0x30000000 /* ECC generation and checking */
+#define SDRAM_CFG0_RDEN 0x08000000 /* Registered DIMM enable */
+#define SDRAM_CFG0_PMUD 0x04000000 /* Page management unit */
+#define SDRAM_CFG0_DMWD_MASK 0x02000000 /* DRAM width mask */
+#define SDRAM_CFG0_DMWD_32 0x00000000 /* 32 bits */
+#define SDRAM_CFG0_DMWD_64 0x02000000 /* 64 bits */
+#define SDRAM_CFG0_UIOS_MASK 0x00C00000 /* Unused IO State */
+#define SDRAM_CFG0_PDP 0x00200000 /* Page deallocation policy */
+
+/*-----------------------------------------------------------------------------
+ | Memory Controller Options 1
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_CFG1_SRE 0x80000000 /* Self-Refresh Entry */
+#define SDRAM_CFG1_PMEN 0x40000000 /* Power Management Enable */
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM DEVPOT Options
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_DEVOPT_DLL 0x80000000
+#define SDRAM_DEVOPT_DS 0x40000000
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM MCSTS Options
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_MCSTS_MRSC 0x80000000
+#define SDRAM_MCSTS_SRMS 0x40000000
+#define SDRAM_MCSTS_CIS 0x20000000
+
+/*-----------------------------------------------------------------------------
+ | SDRAM Refresh Timer Register
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_RTR_RINT_MASK 0xFFFF0000
+#define SDRAM_RTR_RINT_ENCODE(n) (((n) << 16) & SDRAM_RTR_RINT_MASK)
+#define sdram_HZ_to_ns(hertz) (1000000000/(hertz))
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM UABus Base Address Reg
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_UABBA_UBBA_MASK 0x0000000F
+
+/*-----------------------------------------------------------------------------+
+ | Memory Bank 0-7 configuration
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_BXCR_SDBA_MASK 0xff800000 /* Base address */
+#define SDRAM_BXCR_SDSZ_MASK 0x000e0000 /* Size */
+#define SDRAM_BXCR_SDSZ_8 0x00020000 /* 8M */
+#define SDRAM_BXCR_SDSZ_16 0x00040000 /* 16M */
+#define SDRAM_BXCR_SDSZ_32 0x00060000 /* 32M */
+#define SDRAM_BXCR_SDSZ_64 0x00080000 /* 64M */
+#define SDRAM_BXCR_SDSZ_128 0x000a0000 /* 128M */
+#define SDRAM_BXCR_SDSZ_256 0x000c0000 /* 256M */
+#define SDRAM_BXCR_SDSZ_512 0x000e0000 /* 512M */
+#define SDRAM_BXCR_SDAM_MASK 0x0000e000 /* Addressing mode */
+#define SDRAM_BXCR_SDAM_1 0x00000000 /* Mode 1 */
+#define SDRAM_BXCR_SDAM_2 0x00002000 /* Mode 2 */
+#define SDRAM_BXCR_SDAM_3 0x00004000 /* Mode 3 */
+#define SDRAM_BXCR_SDAM_4 0x00006000 /* Mode 4 */
+#define SDRAM_BXCR_SDBE 0x00000001 /* Memory Bank Enable */
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM TR0 Options
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_TR0_SDWR_MASK 0x80000000
+#define SDRAM_TR0_SDWR_2_CLK 0x00000000
+#define SDRAM_TR0_SDWR_3_CLK 0x80000000
+#define SDRAM_TR0_SDWD_MASK 0x40000000
+#define SDRAM_TR0_SDWD_0_CLK 0x00000000
+#define SDRAM_TR0_SDWD_1_CLK 0x40000000
+#define SDRAM_TR0_SDCL_MASK 0x01800000
+#define SDRAM_TR0_SDCL_2_0_CLK 0x00800000
+#define SDRAM_TR0_SDCL_2_5_CLK 0x01000000
+#define SDRAM_TR0_SDCL_3_0_CLK 0x01800000
+#define SDRAM_TR0_SDPA_MASK 0x000C0000
+#define SDRAM_TR0_SDPA_2_CLK 0x00040000
+#define SDRAM_TR0_SDPA_3_CLK 0x00080000
+#define SDRAM_TR0_SDPA_4_CLK 0x000C0000
+#define SDRAM_TR0_SDCP_MASK 0x00030000
+#define SDRAM_TR0_SDCP_2_CLK 0x00000000
+#define SDRAM_TR0_SDCP_3_CLK 0x00010000
+#define SDRAM_TR0_SDCP_4_CLK 0x00020000
+#define SDRAM_TR0_SDCP_5_CLK 0x00030000
+#define SDRAM_TR0_SDLD_MASK 0x0000C000
+#define SDRAM_TR0_SDLD_1_CLK 0x00000000
+#define SDRAM_TR0_SDLD_2_CLK 0x00004000
+#define SDRAM_TR0_SDRA_MASK 0x0000001C
+#define SDRAM_TR0_SDRA_6_CLK 0x00000000
+#define SDRAM_TR0_SDRA_7_CLK 0x00000004
+#define SDRAM_TR0_SDRA_8_CLK 0x00000008
+#define SDRAM_TR0_SDRA_9_CLK 0x0000000C
+#define SDRAM_TR0_SDRA_10_CLK 0x00000010
+#define SDRAM_TR0_SDRA_11_CLK 0x00000014
+#define SDRAM_TR0_SDRA_12_CLK 0x00000018
+#define SDRAM_TR0_SDRA_13_CLK 0x0000001C
+#define SDRAM_TR0_SDRD_MASK 0x00000003
+#define SDRAM_TR0_SDRD_2_CLK 0x00000001
+#define SDRAM_TR0_SDRD_3_CLK 0x00000002
+#define SDRAM_TR0_SDRD_4_CLK 0x00000003
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM TR1 Options
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_TR1_RDSS_MASK 0xC0000000
+#define SDRAM_TR1_RDSS_TR0 0x00000000
+#define SDRAM_TR1_RDSS_TR1 0x40000000
+#define SDRAM_TR1_RDSS_TR2 0x80000000
+#define SDRAM_TR1_RDSS_TR3 0xC0000000
+#define SDRAM_TR1_RDSL_MASK 0x00C00000
+#define SDRAM_TR1_RDSL_STAGE1 0x00000000
+#define SDRAM_TR1_RDSL_STAGE2 0x00400000
+#define SDRAM_TR1_RDSL_STAGE3 0x00800000
+#define SDRAM_TR1_RDCD_MASK 0x00000800
+#define SDRAM_TR1_RDCD_RCD_0_0 0x00000000
+#define SDRAM_TR1_RDCD_RCD_1_2 0x00000800
+#define SDRAM_TR1_RDCT_MASK 0x000001FF
+#define SDRAM_TR1_RDCT_ENCODE(x) (((x) << 0) & SDRAM_TR1_RDCT_MASK)
+#define SDRAM_TR1_RDCT_DECODE(x) (((x) & SDRAM_TR1_RDCT_MASK) >> 0)
+#define SDRAM_TR1_RDCT_MIN 0x00000000
+#define SDRAM_TR1_RDCT_MAX 0x000001FF
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM WDDCTR Options
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_WDDCTR_WRCP_MASK 0xC0000000
+#define SDRAM_WDDCTR_WRCP_0DEG 0x00000000
+#define SDRAM_WDDCTR_WRCP_90DEG 0x40000000
+#define SDRAM_WDDCTR_WRCP_180DEG 0x80000000
+#define SDRAM_WDDCTR_DCD_MASK 0x000001FF
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM CLKTR Options
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_CLKTR_CLKP_MASK 0xC0000000
+#define SDRAM_CLKTR_CLKP_0DEG 0x00000000
+#define SDRAM_CLKTR_CLKP_90DEG 0x40000000
+#define SDRAM_CLKTR_CLKP_180DEG 0x80000000
+#define SDRAM_CLKTR_DCDT_MASK 0x000001FF
+
+/*-----------------------------------------------------------------------------+
+ | SDRAM DLYCAL Options
+ +-----------------------------------------------------------------------------*/
+#define SDRAM_DLYCAL_DLCV_MASK 0x000003FC
+#define SDRAM_DLYCAL_DLCV_ENCODE(x) (((x)<<2) & SDRAM_DLYCAL_DLCV_MASK)
+#define SDRAM_DLYCAL_DLCV_DECODE(x) (((x) & SDRAM_DLYCAL_DLCV_MASK)>>2)
+
+/*-----------------------------------------------------------------------------+
+ | General Definition
+ +-----------------------------------------------------------------------------*/
+#define DEFAULT_SPD_ADDR1 0x53
+#define DEFAULT_SPD_ADDR2 0x52
+#define MAXBANKS 4 /* at most 4 dimm banks */
+#define MAX_SPD_BYTES 256
+#define NUMHALFCYCLES 4
+#define NUMMEMTESTS 8
+#define NUMMEMWORDS 8
+#define MAXBXCR 4
+#define TRUE 1
+#define FALSE 0
+
+const unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = {
+ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF},
+ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000},
+ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555},
+ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA},
+ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A},
+ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5},
+ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA},
+ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55}
+};
+
+/* bank_parms is used to sort the bank sizes by descending order */
+struct bank_param {
+ unsigned long cr;
+ unsigned long bank_size_bytes;
+};
+
+typedef struct bank_param BANKPARMS;
+
+#ifdef CFG_SIMULATE_SPD_EEPROM
+extern unsigned char cfg_simulate_spd_eeprom[128];
+#endif
+
+unsigned char spd_read(uchar chip, uint addr);
+
+void get_spd_info(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+void check_mem_type
+(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+void check_volt_type
+(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+void program_cfg0(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+void program_cfg1(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+void program_rtr (unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+void program_tr0 (unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+void program_tr1 (void);
+
+void program_ecc (unsigned long num_bytes);
+
+unsigned
+long program_bxcr(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+/*
+ * This function is reading data from the DIMM module EEPROM over the SPD bus
+ * and uses that to program the sdram controller.
+ *
+ * This works on boards that has the same schematics that the AMCC walnut has.
+ *
+ * BUG: Don't handle ECC memory
+ * BUG: A few values in the TR register is currently hardcoded
+ */
+
+long int spd_sdram(void) {
+ unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
+ unsigned long dimm_populated[sizeof(iic0_dimm_addr)];
+ unsigned long total_size;
+ unsigned long cfg0;
+ unsigned long mcsts;
+ unsigned long num_dimm_banks; /* on board dimm banks */
+
+ num_dimm_banks = sizeof(iic0_dimm_addr);
+
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+ i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE);
+
+ /*
+ * Read the SPD information using I2C interface. Check to see if the
+ * DIMM slots are populated.
+ */
+ get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * Check the memory type for the dimms plugged.
+ */
+ check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * Check the voltage type for the dimms plugged.
+ */
+ check_volt_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+#if defined(CONFIG_440GX)
+ /*
+ * Soft-reset SDRAM controller.
+ */
+ mtsdr(sdr_srst, SDR0_SRST_DMC);
+ mtsdr(sdr_srst, 0x00000000);
+#endif
+
+ /*
+ * program 440GP SDRAM controller options (SDRAM0_CFG0)
+ */
+ program_cfg0(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program 440GP SDRAM controller options (SDRAM0_CFG1)
+ */
+ program_cfg1(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program SDRAM refresh register (SDRAM0_RTR)
+ */
+ program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program SDRAM Timing Register 0 (SDRAM0_TR0)
+ */
+ program_tr0(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program the BxCR registers to find out total sdram installed
+ */
+ total_size = program_bxcr(dimm_populated, iic0_dimm_addr,
+ num_dimm_banks);
+
+ /*
+ * program SDRAM Clock Timing Register (SDRAM0_CLKTR)
+ */
+ mtsdram(mem_clktr, 0x40000000);
+
+ /*
+ * delay to ensure 200 usec has elapsed
+ */
+ udelay(400);
+
+ /*
+ * enable the memory controller
+ */
+ mfsdram(mem_cfg0, cfg0);
+ mtsdram(mem_cfg0, cfg0 | SDRAM_CFG0_DCEN);
+
+ /*
+ * wait for SDRAM_CFG0_DC_EN to complete
+ */
+ while (1) {
+ mfsdram(mem_mcsts, mcsts);
+ if ((mcsts & SDRAM_MCSTS_MRSC) != 0) {
+ break;
+ }
+ }
+
+ /*
+ * program SDRAM Timing Register 1, adding some delays
+ */
+ program_tr1();
+
+ /*
+ * if ECC is enabled, initialize parity bits
+ */
+
+ return total_size;
+}
+
+unsigned char spd_read(uchar chip, uint addr)
+{
+ unsigned char data[2];
+
+#ifdef CFG_SIMULATE_SPD_EEPROM
+ if (chip == CFG_SIMULATE_SPD_EEPROM) {
+ /*
+ * Onboard spd eeprom requested -> simulate values
+ */
+ return cfg_simulate_spd_eeprom[addr];
+ }
+#endif /* CFG_SIMULATE_SPD_EEPROM */
+
+ if (i2c_probe(chip) == 0) {
+ if (i2c_read(chip, addr, 1, data, 1) == 0) {
+ return data[0];
+ }
+ }
+
+ return 0;
+}
+
+void get_spd_info(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_found;
+ unsigned char num_of_bytes;
+ unsigned char total_size;
+
+ dimm_found = FALSE;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ num_of_bytes = 0;
+ total_size = 0;
+
+ num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+ total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+
+ if ((num_of_bytes != 0) && (total_size != 0)) {
+ dimm_populated[dimm_num] = TRUE;
+ dimm_found = TRUE;
+#if 0
+ printf("DIMM slot %lu: populated\n", dimm_num);
+#endif
+ } else {
+ dimm_populated[dimm_num] = FALSE;
+#if 0
+ printf("DIMM slot %lu: Not populated\n", dimm_num);
+#endif
+ }
+ }
+
+ if (dimm_found == FALSE) {
+ printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n");
+ hang();
+ }
+}
+
+void check_mem_type(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned char dimm_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == TRUE) {
+ dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2);
+ switch (dimm_type) {
+ case 7:
+#if 0
+ printf("DIMM slot %lu: DDR SDRAM detected\n", dimm_num);
+#endif
+ break;
+ default:
+ printf("ERROR: Unsupported DIMM detected in slot %lu.\n",
+ dimm_num);
+ printf("Only DDR SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ }
+ }
+ }
+}
+
+
+void check_volt_type(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long voltage_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == TRUE) {
+ voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+ if (voltage_type != 0x04) {
+ printf("ERROR: DIMM %lu with unsupported voltage level.\n",
+ dimm_num);
+ hang();
+ } else {
+#if 0
+ printf("DIMM %lu voltage level supported.\n", dimm_num);
+#endif
+ }
+ break;
+ }
+ }
+}
+
+void program_cfg0(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long cfg0;
+ unsigned long ecc_enabled;
+ unsigned char ecc;
+ unsigned char attributes;
+ unsigned long data_width;
+ unsigned long dimm_32bit;
+ unsigned long dimm_64bit;
+
+ /*
+ * get Memory Controller Options 0 data
+ */
+ mfsdram(mem_cfg0, cfg0);
+
+ /*
+ * clear bits
+ */
+ cfg0 &= ~(SDRAM_CFG0_DCEN | SDRAM_CFG0_MCHK_MASK |
+ SDRAM_CFG0_RDEN | SDRAM_CFG0_PMUD |
+ SDRAM_CFG0_DMWD_MASK |
+ SDRAM_CFG0_UIOS_MASK | SDRAM_CFG0_PDP);
+
+
+ /*
+ * FIXME: assume the DDR SDRAMs in both banks are the same
+ */
+ ecc_enabled = TRUE;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == TRUE) {
+ ecc = spd_read(iic0_dimm_addr[dimm_num], 11);
+ if (ecc != 0x02) {
+ ecc_enabled = FALSE;
+ }
+
+ /*
+ * program Registered DIMM Enable
+ */
+ attributes = spd_read(iic0_dimm_addr[dimm_num], 21);
+ if ((attributes & 0x02) != 0x00) {
+ cfg0 |= SDRAM_CFG0_RDEN;
+ }
+
+ /*
+ * program DDR SDRAM Data Width
+ */
+ data_width =
+ (unsigned long)spd_read(iic0_dimm_addr[dimm_num],6) +
+ (((unsigned long)spd_read(iic0_dimm_addr[dimm_num],7)) << 8);
+ if (data_width == 64 || data_width == 72) {
+ dimm_64bit = TRUE;
+ cfg0 |= SDRAM_CFG0_DMWD_64;
+ } else if (data_width == 32 || data_width == 40) {
+ dimm_32bit = TRUE;
+ cfg0 |= SDRAM_CFG0_DMWD_32;
+ } else {
+ printf("WARNING: DIMM with datawidth of %lu bits.\n",
+ data_width);
+ printf("Only DIMMs with 32 or 64 bit datawidths supported.\n");
+ hang();
+ }
+ break;
+ }
+ }
+
+ /*
+ * program Memory Data Error Checking
+ */
+ if (ecc_enabled == TRUE) {
+ cfg0 |= SDRAM_CFG0_MCHK_GEN;
+ } else {
+ cfg0 |= SDRAM_CFG0_MCHK_NON;
+ }
+
+ /*
+ * program Page Management Unit
+ */
+ cfg0 |= SDRAM_CFG0_PMUD;
+
+ /*
+ * program Memory Controller Options 0
+ * Note: DCEN must be enabled after all DDR SDRAM controller
+ * configuration registers get initialized.
+ */
+ mtsdram(mem_cfg0, cfg0);
+}
+
+void program_cfg1(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long cfg1;
+ mfsdram(mem_cfg1, cfg1);
+
+ /*
+ * Self-refresh exit, disable PM
+ */
+ cfg1 &= ~(SDRAM_CFG1_SRE | SDRAM_CFG1_PMEN);
+
+ /*
+ * program Memory Controller Options 1
+ */
+ mtsdram(mem_cfg1, cfg1);
+}
+
+void program_rtr (unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long bus_period_x_10;
+ unsigned long refresh_rate = 0;
+ unsigned char refresh_rate_type;
+ unsigned long refresh_interval;
+ unsigned long sdram_rtr;
+ PPC440_SYS_INFO sys_info;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+ bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == TRUE) {
+ refresh_rate_type = 0x7F & spd_read(iic0_dimm_addr[dimm_num], 12);
+ switch (refresh_rate_type) {
+ case 0x00:
+ refresh_rate = 15625;
+ break;
+ case 0x01:
+ refresh_rate = 15625/4;
+ break;
+ case 0x02:
+ refresh_rate = 15625/2;
+ break;
+ case 0x03:
+ refresh_rate = 15626*2;
+ break;
+ case 0x04:
+ refresh_rate = 15625*4;
+ break;
+ case 0x05:
+ refresh_rate = 15625*8;
+ break;
+ default:
+ printf("ERROR: DIMM %lu, unsupported refresh rate/type.\n",
+ dimm_num);
+ printf("Replace the DIMM module with a supported DIMM.\n");
+ break;
+ }
+
+ break;
+ }
+ }
+
+ refresh_interval = refresh_rate * 10 / bus_period_x_10;
+ sdram_rtr = (refresh_interval & 0x3ff8) << 16;
+
+ /*
+ * program Refresh Timer Register (SDRAM0_RTR)
+ */
+ mtsdram(mem_rtr, sdram_rtr);
+}
+
+void program_tr0 (unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long tr0;
+ unsigned char wcsbc;
+ unsigned char t_rp_ns;
+ unsigned char t_rcd_ns;
+ unsigned char t_ras_ns;
+ unsigned long t_rp_clk;
+ unsigned long t_ras_rcd_clk;
+ unsigned long t_rcd_clk;
+ unsigned long t_rfc_clk;
+ unsigned long plb_check;
+ unsigned char cas_bit;
+ unsigned long cas_index;
+ unsigned char cas_2_0_available;
+ unsigned char cas_2_5_available;
+ unsigned char cas_3_0_available;
+ unsigned long cycle_time_ns_x_10[3];
+ unsigned long tcyc_3_0_ns_x_10;
+ unsigned long tcyc_2_5_ns_x_10;
+ unsigned long tcyc_2_0_ns_x_10;
+ unsigned long tcyc_reg;
+ unsigned long bus_period_x_10;
+ PPC440_SYS_INFO sys_info;
+ unsigned long residue;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+ bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+ /*
+ * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits
+ */
+ mfsdram(mem_tr0, tr0);
+ tr0 &= ~(SDRAM_TR0_SDWR_MASK | SDRAM_TR0_SDWD_MASK |
+ SDRAM_TR0_SDCL_MASK | SDRAM_TR0_SDPA_MASK |
+ SDRAM_TR0_SDCP_MASK | SDRAM_TR0_SDLD_MASK |
+ SDRAM_TR0_SDRA_MASK | SDRAM_TR0_SDRD_MASK);
+
+ /*
+ * initialization
+ */
+ wcsbc = 0;
+ t_rp_ns = 0;
+ t_rcd_ns = 0;
+ t_ras_ns = 0;
+ cas_2_0_available = TRUE;
+ cas_2_5_available = TRUE;
+ cas_3_0_available = TRUE;
+ tcyc_2_0_ns_x_10 = 0;
+ tcyc_2_5_ns_x_10 = 0;
+ tcyc_3_0_ns_x_10 = 0;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == TRUE) {
+ wcsbc = spd_read(iic0_dimm_addr[dimm_num], 15);
+ t_rp_ns = spd_read(iic0_dimm_addr[dimm_num], 27) >> 2;
+ t_rcd_ns = spd_read(iic0_dimm_addr[dimm_num], 29) >> 2;
+ t_ras_ns = spd_read(iic0_dimm_addr[dimm_num], 30);
+ cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18);
+
+ for (cas_index = 0; cas_index < 3; cas_index++) {
+ switch (cas_index) {
+ case 0:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+ break;
+ case 1:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23);
+ break;
+ default:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25);
+ break;
+ }
+
+ if ((tcyc_reg & 0x0F) >= 10) {
+ printf("ERROR: Tcyc incorrect for DIMM in slot %lu\n",
+ dimm_num);
+ hang();
+ }
+
+ cycle_time_ns_x_10[cas_index] =
+ (((tcyc_reg & 0xF0) >> 4) * 10) + (tcyc_reg & 0x0F);
+ }
+
+ cas_index = 0;
+
+ if ((cas_bit & 0x80) != 0) {
+ cas_index += 3;
+ } else if ((cas_bit & 0x40) != 0) {
+ cas_index += 2;
+ } else if ((cas_bit & 0x20) != 0) {
+ cas_index += 1;
+ }
+
+ if (((cas_bit & 0x10) != 0) && (cas_index < 3)) {
+ tcyc_3_0_ns_x_10 = cycle_time_ns_x_10[cas_index];
+ cas_index++;
+ } else {
+ if (cas_index != 0) {
+ cas_index++;
+ }
+ cas_3_0_available = FALSE;
+ }
+
+ if (((cas_bit & 0x08) != 0) || (cas_index < 3)) {
+ tcyc_2_5_ns_x_10 = cycle_time_ns_x_10[cas_index];
+ cas_index++;
+ } else {
+ if (cas_index != 0) {
+ cas_index++;
+ }
+ cas_2_5_available = FALSE;
+ }
+
+ if (((cas_bit & 0x04) != 0) || (cas_index < 3)) {
+ tcyc_2_0_ns_x_10 = cycle_time_ns_x_10[cas_index];
+ cas_index++;
+ } else {
+ if (cas_index != 0) {
+ cas_index++;
+ }
+ cas_2_0_available = FALSE;
+ }
+
+ break;
+ }
+ }
+
+ /*
+ * Program SD_WR and SD_WCSBC fields
+ */
+ tr0 |= SDRAM_TR0_SDWR_2_CLK; /* Write Recovery: 2 CLK */
+ switch (wcsbc) {
+ case 0:
+ tr0 |= SDRAM_TR0_SDWD_0_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDWD_1_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_CASL field
+ */
+ if ((cas_2_0_available == TRUE) &&
+ (bus_period_x_10 >= tcyc_2_0_ns_x_10)) {
+ tr0 |= SDRAM_TR0_SDCL_2_0_CLK;
+ } else if ((cas_2_5_available == TRUE) &&
+ (bus_period_x_10 >= tcyc_2_5_ns_x_10)) {
+ tr0 |= SDRAM_TR0_SDCL_2_5_CLK;
+ } else if ((cas_3_0_available == TRUE) &&
+ (bus_period_x_10 >= tcyc_3_0_ns_x_10)) {
+ tr0 |= SDRAM_TR0_SDCL_3_0_CLK;
+ } else {
+ printf("ERROR: No supported CAS latency with the installed DIMMs.\n");
+ printf("Only CAS latencies of 2.0, 2.5, and 3.0 are supported.\n");
+ printf("Make sure the PLB speed is within the supported range.\n");
+ hang();
+ }
+
+ /*
+ * Calculate Trp in clock cycles and round up if necessary
+ * Program SD_PTA field
+ */
+ t_rp_clk = sys_info.freqPLB * t_rp_ns / ONE_BILLION;
+ plb_check = ONE_BILLION * t_rp_clk / t_rp_ns;
+ if (sys_info.freqPLB != plb_check) {
+ t_rp_clk++;
+ }
+ switch ((unsigned long)t_rp_clk) {
+ case 0:
+ case 1:
+ case 2:
+ tr0 |= SDRAM_TR0_SDPA_2_CLK;
+ break;
+ case 3:
+ tr0 |= SDRAM_TR0_SDPA_3_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDPA_4_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_CTP field
+ */
+ t_ras_rcd_clk = sys_info.freqPLB * (t_ras_ns - t_rcd_ns) / ONE_BILLION;
+ plb_check = ONE_BILLION * t_ras_rcd_clk / (t_ras_ns - t_rcd_ns);
+ if (sys_info.freqPLB != plb_check) {
+ t_ras_rcd_clk++;
+ }
+ switch (t_ras_rcd_clk) {
+ case 0:
+ case 1:
+ case 2:
+ tr0 |= SDRAM_TR0_SDCP_2_CLK;
+ break;
+ case 3:
+ tr0 |= SDRAM_TR0_SDCP_3_CLK;
+ break;
+ case 4:
+ tr0 |= SDRAM_TR0_SDCP_4_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDCP_5_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_LDF field
+ */
+ tr0 |= SDRAM_TR0_SDLD_2_CLK;
+
+ /*
+ * Program SD_RFTA field
+ * FIXME tRFC hardcoded as 75 nanoseconds
+ */
+ t_rfc_clk = sys_info.freqPLB / (ONE_BILLION / 75);
+ residue = sys_info.freqPLB % (ONE_BILLION / 75);
+ if (residue >= (ONE_BILLION / 150)) {
+ t_rfc_clk++;
+ }
+ switch (t_rfc_clk) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ tr0 |= SDRAM_TR0_SDRA_6_CLK;
+ break;
+ case 7:
+ tr0 |= SDRAM_TR0_SDRA_7_CLK;
+ break;
+ case 8:
+ tr0 |= SDRAM_TR0_SDRA_8_CLK;
+ break;
+ case 9:
+ tr0 |= SDRAM_TR0_SDRA_9_CLK;
+ break;
+ case 10:
+ tr0 |= SDRAM_TR0_SDRA_10_CLK;
+ break;
+ case 11:
+ tr0 |= SDRAM_TR0_SDRA_11_CLK;
+ break;
+ case 12:
+ tr0 |= SDRAM_TR0_SDRA_12_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDRA_13_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_RCD field
+ */
+ t_rcd_clk = sys_info.freqPLB * t_rcd_ns / ONE_BILLION;
+ plb_check = ONE_BILLION * t_rcd_clk / t_rcd_ns;
+ if (sys_info.freqPLB != plb_check) {
+ t_rcd_clk++;
+ }
+ switch (t_rcd_clk) {
+ case 0:
+ case 1:
+ case 2:
+ tr0 |= SDRAM_TR0_SDRD_2_CLK;
+ break;
+ case 3:
+ tr0 |= SDRAM_TR0_SDRD_3_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDRD_4_CLK;
+ break;
+ }
+
+#if 0
+ printf("tr0: %x\n", tr0);
+#endif
+ mtsdram(mem_tr0, tr0);
+}
+
+void program_tr1 (void)
+{
+ unsigned long tr0;
+ unsigned long tr1;
+ unsigned long cfg0;
+ unsigned long ecc_temp;
+ unsigned long dlycal;
+ unsigned long dly_val;
+ unsigned long i, j, k;
+ unsigned long bxcr_num;
+ unsigned long max_pass_length;
+ unsigned long current_pass_length;
+ unsigned long current_fail_length;
+ unsigned long current_start;
+ unsigned long rdclt;
+ unsigned long rdclt_offset;
+ long max_start;
+ long max_end;
+ long rdclt_average;
+ unsigned char window_found;
+ unsigned char fail_found;
+ unsigned char pass_found;
+ unsigned long * membase;
+ PPC440_SYS_INFO sys_info;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+
+ /*
+ * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits
+ */
+ mfsdram(mem_tr1, tr1);
+ tr1 &= ~(SDRAM_TR1_RDSS_MASK | SDRAM_TR1_RDSL_MASK |
+ SDRAM_TR1_RDCD_MASK | SDRAM_TR1_RDCT_MASK);
+
+ mfsdram(mem_tr0, tr0);
+ if (((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) &&
+ (sys_info.freqPLB > 100000000)) {
+ tr1 |= SDRAM_TR1_RDSS_TR2;
+ tr1 |= SDRAM_TR1_RDSL_STAGE3;
+ tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
+ } else {
+ tr1 |= SDRAM_TR1_RDSS_TR1;
+ tr1 |= SDRAM_TR1_RDSL_STAGE2;
+ tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
+ }
+
+ /*
+ * save CFG0 ECC setting to a temporary variable and turn ECC off
+ */
+ mfsdram(mem_cfg0, cfg0);
+ ecc_temp = cfg0 & SDRAM_CFG0_MCHK_MASK;
+ mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | SDRAM_CFG0_MCHK_NON);
+
+ /*
+ * get the delay line calibration register value
+ */
+ mfsdram(mem_dlycal, dlycal);
+ dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2;
+
+ max_pass_length = 0;
+ max_start = 0;
+ max_end = 0;
+ current_pass_length = 0;
+ current_fail_length = 0;
+ current_start = 0;
+ rdclt_offset = 0;
+ window_found = FALSE;
+ fail_found = FALSE;
+ pass_found = FALSE;
+#ifdef DEBUG
+ printf("Starting memory test ");
+#endif
+ for (k = 0; k < NUMHALFCYCLES; k++) {
+ for (rdclt = 0; rdclt < dly_val; rdclt++) {
+ /*
+ * Set the timing reg for the test.
+ */
+ mtsdram(mem_tr1, (tr1 | SDRAM_TR1_RDCT_ENCODE(rdclt)));
+
+ for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) {
+ mtdcr(memcfga, mem_b0cr + (bxcr_num<<2));
+ if ((mfdcr(memcfgd) & SDRAM_BXCR_SDBE) == SDRAM_BXCR_SDBE) {
+ /* Bank is enabled */
+ membase = (unsigned long*)
+ (mfdcr(memcfgd) & SDRAM_BXCR_SDBA_MASK);
+
+ /*
+ * Run the short memory test
+ */
+ for (i = 0; i < NUMMEMTESTS; i++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ membase[j] = test[i][j];
+ ppcDcbf((unsigned long)&(membase[j]));
+ }
+
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ if (membase[j] != test[i][j]) {
+ ppcDcbf((unsigned long)&(membase[j]));
+ break;
+ }
+ ppcDcbf((unsigned long)&(membase[j]));
+ }
+
+ if (j < NUMMEMWORDS) {
+ break;
+ }
+ }
+
+ /*
+ * see if the rdclt value passed
+ */
+ if (i < NUMMEMTESTS) {
+ break;
+ }
+ }
+ }
+
+ if (bxcr_num == MAXBXCR) {
+ if (fail_found == TRUE) {
+ pass_found = TRUE;
+ if (current_pass_length == 0) {
+ current_start = rdclt_offset + rdclt;
+ }
+
+ current_fail_length = 0;
+ current_pass_length++;
+
+ if (current_pass_length > max_pass_length) {
+ max_pass_length = current_pass_length;
+ max_start = current_start;
+ max_end = rdclt_offset + rdclt;
+ }
+ }
+ } else {
+ current_pass_length = 0;
+ current_fail_length++;
+
+ if (current_fail_length >= (dly_val>>2)) {
+ if (fail_found == FALSE) {
+ fail_found = TRUE;
+ } else if (pass_found == TRUE) {
+ window_found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+#ifdef DEBUG
+ printf(".");
+#endif
+ if (window_found == TRUE) {
+ break;
+ }
+
+ tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
+ rdclt_offset += dly_val;
+ }
+#ifdef DEBUG
+ printf("\n");
+#endif
+
+ /*
+ * make sure we find the window
+ */
+ if (window_found == FALSE) {
+ printf("ERROR: Cannot determine a common read delay.\n");
+ hang();
+ }
+
+ /*
+ * restore the orignal ECC setting
+ */
+ mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | ecc_temp);
+
+ /*
+ * set the SDRAM TR1 RDCD value
+ */
+ tr1 &= ~SDRAM_TR1_RDCD_MASK;
+ if ((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) {
+ tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
+ } else {
+ tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
+ }
+
+ /*
+ * set the SDRAM TR1 RDCLT value
+ */
+ tr1 &= ~SDRAM_TR1_RDCT_MASK;
+ while (max_end >= (dly_val << 1)) {
+ max_end -= (dly_val << 1);
+ max_start -= (dly_val << 1);
+ }
+
+ rdclt_average = ((max_start + max_end) >> 1);
+ if (rdclt_average >= 0x60)
+ while (1)
+ ;
+
+ if (rdclt_average < 0) {
+ rdclt_average = 0;
+ }
+
+ if (rdclt_average >= dly_val) {
+ rdclt_average -= dly_val;
+ tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
+ }
+ tr1 |= SDRAM_TR1_RDCT_ENCODE(rdclt_average);
+
+#if 0
+ printf("tr1: %x\n", tr1);
+#endif
+ /*
+ * program SDRAM Timing Register 1 TR1
+ */
+ mtsdram(mem_tr1, tr1);
+}
+
+unsigned long program_bxcr(unsigned long* dimm_populated,
+ unsigned char* iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long bank_base_addr;
+ unsigned long cr;
+ unsigned long i;
+ unsigned long j;
+ unsigned long temp;
+ unsigned char num_row_addr;
+ unsigned char num_col_addr;
+ unsigned char num_banks;
+ unsigned char bank_size_id;
+ unsigned long ctrl_bank_num[MAXBANKS];
+ unsigned long bx_cr_num;
+ unsigned long largest_size_index;
+ unsigned long largest_size;
+ unsigned long current_size_index;
+ BANKPARMS bank_parms[MAXBXCR];
+ unsigned long sorted_bank_num[MAXBXCR]; /* DDR Controller bank number table (sorted by size) */
+ unsigned long sorted_bank_size[MAXBXCR]; /* DDR Controller bank size table (sorted by size)*/
+
+ /*
+ * Set the BxCR regs. First, wipe out the bank config registers.
+ */
+ for (bx_cr_num = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
+ mtdcr(memcfga, mem_b0cr + (bx_cr_num << 2));
+ mtdcr(memcfgd, 0x00000000);
+ bank_parms[bx_cr_num].bank_size_bytes = 0;
+ }
+
+#ifdef CONFIG_BAMBOO
+ /*
+ * This next section is hardware dependent and must be programmed
+ * to match the hardware. For bammboo, the following holds...
+ * 1. SDRAM0_B0CR: Bank 0 of dimm 0 ctrl_bank_num : 0
+ * 2. SDRAM0_B1CR: Bank 0 of dimm 1 ctrl_bank_num : 1
+ * 3. SDRAM0_B2CR: Bank 1 of dimm 1 ctrl_bank_num : 1
+ * 4. SDRAM0_B3CR: Bank 0 of dimm 2 ctrl_bank_num : 3
+ * ctrl_bank_num corresponds to the first usable DDR controller bank number by DIMM
+ */
+ ctrl_bank_num[0] = 0;
+ ctrl_bank_num[1] = 1;
+ ctrl_bank_num[2] = 3;
+#else
+ ctrl_bank_num[0] = 0;
+ ctrl_bank_num[1] = 1;
+ ctrl_bank_num[2] = 2;
+ ctrl_bank_num[3] = 3;
+#endif
+
+ /*
+ * reset the bank_base address
+ */
+ bank_base_addr = CFG_SDRAM_BASE;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == TRUE) {
+ num_row_addr = spd_read(iic0_dimm_addr[dimm_num], 3);
+ num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4);
+ num_banks = spd_read(iic0_dimm_addr[dimm_num], 5);
+ bank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31);
+
+ /*
+ * Set the SDRAM0_BxCR regs
+ */
+ cr = 0;
+ switch (bank_size_id) {
+ case 0x02:
+ cr |= SDRAM_BXCR_SDSZ_8;
+ break;
+ case 0x04:
+ cr |= SDRAM_BXCR_SDSZ_16;
+ break;
+ case 0x08:
+ cr |= SDRAM_BXCR_SDSZ_32;
+ break;
+ case 0x10:
+ cr |= SDRAM_BXCR_SDSZ_64;
+ break;
+ case 0x20:
+ cr |= SDRAM_BXCR_SDSZ_128;
+ break;
+ case 0x40:
+ cr |= SDRAM_BXCR_SDSZ_256;
+ break;
+ case 0x80:
+ cr |= SDRAM_BXCR_SDSZ_512;
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
+ dimm_num);
+ printf("ERROR: Unsupported value for the banksize: %d.\n",
+ bank_size_id);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ }
+
+ switch (num_col_addr) {
+ case 0x08:
+ cr |= SDRAM_BXCR_SDAM_1;
+ break;
+ case 0x09:
+ cr |= SDRAM_BXCR_SDAM_2;
+ break;
+ case 0x0A:
+ cr |= SDRAM_BXCR_SDAM_3;
+ break;
+ case 0x0B:
+ cr |= SDRAM_BXCR_SDAM_4;
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
+ dimm_num);
+ printf("ERROR: Unsupported value for number of "
+ "column addresses: %d.\n", num_col_addr);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ }
+
+ /*
+ * enable the bank
+ */
+ cr |= SDRAM_BXCR_SDBE;
+
+ for (i = 0; i < num_banks; i++) {
+ bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes =
+ (4 * 1024 * 1024) * bank_size_id;
+ bank_parms[ctrl_bank_num[dimm_num]+i].cr = cr;
+ }
+ }
+ }
+
+ /* Initialize sort tables */
+ for (i = 0; i < MAXBXCR; i++) {
+ sorted_bank_num[i] = i;
+ sorted_bank_size[i] = bank_parms[i].bank_size_bytes;
+ }
+
+ for (i = 0; i < MAXBXCR-1; i++) {
+ largest_size = sorted_bank_size[i];
+ largest_size_index = 255;
+
+ /* Find the largest remaining value */
+ for (j = i + 1; j < MAXBXCR; j++) {
+ if (sorted_bank_size[j] > largest_size) {
+ /* Save largest remaining value and its index */
+ largest_size = sorted_bank_size[j];
+ largest_size_index = j;
+ }
+ }
+
+ if (largest_size_index != 255) {
+ /* Swap the current and largest values */
+ current_size_index = sorted_bank_num[largest_size_index];
+ sorted_bank_size[largest_size_index] = sorted_bank_size[i];
+ sorted_bank_size[i] = largest_size;
+ sorted_bank_num[largest_size_index] = sorted_bank_num[i];
+ sorted_bank_num[i] = current_size_index;
+ }
+ }
+
+ /* Set the SDRAM0_BxCR regs thanks to sort tables */
+ for (bx_cr_num = 0, bank_base_addr = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
+ if (bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes) {
+ mtdcr(memcfga, mem_b0cr + (sorted_bank_num[bx_cr_num] << 2));
+ temp = mfdcr(memcfgd) & ~(SDRAM_BXCR_SDBA_MASK | SDRAM_BXCR_SDSZ_MASK |
+ SDRAM_BXCR_SDAM_MASK | SDRAM_BXCR_SDBE);
+ temp = temp | (bank_base_addr & SDRAM_BXCR_SDBA_MASK) |
+ bank_parms[sorted_bank_num[bx_cr_num]].cr;
+ mtdcr(memcfgd, temp);
+ bank_base_addr += bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes;
+ }
+ }
+
+ return(bank_base_addr);
+}
+
+void program_ecc (unsigned long num_bytes)
+{
+ unsigned long bank_base_addr;
+ unsigned long current_address;
+ unsigned long end_address;
+ unsigned long address_increment;
+ unsigned long cfg0;
+
+ /*
+ * get Memory Controller Options 0 data
+ */
+ mfsdram(mem_cfg0, cfg0);
+
+ /*
+ * reset the bank_base address
+ */
+ bank_base_addr = CFG_SDRAM_BASE;
+
+ if ((cfg0 & SDRAM_CFG0_MCHK_MASK) != SDRAM_CFG0_MCHK_NON) {
+ mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) |
+ SDRAM_CFG0_MCHK_GEN);
+
+ if ((cfg0 & SDRAM_CFG0_DMWD_MASK) == SDRAM_CFG0_DMWD_32) {
+ address_increment = 4;
+ } else {
+ address_increment = 8;
+ }
+
+ current_address = (unsigned long)(bank_base_addr);
+ end_address = (unsigned long)(bank_base_addr) + num_bytes;
+
+ while (current_address < end_address) {
+ *((unsigned long*)current_address) = 0x00000000;
+ current_address += address_increment;
+ }
+
+ mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) |
+ SDRAM_CFG0_MCHK_CHK);
+ }
+}
+
+#endif /* CONFIG_440 */
+
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c
new file mode 100755
index 0000000..553c491
--- /dev/null
+++ b/cpu/ppc4xx/speed.c
@@ -0,0 +1,568 @@
+/*
+ * (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 <ppc_asm.tmpl>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/* ------------------------------------------------------------------------- */
+
+#define ONE_BILLION 1000000000
+
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
+
+void get_sys_info (PPC405_SYS_INFO * sysInfo)
+{
+ unsigned long pllmr;
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+ uint pvr = get_pvr();
+ unsigned long psr;
+ unsigned long m;
+
+ /*
+ * Read PLL Mode register
+ */
+ pllmr = mfdcr (pllmd);
+
+ /*
+ * Read Pin Strapping register
+ */
+ psr = mfdcr (strap);
+
+ /*
+ * Determine FWD_DIV.
+ */
+ sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
+ if (sysInfo->pllFbkDiv == 0) {
+ sysInfo->pllFbkDiv = 16;
+ }
+
+ /*
+ * Determine PLB_DIV.
+ */
+ sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
+
+ /*
+ * Determine PCI_DIV.
+ */
+ sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
+
+ /*
+ * Determine EXTBUS_DIV.
+ */
+ sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
+
+ /*
+ * Determine OPB_DIV.
+ */
+ sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
+
+ /*
+ * Check if PPC405GPr used (mask minor revision field)
+ */
+ if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
+ /*
+ * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
+ */
+ sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
+
+ /*
+ * Determine factor m depending on PLL feedback clock source
+ */
+ if (!(psr & PSR_PCI_ASYNC_EN)) {
+ if (psr & PSR_NEW_MODE_EN) {
+ /*
+ * sync pci clock used as feedback (new mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
+ } else {
+ /*
+ * sync pci clock used as feedback (legacy mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
+ }
+ } else if (psr & PSR_NEW_MODE_EN) {
+ if (psr & PSR_PERCLK_SYNC_MODE_EN) {
+ /*
+ * PerClk used as feedback (new mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
+ } else {
+ /*
+ * CPU clock used as feedback (new mode)
+ */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
+ }
+ } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
+ /*
+ * PerClk used as feedback (legacy mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
+ } else {
+ /*
+ * PLB clock used as feedback (legacy mode)
+ */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
+ }
+
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+ sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
+ sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
+ } else {
+ /*
+ * Check pllFwdDiv to see if running in bypass mode where the CPU speed
+ * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
+ * to make sure it is within the proper range.
+ * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
+ * Note freqVCO is calculated in Mhz to avoid errors introduced by rounding.
+ */
+ if (sysInfo->pllFwdDiv == 1) {
+ sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
+ sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
+ } else {
+ sysInfo->freqVCOHz = ( 1000000000000LL *
+ (unsigned long long)sysInfo->pllFwdDiv *
+ (unsigned long long)sysInfo->pllFbkDiv *
+ (unsigned long long)sysInfo->pllPlbDiv
+ ) / (unsigned long long)sysClkPeriodPs;
+ sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
+ sysInfo->pllFbkDiv)) * 10000;
+ sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
+ }
+ }
+}
+
+
+/********************************************
+ * get_OPB_freq
+ * return OPB bus freq in Hz
+ *********************************************/
+ulong get_OPB_freq (void)
+{
+ ulong val = 0;
+
+ PPC405_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB / sys_info.pllOpbDiv;
+
+ return val;
+}
+
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+ ulong val;
+ PPC405_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB / sys_info.pllPciDiv;
+ return val;
+}
+
+
+#elif defined(CONFIG_440)
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+void get_sys_info (sys_info_t *sysInfo)
+{
+ unsigned long temp;
+ unsigned long reg;
+ unsigned long lfdiv;
+ unsigned long m;
+ unsigned long prbdv0;
+ /*
+ WARNING: ASSUMES the following:
+ ENG=1
+ PRADV0=1
+ PRBDV0=1
+ */
+
+ /* Decode CPR0_PLLD0 for divisors */
+ mfclk(clk_plld, reg);
+ temp = (reg & PLLD_FWDVA_MASK) >> 16;
+ sysInfo->pllFwdDivA = temp ? temp : 16;
+ temp = (reg & PLLD_FWDVB_MASK) >> 8;
+ sysInfo->pllFwdDivB = temp ? temp: 8 ;
+ temp = (reg & PLLD_FBDV_MASK) >> 24;
+ sysInfo->pllFbkDiv = temp ? temp : 32;
+ lfdiv = reg & PLLD_LFBDV_MASK;
+
+ mfclk(clk_opbd, reg);
+ temp = (reg & OPBDDV_MASK) >> 24;
+ sysInfo->pllOpbDiv = temp ? temp : 4;
+
+ mfclk(clk_perd, reg);
+ temp = (reg & PERDV_MASK) >> 24;
+ sysInfo->pllExtBusDiv = temp ? temp : 8;
+
+ mfclk(clk_primbd, reg);
+ temp = (reg & PRBDV_MASK) >> 24;
+ prbdv0 = temp ? temp : 8;
+
+ mfclk(clk_spcid, reg);
+ temp = (reg & SPCID_MASK) >> 24;
+ sysInfo->pllPciDiv = temp ? temp : 4;
+
+ /* Calculate 'M' based on feedback source */
+ mfsdr(sdr_sdstp0, reg);
+ temp = (reg & PLLSYS0_SEL_MASK) >> 27;
+ if (temp == 0) { /* PLL output */
+ /* Figure which pll to use */
+ mfclk(clk_pllc, reg);
+ temp = (reg & PLLC_SRC_MASK) >> 29;
+ if (!temp) /* PLLOUTA */
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
+ else /* PLLOUTB */
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
+ }
+ else if (temp == 1) /* CPU output */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+ else /* PerClk */
+ m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+
+ /* Now calculate the individual clocks */
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqEPB = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
+ sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
+
+ /* Figure which timer source to use */
+ if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
+ temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
+ if (CONFIG_SYS_CLK_FREQ > temp)
+ sysInfo->freqTmrClk = temp;
+ else
+ sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
+ }
+ else /* Internal clock */
+ sysInfo->freqTmrClk = sysInfo->freqProcessor;
+}
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+ sys_info_t sys_info;
+ get_sys_info (&sys_info);
+ return sys_info.freqPCI;
+}
+
+#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP)
+void get_sys_info (sys_info_t * sysInfo)
+{
+ unsigned long strp0;
+ unsigned long temp;
+ unsigned long m;
+
+ /* Extract configured divisors */
+ strp0 = mfdcr( cpc0_strp0 );
+ sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
+ sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
+ temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
+ sysInfo->pllFbkDiv = temp ? temp : 16;
+ sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
+ sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
+
+ /* Calculate 'M' based on feedback source */
+ if( strp0 & PLLSYS0_EXTSL_MASK )
+ m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+ else
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+
+ /* Now calculate the individual clocks */
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
+ if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
+ sysInfo->freqPLB >>= 1;
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+
+}
+#else
+void get_sys_info (sys_info_t * sysInfo)
+{
+ unsigned long strp0;
+ unsigned long strp1;
+ unsigned long temp;
+ unsigned long temp1;
+ unsigned long lfdiv;
+ unsigned long m;
+ unsigned long prbdv0;
+
+ /* Extract configured divisors */
+ mfsdr( sdr_sdstp0,strp0 );
+ mfsdr( sdr_sdstp1,strp1 );
+
+ temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
+ sysInfo->pllFwdDivA = temp ? temp : 16 ;
+ temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
+ sysInfo->pllFwdDivB = temp ? temp: 8 ;
+ temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
+ sysInfo->pllFbkDiv = temp ? temp : 32;
+ temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
+ sysInfo->pllOpbDiv = temp ? temp : 4;
+ temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
+ sysInfo->pllExtBusDiv = temp ? temp : 4;
+ prbdv0 = (strp0 >> 2) & 0x7;
+
+ /* Calculate 'M' based on feedback source */
+ temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
+ temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
+ lfdiv = temp1 ? temp1 : 64;
+ if (temp == 0) { /* PLL output */
+ /* Figure which pll to use */
+ temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
+ if (!temp)
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
+ else
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
+ }
+ else if (temp == 1) /* CPU output */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+ else /* PerClk */
+ m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+
+ /* Now calculate the individual clocks */
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+
+}
+#endif
+
+ulong get_OPB_freq (void)
+{
+
+ sys_info_t sys_info;
+ get_sys_info (&sys_info);
+ return sys_info.freqOPB;
+}
+
+#elif defined(CONFIG_XILINX_ML300)
+extern void get_sys_info (sys_info_t * sysInfo);
+extern ulong get_PCI_freq (void);
+
+#elif defined(CONFIG_AP1000)
+void get_sys_info (sys_info_t * sysInfo) {
+ sysInfo->freqProcessor = 240 * 1000 * 1000;
+ sysInfo->freqPLB = 80 * 1000 * 1000;
+ sysInfo->freqPCI = 33 * 1000 * 1000;
+}
+
+#elif defined(CONFIG_405)
+
+void get_sys_info (sys_info_t * sysInfo) {
+
+ sysInfo->freqVCOMhz=3125000;
+ sysInfo->freqProcessor=12*1000*1000;
+ sysInfo->freqPLB=50*1000*1000;
+ sysInfo->freqPCI=66*1000*1000;
+
+}
+
+#elif defined(CONFIG_405EP)
+void get_sys_info (PPC405_SYS_INFO * sysInfo)
+{
+ unsigned long pllmr0;
+ unsigned long pllmr1;
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+ unsigned long m;
+ unsigned long pllmr0_ccdv;
+
+ /*
+ * Read PLL Mode registers
+ */
+ pllmr0 = mfdcr (cpc0_pllmr0);
+ pllmr1 = mfdcr (cpc0_pllmr1);
+
+ /*
+ * Determine forward divider A
+ */
+ sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
+
+ /*
+ * Determine forward divider B (should be equal to A)
+ */
+ sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
+ if (sysInfo->pllFbkDiv == 0) {
+ sysInfo->pllFbkDiv = 16;
+ }
+
+ /*
+ * Determine PLB_DIV.
+ */
+ sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
+
+ /*
+ * Determine PCI_DIV.
+ */
+ sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
+
+ /*
+ * Determine EXTBUS_DIV.
+ */
+ sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
+
+ /*
+ * Determine OPB_DIV.
+ */
+ sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
+
+ /*
+ * Determine the M factor
+ */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
+
+ /*
+ * Determine VCO clock frequency
+ */
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+
+ /*
+ * Determine CPU clock frequency
+ */
+ pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
+ if (pllmr1 & PLLMR1_SSCS_MASK) {
+ /*
+ * This is true if FWDVA == FWDVB:
+ * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
+ * / pllmr0_ccdv;
+ */
+ sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
+ / sysInfo->pllFwdDiv / pllmr0_ccdv;
+ } else {
+ sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
+ }
+
+ /*
+ * Determine PLB clock frequency
+ */
+ sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
+}
+
+
+/********************************************
+ * get_OPB_freq
+ * return OPB bus freq in Hz
+ *********************************************/
+ulong get_OPB_freq (void)
+{
+ ulong val = 0;
+
+ PPC405_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB / sys_info.pllOpbDiv;
+
+ return val;
+}
+
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+ ulong val;
+ PPC405_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB / sys_info.pllPciDiv;
+ return val;
+}
+
+#endif
+
+int get_clocks (void)
+{
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405) || defined(CONFIG_405EP)
+ DECLARE_GLOBAL_DATA_PTR;
+
+ sys_info_t sys_info;
+
+ get_sys_info (&sys_info);
+ gd->cpu_clk = sys_info.freqProcessor;
+ gd->bus_clk = sys_info.freqPLB;
+
+#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
+
+#ifdef CONFIG_IOP480
+ DECLARE_GLOBAL_DATA_PTR;
+
+ gd->cpu_clk = 66000000;
+ gd->bus_clk = 66000000;
+#endif
+ return (0);
+}
+
+
+/********************************************
+ * get_bus_freq
+ * return PLB bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+ ulong val;
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_440) || defined(CONFIG_405EP)
+ sys_info_t sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB;
+
+#elif defined(CONFIG_IOP480)
+
+ val = 66;
+
+#else
+# error get_bus_freq() not implemented
+#endif
+
+ return val;
+}
diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S
new file mode 100755
index 0000000..48b430d
--- /dev/null
+++ b/cpu/ppc4xx/start.S
@@ -0,0 +1,1687 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+/*------------------------------------------------------------------------------+ */
+/* */
+/* 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 */
+/*------------------------------------------------------------------------------- */
+
+/* U-Boot - Startup Code for AMCC 4xx PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0xfffffffc and the code is executed
+ * from flash/rom.
+ * in memory, but as long we don't jump around before relocating.
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ * This works because the cpu gives the FLASH (CS0) the whole
+ * address space at startup, and board_init lies as a echo of
+ * the flash somewhere up there in the memorymap.
+ *
+ * board_init will change CS0 to be positioned at the correct
+ * address and (s)dram will be positioned at address 0
+ */
+#include <config.h>
+#include <mpc8xx.h>
+#include <ppc4xx.h>
+#include <version.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>
+
+#ifndef CONFIG_IDENT_STRING
+#define CONFIG_IDENT_STRING ""
+#endif
+
+#ifdef CFG_INIT_DCACHE_CS
+# if (CFG_INIT_DCACHE_CS == 0)
+# define PBxAP pb0ap
+# define PBxCR pb0cr
+# endif
+# if (CFG_INIT_DCACHE_CS == 1)
+# define PBxAP pb1ap
+# define PBxCR pb1cr
+# endif
+# if (CFG_INIT_DCACHE_CS == 2)
+# define PBxAP pb2ap
+# define PBxCR pb2cr
+# endif
+# if (CFG_INIT_DCACHE_CS == 3)
+# define PBxAP pb3ap
+# define PBxCR pb3cr
+# endif
+# if (CFG_INIT_DCACHE_CS == 4)
+# define PBxAP pb4ap
+# define PBxCR pb4cr
+# endif
+# if (CFG_INIT_DCACHE_CS == 5)
+# define PBxAP pb5ap
+# define PBxCR pb5cr
+# endif
+# if (CFG_INIT_DCACHE_CS == 6)
+# define PBxAP pb6ap
+# define PBxCR pb6cr
+# endif
+# if (CFG_INIT_DCACHE_CS == 7)
+# define PBxAP pb7ap
+# define PBxCR pb7cr
+# endif
+#endif /* CFG_INIT_DCACHE_CS */
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME ) /* Machine Check */
+
+
+ .extern ext_bus_cntlr_init
+ .extern sdram_init
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r14 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * 440 Startup -- on reset only the top 4k of the effective
+ * address space is mapped in by an entry in the instruction
+ * and data shadow TLB. The .bootpg section is located in the
+ * top 4k & does only what's necessary to map in the the rest
+ * of the boot rom. Once the boot rom is mapped in we can
+ * proceed with normal startup.
+ *
+ * NOTE: CS0 only covers the top 2MB of the effective address
+ * space after reset.
+ */
+
+#if defined(CONFIG_440)
+ .section .bootpg,"ax"
+ .globl _start_440
+
+/**************************************************************************/
+_start_440:
+ /*----------------------------------------------------------------*/
+ /* Clear and set up some registers. */
+ /*----------------------------------------------------------------*/
+ iccci r0,r0 /* NOTE: operands not used for 440 */
+ dccci r0,r0 /* NOTE: operands not used for 440 */
+ sync
+ li r0,0
+ mtspr srr0,r0
+ mtspr srr1,r0
+ mtspr csrr0,r0
+ mtspr csrr1,r0
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) /* NOTE: 440GX adds machine check status regs */
+ mtspr mcsrr0,r0
+ mtspr mcsrr1,r0
+ mfspr r1, mcsr
+ mtspr mcsr,r1
+#endif
+ /*----------------------------------------------------------------*/
+ /* Initialize debug */
+ /*----------------------------------------------------------------*/
+ mtspr dbcr0,r0
+ mtspr dbcr1,r0
+ mtspr dbcr2,r0
+ mtspr iac1,r0
+ mtspr iac2,r0
+ mtspr iac3,r0
+ mtspr dac1,r0
+ mtspr dac2,r0
+ mtspr dvc1,r0
+ mtspr dvc2,r0
+
+ mfspr r1,dbsr
+ mtspr dbsr,r1 /* Clear all valid bits */
+
+ /*----------------------------------------------------------------*/
+ /* CCR0 init */
+ /*----------------------------------------------------------------*/
+ /* Disable store gathering & broadcast, guarantee inst/data
+ * cache block touch, force load/store alignment
+ * (see errata 1.12: 440_33)
+ */
+ lis r1,0x0030 /* store gathering & broadcast disable */
+ ori r1,r1,0x6000 /* cache touch */
+ mtspr ccr0,r1
+
+ /*----------------------------------------------------------------*/
+ /* Setup interrupt vectors */
+ /*----------------------------------------------------------------*/
+ mtspr ivpr,r0 /* Vectors start at 0x0000_0000 */
+ li r1,0x0100
+ mtspr ivor0,r1 /* Critical input */
+ li r1,0x0200
+ mtspr ivor1,r1 /* Machine check */
+ li r1,0x0300
+ mtspr ivor2,r1 /* Data storage */
+ li r1,0x0400
+ mtspr ivor3,r1 /* Instruction storage */
+ li r1,0x0500
+ mtspr ivor4,r1 /* External interrupt */
+ li r1,0x0600
+ mtspr ivor5,r1 /* Alignment */
+ li r1,0x0700
+ mtspr ivor6,r1 /* Program check */
+ li r1,0x0800
+ mtspr ivor7,r1 /* Floating point unavailable */
+ li r1,0x0c00
+ mtspr ivor8,r1 /* System call */
+ li r1,0x1000
+ mtspr ivor10,r1 /* Decrementer (PIT for 440) */
+ li r1,0x1400
+ mtspr ivor13,r1 /* Data TLB error */
+ li r1,0x1300
+ mtspr ivor14,r1 /* Instr TLB error */
+ li r1,0x2000
+ mtspr ivor15,r1 /* Debug */
+
+ /*----------------------------------------------------------------*/
+ /* Configure cache regions */
+ /*----------------------------------------------------------------*/
+ mtspr inv0,r0
+ mtspr inv1,r0
+ mtspr inv2,r0
+ mtspr inv3,r0
+ mtspr dnv0,r0
+ mtspr dnv1,r0
+ mtspr dnv2,r0
+ mtspr dnv3,r0
+ mtspr itv0,r0
+ mtspr itv1,r0
+ mtspr itv2,r0
+ mtspr itv3,r0
+ mtspr dtv0,r0
+ mtspr dtv1,r0
+ mtspr dtv2,r0
+ mtspr dtv3,r0
+
+ /*----------------------------------------------------------------*/
+ /* Cache victim limits */
+ /*----------------------------------------------------------------*/
+ /* floors 0, ceiling max to use the entire cache -- nothing locked
+ */
+ lis r1,0x0001
+ ori r1,r1,0xf800
+ mtspr ivlim,r1
+ mtspr dvlim,r1
+
+ /*----------------------------------------------------------------*/
+ /* Clear all TLB entries -- TID = 0, TS = 0 */
+ /*----------------------------------------------------------------*/
+ mtspr mmucr,r0
+ li r1,0x003f /* 64 TLB entries */
+ mtctr r1
+0: tlbwe r0,r1,0x0000 /* Invalidate all entries (V=0)*/
+ subi r1,r1,0x0001
+ bdnz 0b
+
+ /*----------------------------------------------------------------*/
+ /* TLB entry setup -- step thru tlbtab */
+ /*----------------------------------------------------------------*/
+ bl tlbtab /* Get tlbtab pointer */
+ mr r5,r0
+ li r1,0x003f /* 64 TLB entries max */
+ mtctr r1
+ li r4,0 /* TLB # */
+
+ addi r5,r5,-4
+1: lwzu r0,4(r5)
+ cmpwi r0,0
+ beq 2f /* 0 marks end */
+ lwzu r1,4(r5)
+ lwzu r2,4(r5)
+ tlbwe r0,r4,0 /* TLB Word 0 */
+ tlbwe r1,r4,1 /* TLB Word 1 */
+ tlbwe r2,r4,2 /* TLB Word 2 */
+ addi r4,r4,1 /* Next TLB */
+ bdnz 1b
+
+ /*----------------------------------------------------------------*/
+ /* Continue from 'normal' start */
+ /*----------------------------------------------------------------*/
+2: bl 3f
+ b _start
+
+3: li r0,0
+ mtspr srr1,r0 /* Keep things disabled for now */
+ mflr r1
+ mtspr srr0,r1
+ rfi
+#endif /* CONFIG_440 */
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION
+ .ascii " (", __DATE__, " - ", __TIME__, ")"
+ .ascii CONFIG_IDENT_STRING, "\0"
+
+/*
+ * Maybe this should be moved somewhere else because the current
+ * location (0x100) is where the CriticalInput Execption should be.
+ */
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+
+/*****************************************************************************/
+#if defined(CONFIG_440)
+
+ /*----------------------------------------------------------------*/
+ /* Clear and set up some registers. */
+ /*----------------------------------------------------------------*/
+ li r0,0x0000
+ lis r1,0xffff
+ mtspr dec,r0 /* prevent dec exceptions */
+ mtspr tbl,r0 /* prevent fit & wdt exceptions */
+ mtspr tbu,r0
+ mtspr tsr,r1 /* clear all timer exception status */
+ mtspr tcr,r0 /* disable all */
+ mtspr esr,r0 /* clear exception syndrome register */
+ mtxer r0 /* clear integer exception register */
+#if !defined(CONFIG_440GX)
+ lis r1,0x0002 /* set CE bit (Critical Exceptions) */
+ ori r1,r1,0x1000 /* set ME bit (Machine Exceptions) */
+ mtmsr r1 /* change MSR */
+#elif !defined(CONFIG_440EP) && !defined(CONFIG_440GR)
+ bl __440gx_msr_set
+ b __440gx_msr_continue
+
+__440gx_msr_set:
+ lis r1, 0x0002 /* set CE bit (Critical Exceptions) */
+ ori r1,r1,0x1000 /* set ME bit (Machine Exceptions) */
+ mtspr srr1,r1
+ mflr r1
+ mtspr srr0,r1
+ rfi
+__440gx_msr_continue:
+#endif
+
+ /*----------------------------------------------------------------*/
+ /* Debug setup -- some (not very good) ice's need an event*/
+ /* to establish control :-( Define CFG_INIT_DBCR to the dbsr */
+ /* value you need in this case 0x8cff 0000 should do the trick */
+ /*----------------------------------------------------------------*/
+#if defined(CFG_INIT_DBCR)
+ lis r1,0xffff
+ ori r1,r1,0xffff
+ mtspr dbsr,r1 /* Clear all status bits */
+ lis r0,CFG_INIT_DBCR@h
+ ori r0,r0,CFG_INIT_DBCR@l
+ mtspr dbcr0,r0
+ isync
+#endif
+
+ /*----------------------------------------------------------------*/
+ /* Setup the internal SRAM */
+ /*----------------------------------------------------------------*/
+ li r0,0
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ /* Clear Dcache to use as RAM */
+ addis r3,r0,CFG_INIT_RAM_ADDR@h
+ ori r3,r3,CFG_INIT_RAM_ADDR@l
+ addis r4,r0,CFG_INIT_RAM_END@h
+ ori r4,r4,CFG_INIT_RAM_END@l
+ rlwinm. r5,r4,0,27,31
+ rlwinm r5,r4,27,5,31
+ beq ..d_ran
+ addi r5,r5,0x0001
+..d_ran:
+ mtctr r5
+..d_ag:
+ dcbz r0,r3
+ addi r3,r3,32
+ bdnz ..d_ag
+#else
+#if defined (CONFIG_440GX) || defined(CONFIG_440SP)
+ mtdcr l2_cache_cfg,r0 /* Ensure L2 Cache is off */
+#endif
+ mtdcr isram0_sb1cr,r0 /* Disable bank 1 */
+
+ li r2,0x7fff
+ ori r2,r2,0xffff
+ mfdcr r1,isram0_dpc
+ and r1,r1,r2 /* Disable parity check */
+ mtdcr isram0_dpc,r1
+ mfdcr r1,isram0_pmeg
+ andis. r1,r1,r2 /* Disable pwr mgmt */
+ mtdcr isram0_pmeg,r1
+
+ lis r1,0x8000 /* BAS = 8000_0000 */
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+ ori r1,r1,0x0980 /* first 64k */
+ mtdcr isram0_sb0cr,r1
+ lis r1,0x8001
+ ori r1,r1,0x0980 /* second 64k */
+ mtdcr isram0_sb1cr,r1
+ lis r1, 0x8002
+ ori r1,r1, 0x0980 /* third 64k */
+ mtdcr isram0_sb2cr,r1
+ lis r1, 0x8003
+ ori r1,r1, 0x0980 /* fourth 64k */
+ mtdcr isram0_sb3cr,r1
+#else
+ ori r1,r1,0x0380 /* 8k rw */
+ mtdcr isram0_sb0cr,r1
+#endif
+#endif
+
+ /*----------------------------------------------------------------*/
+ /* Setup the stack in internal SRAM */
+ /*----------------------------------------------------------------*/
+ lis r1,CFG_INIT_RAM_ADDR@h
+ ori r1,r1,CFG_INIT_SP_OFFSET@l
+ li r0,0
+ stwu r0,-4(r1)
+ stwu r0,-4(r1) /* Terminate call chain */
+
+ stwu r1,-8(r1) /* Save back chain and move SP */
+ lis r0,RESET_VECTOR@h /* Address of reset vector */
+ ori r0,r0, RESET_VECTOR@l
+ stwu r1,-8(r1) /* Save back chain and move SP */
+ stw r0,+12(r1) /* Save return addr (underflow vect) */
+
+ GET_GOT
+
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+ bl board_init_f
+
+#endif /* CONFIG_440 */
+
+/*****************************************************************************/
+#ifdef CONFIG_IOP480
+ /*----------------------------------------------------------------------- */
+ /* Set up some machine state registers. */
+ /*----------------------------------------------------------------------- */
+ addi r0,r0,0x0000 /* initialize r0 to zero */
+ mtspr esr,r0 /* clear Exception Syndrome Reg */
+ mttcr r0 /* timer control register */
+ mtexier r0 /* disable all interrupts */
+ addi r4,r0,0x1000 /* set ME bit (Machine Exceptions) */
+ oris r4,r4,0x2 /* set CE bit (Critical Exceptions) */
+ mtmsr r4 /* change MSR */
+ addis r4,r0,0xFFFF /* set r4 to 0xFFFFFFFF (status in the */
+ ori r4,r4,0xFFFF /* dbsr is cleared by setting bits to 1) */
+ mtdbsr r4 /* clear/reset the dbsr */
+ mtexisr r4 /* clear all pending interrupts */
+ addis r4,r0,0x8000
+ mtexier r4 /* enable critical exceptions */
+ addis r4,r0,0x0000 /* assume 403GCX - enable core clk */
+ ori r4,r4,0x4020 /* dbling (no harm done on GA and GC */
+ mtiocr r4 /* since bit not used) & DRC to latch */
+ /* data bus on rising edge of CAS */
+ /*----------------------------------------------------------------------- */
+ /* Clear XER. */
+ /*----------------------------------------------------------------------- */
+ mtxer r0
+ /*----------------------------------------------------------------------- */
+ /* Invalidate i-cache and d-cache TAG arrays. */
+ /*----------------------------------------------------------------------- */
+ addi r3,0,1024 /* 1/4 of I-cache size, half of D-cache */
+ addi r4,0,1024 /* 1/4 of I-cache */
+..cloop:
+ iccci 0,r3
+ iccci r4,r3
+ dccci 0,r3
+ addic. r3,r3,-16 /* move back one cache line */
+ bne ..cloop /* loop back to do rest until r3 = 0 */
+
+ /* */
+ /* initialize IOP480 so it can read 1 MB code area for SRAM spaces */
+ /* this requires enabling MA[17..0], by default only MA[12..0] are enabled. */
+ /* */
+
+ /* first copy IOP480 register base address into r3 */
+ addis r3,0,0x5000 /* IOP480 register base address hi */
+/* ori r3,r3,0x0000 / IOP480 register base address lo */
+
+#ifdef CONFIG_ADCIOP
+ /* use r4 as the working variable */
+ /* turn on CS3 (LOCCTL.7) */
+ lwz r4,0x84(r3) /* LOCTL is at offset 0x84 */
+ andi. r4,r4,0xff7f /* make bit 7 = 0 -- CS3 mode */
+ stw r4,0x84(r3) /* LOCTL is at offset 0x84 */
+#endif
+
+#ifdef CONFIG_DASA_SIM
+ /* use r4 as the working variable */
+ /* turn on MA17 (LOCCTL.7) */
+ lwz r4,0x84(r3) /* LOCTL is at offset 0x84 */
+ ori r4,r4,0x80 /* make bit 7 = 1 -- MA17 mode */
+ stw r4,0x84(r3) /* LOCTL is at offset 0x84 */
+#endif
+
+ /* turn on MA16..13 (LCS0BRD.12 = 0) */
+ lwz r4,0x100(r3) /* LCS0BRD is at offset 0x100 */
+ andi. r4,r4,0xefff /* make bit 12 = 0 */
+ stw r4,0x100(r3) /* LCS0BRD is at offset 0x100 */
+
+ /* make sure above stores all comlete before going on */
+ sync
+
+ /* last thing, set local init status done bit (DEVINIT.31) */
+ lwz r4,0x80(r3) /* DEVINIT is at offset 0x80 */
+ oris r4,r4,0x8000 /* make bit 31 = 1 */
+ stw r4,0x80(r3) /* DEVINIT is at offset 0x80 */
+
+ /* clear all pending interrupts and disable all interrupts */
+ li r4,-1 /* set p1 to 0xffffffff */
+ stw r4,0x1b0(r3) /* clear all pending interrupts */
+ stw r4,0x1b8(r3) /* clear all pending interrupts */
+ li r4,0 /* set r4 to 0 */
+ stw r4,0x1b4(r3) /* disable all interrupts */
+ stw r4,0x1bc(r3) /* disable all interrupts */
+
+ /* make sure above stores all comlete before going on */
+ sync
+
+ /*----------------------------------------------------------------------- */
+ /* Enable two 128MB cachable regions. */
+ /*----------------------------------------------------------------------- */
+ addis r1,r0,0x8000
+ addi r1,r1,0x0001
+ mticcr r1 /* instruction cache */
+
+ addis r1,r0,0x0000
+ addi r1,r1,0x0000
+ mtdccr r1 /* data cache */
+
+ addis r1,r0,CFG_INIT_RAM_ADDR@h
+ ori r1,r1,CFG_INIT_SP_OFFSET /* set up the stack to SDRAM */
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ GET_GOT /* initialize GOT access */
+
+ bl board_init_f /* run first part of init code (from Flash) */
+
+#endif /* CONFIG_IOP480 */
+
+/*****************************************************************************/
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_405EP)
+ /*----------------------------------------------------------------------- */
+ /* Clear and set up some registers. */
+ /*----------------------------------------------------------------------- */
+ addi r4,r0,0x0000
+ mtspr sgr,r4
+ mtspr dcwr,r4
+ mtesr r4 /* clear Exception Syndrome Reg */
+ mttcr r4 /* clear Timer Control Reg */
+ mtxer r4 /* clear Fixed-Point Exception Reg */
+ mtevpr r4 /* clear Exception Vector Prefix Reg */
+ addi r4,r0,0x1000 /* set ME bit (Machine Exceptions) */
+ oris r4,r4,0x0002 /* set CE bit (Critical Exceptions) */
+ mtmsr r4 /* change MSR */
+ addi r4,r0,(0xFFFF-0x10000) /* set r4 to 0xFFFFFFFF (status in the */
+ /* dbsr is cleared by setting bits to 1) */
+ mtdbsr r4 /* clear/reset the dbsr */
+
+ /*----------------------------------------------------------------------- */
+ /* Invalidate I and D caches. Enable I cache for defined memory regions */
+ /* to speed things up. Leave the D cache disabled for now. It will be */
+ /* enabled/left disabled later based on user selected menu options. */
+ /* Be aware that the I cache may be disabled later based on the menu */
+ /* options as well. See miscLib/main.c. */
+ /*----------------------------------------------------------------------- */
+ bl invalidate_icache
+ bl invalidate_dcache
+
+ /*----------------------------------------------------------------------- */
+ /* Enable two 128MB cachable regions. */
+ /*----------------------------------------------------------------------- */
+ addis r4,r0,0x8000
+ addi r4,r4,0x0001
+ mticcr r4 /* instruction cache */
+ isync
+
+ addis r4,r0,0x0000
+ addi r4,r4,0x0000
+ mtdccr r4 /* data cache */
+
+#if !(defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR))
+ /*----------------------------------------------------------------------- */
+ /* Tune the speed and size for flash CS0 */
+ /*----------------------------------------------------------------------- */
+ bl ext_bus_cntlr_init
+#endif
+
+#if defined(CONFIG_405EP)
+ /*----------------------------------------------------------------------- */
+ /* DMA Status, clear to come up clean */
+ /*----------------------------------------------------------------------- */
+ addis r3,r0, 0xFFFF /* Clear all existing DMA status */
+ ori r3,r3, 0xFFFF
+ mtdcr dmasr, r3
+
+ bl ppc405ep_init /* do ppc405ep specific init */
+#endif /* CONFIG_405EP */
+
+#if defined(CFG_OCM_DATA_ADDR) && defined(CFG_OCM_DATA_SIZE)
+ /********************************************************************
+ * Setup OCM - On Chip Memory
+ *******************************************************************/
+ /* Setup OCM */
+ lis r0, 0x7FFF
+ ori r0, r0, 0xFFFF
+ mfdcr r3, ocmiscntl /* get instr-side IRAM config */
+ mfdcr r4, ocmdscntl /* get data-side IRAM config */
+ and r3, r3, r0 /* disable data-side IRAM */
+ and r4, r4, r0 /* disable data-side IRAM */
+ mtdcr ocmiscntl, r3 /* set instr-side IRAM config */
+ mtdcr ocmdscntl, r4 /* set data-side IRAM config */
+ isync
+
+ addis r3, 0, CFG_OCM_DATA_ADDR@h /* OCM location */
+ mtdcr ocmdsarc, r3
+ addis r4, 0, 0xC000 /* OCM data area enabled */
+ mtdcr ocmdscntl, r4
+ isync
+#endif
+
+ /*----------------------------------------------------------------------- */
+ /* Setup temporary stack in DCACHE or OCM if needed for SDRAM SPD. */
+ /*----------------------------------------------------------------------- */
+#ifdef CFG_INIT_DCACHE_CS
+ /*----------------------------------------------------------------------- */
+ /* Memory Bank x (nothingness) initialization 1GB+64MEG */
+ /* used as temporary stack pointer for stage0 */
+ /*----------------------------------------------------------------------- */
+ li r4,PBxAP
+ mtdcr ebccfga,r4
+ lis r4,0x0380
+ ori r4,r4,0x0480
+ mtdcr ebccfgd,r4
+
+ addi r4,0,PBxCR
+ mtdcr ebccfga,r4
+ lis r4,0x400D
+ ori r4,r4,0xa000
+ mtdcr ebccfgd,r4
+
+ /* turn on data chache for this region */
+ lis r4,0x0080
+ mtdccr r4
+
+ /* set stack pointer and clear stack to known value */
+
+ lis r1,CFG_INIT_RAM_ADDR@h
+ ori r1,r1,CFG_INIT_SP_OFFSET@l
+
+ li r4,2048 /* we store 2048 words to stack */
+ mtctr r4
+
+ lis r2,CFG_INIT_RAM_ADDR@h /* we also clear data area */
+ ori r2,r2,CFG_INIT_RAM_END@l /* so cant copy value from r1 */
+
+ lis r4,0xdead /* we store 0xdeaddead in the stack */
+ ori r4,r4,0xdead
+
+..stackloop:
+ stwu r4,-4(r2)
+ bdnz ..stackloop
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+ /*
+ * Set up a dummy frame to store reset vector as return address.
+ * this causes stack underflow to reset board.
+ */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ addis r0, 0, RESET_VECTOR@h /* Address of reset vector */
+ ori r0, r0, RESET_VECTOR@l
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save return addr (underflow vect) */
+
+#elif defined(CFG_TEMP_STACK_OCM) && \
+ (defined(CFG_OCM_DATA_ADDR) && defined(CFG_OCM_DATA_SIZE))
+ /*
+ * Stack in OCM.
+ */
+
+ /* Set up Stack at top of OCM */
+ lis r1, (CFG_INIT_RAM_ADDR + CFG_INIT_SP_OFFSET)@h
+ ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_INIT_SP_OFFSET)@l
+
+ /* Set up a zeroized stack frame so that backtrace works right */
+ li r0, 0
+ stwu r0, -4(r1)
+ stwu r0, -4(r1)
+
+ /*
+ * Set up a dummy frame to store reset vector as return address.
+ * this causes stack underflow to reset board.
+ */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ lis r0, RESET_VECTOR@h /* Address of reset vector */
+ ori r0, r0, RESET_VECTOR@l
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save return addr (underflow vect) */
+#endif /* CFG_INIT_DCACHE_CS */
+
+ /*----------------------------------------------------------------------- */
+ /* Initialize SDRAM Controller */
+ /*----------------------------------------------------------------------- */
+ bl sdram_init
+
+ /*
+ * Setup temporary stack pointer only for boards
+ * that do not use SDRAM SPD I2C stuff since it
+ * is already initialized to use DCACHE or OCM
+ * stacks.
+ */
+#if !(defined(CFG_INIT_DCACHE_CS) || defined(CFG_TEMP_STACK_OCM))
+ lis r1, CFG_INIT_RAM_ADDR@h
+ ori r1,r1,CFG_INIT_SP_OFFSET /* set up the stack in SDRAM */
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+ /*
+ * Set up a dummy frame to store reset vector as return address.
+ * this causes stack underflow to reset board.
+ */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ lis r0, RESET_VECTOR@h /* Address of reset vector */
+ ori r0, r0, RESET_VECTOR@l
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save return addr (underflow vect) */
+#endif /* !(CFG_INIT_DCACHE_CS || !CFG_TEM_STACK_OCM) */
+
+ GET_GOT /* initialize GOT access */
+
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+
+ /* NEVER RETURNS! */
+ bl board_init_f /* run first part of init code (from Flash) */
+
+#endif /* CONFIG_405GP || CONFIG_405CR || CONFIG_405 || CONFIG_405EP */
+ /*----------------------------------------------------------------------- */
+
+
+/*****************************************************************************/
+ .globl _start_of_vectors
+_start_of_vectors:
+
+#if 0
+/*TODO Fixup _start above so we can do this*/
+/* Critical input. */
+ CRIT_EXCEPTION(0x100, CritcalInput, CritcalInputException)
+#endif
+
+/* Machine check */
+ CRIT_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_Alignment:
+ .long AlignmentException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_ProgramCheck:
+ .long ProgramCheckException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+ /* No FPU on MPC8xx. This exception is not supposed to happen.
+ */
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ /* On the MPC8xx, this is a software emulation interrupt. It occurs
+ * for all unimplemented and illegal instructions.
+ */
+ STD_EXCEPTION(0x1000, PIT, PITException)
+
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+ STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+ CRIT_EXCEPTION(0x2000, DebugBreakpoint, DebugException )
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+
+ . = 0x2100
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+#if 0
+ andi. r23,r23,MSR_PR
+ mfspr r23,SPRG3 /* if from user, fix up tss.regs */
+ beq 2f
+ addi r24,r1,STACK_FRAME_OVERHEAD
+ stw r24,PT_REGS(r23)
+2: addi r2,r23,-TSS /* set r2 to current */
+ tovirt(r2,r2,r23)
+#endif
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+#if 0
+ addi r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */
+ cmplw 0,r1,r2
+ cmplw 1,r1,r24
+ crand 1,1,4
+ bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+#endif
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+crit_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr 990,r2 /* SRR2 */
+ mtspr 991,r0 /* SRR3 */
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfci
+
+/* Cache functions.
+*/
+invalidate_icache:
+ iccci r0,r0 /* for 405, iccci invalidates the */
+ blr /* entire I cache */
+
+invalidate_dcache:
+ addi r6,0,0x0000 /* clear GPR 6 */
+ /* Do loop for # of dcache congruence classes. */
+ lis r7, (CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@ha /* TBS for large sized cache */
+ ori r7, r7, (CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@l
+ /* NOTE: dccci invalidates both */
+ mtctr r7 /* ways in the D cache */
+..dcloop:
+ dccci 0,r6 /* invalidate line */
+ addi r6,r6, CFG_CACHELINE_SIZE /* bump to next line */
+ bdnz ..dcloop
+ blr
+
+flush_dcache:
+ addis r9,r0,0x0002 /* set mask for EE and CE msr bits */
+ ori r9,r9,0x8000
+ mfmsr r12 /* save msr */
+ andc r9,r12,r9
+ mtmsr r9 /* disable EE and CE */
+ addi r10,r0,0x0001 /* enable data cache for unused memory */
+ mfdccr r9 /* region 0xF8000000-0xFFFFFFFF via */
+ or r10,r10,r9 /* bit 31 in dccr */
+ mtdccr r10
+
+ /* do loop for # of congruence classes. */
+ lis r10,(CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@ha /* TBS: for large cache sizes */
+ ori r10,r10,(CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@l
+ lis r11,(CFG_DCACHE_SIZE / 2)@ha /* D cache set size - 2 way sets */
+ ori r11,r11,(CFG_DCACHE_SIZE / 2)@l /* D cache set size - 2 way sets */
+ mtctr r10
+ addi r10,r0,(0xE000-0x10000) /* start at 0xFFFFE000 */
+ add r11,r10,r11 /* add to get to other side of cache line */
+..flush_dcache_loop:
+ lwz r3,0(r10) /* least recently used side */
+ lwz r3,0(r11) /* the other side */
+ dccci r0,r11 /* invalidate both sides */
+ addi r10,r10,CFG_CACHELINE_SIZE /* bump to next line */
+ addi r11,r11,CFG_CACHELINE_SIZE /* bump to next line */
+ bdnz ..flush_dcache_loop
+ sync /* allow memory access to complete */
+ mtdccr r9 /* restore dccr */
+ mtmsr r12 /* restore msr */
+ blr
+
+ .globl icache_enable
+icache_enable:
+ mflr r8
+ bl invalidate_icache
+ mtlr r8
+ isync
+ addis r3,r0, 0x8000 /* set bit 0 */
+ mticcr r3
+ blr
+
+ .globl icache_disable
+icache_disable:
+ addis r3,r0, 0x0000 /* clear bit 0 */
+ mticcr r3
+ isync
+ blr
+
+ .globl icache_status
+icache_status:
+ mficcr r3
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mflr r8
+ bl invalidate_dcache
+ mtlr r8
+ isync
+ addis r3,r0, 0x8000 /* set bit 0 */
+ mtdccr r3
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mflr r8
+ bl flush_dcache
+ mtlr r8
+ addis r3,r0, 0x0000 /* clear bit 0 */
+ mtdccr r3
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfdccr r3
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+#if !defined(CONFIG_440)
+ .globl wr_pit
+wr_pit:
+ mtspr pit, r3
+ blr
+#endif
+
+ .globl wr_tcr
+wr_tcr:
+ mtspr tcr, r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in8 */
+/* Description: Input 8 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in8
+in8:
+ lbz r3,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out8 */
+/* Description: Output 8 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out8
+out8:
+ stb r4,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out16 */
+/* Description: Output 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out16
+out16:
+ sth r4,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out16r */
+/* Description: Byte reverse and output 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out16r
+out16r:
+ sthbrx r4,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out32 */
+/* Description: Output 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out32
+out32:
+ stw r4,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out32r */
+/* Description: Byte reverse and output 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out32r
+out32r:
+ stwbrx r4,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in16 */
+/* Description: Input 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in16
+in16:
+ lhz r3,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in16r */
+/* Description: Input 16 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+ .globl in16r
+in16r:
+ lhbrx r3,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in32 */
+/* Description: Input 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in32
+in32:
+ lwz 3,0x0000(3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in32r */
+/* Description: Input 32 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+ .globl in32r
+in32r:
+ lwbrx r3,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: ppcDcbf */
+/* Description: Data Cache block flush */
+/* Input: r3 = effective address */
+/* Output: none. */
+/*------------------------------------------------------------------------------- */
+ .globl ppcDcbf
+ppcDcbf:
+ dcbf r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: ppcDcbi */
+/* Description: Data Cache block Invalidate */
+/* Input: r3 = effective address */
+/* Output: none. */
+/*------------------------------------------------------------------------------- */
+ .globl ppcDcbi
+ppcDcbi:
+ dcbi r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: ppcSync */
+/* Description: Processor Synchronize */
+/* Input: none. */
+/* Output: none. */
+/*------------------------------------------------------------------------------- */
+ .globl ppcSync
+ppcSync:
+ sync
+ blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ dccci 0,0 /* Invalidate data cache, now no longer our stack */
+ sync
+ addi r1,r0,0x0000 /* TLB entry #0 */
+ tlbre r0,r1,0x0002 /* Read contents */
+ ori r0,r0,0x0c00 /* Or in the inhibit, write through bit */
+ tlbwe r0,r1,0x0002 /* Save it out */
+ isync
+#endif
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Init Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ mr r3, r5 /* Destination Address */
+ lis r4, CFG_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CFG_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r14, r14, r15
+ /* the the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr /* NEVER RETURNS! */
+
+in_ram:
+
+ /*
+ * Relocation Function, r14 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ add r0,r0,r11
+ stw r0,0(r3)
+ bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+2: li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ add r0,r0,r11
+ stw r10,0(r3)
+ stw r0,0(r4)
+ bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+
+ mr r3, r9 /* Init Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+
+ mflr r4 /* save link register */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mtlr r4 /* restore link register */
+ blr
+
+ /*
+ * Function: relocate entries for one exception vector
+ */
+trap_reloc:
+ lwz r0, 0(r7) /* hdlr ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 0(r7)
+
+ lwz r0, 4(r7) /* int_return ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 4(r7)
+
+ blr
+
+
+/**************************************************************************/
+/* PPC405EP specific stuff */
+/**************************************************************************/
+#ifdef CONFIG_405EP
+ppc405ep_init:
+
+#ifdef CONFIG_BUBINGA
+ /*
+ * Initialize EBC chip selects 1 & 4 and GPIO pins (for alternate
+ * function) to support FPGA and NVRAM accesses below.
+ */
+
+ lis r3,GPIO0_OSRH@h /* config GPIO output select */
+ ori r3,r3,GPIO0_OSRH@l
+ lis r4,CFG_GPIO0_OSRH@h
+ ori r4,r4,CFG_GPIO0_OSRH@l
+ stw r4,0(r3)
+ lis r3,GPIO0_OSRL@h
+ ori r3,r3,GPIO0_OSRL@l
+ lis r4,CFG_GPIO0_OSRL@h
+ ori r4,r4,CFG_GPIO0_OSRL@l
+ stw r4,0(r3)
+
+ lis r3,GPIO0_ISR1H@h /* config GPIO input select */
+ ori r3,r3,GPIO0_ISR1H@l
+ lis r4,CFG_GPIO0_ISR1H@h
+ ori r4,r4,CFG_GPIO0_ISR1H@l
+ stw r4,0(r3)
+ lis r3,GPIO0_ISR1L@h
+ ori r3,r3,GPIO0_ISR1L@l
+ lis r4,CFG_GPIO0_ISR1L@h
+ ori r4,r4,CFG_GPIO0_ISR1L@l
+ stw r4,0(r3)
+
+ lis r3,GPIO0_TSRH@h /* config GPIO three-state select */
+ ori r3,r3,GPIO0_TSRH@l
+ lis r4,CFG_GPIO0_TSRH@h
+ ori r4,r4,CFG_GPIO0_TSRH@l
+ stw r4,0(r3)
+ lis r3,GPIO0_TSRL@h
+ ori r3,r3,GPIO0_TSRL@l
+ lis r4,CFG_GPIO0_TSRL@h
+ ori r4,r4,CFG_GPIO0_TSRL@l
+ stw r4,0(r3)
+
+ lis r3,GPIO0_TCR@h /* config GPIO driver output enables */
+ ori r3,r3,GPIO0_TCR@l
+ lis r4,CFG_GPIO0_TCR@h
+ ori r4,r4,CFG_GPIO0_TCR@l
+ stw r4,0(r3)
+
+ li r3,pb1ap /* program EBC bank 1 for RTC access */
+ mtdcr ebccfga,r3
+ lis r3,CFG_EBC_PB1AP@h
+ ori r3,r3,CFG_EBC_PB1AP@l
+ mtdcr ebccfgd,r3
+ li r3,pb1cr
+ mtdcr ebccfga,r3
+ lis r3,CFG_EBC_PB1CR@h
+ ori r3,r3,CFG_EBC_PB1CR@l
+ mtdcr ebccfgd,r3
+
+ li r3,pb1ap /* program EBC bank 1 for RTC access */
+ mtdcr ebccfga,r3
+ lis r3,CFG_EBC_PB1AP@h
+ ori r3,r3,CFG_EBC_PB1AP@l
+ mtdcr ebccfgd,r3
+ li r3,pb1cr
+ mtdcr ebccfga,r3
+ lis r3,CFG_EBC_PB1CR@h
+ ori r3,r3,CFG_EBC_PB1CR@l
+ mtdcr ebccfgd,r3
+
+ li r3,pb4ap /* program EBC bank 4 for FPGA access */
+ mtdcr ebccfga,r3
+ lis r3,CFG_EBC_PB4AP@h
+ ori r3,r3,CFG_EBC_PB4AP@l
+ mtdcr ebccfgd,r3
+ li r3,pb4cr
+ mtdcr ebccfga,r3
+ lis r3,CFG_EBC_PB4CR@h
+ ori r3,r3,CFG_EBC_PB4CR@l
+ mtdcr ebccfgd,r3
+#endif
+
+ addi r3,0,CPC0_PCI_HOST_CFG_EN
+#ifdef CONFIG_BUBINGA
+ /*
+ !-----------------------------------------------------------------------
+ ! Check FPGA for PCI internal/external arbitration
+ ! If board is set to internal arbitration, update cpc0_pci
+ !-----------------------------------------------------------------------
+ */
+ addis r5,r0,FPGA_REG1@h /* set offset for FPGA_REG1 */
+ ori r5,r5,FPGA_REG1@l
+ lbz r5,0x0(r5) /* read to get PCI arb selection */
+ andi. r6,r5,FPGA_REG1_PCI_INT_ARB /* using internal arbiter ?*/
+ beq ..pci_cfg_set /* if not set, then bypass reg write*/
+#endif
+ ori r3,r3,CPC0_PCI_ARBIT_EN
+..pci_cfg_set:
+ mtdcr CPC0_PCI, r3 /* Enable internal arbiter*/
+
+ /*
+ !-----------------------------------------------------------------------
+ ! Check to see if chip is in bypass mode.
+ ! If so, write stored CPC0_PLLMR0 and CPC0_PLLMR1 values and perform a
+ ! CPU reset Otherwise, skip this step and keep going.
+ ! Note: Running BIOS in bypass mode is not supported since PLB speed
+ ! will not be fast enough for the SDRAM (min 66MHz)
+ !-----------------------------------------------------------------------
+ */
+ mfdcr r5, CPC0_PLLMR1
+ rlwinm r4,r5,1,0x1 /* get system clock source (SSCS) */
+ cmpi cr0,0,r4,0x1
+
+ beq pll_done /* if SSCS =b'1' then PLL has */
+ /* already been set */
+ /* and CPU has been reset */
+ /* so skip to next section */
+
+#ifdef CONFIG_BUBINGA
+ /*
+ !-----------------------------------------------------------------------
+ ! Read NVRAM to get value to write in PLLMR.
+ ! If value has not been correctly saved, write default value
+ ! Default config values (assuming on-board 33MHz SYS_CLK) are above.
+ ! See CPU_DEFAULT_200 and CPU_DEFAULT_266 above.
+ !
+ ! WARNING: This code assumes the first three words in the nvram_t
+ ! structure in openbios.h. Changing the beginning of
+ ! the structure will break this code.
+ !
+ !-----------------------------------------------------------------------
+ */
+ addis r3,0,NVRAM_BASE@h
+ addi r3,r3,NVRAM_BASE@l
+
+ lwz r4, 0(r3)
+ addis r5,0,NVRVFY1@h
+ addi r5,r5,NVRVFY1@l
+ cmp cr0,0,r4,r5 /* Compare 1st NVRAM Magic number*/
+ bne ..no_pllset
+ addi r3,r3,4
+ lwz r4, 0(r3)
+ addis r5,0,NVRVFY2@h
+ addi r5,r5,NVRVFY2@l
+ cmp cr0,0,r4,r5 /* Compare 2 NVRAM Magic number */
+ bne ..no_pllset
+ addi r3,r3,8 /* Skip over conf_size */
+ lwz r4, 4(r3) /* Load PLLMR1 value from NVRAM */
+ lwz r3, 0(r3) /* Load PLLMR0 value from NVRAM */
+ rlwinm r5,r4,1,0x1 /* get system clock source (SSCS) */
+ cmpi cr0,0,r5,1 /* See if PLL is locked */
+ beq pll_write
+..no_pllset:
+#endif /* CONFIG_BUBINGA */
+
+ addis r3,0,PLLMR0_DEFAULT@h /* PLLMR0 default value */
+ ori r3,r3,PLLMR0_DEFAULT@l /* */
+ addis r4,0,PLLMR1_DEFAULT@h /* PLLMR1 default value */
+ ori r4,r4,PLLMR1_DEFAULT@l /* */
+
+ b pll_write /* Write the CPC0_PLLMR with new value */
+
+pll_done:
+ /*
+ !-----------------------------------------------------------------------
+ ! Clear Soft Reset Register
+ ! This is needed to enable PCI if not booting from serial EPROM
+ !-----------------------------------------------------------------------
+ */
+ addi r3, 0, 0x0
+ mtdcr CPC0_SRR, r3
+
+ addis r3,0,0x0010
+ mtctr r3
+pci_wait:
+ bdnz pci_wait
+
+ blr /* return to main code */
+
+/*
+!-----------------------------------------------------------------------------
+! Function: pll_write
+! Description: Updates the value of the CPC0_PLLMR according to CMOS27E documentation
+! That is:
+! 1. Pll is first disabled (de-activated by putting in bypass mode)
+! 2. PLL is reset
+! 3. Clock dividers are set while PLL is held in reset and bypassed
+! 4. PLL Reset is cleared
+! 5. Wait 100us for PLL to lock
+! 6. A core reset is performed
+! Input: r3 = Value to write to CPC0_PLLMR0
+! Input: r4 = Value to write to CPC0_PLLMR1
+! Output r3 = none
+!-----------------------------------------------------------------------------
+*/
+pll_write:
+ mfdcr r5, CPC0_UCR
+ andis. r5,r5,0xFFFF
+ ori r5,r5,0x0101 /* Stop the UART clocks */
+ mtdcr CPC0_UCR,r5 /* Before changing PLL */
+
+ mfdcr r5, CPC0_PLLMR1
+ rlwinm r5,r5,0,0x7FFFFFFF /* Disable PLL */
+ mtdcr CPC0_PLLMR1,r5
+ oris r5,r5,0x4000 /* Set PLL Reset */
+ mtdcr CPC0_PLLMR1,r5
+
+ mtdcr CPC0_PLLMR0,r3 /* Set clock dividers */
+ rlwinm r5,r4,0,0x3FFFFFFF /* Reset & Bypass new PLL dividers */
+ oris r5,r5,0x4000 /* Set PLL Reset */
+ mtdcr CPC0_PLLMR1,r5 /* Set clock dividers */
+ rlwinm r5,r5,0,0xBFFFFFFF /* Clear PLL Reset */
+ mtdcr CPC0_PLLMR1,r5
+
+ /*
+ ! Wait min of 100us for PLL to lock.
+ ! See CMOS 27E databook for more info.
+ ! At 200MHz, that means waiting 20,000 instructions
+ */
+ addi r3,0,20000 /* 2000 = 0x4e20 */
+ mtctr r3
+pll_wait:
+ bdnz pll_wait
+
+ oris r5,r5,0x8000 /* Enable PLL */
+ mtdcr CPC0_PLLMR1,r5 /* Engage */
+
+ /*
+ * Reset CPU to guarantee timings are OK
+ * Not sure if this is needed...
+ */
+ addis r3,0,0x1000
+ mtspr dbcr0,r3 /* This will cause a CPU core reset, and */
+ /* execution will continue from the poweron */
+ /* vector of 0xfffffffc */
+#endif /* CONFIG_405EP */
diff --git a/cpu/ppc4xx/traps.c b/cpu/ppc4xx/traps.c
new file mode 100755
index 0000000..6aecca2
--- /dev/null
+++ b/cpu/ppc4xx/traps.c
@@ -0,0 +1,290 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (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
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+ */
+#define END_OF_MEM 0x00400000
+
+
+static __inline__ void set_tsr(unsigned long val)
+{
+#if defined(CONFIG_440)
+ asm volatile("mtspr 0x150, %0" : : "r" (val));
+#else
+ asm volatile("mttsr %0" : : "r" (val));
+#endif
+}
+
+static __inline__ unsigned long get_esr(void)
+{
+ unsigned long val;
+
+#if defined(CONFIG_440)
+ asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
+#else
+ asm volatile("mfesr %0" : "=r" (val) :);
+#endif
+ return val;
+}
+
+#define ESR_MCI 0x80000000
+#define ESR_PIL 0x08000000
+#define ESR_PPR 0x04000000
+#define ESR_PTR 0x02000000
+#define ESR_DST 0x00800000
+#define ESR_DIZ 0x00400000
+#define ESR_U0F 0x00008000
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+ long esr_val;
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+
+ esr_val = get_esr();
+ if( esr_val & ESR_PIL )
+ printf( "** Illegal Instruction **\n" );
+ else if( esr_val & ESR_PPR )
+ printf( "** Privileged Instruction **\n" );
+ else if( esr_val & ESR_PTR )
+ printf( "** Trap Instruction **\n" );
+
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+PITException(struct pt_regs *regs)
+{
+ /*
+ * Reset PIT interrupt
+ */
+ set_tsr(0x08000000);
+
+ /*
+ * Call timer_interrupt routine in interrupts.c
+ */
+ timer_interrupt(NULL);
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/cpu/ppc4xx/usb_ohci.c b/cpu/ppc4xx/usb_ohci.c
new file mode 100755
index 0000000..bb57658
--- /dev/null
+++ b/cpu/ppc4xx/usb_ohci.c
@@ -0,0 +1,1642 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the PPC440EP.
+ *
+ * (C) Copyright 2003-2004
+ * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ * (C) Copyright 2004
+ * Pierre Aubert, Staubli Faverges <p.aubert@staubli.com>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * 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
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - this driver is intended for use with USB Mass Storage Devices
+ * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI
+
+#include <malloc.h>
+#include <usb.h>
+#include "usb_ohci.h"
+
+#include "usbdev.h"
+
+#define OHCI_USE_NPS /* force NoPowerSwitching mode */
+#undef OHCI_VERBOSE_DEBUG /* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define readl(a) (*((vu_long *)(a)))
+#define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a))
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#define m16_swap(x) swap_16(x)
+#define m32_swap(x) swap_32(x)
+
+#ifdef CONFIG_440EP
+#define ohci_cpu_to_le16(x) (x)
+#define ohci_cpu_to_le32(x) (x)
+#else
+#define ohci_cpu_to_le16(x) swap_16(x)
+#define ohci_cpu_to_le32(x) swap_32(x)
+#endif
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* urb_priv */
+urb_priv_t urb_priv;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect. AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+ u32 temp = readl (&hc->regs->roothub.register); \
+ if (hc->flags & OHCI_QUIRK_AMD756) \
+ while (temp & mask) \
+ temp = readl (&hc->regs->roothub.register); \
+ temp; })
+
+static u32 roothub_a (struct ohci *hc)
+ { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+ { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+ { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+ { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+ int i;
+ int last;
+ struct td * td;
+
+ last = urb->length - 1;
+ if (last >= 0) {
+ for (i = 0; i <= last; i++) {
+ td = urb->td[i];
+ if (td) {
+ td->usb_dev = NULL;
+ urb->td[i] = NULL;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, char * str, int small)
+{
+ urb_priv_t * purb = &urb_priv;
+
+ dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+ str,
+ sohci_get_current_frame_number (dev),
+ usb_pipedevice (pipe),
+ usb_pipeendpoint (pipe),
+ usb_pipeout (pipe)? 'O': 'I',
+ usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+ (usb_pipecontrol (pipe)? "CTRL": "BULK"),
+ purb->actual_length,
+ transfer_len, dev->status);
+#ifdef OHCI_VERBOSE_DEBUG
+ if (!small) {
+ int i, len;
+
+ if (usb_pipecontrol (pipe)) {
+ printf (__FILE__ ": cmd(8):");
+ for (i = 0; i < 8 ; i++)
+ printf (" %02x", ((__u8 *) setup) [i]);
+ printf ("\n");
+ }
+ if (transfer_len > 0 && buffer) {
+ printf (__FILE__ ": data(%d/%d):",
+ purb->actual_length,
+ transfer_len);
+ len = usb_pipeout (pipe)?
+ transfer_len: purb->actual_length;
+ for (i = 0; i < 16 && i < len; i++)
+ printf (" %02x", ((__u8 *) buffer) [i]);
+ printf ("%s\n", i < len? "...": "");
+ }
+ }
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+ int i, j;
+ __u32 * ed_p;
+ for (i= 0; i < 32; i++) {
+ j = 5;
+ ed_p = &(ohci->hcca->int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+ while (*ed_p != 0 && j--) {
+ ed_t *ed = (ed_t *)ohci_cpu_to_le32(ed_p);
+ printf (" ed: %4x;", ed->hwINFO);
+ ed_p = &ed->hwNextED;
+ }
+ printf ("\n");
+ }
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ ed_t *edp = (ed_t *)value;
+
+ if (value) {
+ dbg ("%s %08x", label, value);
+ dbg ("%08x", edp->hwINFO);
+ dbg ("%08x", edp->hwTailP);
+ dbg ("%08x", edp->hwHeadP);
+ dbg ("%08x", edp->hwNextED);
+ }
+}
+
+static char * hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (&regs->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (&regs->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (&regs->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+ __u32 temp, ndp, i;
+
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = roothub_b (controller);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = roothub_status (controller);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+ dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+ /* dumps some of the state we know about */
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca->frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ ohci_t *ohci;
+ ed_t * ed;
+ urb_priv_t *purb_priv;
+ int i, size = 0;
+
+ ohci = &gohci;
+
+ /* when controller's hung, permit only roothub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled) {
+ err("sohci_submit_job: EPIPE");
+ return -1;
+ }
+
+ /* if we have an unfinished URB from previous transaction let's
+ * fail and scream as quickly as possible so as not to corrupt
+ * further communication */
+ if (!urb_finished) {
+ err("sohci_submit_job: URB NOT FINISHED");
+ return -1;
+ }
+ /* we're about to begin a new transaction here so mark the URB unfinished */
+ urb_finished = 0;
+
+ /* every endpoint has a ed, locate and fill it */
+ if (!(ed = ep_add_ed (dev, pipe))) {
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+
+ /* for the private part of the URB we need the number of TDs (size) */
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK: /* one TD for every 4096 Byte */
+ size = (transfer_len - 1) / 4096 + 1;
+ break;
+ case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+ size = (transfer_len == 0)? 2:
+ (transfer_len - 1) / 4096 + 3;
+ break;
+ }
+
+ if (size >= (N_URB_TD - 1)) {
+ err("need %d TDs, only have %d", size, N_URB_TD);
+ return -1;
+ }
+ purb_priv = &urb_priv;
+ purb_priv->pipe = pipe;
+
+ /* fill the private part of the URB */
+ purb_priv->length = size;
+ purb_priv->ed = ed;
+ purb_priv->actual_length = 0;
+
+ /* allocate the TDs */
+ /* note that td[0] was allocated in ep_add_ed */
+ for (i = 0; i < size; i++) {
+ purb_priv->td[i] = td_alloc (dev);
+ if (!purb_priv->td[i]) {
+ purb_priv->length = i;
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+ }
+
+ if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: EINVAL");
+ return -1;
+ }
+
+ /* link the ed into a chain if is not already */
+ if (ed->state != ED_OPER)
+ ep_link (ohci, ed);
+
+ /* fill the TDs and link it to the ed */
+ td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+ ohci_t *ohci = &gohci;
+
+ return ohci_cpu_to_le16 (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+
+ ed->state = ED_OPER;
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ed->hwNextED = 0;
+ if (ohci->ed_controltail == NULL) {
+ writel (ed, &ohci->regs->ed_controlhead);
+ } else {
+ ohci->ed_controltail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+ }
+ ed->ed_prev = ohci->ed_controltail;
+ if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_controltail = edi;
+ break;
+
+ case PIPE_BULK:
+ ed->hwNextED = 0;
+ if (ohci->ed_bulktail == NULL) {
+ writel (ed, &ohci->regs->ed_bulkhead);
+ } else {
+ ohci->ed_bulktail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+ }
+ ed->ed_prev = ohci->ed_bulktail;
+ if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_bulktail = edi;
+ break;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+
+ ed->hwINFO |= ohci_cpu_to_le32 (OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_controltail == ed) {
+ ohci->ed_controltail = ed->ed_prev;
+ } else {
+ ((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_BULK:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_bulktail == ed) {
+ ohci->ed_bulktail = ed->ed_prev;
+ } else {
+ ((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
+{
+ td_t *td;
+ ed_t *ed_ret;
+ volatile ed_t *ed;
+
+ ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+ (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+ err("ep_add_ed: pending delete");
+ /* pending delete request */
+ return NULL;
+ }
+
+ if (ed->state == ED_NEW) {
+ ed->hwINFO = ohci_cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+ /* dummy td; end of td list for ed */
+ td = td_alloc (usb_dev);
+ ed->hwTailP = ohci_cpu_to_le32 ((unsigned long)td);
+ ed->hwHeadP = ed->hwTailP;
+ ed->state = ED_UNLINK;
+ ed->type = usb_pipetype (pipe);
+ ohci_dev.ed_cnt++;
+ }
+
+ ed->hwINFO = ohci_cpu_to_le32 (usb_pipedevice (pipe)
+ | usb_pipeendpoint (pipe) << 7
+ | (usb_pipeisoc (pipe)? 0x8000: 0)
+ | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+ | usb_pipeslow (pipe) << 13
+ | usb_maxpacket (usb_dev, pipe) << 16);
+
+ return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+ void *data, int len,
+ struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+ volatile td_t *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+ int i;
+#endif
+
+ if (index > urb_priv->length) {
+ err("index > length");
+ return;
+ }
+ /* use this td as the next dummy */
+ td_pt = urb_priv->td [index];
+ td_pt->hwNextTD = 0;
+
+ /* fill the old dummy TD */
+ td = urb_priv->td [index] = (td_t *)(ohci_cpu_to_le32 (urb_priv->ed->hwTailP) & ~0xf);
+
+ td->ed = urb_priv->ed;
+ td->next_dl_td = NULL;
+ td->index = index;
+ td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+ if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
+ for (i = 0; i < len; i++)
+ printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+ printf("\n");
+ }
+#endif
+ if (!len)
+ data = 0;
+
+ td->hwINFO = ohci_cpu_to_le32 (info);
+ td->hwCBP = ohci_cpu_to_le32 ((unsigned long)data);
+ if (data)
+ td->hwBE = ohci_cpu_to_le32 ((unsigned long)(data + len - 1));
+ else
+ td->hwBE = 0;
+ td->hwNextTD = ohci_cpu_to_le32 ((unsigned long)td_pt);
+
+ /* append to queue */
+ td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+ ohci_t *ohci = &gohci;
+ int data_len = transfer_len;
+ void *data;
+ int cnt = 0;
+ __u32 info = 0;
+ unsigned int toggle = 0;
+
+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+ if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+ toggle = TD_T_TOGGLE;
+ } else {
+ toggle = TD_T_DATA0;
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+ }
+ urb->td_cnt = 0;
+ if (data_len)
+ data = buffer;
+ else
+ data = 0;
+
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK:
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+ while(data_len > 4096) {
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+ data += 4096; data_len -= 4096; cnt++;
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+ cnt++;
+
+ if (!ohci->sleeping)
+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ break;
+
+ case PIPE_CONTROL:
+ info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+ td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+ if (data_len > 0) {
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+ /* NOTE: mishandles transfers >8K, some >4K */
+ td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+ td_fill (ohci, info, data, 0, dev, cnt++, urb);
+ if (!ohci->sleeping)
+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+ break;
+ }
+ if (urb->length != cnt)
+ dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+ __u32 tdINFO, tdBE, tdCBP;
+ urb_priv_t *lurb_priv = &urb_priv;
+
+ tdINFO = ohci_cpu_to_le32 (td->hwINFO);
+ tdBE = ohci_cpu_to_le32 (td->hwBE);
+ tdCBP = ohci_cpu_to_le32 (td->hwCBP);
+
+
+ if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
+ ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+ if (tdBE != 0) {
+ if (td->hwCBP == 0)
+ lurb_priv->actual_length += tdBE - td->data + 1;
+ else
+ lurb_priv->actual_length += tdCBP - td->data;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+ __u32 td_list_hc;
+ td_t *td_rev = NULL;
+ td_t *td_list = NULL;
+ urb_priv_t *lurb_priv = NULL;
+
+ td_list_hc = ohci_cpu_to_le32 (ohci->hcca->done_head) & 0xfffffff0;
+ ohci->hcca->done_head = 0;
+
+ while (td_list_hc) {
+ td_list = (td_t *)td_list_hc;
+
+ if (TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO))) {
+ lurb_priv = &urb_priv;
+ dbg(" USB-error/status: %x : %p",
+ TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO)), td_list);
+ if (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x1)) {
+ if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+ td_list->ed->hwHeadP =
+ (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & ohci_cpu_to_le32 (0xfffffff0)) |
+ (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x2));
+ lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+ } else
+ td_list->ed->hwHeadP &= ohci_cpu_to_le32 (0xfffffff2);
+ }
+#ifdef CONFIG_MPC5200
+ td_list->hwNextTD = 0;
+#endif
+ }
+
+ td_list->next_dl_td = td_rev;
+ td_rev = td_list;
+ td_list_hc = ohci_cpu_to_le32 (td_list->hwNextTD) & 0xfffffff0;
+ }
+ return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+ td_t *td_list_next = NULL;
+ ed_t *ed;
+ int cc = 0;
+ int stat = 0;
+ /* urb_t *urb; */
+ urb_priv_t *lurb_priv;
+ __u32 tdINFO, edHeadP, edTailP;
+
+ while (td_list) {
+ td_list_next = td_list->next_dl_td;
+
+ lurb_priv = &urb_priv;
+ tdINFO = ohci_cpu_to_le32 (td_list->hwINFO);
+
+ ed = td_list->ed;
+
+ dl_transfer_length(td_list);
+
+ /* error code of transfer */
+ cc = TD_CC_GET (tdINFO);
+ if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+ if ((ed->state & (ED_OPER | ED_UNLINK))
+ && (lurb_priv->state != URB_DEL)) {
+ dbg("ConditionCode %#x", cc);
+ stat = cc_to_error[cc];
+ urb_finished = 1;
+ }
+ }
+
+ if (ed->state != ED_NEW) {
+ edHeadP = ohci_cpu_to_le32 (ed->hwHeadP) & 0xfffffff0;
+ edTailP = ohci_cpu_to_le32 (ed->hwTailP);
+
+ /* unlink eds if they are not busy */
+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+ ep_unlink (ohci, ed);
+ }
+
+ td_list = td_list_next;
+ }
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 28, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'O', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'C', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT roothub_status(&gohci)
+#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+ __u32 temp, ndp, i;
+ int res;
+
+ res = -1;
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ /* check for a device disconnect */
+ if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+ (RH_PS_PESC | RH_PS_CSC)) &&
+ ((temp & RH_PS_CCS) == 0)) {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *cmd)
+{
+ void * data = buffer;
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ __u32 datab[4];
+ __u8 *data_buf = (__u8 *)datab;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+#ifdef DEBUG
+urb_priv.actual_length = 0;
+pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#endif
+ if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ info("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = m16_swap (cmd->value);
+ wIndex = m16_swap (cmd->index);
+ wLength = m16_swap (cmd->length);
+
+ info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+ dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(__u16 *) data_buf = m16_swap (1); OK (2);
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK (4);
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case (RH_ENDPOINT_STALL): OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ OK(0);
+ case (RH_C_HUB_OVER_CURRENT):
+ WR_RH_STAT(RH_HS_OCIC); OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+ case (RH_C_PORT_CONNECTION):
+ WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+ case (RH_C_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+ case (RH_C_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+ case (RH_C_PORT_OVER_CURRENT):
+ WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+ case (RH_C_PORT_RESET):
+ WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+ case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PRS);
+ OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
+ case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PES );
+ OK (0);
+ }
+ break;
+
+ case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des; OK(len);
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des; OK(len);
+ case (0x03): /* string descriptors */
+ if(wValue==0x0300) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ OK(len);
+ }
+ if(wValue==0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ OK(len);
+ }
+ default:
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ {
+ __u32 temp = roothub_a (&gohci);
+
+ data_buf [0] = 9; /* min length; */
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ /* corresponds to data_buf[4-7] */
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = roothub_b (&gohci);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data_buf [0], wLength));
+ OK (len);
+ }
+
+ case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
+
+ case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
+
+ default:
+ dbg ("unsupported root hub command");
+ stat = USB_ST_STALLED;
+ }
+
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#endif
+
+ len = min_t(int, len, leni);
+ if (data != data_buf)
+ memcpy (data, data_buf, len);
+ dev->act_len = len;
+ dev->status = stat;
+
+#ifdef DEBUG
+ if (transfer_len)
+ urb_priv.actual_length = transfer_len;
+ pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#endif
+
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ int stat = 0;
+ int maxsize = usb_maxpacket(dev, pipe);
+ int timeout;
+
+ /* device pulled? Shortcut the action. */
+ if (devgone == dev) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+ if (!maxsize) {
+ err("submit_common_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+
+ if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
+ err("sohci_submit_job failed");
+ return -1;
+ }
+
+ /* allow more time for a BULK device to react - some are slow */
+#define BULK_TO 5000 /* timeout in milliseconds */
+ if (usb_pipetype (pipe) == PIPE_BULK)
+ timeout = BULK_TO;
+ else
+ timeout = 100;
+
+ /* wait for it to complete */
+ for (;;) {
+ /* check whether the controller is done */
+ stat = hc_interrupt();
+ if (stat < 0) {
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+
+ /* NOTE: since we are not interrupt driven in U-Boot and always
+ * handle only one URB at a time, we cannot assume the
+ * transaction finished on the first successful return from
+ * hc_interrupt().. unless the flag for current URB is set,
+ * meaning that all TD's to/from device got actually
+ * transferred and processed. If the current URB is not
+ * finished we need to re-iterate this loop so as
+ * hc_interrupt() gets called again as there needs to be some
+ * more TD's to process still */
+ if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
+ /* 0xff is returned for an SF-interrupt */
+ break;
+ }
+
+ if (--timeout) {
+ wait_ms(1);
+ if (!urb_finished)
+ dbg("\%");
+
+ } else {
+ err("CTL:TIMEOUT ");
+ dbg("submit_common_msg: TO status %x\n", stat);
+ stat = USB_ST_CRC_ERR;
+ urb_finished = 1;
+ break;
+ }
+ }
+#if 0
+ /* we got an Root Hub Status Change interrupt */
+ if (got_rhsc) {
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#endif
+ got_rhsc = 0;
+ /* abuse timeout */
+ timeout = rh_check_port_status(&gohci);
+ if (timeout >= 0) {
+#if 0 /* this does nothing useful, but leave it here in case that changes */
+ /* the called routine adds 1 to the passed value */
+ usb_hub_port_connect_change(gohci.rh.dev, timeout - 1);
+#endif
+ /*
+ * XXX
+ * This is potentially dangerous because it assumes
+ * that only one device is ever plugged in!
+ */
+ devgone = dev;
+ }
+ }
+#endif
+
+ dev->status = stat;
+ dev->act_len = transfer_len;
+
+#ifdef DEBUG
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#endif
+
+ /* free TDs in urb_priv */
+ urb_free_priv (&urb_priv);
+ return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len)
+{
+ info("submit_bulk_msg");
+ return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup)
+{
+ int maxsize = usb_maxpacket(dev, pipe);
+
+ info("submit_control_msg");
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+ if (!maxsize) {
+ err("submit_control_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+ if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+ gohci.rh.dev = dev;
+ /* root hub - redirect */
+ return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+ setup);
+ }
+
+ return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, int interval)
+{
+ info("submit_int_msg");
+ return -1;
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+ int timeout = 30;
+ int smm_timeout = 50; /* 0,5 sec */
+
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+ info("USB HC TakeOver from SMM");
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+ wait_ms (10);
+ if (--smm_timeout == 0) {
+ err("USB HC TakeOver failed!");
+ return -1;
+ }
+ }
+ }
+
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+ dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
+ ohci->slot_name,
+ readl (&ohci->regs->control));
+
+ /* Reset USB (needed by some controllers) */
+ ohci->hc_control = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* HC Reset requires max 10 us delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+ if (--timeout == 0) {
+ err("USB HC reset timed out!");
+ return -1;
+ }
+ udelay (1);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+ __u32 mask;
+ unsigned int fminterval;
+
+ ohci->disabled = 1;
+
+ /* Tell the controller where the control and bulk lists are
+ * The lists are empty now. */
+
+ writel (0, &ohci->regs->ed_controlhead);
+ writel (0, &ohci->regs->ed_bulkhead);
+
+ writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+ fminterval = 0x2edf;
+ writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+ fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+ writel (fminterval, &ohci->regs->fminterval);
+ writel (0x628, &ohci->regs->lsthresh);
+
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* disable all interrupts */
+ mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+ OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+ OHCI_INTR_OC | OHCI_INTR_MIE);
+ writel (mask, &ohci->regs->intrdisable);
+ /* clear all interrupts */
+ mask &= ~OHCI_INTR_MIE;
+ writel (mask, &ohci->regs->intrstatus);
+ /* Choose the interrupts we care about now - but w/o MIE */
+ mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ writel (mask, &ohci->regs->intrenable);
+
+#ifdef OHCI_USE_NPS
+ /* required for AMD-756 and some Mac platforms */
+ writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+ &ohci->regs->roothub.a);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+ /* POTPGT delay is bits 24-31, in 2 ms units. */
+ mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+ /* connect the virtual root hub */
+ ohci->rh.devnum = 0;
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static int
+hc_interrupt (void)
+{
+ ohci_t *ohci = &gohci;
+ struct ohci_regs *regs = ohci->regs;
+ int ints;
+ int stat = -1;
+
+ if ((ohci->hcca->done_head != 0) &&
+ !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
+
+ ints = OHCI_INTR_WDH;
+
+ } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+ ohci->disabled++;
+ err ("%s device removed!", ohci->slot_name);
+ return -1;
+
+ } else if ((ints &= readl (&regs->intrenable)) == 0) {
+ dbg("hc_interrupt: returning..\n");
+ return 0xff;
+ }
+
+ /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+ if (ints & OHCI_INTR_RHSC) {
+ got_rhsc = 1;
+ stat = 0xff;
+ }
+
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+ ohci->slot_name);
+ /* e.g. due to PCI Master/Target Abort */
+
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+ /* FIXME: be optimistic, hope that bug won't repeat often. */
+ /* Make some non-interrupt context restart the controller. */
+ /* Count and limit the retries though; either hardware or */
+ /* software errors can go forever... */
+ hc_reset (ohci);
+ return -1;
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+ writel (OHCI_INTR_WDH, &regs->intrdisable);
+ stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+ writel (OHCI_INTR_WDH, &regs->intrenable);
+ }
+
+ if (ints & OHCI_INTR_SO) {
+ dbg("USB Schedule overrun\n");
+ writel (OHCI_INTR_SO, &regs->intrenable);
+ stat = -1;
+ }
+
+ /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
+ if (ints & OHCI_INTR_SF) {
+ unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
+ wait_ms(1);
+ writel (OHCI_INTR_SF, &regs->intrdisable);
+ if (ohci->ed_rm_list[frame] != NULL)
+ writel (OHCI_INTR_SF, &regs->intrenable);
+ stat = 0xff;
+ }
+
+ writel (ints, &regs->intrstatus);
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+ dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+ if (!ohci->disabled)
+ hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(void)
+{
+ memset (&gohci, 0, sizeof (ohci_t));
+ memset (&urb_priv, 0, sizeof (urb_priv_t));
+
+ /* align the storage */
+ if ((__u32)&ghcca[0] & 0xff) {
+ err("HCCA not aligned!!");
+ return -1;
+ }
+ phcca = &ghcca[0];
+ info("aligned ghcca %p", phcca);
+ memset(&ohci_dev, 0, sizeof(struct ohci_device));
+ if ((__u32)&ohci_dev.ed[0] & 0x7) {
+ err("EDs not aligned!!");
+ return -1;
+ }
+ memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+ if ((__u32)gtd & 0x7) {
+ err("TDs not aligned!!");
+ return -1;
+ }
+ ptd = gtd;
+ gohci.hcca = phcca;
+ memset (phcca, 0, sizeof (struct ohci_hcca));
+
+ gohci.disabled = 1;
+ gohci.sleeping = 0;
+ gohci.irq = -1;
+ gohci.regs = (struct ohci_regs *)(CFG_PERIPHERAL_BASE | 0x1000);
+
+ gohci.flags = 0;
+ gohci.slot_name = "ppc440";
+
+ if (hc_reset (&gohci) < 0) {
+ hc_release_ohci (&gohci);
+ return -1;
+ }
+
+ if (hc_start (&gohci) < 0) {
+ err ("can't start usb-%s", gohci.slot_name);
+ hc_release_ohci (&gohci);
+ return -1;
+ }
+
+#ifdef DEBUG
+ ohci_dump (&gohci, 1);
+#endif
+ ohci_inited = 1;
+ urb_finished = 1;
+
+ /* init the device driver */
+ usb_dev_init();
+
+ return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+ /* this gets called really early - before the controller has */
+ /* even been initialized! */
+ if (!ohci_inited)
+ return 0;
+ /* TODO release any interrupts, etc. */
+ /* call hc_release_ohci() here ? */
+ hc_reset (&gohci);
+ return 0;
+}
+
+#endif /* CONFIG_USB_OHCI */
diff --git a/cpu/ppc4xx/usb_ohci.h b/cpu/ppc4xx/usb_ohci.h
new file mode 100755
index 0000000..706e05e
--- /dev/null
+++ b/cpu/ppc4xx/usb_ohci.h
@@ -0,0 +1,410 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+ /* No Error */ 0,
+ /* CRC Error */ USB_ST_CRC_ERR,
+ /* Bit Stuff */ USB_ST_BIT_ERR,
+ /* Data Togg */ USB_ST_CRC_ERR,
+ /* Stall */ USB_ST_STALLED,
+ /* DevNotResp */ -1,
+ /* PIDCheck */ USB_ST_BIT_ERR,
+ /* UnExpPID */ USB_ST_BIT_ERR,
+ /* DataOver */ USB_ST_BUF_ERR,
+ /* DataUnder */ USB_ST_BUF_ERR,
+ /* reservd */ -1,
+ /* reservd */ -1,
+ /* BufferOver */ USB_ST_BUF_ERR,
+ /* BuffUnder */ USB_ST_BUF_ERR,
+ /* Not Access */ -1,
+ /* Not Access */ -1
+};
+
+/* ED States */
+
+#define ED_NEW 0x00
+#define ED_UNLINK 0x01
+#define ED_OPER 0x02
+#define ED_DEL 0x04
+#define ED_URB_DEL 0x08
+
+/* usb_ohci_ed */
+struct ed {
+ __u32 hwINFO;
+ __u32 hwTailP;
+ __u32 hwHeadP;
+ __u32 hwNextED;
+
+ struct ed *ed_prev;
+ __u8 int_period;
+ __u8 int_branch;
+ __u8 int_load;
+ __u8 int_interval;
+ __u8 state;
+ __u8 type;
+ __u16 last_iso;
+ struct ed *ed_rm_list;
+
+ struct usb_device *usb_dev;
+ __u32 unused[3];
+} __attribute((aligned(16)));
+typedef struct ed ed_t;
+
+/* TD info field */
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R 0x00040000
+#define TD_DI 0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_ISO 0x00010000
+#define TD_DEL 0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+#define TD_NOTACCESSED 0x0F
+
+#define MAXPSW 1
+
+struct td {
+ __u32 hwINFO;
+ __u32 hwCBP; /* Current Buffer Pointer */
+ __u32 hwNextTD; /* Next TD Pointer */
+ __u32 hwBE; /* Memory Buffer End Pointer */
+
+ __u16 hwPSW[MAXPSW];
+ __u8 unused;
+ __u8 index;
+ struct ed *ed;
+ struct td *next_dl_td;
+ struct usb_device *usb_dev;
+ int transfer_len;
+ __u32 data;
+
+ __u32 unused2[2];
+} __attribute((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of. It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32 /* part of the OHCI standard */
+struct ohci_hcca {
+ __u32 int_table[NUM_INTS]; /* Interrupt ED table */
+#if defined(CONFIG_MPC5200)
+ __u16 pad1; /* set to 0 on each frame_no change */
+ __u16 frame_no; /* current frame number */
+#else
+ __u16 frame_no; /* current frame number */
+ __u16 pad1; /* set to 0 on each frame_no change */
+#endif
+ __u32 done_head; /* info returned for an interrupt */
+ u8 reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+/*
+ * Maximum number of root hub ports.
+ */
+#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region. This is Memory Mapped I/O. You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+ /* control and status registers */
+ __u32 revision;
+ __u32 control;
+ __u32 cmdstatus;
+ __u32 intrstatus;
+ __u32 intrenable;
+ __u32 intrdisable;
+ /* memory pointers */
+ __u32 hcca;
+ __u32 ed_periodcurrent;
+ __u32 ed_controlhead;
+ __u32 ed_controlcurrent;
+ __u32 ed_bulkhead;
+ __u32 ed_bulkcurrent;
+ __u32 donehead;
+ /* frame counters */
+ __u32 fminterval;
+ __u32 fmremaining;
+ __u32 fmnumber;
+ __u32 periodicstart;
+ __u32 lsthresh;
+ /* Root hub ports */
+ struct ohci_roothub_regs {
+ __u32 a;
+ __u32 b;
+ __u32 status;
+ __u32 portstatus[MAX_ROOT_PORTS];
+ } roothub;
+} __attribute((aligned(32)));
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void *dev; /* was urb */
+ void *int_addr;
+ int send;
+ int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status */
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct {
+ ed_t *ed;
+ __u16 length; /* number of tds associated with this request */
+ __u16 td_cnt; /* number of tds already serviced */
+ int state;
+ unsigned long pipe;
+ int actual_length;
+ td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+typedef struct ohci {
+ struct ohci_hcca *hcca; /* hcca */
+ /*dma_addr_t hcca_dma; */
+
+ int irq;
+ int disabled; /* e.g. got a UE, we're hung */
+ int sleeping;
+ unsigned long flags; /* for HC bugs */
+
+ struct ohci_regs *regs; /* OHCI controller's memory */
+
+ ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
+ ed_t *ed_bulktail; /* last endpoint of bulk list */
+ ed_t *ed_controltail; /* last endpoint of control list */
+ int intrstatus;
+ __u32 hc_control; /* copy of the hc control reg */
+ struct usb_device *dev[32];
+ struct virt_root_hub rh;
+
+ const char *slot_name;
+} ohci_t;
+
+#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+ ed_t ed[NUM_EDS];
+ int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD + 1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *td_alloc(struct usb_device *usb_dev)
+{
+ int i;
+ struct td *td;
+
+ td = NULL;
+ for (i = 0; i < NUM_TD; i++) {
+ if (ptd[i].usb_dev == NULL) {
+ td = &ptd[i];
+ td->usb_dev = usb_dev;
+ break;
+ }
+ }
+
+ return td;
+}
+
+static inline void ed_free(struct ed *ed)
+{
+ ed->usb_dev = NULL;
+}
diff --git a/cpu/ppc4xx/usbdev.c b/cpu/ppc4xx/usbdev.c
new file mode 100755
index 0000000..8262c54
--- /dev/null
+++ b/cpu/ppc4xx/usbdev.c
@@ -0,0 +1,214 @@
+/*USB 1.1,2.0 device*/
+
+#include <common.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_440EP
+
+#include <usb.h>
+#include "usbdev.h"
+#include "vecnum.h"
+
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+
+int set_value = -1;
+
+void process_endpoints(unsigned short usb2d0_intrin)
+{
+ /*will hold the packet received */
+ struct usb_device_descriptor usb_device_packet;
+ struct usb_config_descriptor usb_config_packet;
+ struct usb_string_descriptor usb_string_packet;
+ struct devrequest setup_packet;
+ unsigned int *setup_packet_pt;
+ unsigned char *packet_pt = NULL;
+ int temp, temp1;
+
+ int i;
+
+ /*printf("{USB device} - endpoint 0x%X \n", usb2d0_intrin); */
+
+ /*set usb address, seems to not work unless it is done in the next
+ interrupt, so that is why it is done this way */
+ if (set_value != -1)
+ *(unsigned char *)USB2D0_FADDR_8 = (unsigned char)set_value;
+
+ /*endpoint 1 */
+ if (usb2d0_intrin & 0x01) {
+ setup_packet_pt = (unsigned int *)&setup_packet;
+
+ /*copy packet */
+ setup_packet_pt[0] = *(unsigned int *)USB2D0_FIFO_0;
+ setup_packet_pt[1] = *(unsigned int *)USB2D0_FIFO_0;
+ temp = *(unsigned int *)USB2D0_FIFO_0;
+ temp1 = *(unsigned int *)USB2D0_FIFO_0;
+
+ /*do some swapping */
+ setup_packet.value = swap_16(setup_packet.value);
+ setup_packet.index = swap_16(setup_packet.index);
+ setup_packet.length = swap_16(setup_packet.length);
+
+ /*clear rx packet */
+ *(unsigned short *)USB2D0_INCSR0_8 = 0x48;
+
+ /*printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", setup_packet.requesttype,
+ setup_packet.request, setup_packet.value,
+ setup_packet.index, setup_packet.length, temp, temp1 ); */
+
+ switch (setup_packet.request) {
+ case USB_REQ_GET_DESCRIPTOR:
+
+ switch (setup_packet.value >> 8) {
+ case USB_DT_DEVICE:
+ /*create packet */
+ usb_device_packet.bLength = 18;
+ usb_device_packet.bDescriptorType =
+ USB_DT_DEVICE;
+#ifdef USB_2_0_DEVICE
+ usb_device_packet.bcdUSB = swap_16(0x200);
+#else
+ usb_device_packet.bcdUSB = swap_16(0x110);
+#endif
+ usb_device_packet.bDeviceClass = 0xff;
+ usb_device_packet.bDeviceSubClass = 0;
+ usb_device_packet.bDeviceProtocol = 0;
+ usb_device_packet.bMaxPacketSize0 = 32;
+ usb_device_packet.idVendor = swap_16(1);
+ usb_device_packet.idProduct = swap_16(2);
+ usb_device_packet.bcdDevice = swap_16(0x300);
+ usb_device_packet.iManufacturer = 1;
+ usb_device_packet.iProduct = 1;
+ usb_device_packet.iSerialNumber = 1;
+ usb_device_packet.bNumConfigurations = 1;
+
+ /*put packet in fifo */
+ packet_pt = (unsigned char *)&usb_device_packet;
+ break;
+
+ case USB_DT_CONFIG:
+ /*create packet */
+ usb_config_packet.bLength = 9;
+ usb_config_packet.bDescriptorType =
+ USB_DT_CONFIG;
+ usb_config_packet.wTotalLength = swap_16(25);
+ usb_config_packet.bNumInterfaces = 1;
+ usb_config_packet.bConfigurationValue = 1;
+ usb_config_packet.iConfiguration = 0;
+ usb_config_packet.bmAttributes = 0x40;
+ usb_config_packet.MaxPower = 0;
+
+ /*put packet in fifo */
+ packet_pt = (unsigned char *)&usb_config_packet;
+ break;
+
+ case USB_DT_STRING:
+ /*create packet */
+ usb_string_packet.bLength = 2;
+ usb_string_packet.bDescriptorType =
+ USB_DT_STRING;
+ usb_string_packet.wData[0] = 0x0094;
+
+ /*put packet in fifo */
+ packet_pt = (unsigned char *)&usb_string_packet;
+ break;
+ }
+
+ /*put packet in fifo */
+ for (i = 0; i < (setup_packet.length); i++) {
+ *(unsigned char *)USB2D0_FIFO_0 = packet_pt[i];
+ }
+
+ /*give tx command */
+ *(unsigned short *)USB2D0_INCSR0_8 = 0x0a;
+
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+
+ /*copy usb address */
+ set_value = setup_packet.value;
+
+ break;
+ }
+
+ }
+}
+
+void process_other(unsigned char usb2d0_intrusb)
+{
+
+ /*check for sof */
+ if (usb2d0_intrusb & 0x08) {
+ /*printf("{USB device} - sof detected\n"); */
+ }
+
+ /*check for reset */
+ if (usb2d0_intrusb & 0x04) {
+ /*printf("{USB device} - reset detected\n"); */
+
+ /*copy usb address of zero, need to do this when usb reset */
+ set_value = 0;
+ }
+
+ if (usb2d0_intrusb & 0x02) {
+ /*printf("{USB device} - resume detected\n"); */
+ }
+
+ if (usb2d0_intrusb & 0x01) {
+ /*printf("{USB device} - suspend detected\n"); */
+ }
+}
+
+int usbInt(void)
+{
+ /*Must read these 2 registers and use values to clear interrupts. If you
+ do not read them then the interrupt will not be cleared. If you do not
+ use the variable the optimizer will not do a read. */
+ volatile unsigned short usb2d0_intrin =
+ *(unsigned short *)USB2D0_INTRIN_16;
+ volatile unsigned char usb2d0_intrusb =
+ *(unsigned char *)USB2D0_INTRUSB_8;
+
+ /*check if there was an endpoint interrupt */
+ if (usb2d0_intrin != 0) {
+ process_endpoints(usb2d0_intrin);
+ }
+
+ /*check for other interrupts */
+ if (usb2d0_intrusb != 0) {
+ process_other(usb2d0_intrusb);
+ }
+
+ return 0;
+}
+
+void usb_dev_init()
+{
+#ifdef USB_2_0_DEVICE
+ printf("USB 2.0 Device init\n");
+ /*select 2.0 device */
+ mtsdr(sdr_usb0, 0x0); /* 2.0 */
+
+ /*usb dev init */
+ *(unsigned char *)USB2D0_POWER_8 = 0xa1; /* 2.0 */
+#else
+ printf("USB 1.1 Device init\n");
+ /*select 1.1 device */
+ mtsdr(sdr_usb0, 0x2); /* 1.1 */
+
+ /*usb dev init */
+ *(unsigned char *)USB2D0_POWER_8 = 0xc0; /* 1.1 */
+#endif
+
+ /*enable interrupts */
+ *(unsigned char *)USB2D0_INTRUSBE_8 = 0x0f;
+
+ irq_install_handler(VECNUM_USBDEV, (interrupt_handler_t *) usbInt,
+ NULL);
+}
+
+#endif /*CONFIG_440EP */
diff --git a/cpu/ppc4xx/usbdev.h b/cpu/ppc4xx/usbdev.h
new file mode 100755
index 0000000..3446d98
--- /dev/null
+++ b/cpu/ppc4xx/usbdev.h
@@ -0,0 +1,31 @@
+#include <config.h>
+
+/*Common Registers*/
+#define USB2D0_INTRIN_16 (CFG_USB_DEVICE | 0x100)
+#define USB2D0_POWER_8 (CFG_USB_DEVICE | 0x102)
+#define USB2D0_FADDR_8 (CFG_USB_DEVICE | 0x103)
+#define USB2D0_INTRINE_16 (CFG_USB_DEVICE | 0x104)
+#define USB2D0_INTROUT_16 (CFG_USB_DEVICE | 0x106)
+#define USB2D0_INTRUSBE_8 (CFG_USB_DEVICE | 0x108)
+#define USB2D0_INTRUSB_8 (CFG_USB_DEVICE | 0x109)
+#define USB2D0_INTROUTE_16 (CFG_USB_DEVICE | 0x10a)
+#define USB2D0_TSTMODE_8 (CFG_USB_DEVICE | 0x10c)
+#define USB2D0_INDEX_8 (CFG_USB_DEVICE | 0x10d)
+#define USB2D0_FRAME_16 (CFG_USB_DEVICE | 0x10e)
+
+/*Indexed Registers*/
+#define USB2D0_INCSR0_8 (CFG_USB_DEVICE | 0x110)
+#define USB2D0_INCSR_16 (CFG_USB_DEVICE | 0x110)
+#define USB2D0_INMAXP_16 (CFG_USB_DEVICE | 0x112)
+#define USB2D0_OUTCSR_16 (CFG_USB_DEVICE | 0x114)
+#define USB2D0_OUTMAXP_16 (CFG_USB_DEVICE | 0x116)
+#define USB2D0_OUTCOUNT0_8 (CFG_USB_DEVICE | 0x11a)
+#define USB2D0_OUTCOUNT_16 (CFG_USB_DEVICE | 0x11a)
+
+/*FIFOs*/
+#define USB2D0_FIFO_0 (CFG_USB_DEVICE | 0x120)
+#define USB2D0_FIFO_1 (CFG_USB_DEVICE | 0x124)
+#define USB2D0_FIFO_2 (CFG_USB_DEVICE | 0x128)
+#define USB2D0_FIFO_3 (CFG_USB_DEVICE | 0x12c)
+
+void usb_dev_init(void);
diff --git a/cpu/ppc4xx/vecnum.h b/cpu/ppc4xx/vecnum.h
new file mode 100755
index 0000000..cbfe41d
--- /dev/null
+++ b/cpu/ppc4xx/vecnum.h
@@ -0,0 +1,129 @@
+/*
+* 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
+*/
+
+/*
+ * Interrupt vector number definitions to ease the
+ * 405 -- 440 porting pain ;-)
+ *
+ * NOTE: They're not all here yet ... update as needed.
+ *
+ */
+
+#ifndef _VECNUMS_H_
+#define _VECNUMS_H_
+
+#if defined(CONFIG_440SP)
+
+/* UIC 0 */
+#define VECNUM_U0 0 /* UART0 */
+#define VECNUM_U1 1 /* UART1 */
+#define VECNUM_IIC0 2 /* IIC0 */
+#define VECNUM_IIC1 3 /* IIC1 */
+#define VECNUM_PIM 4 /* PCI inbound message */
+#define VECNUM_PCRW 5 /* PCI command reg write */
+#define VECNUM_PPM 6 /* PCI power management */
+#define VECNUM_UIC1NC 30 /* UIC1 non-critical interrupt */
+#define VECNUM_UIC1C 31 /* UIC1 critical interrupt */
+
+/* UIC 1 */
+#define VECNUM_EIR0 (32 + 0) /* External interrupt 0 */
+#define VECNUM_MS (32 + 1) /* MAL SERR */
+#define VECNUM_TXDE (32 + 2) /* MAL TXDE */
+#define VECNUM_RXDE (32 + 3) /* MAL RXDE */
+#define VECNUM_MTE (32 + 6) /* MAL Tx EOB */
+#define VECNUM_MRE (32 + 7) /* MAL Rx EOB */
+#define VECNUM_CT0 (32 + 12) /* GPT compare timer 0 */
+#define VECNUM_CT1 (32 + 13) /* GPT compare timer 1 */
+#define VECNUM_CT2 (32 + 14) /* GPT compare timer 2 */
+#define VECNUM_CT3 (32 + 15) /* GPT compare timer 3 */
+#define VECNUM_CT4 (32 + 16) /* GPT compare timer 4 */
+#define VECNUM_ETH0 (32 + 28) /* Ethernet interrupt status */
+#define VECNUM_EWU0 (32 + 29) /* Emac wakeup */
+
+#elif defined(CONFIG_440)
+
+/* UIC 0 */
+#define VECNUM_U0 0 /* UART0 */
+#define VECNUM_U1 1 /* UART1 */
+#define VECNUM_IIC0 2 /* IIC0 */
+#define VECNUM_IIC1 3 /* IIC1 */
+#define VECNUM_PIM 4 /* PCI inbound message */
+#define VECNUM_PCRW 5 /* PCI command reg write */
+#define VECNUM_PPM 6 /* PCI power management */
+#define VECNUM_MSI0 7 /* PCI MSI level 0 */
+#define VECNUM_MSI1 8 /* PCI MSI level 0 */
+#define VECNUM_MSI2 9 /* PCI MSI level 0 */
+#define VECNUM_MTE 10 /* MAL TXEOB */
+#define VECNUM_MRE 11 /* MAL RXEOB */
+#define VECNUM_D0 12 /* DMA channel 0 */
+#define VECNUM_D1 13 /* DMA channel 1 */
+#define VECNUM_D2 14 /* DMA channel 2 */
+#define VECNUM_D3 15 /* DMA channel 3 */
+#define VECNUM_CT0 18 /* GPT compare timer 0 */
+#define VECNUM_CT1 19 /* GPT compare timer 1 */
+#define VECNUM_CT2 20 /* GPT compare timer 2 */
+#define VECNUM_CT3 21 /* GPT compare timer 3 */
+#define VECNUM_CT4 22 /* GPT compare timer 4 */
+#define VECNUM_EIR0 23 /* External interrupt 0 */
+#define VECNUM_EIR1 24 /* External interrupt 1 */
+#define VECNUM_EIR2 25 /* External interrupt 2 */
+#define VECNUM_EIR3 26 /* External interrupt 3 */
+#define VECNUM_EIR4 27 /* External interrupt 4 */
+#define VECNUM_EIR5 28 /* External interrupt 5 */
+#define VECNUM_EIR6 29 /* External interrupt 6 */
+#define VECNUM_UIC1NC 30 /* UIC1 non-critical interrupt */
+#define VECNUM_UIC1C 31 /* UIC1 critical interrupt */
+
+/* UIC 1 */
+#define VECNUM_MS (32 + 0 ) /* MAL SERR */
+#define VECNUM_TXDE (32 + 1 ) /* MAL TXDE */
+#define VECNUM_RXDE (32 + 2 ) /* MAL RXDE */
+#define VECNUM_USBDEV (32 + 23) /* USB 1.1/USB 2.0 Device */
+#define VECNUM_ETH0 (32 + 28) /* Ethernet 0 interrupt status */
+#define VECNUM_EWU0 (32 + 29) /* Ethernet 0 wakeup */
+
+#else /* !defined(CONFIG_440) */
+
+#define VECNUM_U0 0 /* UART0 */
+#define VECNUM_U1 1 /* UART1 */
+#define VECNUM_D0 5 /* DMA channel 0 */
+#define VECNUM_D1 6 /* DMA channel 1 */
+#define VECNUM_D2 7 /* DMA channel 2 */
+#define VECNUM_D3 8 /* DMA channel 3 */
+#define VECNUM_EWU0 9 /* Ethernet wakeup */
+#define VECNUM_MS 10 /* MAL SERR */
+#define VECNUM_MTE 11 /* MAL TXEOB */
+#define VECNUM_MRE 12 /* MAL RXEOB */
+#define VECNUM_TXDE 13 /* MAL TXDE */
+#define VECNUM_RXDE 14 /* MAL RXDE */
+#define VECNUM_ETH0 15 /* Ethernet interrupt status */
+#define VECNUM_EIR0 25 /* External interrupt 0 */
+#define VECNUM_EIR1 26 /* External interrupt 1 */
+#define VECNUM_EIR2 27 /* External interrupt 2 */
+#define VECNUM_EIR3 28 /* External interrupt 3 */
+#define VECNUM_EIR4 29 /* External interrupt 4 */
+#define VECNUM_EIR5 30 /* External interrupt 5 */
+#define VECNUM_EIR6 31 /* External interrupt 6 */
+
+#endif /* defined(CONFIG_440) */
+
+#endif /* _VECNUMS_H_ */