summaryrefslogtreecommitdiff
path: root/cpu/ppc4xx
diff options
context:
space:
mode:
authorwdenk <wdenk>2002-11-03 00:24:07 +0000
committerwdenk <wdenk>2002-11-03 00:24:07 +0000
commitc609719b8d1b2dca590e0ed499016d041203e403 (patch)
tree7ea1755d80903ff972f312a249eb856061d40e15 /cpu/ppc4xx
parent5b1d713721c3ea02549940133f09236783dda1f9 (diff)
downloadu-boot-imx-c609719b8d1b2dca590e0ed499016d041203e403.zip
u-boot-imx-c609719b8d1b2dca590e0ed499016d041203e403.tar.gz
u-boot-imx-c609719b8d1b2dca590e0ed499016d041203e403.tar.bz2
Initial revision
Diffstat (limited to 'cpu/ppc4xx')
-rw-r--r--cpu/ppc4xx/405gp_enet.c867
-rw-r--r--cpu/ppc4xx/405gp_pci.c502
-rw-r--r--cpu/ppc4xx/cpu.c253
-rw-r--r--cpu/ppc4xx/i2c.c417
-rw-r--r--cpu/ppc4xx/sdram.c191
-rw-r--r--cpu/ppc4xx/speed.c308
-rw-r--r--cpu/ppc4xx/vecnum.h100
7 files changed, 2638 insertions, 0 deletions
diff --git a/cpu/ppc4xx/405gp_enet.c b/cpu/ppc4xx/405gp_enet.c
new file mode 100644
index 0000000..49e9e42
--- /dev/null
+++ b/cpu/ppc4xx/405gp_enet.c
@@ -0,0 +1,867 @@
+/*-----------------------------------------------------------------------------+
+ *
+ * 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).
+ *-----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <asm/processor.h>
+#include <ppc4xx.h>
+#include <commproc.h>
+#include <405gp_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+#include <net.h>
+#include <malloc.h>
+#include "vecnum.h"
+
+#if defined(CONFIG_405GP) || defined(CONFIG_440)
+
+#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */
+#define PHY_AUTONEGOTIATE_TIMEOUT 2000 /* 2000 ms autonegotiate timeout */
+
+#define NUM_TX_BUFF 1
+/* AS.HARNOIS
+ * Use PKTBUFSRX (include/net.h) instead of setting NUM_RX_BUFF again
+ * These both variables are used to define the same thing!
+ * #define NUM_RX_BUFF 4
+ */
+#define NUM_RX_BUFF PKTBUFSRX
+
+/* 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
+
+static char *txbuf_ptr;
+
+/* define the number of channels implemented */
+#define EMAC_RXCHL 1
+#define EMAC_TXCHL 1
+
+/*-----------------------------------------------------------------------------+
+ * 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
+
+/*-----------------------------------------------------------------------------+
+ * Global variables. TX and RX descriptors and buffers.
+ *-----------------------------------------------------------------------------*/
+static volatile mal_desc_t *tx;
+static volatile mal_desc_t *rx;
+static mal_desc_t *alloc_tx_buf = NULL;
+static mal_desc_t *alloc_rx_buf = NULL;
+
+/* IER globals */
+static unsigned long emac_ier;
+static unsigned long mal_ier;
+
+
+/* Statistic Areas */
+#define MAX_ERR_LOG 10
+struct emac_stats {
+ int data_len_err;
+ int rx_frames;
+ int rx;
+ int rx_prot_err;
+};
+
+static struct stats { /* Statistic Block */
+ struct emac_stats emac;
+ int int_err;
+ short tx_err_log[MAX_ERR_LOG];
+ short rx_err_log[MAX_ERR_LOG];
+} stats;
+
+static int first_init = 0;
+
+static int tx_err_index = 0; /* Transmit Error Index for tx_err_log */
+static int rx_err_index = 0; /* Receive Error Index for rx_err_log */
+
+static int rx_slot = 0; /* MAL Receive Slot */
+static int rx_i_index = 0; /* Receive Interrupt Queue Index */
+static int rx_u_index = 0; /* Receive User Queue Index */
+static int rx_ready[NUM_RX_BUFF]; /* Receive Ready Queue */
+
+static int tx_slot = 0; /* MAL Transmit Slot */
+static int tx_i_index = 0; /* Transmit Interrupt Queue Index */
+static int tx_u_index = 0; /* Transmit User Queue Index */
+static int tx_run[NUM_TX_BUFF]; /* Transmit Running Queue */
+
+#undef INFO_405_ENET 1
+#ifdef INFO_405_ENET
+static int packetSent = 0;
+static int packetReceived = 0;
+static int packetHandled = 0;
+#endif
+
+static char emac_hwd_addr[ENET_ADDR_LENGTH];
+
+static bd_t *bis_save = NULL; /* for eth_init upon mal error */
+
+static int is_receiving = 0; /* sync with eth interrupt */
+static int print_speed = 1; /* print speed message upon start */
+
+static void enet_rcv (unsigned long malisr);
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes and externals.
+ *-----------------------------------------------------------------------------*/
+void mal_err (unsigned long isr, unsigned long uic, unsigned long mal_def,
+ unsigned long mal_errr);
+void emac_err (unsigned long isr);
+
+
+void eth_halt (void)
+{
+ mtdcr (malier, 0x00000000); /* disable mal interrupts */
+ out32 (EMAC_IER, 0x00000000); /* disable emac interrupts */
+
+ /* 1st reset MAL */
+ mtdcr (malmcr, MAL_CR_MMSR);
+
+ /* wait for reset */
+ while (mfdcr (malmcr) & MAL_CR_MMSR) {
+ };
+
+ /* EMAC RESET */
+ out32 (EMAC_M0, EMAC_M0_SRST);
+
+ print_speed = 1; /* print speed message again next time */
+}
+
+
+int eth_init (bd_t * bis)
+{
+ int i;
+ unsigned long reg;
+ unsigned long msr;
+ unsigned long speed;
+ unsigned long duplex;
+ unsigned mode_reg;
+ unsigned short reg_short;
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE)); /* disable interrupts */
+
+#ifdef INFO_405_ENET
+ /* AS.HARNOIS
+ * We should have :
+ * packetHandled <= packetReceived <= packetHandled+PKTBUFSRX
+ * In the most cases packetHandled = packetReceived, 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:\n"
+ "- Sent packet number %d\n"
+ "- Received packet number %d\n"
+ "- Handled packet number %d\n",
+ packetSent, packetReceived, packetHandled);
+ packetSent = 0;
+ packetReceived = 0;
+ packetHandled = 0;
+#endif
+
+ /* MAL RESET */
+ mtdcr (malmcr, MAL_CR_MMSR);
+ /* wait for reset */
+ while (mfdcr (malmcr) & MAL_CR_MMSR) {
+ };
+
+ tx_err_index = 0; /* Transmit Error Index for tx_err_log */
+ rx_err_index = 0; /* Receive Error Index for rx_err_log */
+
+ rx_slot = 0; /* MAL Receive Slot */
+ rx_i_index = 0; /* Receive Interrupt Queue Index */
+ rx_u_index = 0; /* Receive User Queue Index */
+
+ tx_slot = 0; /* MAL Transmit Slot */
+ tx_i_index = 0; /* Transmit Interrupt Queue Index */
+ tx_u_index = 0; /* Transmit User Queue Index */
+
+#if defined(CONFIG_440)
+ /* set RMII mode */
+ out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0);
+#endif /* CONFIG_440 */
+
+ /* EMAC RESET */
+ out32 (EMAC_M0, EMAC_M0_SRST);
+
+ /* wait for PHY to complete auto negotiation */
+ reg_short = 0;
+#ifndef CONFIG_CS8952_PHY
+ miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, &reg_short);
+
+ /*
+ * Wait if PHY is able 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)) {
+ if ((i++ % 100) == 0)
+ putc ('.');
+ udelay (10000); /* 10 ms */
+ miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, &reg_short);
+
+ /*
+ * Timeout reached ?
+ */
+ if (i * 10 > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts (" TIMEOUT !\n");
+ break;
+ }
+ }
+ puts (" done\n");
+ udelay (500000); /* another 500 ms (results in faster booting) */
+ }
+#endif
+ speed = miiphy_speed (CONFIG_PHY_ADDR);
+ duplex = miiphy_duplex (CONFIG_PHY_ADDR);
+ if (print_speed) {
+ print_speed = 0;
+ printf ("ENET Speed is %d Mbps - %s duplex connection\n",
+ (int) speed, (duplex == HALF) ? "HALF" : "FULL");
+ }
+
+ /* set the Mal configuration reg */
+#if defined(CONFIG_440)
+ /* Errata 1.12: MAL_1 -- Disable MAL bursting */
+ if( get_pvr() == PVR_440GP_RB )
+ mtdcr (malmcr, MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+ else
+#else
+ mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+#endif
+
+ /* Free "old" buffers */
+ if (alloc_tx_buf) free(alloc_tx_buf);
+ if (alloc_rx_buf) free(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.
+ */
+ alloc_tx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_TX_BUFF) +
+ ((2 * CFG_CACHELINE_SIZE) - 2));
+ if (((int)alloc_tx_buf & CACHELINE_MASK) != 0) {
+ tx = (mal_desc_t *)((int)alloc_tx_buf + CFG_CACHELINE_SIZE -
+ ((int)alloc_tx_buf & CACHELINE_MASK));
+ } else {
+ tx = alloc_tx_buf;
+ }
+
+ alloc_rx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_RX_BUFF) +
+ ((2 * CFG_CACHELINE_SIZE) - 2));
+ if (((int)alloc_rx_buf & CACHELINE_MASK) != 0) {
+ rx = (mal_desc_t *)((int)alloc_rx_buf + CFG_CACHELINE_SIZE -
+ ((int)alloc_rx_buf & CACHELINE_MASK));
+ } else {
+ rx = alloc_rx_buf;
+ }
+
+ for (i = 0; i < NUM_TX_BUFF; i++) {
+ tx[i].ctrl = 0;
+ tx[i].data_len = 0;
+ if (first_init == 0)
+ txbuf_ptr = (char *) malloc (ENET_MAX_MTU_ALIGNED);
+ tx[i].data_ptr = txbuf_ptr;
+ if ((NUM_TX_BUFF - 1) == i)
+ tx[i].ctrl |= MAL_TX_CTRL_WRAP;
+ tx_run[i] = -1;
+#if 0
+ printf ("TX_BUFF %d @ 0x%08lx\n", i, (ulong) tx[i].data_ptr);
+#endif
+ }
+
+ for (i = 0; i < NUM_RX_BUFF; i++) {
+ rx[i].ctrl = 0;
+ rx[i].data_len = 0;
+ /* rx[i].data_ptr = (char *) &rx_buff[i]; */
+ rx[i].data_ptr = (char *) NetRxPackets[i];
+ if ((NUM_RX_BUFF - 1) == i)
+ rx[i].ctrl |= MAL_RX_CTRL_WRAP;
+ rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
+ rx_ready[i] = -1;
+#if 0
+ printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);
+#endif
+ }
+
+ memcpy (emac_hwd_addr, bis->bi_enetaddr, ENET_ADDR_LENGTH);
+
+ reg = 0x00000000;
+
+ reg |= emac_hwd_addr[0]; /* set high address */
+ reg = reg << 8;
+ reg |= emac_hwd_addr[1];
+
+ out32 (EMAC_IAH, reg);
+
+ reg = 0x00000000;
+ reg |= emac_hwd_addr[2]; /* set low address */
+ reg = reg << 8;
+ reg |= emac_hwd_addr[3];
+ reg = reg << 8;
+ reg |= emac_hwd_addr[4];
+ reg = reg << 8;
+ reg |= emac_hwd_addr[5];
+
+ out32 (EMAC_IAL, reg);
+
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (maltxctp0r, tx);
+ mtdcr (malrxctp0r, rx);
+
+ /* Reset transmit and receive channels */
+ mtdcr (malrxcarr, 0x80000000); /* 2 channels */
+ mtdcr (maltxcarr, 0x80000000); /* 2 channels */
+
+ /* Enable MAL transmit and receive channels */
+ mtdcr (maltxcasr, 0x80000000); /* 1 channel */
+ mtdcr (malrxcasr, 0x80000000); /* 1 channel */
+
+ /* set RX buffer size */
+ mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16);
+
+ /* set transmit enable & receive enable */
+ out32 (EMAC_M0, EMAC_M0_TXE | EMAC_M0_RXE);
+
+ /* set receive fifo to 4k and tx fifo to 2k */
+ mode_reg = EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
+
+ /* set speed */
+ 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, mode_reg);
+
+ /* Enable broadcast and indvidual address */
+ out32 (EMAC_RXM, EMAC_RMR_BAE | EMAC_RMR_IAE
+ /*| EMAC_RMR_ARRP| EMAC_RMR_SFCS | EMAC_RMR_SP */ );
+
+ /* we probably need to set the tx mode1 reg? maybe at tx time */
+
+ /* set transmit request threshold register */
+ out32 (EMAC_TRTR, 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, 0x80009000);
+ out32 (EMAC_TXM1, 0xf8640000);
+#else /* CONFIG_440 */
+ /* 405s have a 16 byte burst length */
+ out32 (EMAC_RX_HI_LO_WMARK, 0x0f002000);
+#endif /* CONFIG_440 */
+
+ /* Frame gap set */
+ out32 (EMAC_I_FRAME_GAP_REG, 0x00000008);
+
+ if (first_init == 0) {
+ /*
+ * Connect interrupt service routines
+ */
+ irq_install_handler (VECNUM_EWU0, (interrupt_handler_t *) enetInt, NULL);
+ irq_install_handler (VECNUM_MS, (interrupt_handler_t *) enetInt, NULL);
+ irq_install_handler (VECNUM_MTE, (interrupt_handler_t *) enetInt, NULL);
+ irq_install_handler (VECNUM_MRE, (interrupt_handler_t *) enetInt, NULL);
+ irq_install_handler (VECNUM_TXDE, (interrupt_handler_t *) enetInt, NULL);
+ irq_install_handler (VECNUM_RXDE, (interrupt_handler_t *) enetInt, NULL);
+ irq_install_handler (VECNUM_ETH0, (interrupt_handler_t *) enetInt, NULL);
+ }
+
+ /* set up interrupt handler */
+ /* setup interrupt controler to take interrupts from the MAL &
+ EMAC */
+ mtdcr (uicsr, 0xffffffff); /* clear pending interrupts */
+ mtdcr (uicer, mfdcr (uicer) | MAL_UIC_DEF | EMAC_UIC_DEF);
+
+ /* 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);
+
+ /* Set EMAC IER */
+ emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS |
+ EMAC_ISR_PTLE | EMAC_ISR_ORE | EMAC_ISR_IRE;
+ if (speed == _100BASET)
+ emac_ier = emac_ier | EMAC_ISR_SYE;
+
+ out32 (EMAC_ISR, 0xffffffff); /* clear pending interrupts */
+ out32 (EMAC_IER, emac_ier);
+
+ mtmsr (msr); /* enable interrupts again */
+
+ bis_save = bis;
+ first_init = 1;
+
+ return (0);
+}
+
+
+int eth_send (volatile void *ptr, int len)
+{
+ struct enet_frame *ef_ptr;
+ ulong time_start, time_now;
+ unsigned long temp_txm0;
+
+ ef_ptr = (struct enet_frame *) ptr;
+
+ /*-----------------------------------------------------------------------+
+ * Copy in our address into the frame.
+ *-----------------------------------------------------------------------*/
+ (void) memcpy (ef_ptr->source_addr, emac_hwd_addr, ENET_ADDR_LENGTH);
+
+ /*-----------------------------------------------------------------------+
+ * If frame is too long or too short, modify length.
+ *-----------------------------------------------------------------------*/
+ if (len > ENET_MAX_MTU)
+ len = ENET_MAX_MTU;
+
+ /* memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */
+ memcpy ((void *) txbuf_ptr, (const void *) ptr, len);
+
+ /*-----------------------------------------------------------------------+
+ * set TX Buffer busy, and send it
+ *-----------------------------------------------------------------------*/
+ tx[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) == tx_slot)
+ tx[tx_slot].ctrl |= MAL_TX_CTRL_WRAP;
+
+ tx[tx_slot].data_len = (short) len;
+ tx[tx_slot].ctrl |= MAL_TX_CTRL_READY;
+
+ __asm__ volatile ("eieio");
+ out32 (EMAC_TXM0, in32 (EMAC_TXM0) | EMAC_TXM0_GNP0);
+#ifdef INFO_405_ENET
+ packetSent++;
+#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);
+ /* 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 (0);
+ }
+ }
+}
+
+
+#if defined(CONFIG_440)
+/*-----------------------------------------------------------------------------+
+| EnetInt.
+| EnetInt is the interrupt handler. It will determine the
+| cause of the interrupt and call the apporpriate servive
+| routine.
++-----------------------------------------------------------------------------*/
+int enetInt ()
+{
+ 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;
+
+ /* enter loop that stays in interrupt code until nothing to service */
+ do {
+ serviced = 0;
+
+ my_uic0msr = mfdcr (uic0msr);
+ my_uic1msr = mfdcr (uic1msr);
+
+ if (!(my_uic0msr & UIC_MRE)
+ && !(my_uic1msr & (UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ /* not for us */
+ return (rc);
+ }
+
+ /* get and clear controller status interrupts */
+ /* look at Mal and EMAC interrupts */
+ if ((my_uic0msr & UIC_MRE)
+ || (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 (mal_isr, my_uic0msr, MAL_UIC_DEF, MAL_UIC_ERR);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if (UIC_ETH0 & my_uic1msr) { /* look for EMAC errors */
+ emac_isr = in32 (EMAC_ISR);
+ if ((emac_ier & emac_isr) != 0) {
+ emac_err (emac_isr);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if ((emac_ier & emac_isr)
+ || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+ mtdcr (uic0sr, UIC_MRE); /* Clear */
+ mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+ return (rc); /* we had errors so get out */
+ }
+
+ /* 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) != 0) { /* call emac routine for channel 0 */
+ /* clear EOB
+ mtdcr(malrxeobisr, mal_rx_eob); */
+ enet_rcv (emac_isr);
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ mtdcr (uic0sr, UIC_MRE); /* Clear */
+ mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+ } while (serviced);
+
+ return (rc);
+}
+#else /* CONFIG_440 */
+/*-----------------------------------------------------------------------------+
+ * EnetInt.
+ * EnetInt is the interrupt handler. It will determine the
+ * cause of the interrupt and call the apporpriate servive
+ * routine.
+ *-----------------------------------------------------------------------------*/
+int enetInt ()
+{
+ 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;
+
+ /* 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 (mal_isr, my_uicmsr, MAL_UIC_DEF, MAL_UIC_ERR);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if ((EMAC_UIC_DEF & my_uicmsr) != 0) { /* look for EMAC errors */
+ emac_isr = in32 (EMAC_ISR);
+ if ((emac_ier & emac_isr) != 0) {
+ emac_err (emac_isr);
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ if (((emac_ier & emac_isr) != 0) | ((MAL_UIC_ERR & my_uicmsr) != 0)) {
+ mtdcr (uicsr, MAL_UIC_DEF | EMAC_UIC_DEF); /* Clear */
+ return (rc); /* we had errors so get out */
+ }
+
+
+ /* handle MAL RX EOB interupt from a receive */
+ /* check for EOB on valid channels */
+ if ((my_uicmsr & UIC_MAL_RXEOB) != 0) {
+ mal_rx_eob = mfdcr (malrxeobisr);
+ if ((mal_rx_eob & 0x80000000) != 0) { /* call emac routine for channel 0 */
+ /* clear EOB
+ mtdcr(malrxeobisr, mal_rx_eob); */
+ enet_rcv (emac_isr);
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ mtdcr (uicsr, MAL_UIC_DEF | EMAC_UIC_DEF); /* Clear */
+ }
+ while (serviced);
+
+ return (rc);
+}
+#endif /* CONFIG_440 */
+
+/*-----------------------------------------------------------------------------+
+ * MAL Error Routine
+ *-----------------------------------------------------------------------------*/
+void mal_err (unsigned long isr, unsigned long uic, unsigned long maldef,
+ unsigned long mal_errr)
+{
+ mtdcr (malesr, isr); /* clear interrupt */
+
+ /* clear DE interrupt */
+ mtdcr (maltxdeir, 0xC0000000);
+ mtdcr (malrxdeir, 0x80000000);
+
+#if 1 /*sr */
+ printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n",
+ isr, uic, maldef, mal_errr);
+#else
+#if 0
+ /*
+ * MAL error is RX DE error (out of rx buffers)! This is OK here, upon
+ * many incoming packets with only 4 rx buffers.
+ */
+ printf ("M"); /* just to see something upon mal error */
+#endif
+#endif /*sr */
+
+ eth_init (bis_save); /* start again... */
+}
+
+/*-----------------------------------------------------------------------------+
+ * EMAC Error Routine
+ *-----------------------------------------------------------------------------*/
+void emac_err (unsigned long isr)
+{
+ printf ("EMAC error occured.... ISR = %lx\n", isr);
+ out32 (EMAC_ISR, isr);
+}
+
+/*-----------------------------------------------------------------------------+
+ * enet_rcv() handles the ethernet receive data
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (unsigned long malisr)
+{
+ struct enet_frame *ef_ptr;
+ unsigned long data_len;
+ unsigned long rx_eob_isr;
+
+ int handled = 0;
+ int i;
+ int loop_count = 0;
+
+ rx_eob_isr = mfdcr (malrxeobisr);
+ if ((0x80000000 >> (EMAC_RXCHL - 1)) & rx_eob_isr) {
+ /* clear EOB */
+ mtdcr (malrxeobisr, rx_eob_isr);
+
+ /* EMAC RX done */
+ while (1) { /* do all */
+ i = rx_slot;
+
+ if ((MAL_RX_CTRL_EMPTY & rx[i].ctrl)
+ || (loop_count >= NUM_RX_BUFF))
+ break;
+ loop_count++;
+ rx_slot++;
+ if (NUM_RX_BUFF == rx_slot)
+ rx_slot = 0;
+ handled++;
+ data_len = (unsigned long) 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 & rx[i].ctrl) { /* Check Errors */
+ data_len = 0;
+ stats.rx_err_log[rx_err_index] = rx[i].ctrl;
+ rx_err_index++;
+ if (rx_err_index == MAX_ERR_LOG)
+ rx_err_index = 0;
+ } /* emac_erros */
+ } /* data_len < max mtu */
+ } /* if data_len */
+ if (!data_len) { /* no data */
+ rx[i].ctrl |= MAL_RX_CTRL_EMPTY; /* Free Recv Buffer */
+
+ stats.emac.data_len_err++; /* Error at Rx */
+ }
+
+ /* !data_len */
+ /* AS.HARNOIS */
+ /* Check if user has already eaten buffer */
+ /* if not => ERROR */
+ else if (rx_ready[rx_i_index] != -1) {
+ if (is_receiving)
+ printf ("ERROR : Receive buffers are full!\n");
+ break;
+ } else {
+ stats.emac.rx_frames++;
+ stats.emac.rx += data_len;
+ ef_ptr = (struct enet_frame *) rx[i].data_ptr;
+#ifdef INFO_405_ENET
+ packetReceived++;
+#endif
+ /* AS.HARNOIS
+ * use ring buffer
+ */
+ rx_ready[rx_i_index] = i;
+ rx_i_index++;
+ if (NUM_RX_BUFF == rx_i_index)
+ rx_i_index = 0;
+
+ /* printf("X"); /|* test-only *|/ */
+
+ /* 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 */
+}
+
+
+int eth_rx (void)
+{
+ int length;
+ int user_index;
+ unsigned long msr;
+
+ is_receiving = 1; /* tell driver */
+
+ for (;;) {
+ /* AS.HARNOIS
+ * use ring buffer and
+ * get index from rx buffer desciptor queue
+ */
+ user_index = rx_ready[rx_u_index];
+ if (user_index == -1) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE));
+
+ length = 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 */
+ rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
+ /* Free rx buffer descriptor queue */
+ rx_ready[rx_u_index] = -1;
+ rx_u_index++;
+ if (NUM_RX_BUFF == rx_u_index)
+ rx_u_index = 0;
+
+#ifdef INFO_405_ENET
+ packetHandled++;
+#endif
+
+ mtmsr (msr); /* Enable IRQ's */
+ }
+
+ is_receiving = 0; /* tell driver */
+
+ return length;
+}
+
+#endif /* CONFIG_405GP */
diff --git a/cpu/ppc4xx/405gp_pci.c b/cpu/ppc4xx/405gp_pci.c
new file mode 100644
index 0000000..1c2c59b
--- /dev/null
+++ b/cpu/ppc4xx/405gp_pci.c
@@ -0,0 +1,502 @@
+/*-----------------------------------------------------------------------------+
+ *
+ * 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>
+#include <cmd_boot.h>
+#if !defined(CONFIG_440)
+#include <405gp_pci.h>
+#endif
+#include <asm/processor.h>
+#include <pci.h>
+
+#if defined(CONFIG_405GP)
+
+#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)
+ unsigned long ptmla[2] = {bd->bi_memstart, bd->bi_flashstart};
+ unsigned long ptmms[2] = {~(bd->bi_memsize - 1) | 1, ~(bd->bi_flashsize - 1) | 1};
+#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
+
+ /*
+ * 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]); /* ensure disabled b4 setting PMM0LA */
+ 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]); /* ensure disabled b4 setting PMM2LA */
+ 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]); /* ensure disabled b4 setting PMM2LA */
+ 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 */
+
+ /*--------------------------------------------------------------------------+
+ * 405GP PCI Target configuration. (PTM2)
+ *--------------------------------------------------------------------------*/
+ out32r(PTM2LA, ptmla[1]); /* insert address */
+ 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_HOSE == PCI_HOST_AUTO)
+ if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+#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
+
+ /*
+ * 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)
+#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)*/
+#if 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(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;
+ unsigned long strap;
+
+ /*--------------------------------------------------------------------------+
+ * The PCI initialization sequence enable bit must be set ... if not abort
+ * pci setup since updating the bit requires chip reset.
+ *--------------------------------------------------------------------------*/
+ strap = mfdcr(cpc0_strp1);
+ if( (strap & 0x00040000) == 0 ){
+ printf("PCI: CPC0_STRP1[PISE] not set.\n");
+ printf("PCI: Configuration aborted.\n");
+ return;
+ }
+
+ /*--------------------------------------------------------------------------+
+ * 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
+
+ out32r( PCIX0_BRDGOPT1, 0x10000060 ); /* PLB Rq pri highest */
+ out32r( PCIX0_BRDGOPT2, in32(PCIX0_BRDGOPT2) | 1 ); /* Enable host config */
+
+ /*--------------------------------------------------------------------------+
+ * 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
+ out16r( PCIX0_CMD, in16r( PCIX0_CMD ) | PCI_COMMAND_MASTER);
+ hose->last_busno = pci_hose_scan(hose);
+ }
+}
+
+
+void pci_init(void)
+{
+ pci_440_init (&ppc440_hose);
+}
+
+#endif /* CONFIG_440 & CONFIG_PCI */
diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c
new file mode 100644
index 0000000..8aaffb1
--- /dev/null
+++ b/cpu/ppc4xx/cpu.c
@@ -0,0 +1,253 @@
+/*
+ * (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
+ */
+
+/*
+ * m8xx.c
+ *
+ * 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)
+static int do_chip_reset( unsigned long sys0, unsigned long sys1 );
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+int checkcpu (void)
+{
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_IOP480) || defined(CONFIG_440)
+ uint pvr = get_pvr();
+#endif
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_IOP480)
+ DECLARE_GLOBAL_DATA_PTR;
+
+ ulong clock = gd->cpu_clk;
+ char buf[32];
+#endif
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
+ PPC405_SYS_INFO sys_info;
+
+ puts ("CPU: ");
+
+ get_sys_info(&sys_info);
+
+#if CONFIG_405GP
+ puts("IBM PowerPC 405GP");
+ if (pvr == PVR_405GPR_RA) {
+ putc('r');
+ }
+ puts(" Rev. ");
+#endif
+#if CONFIG_405CR
+ puts("IBM PowerPC 405CR Rev. ");
+#endif
+ switch (pvr) {
+ case PVR_405GP_RB:
+ putc('B');
+ break;
+ case PVR_405GP_RC:
+#if CONFIG_405CR
+ case PVR_405CR_RC:
+#endif
+ putc('C');
+ break;
+ case PVR_405GP_RD:
+ putc('D');
+ break;
+#if CONFIG_405GP
+ case PVR_405GP_RE:
+ putc('E');
+ break;
+#endif
+ case PVR_405CR_RA:
+ case PVR_405GPR_RA:
+ putc('A');
+ break;
+ case PVR_405CR_RB:
+ putc('B');
+ break;
+ default:
+ printf("? (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,
+ sys_info.freqPLB / sys_info.pllExtBusDiv / 1000000);
+
+#if CONFIG_405GP
+ if (mfdcr(strap) & PSR_PCI_ASYNC_EN)
+ printf(" PCI async ext clock used, ");
+ else
+ printf(" PCI sync clock at %lu MHz, ",
+ sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
+ if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+ printf("internal PCI arbiter enabled\n");
+ else
+ printf("external PCI arbiter enabled\n");
+#endif
+
+ if ((pvr | 0x00000001) == PVR_405GPR_RA) {
+ printf(" 16 kB I-Cache 16 kB D-Cache");
+ } else {
+ printf(" 16 kB I-Cache 8 kB D-Cache");
+ }
+
+
+#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
+
+#ifdef 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
+
+#if defined(CONFIG_440)
+ puts("IBM PowerPC 440 Rev. ");
+ switch(pvr)
+ {
+ case PVR_440GP_RB:
+ putc('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:
+ putc('C');
+ break;
+ default:
+ printf("UNKNOWN (PVR=%08x)", pvr);
+ break;
+ }
+#endif
+
+ printf("\n");
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+ /*
+ * 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
+ 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_440)
+
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ return (sys_info.freqProcessor);
+
+#elif defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405)
+
+ PPC405_SYS_INFO sys_info;
+
+ get_sys_info(&sys_info);
+ return (sys_info.freqProcessor);
+
+#elif defined(CONFIG_IOP480)
+
+ return (66000000);
+
+#else
+
+# error get_tbclk() not implemented
+
+#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/i2c.c b/cpu/ppc4xx/i2c.c
new file mode 100644
index 0000000..68af057
--- /dev/null
+++ b/cpu/ppc4xx/i2c.c
@@ -0,0 +1,417 @@
+/*****************************************************************************/
+/* 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;
+
+ /* Handle possible failed I2C state */
+ _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;
+
+ 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) {
+ 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);
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c
new file mode 100644
index 0000000..d64bf96
--- /dev/null
+++ b/cpu/ppc4xx/sdram.c
@@ -0,0 +1,191 @@
+/*
+ * (C) Copyright 2002
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+#include <pci.h>
+
+
+#ifdef CONFIG_SDRAM_BANK0
+
+
+#define MAGIC0 0x00000000
+#define MAGIC1 0x11111111
+#define MAGIC2 0x22222222
+#define MAGIC3 0x33333333
+#define MAGIC4 0x44444444
+
+#define ADDR_ZERO 0x00000000
+#define ADDR_400 0x00000400
+#define ADDR_08MB 0x00800000
+#define ADDR_16MB 0x01000000
+#define ADDR_32MB 0x02000000
+#define ADDR_64MB 0x04000000
+
+#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data)
+
+
+/*-----------------------------------------------------------------------
+ */
+void sdram_init(void)
+{
+ ulong speed;
+ ulong sdtr1;
+ ulong rtr;
+
+ /*
+ * Determine SDRAM speed
+ */
+ speed = get_bus_freq(0); /* parameter not used on ppc4xx */
+
+ /*
+ * Support for 100MHz and 133MHz SDRAM
+ */
+ if (speed > 100000000) {
+ /*
+ * 133 MHz SDRAM
+ */
+ sdtr1 = 0x01074015;
+ rtr = 0x07f00000;
+ } else {
+ /*
+ * default: 100 MHz SDRAM
+ */
+ sdtr1 = 0x0086400d;
+ rtr = 0x05f00000;
+ }
+
+ /*
+ * Set MB0CF for bank 0. (0-64MB) Address Mode 3 since 13x9(4)
+ */
+ mtsdram0(mem_mb0cf, 0x00084001);
+
+ mtsdram0(mem_sdtr1, sdtr1);
+ mtsdram0(mem_rtr, rtr);
+
+ /*
+ * Wait for 200us
+ */
+ 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);
+
+ /*
+ * Wait for 10ms
+ */
+ udelay(10000);
+
+ /*
+ * Test if 64 MByte are equipped (mirror test)
+ */
+ *(volatile ulong *)ADDR_ZERO = MAGIC0;
+ *(volatile ulong *)ADDR_08MB = MAGIC1;
+ *(volatile ulong *)ADDR_16MB = MAGIC2;
+ *(volatile ulong *)ADDR_32MB = MAGIC3;
+
+ if ((*(volatile ulong *)ADDR_ZERO == MAGIC0) &&
+ (*(volatile ulong *)ADDR_08MB == MAGIC1) &&
+ (*(volatile ulong *)ADDR_16MB == MAGIC2)) {
+ /*
+ * OK, 64MB detected -> all done
+ */
+ return;
+ }
+
+ /*
+ * Now test for 32 MByte...
+ */
+
+ /*
+ * Disable memory controller.
+ */
+ mtsdram0(mem_mcopt1, 0x00000000);
+
+ /*
+ * Set MB0CF for bank 0. (0-32MB) Address Mode 2 since 12x9(4)
+ */
+ mtsdram0(mem_mb0cf, 0x00062001);
+
+ /*
+ * 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);
+
+ /*
+ * Wait for 10ms
+ */
+ udelay(10000);
+
+ /*
+ * Test if 32 MByte are equipped (mirror test)
+ */
+ *(volatile ulong *)ADDR_ZERO = MAGIC0;
+ *(volatile ulong *)ADDR_400 = MAGIC1;
+ *(volatile ulong *)ADDR_08MB = MAGIC2;
+ *(volatile ulong *)ADDR_16MB = MAGIC3;
+
+ if ((*(volatile ulong *)ADDR_ZERO == MAGIC0) &&
+ (*(volatile ulong *)ADDR_400 == MAGIC1) &&
+ (*(volatile ulong *)ADDR_08MB == MAGIC2)) {
+ /*
+ * OK, 32MB detected -> all done
+ */
+ return;
+ }
+
+ /*
+ * Setup for 16 MByte...
+ */
+
+ /*
+ * Disable memory controller.
+ */
+ mtsdram0(mem_mcopt1, 0x00000000);
+
+ /*
+ * Set MB0CF for bank 0. (0-16MB) Address Mode 4 since 12x8(4)
+ */
+ mtsdram0(mem_mb0cf, 0x00046001);
+
+ /*
+ * 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);
+
+ /*
+ * Wait for 10ms
+ */
+ udelay(10000);
+}
+
+#endif /* CONFIG_SDRAM_BANK0 */
diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c
new file mode 100644
index 0000000..4541529
--- /dev/null
+++ b/cpu/ppc4xx/speed.c
@@ -0,0 +1,308 @@
+/*
+ * (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_RA & 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->freqVCOMhz = (1000000 * m) / sysClkPeriodPs;
+ sysInfo->freqProcessor = (sysInfo->freqVCOMhz * 1000000) / sysInfo->pllFwdDiv;
+ sysInfo->freqPLB = (sysInfo->freqVCOMhz * 1000000) /
+ (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->freqVCOMhz = ( 1000000 *
+ sysInfo->pllFwdDiv *
+ sysInfo->pllFbkDiv *
+ sysInfo->pllPlbDiv
+ ) / sysClkPeriodPs;
+ if (sysInfo->freqVCOMhz >= VCO_MIN
+ && sysInfo->freqVCOMhz <= VCO_MAX) {
+ sysInfo->freqPLB = (ONE_BILLION /
+ ((sysClkPeriodPs * 10) /
+ sysInfo->pllFbkDiv)) * 10000;
+ sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
+ } else {
+ printf ("\nInvalid VCO frequency calculated : %ld MHz \a\n",
+ sysInfo->freqVCOMhz);
+ printf ("It must be between %d-%d MHz \a\n",
+ VCO_MIN, VCO_MAX);
+ printf ("PLL Mode reg : %8.8lx\a\n",
+ pllmr);
+ hang ();
+ }
+ }
+ }
+}
+
+
+/********************************************
+ * 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)
+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;
+
+}
+
+ulong get_OPB_freq (void)
+{
+
+ sys_info_t sys_info;
+ get_sys_info (&sys_info);
+ return sys_info.freqOPB;
+}
+
+#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;
+
+}
+
+#endif
+
+int get_clocks (void)
+{
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405)
+ 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)
+ 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/vecnum.h b/cpu/ppc4xx/vecnum.h
new file mode 100644
index 0000000..d493a5d
--- /dev/null
+++ b/cpu/ppc4xx/vecnum.h
@@ -0,0 +1,100 @@
+/*
+* 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_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_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_ */