[PATCH] PPC4xx: Add support for multiple I2C busses

This patch adds support for multiple I2C busses on the PPC4xx
platforms. Define CONFIG_I2C_MULTI_BUS in the board config file
to make use of this feature.

It also merges the 405 and 440 i2c header files into one common
file 4xx_i2c.h.

Also the 4xx i2c reset procedure is reworked since I experienced
some problems with the first access on the 440SPe Katmai board.

Signed-off-by: Stefan Roese <sr@denx.de>
diff --git a/board/cray/L1/L1.c b/board/cray/L1/L1.c
index a7114eb..a0fac7f 100644
--- a/board/cray/L1/L1.c
+++ b/board/cray/L1/L1.c
@@ -23,7 +23,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
-#include <405gp_i2c.h>
+#include <4xx_i2c.h>
 #include <command.h>
 #include <rtc.h>
 #include <post.h>
diff --git a/board/esd/du405/du405.c b/board/esd/du405/du405.c
index a019ce4..6943213 100644
--- a/board/esd/du405/du405.c
+++ b/board/esd/du405/du405.c
@@ -25,7 +25,7 @@
 #include "du405.h"
 #include <asm/processor.h>
 #include <ppc4xx.h>
-#include <405gp_i2c.h>
+#include <4xx_i2c.h>
 #include <command.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/board/mpl/common/memtst.c b/board/mpl/common/memtst.c
index ff1190a..1d28513 100644
--- a/board/mpl/common/memtst.c
+++ b/board/mpl/common/memtst.c
@@ -48,7 +48,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
-#include <405gp_i2c.h>
+#include <4xx_i2c.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
diff --git a/board/mpl/mip405/mip405.c b/board/mpl/mip405/mip405.c
index 34f3289..4dbf492 100644
--- a/board/mpl/mip405/mip405.c
+++ b/board/mpl/mip405/mip405.c
@@ -65,7 +65,7 @@
 #include <common.h>
 #include "mip405.h"
 #include <asm/processor.h>
-#include <405gp_i2c.h>
+#include <4xx_i2c.h>
 #include <miiphy.h>
 #include "../common/common_util.h"
 #include <i2c.h>
diff --git a/board/sandburst/common/ppc440gx_i2c.c b/board/sandburst/common/ppc440gx_i2c.c
index 859dd7a..1e3dffb 100644
--- a/board/sandburst/common/ppc440gx_i2c.c
+++ b/board/sandburst/common/ppc440gx_i2c.c
@@ -27,13 +27,8 @@
  */
 #include <common.h>
 #include <ppc4xx.h>
-#if defined(CONFIG_440)
-#   include <440_i2c.h>
-#else
-#   include <405gp_i2c.h>
-#endif
+#include <4xx_i2c.h>
 #include <i2c.h>
-#include <440_i2c.h>
 #include <command.h>
 #include "ppc440gx_i2c.h"
 
diff --git a/board/sandburst/common/ppc440gx_i2c.h b/board/sandburst/common/ppc440gx_i2c.h
index cd4fc86..10000f5 100644
--- a/board/sandburst/common/ppc440gx_i2c.h
+++ b/board/sandburst/common/ppc440gx_i2c.h
@@ -27,11 +27,7 @@
  */
 #include <common.h>
 #include <ppc4xx.h>
-#if defined(CONFIG_440)
-#   include <440_i2c.h>
-#else
-#   include <405gp_i2c.h>
-#endif
+#include <4xx_i2c.h>
 #include <i2c.h>
 
 #ifdef CONFIG_HARD_I2C
diff --git a/cpu/ppc4xx/i2c.c b/cpu/ppc4xx/i2c.c
index 7db1cd8..0b056a1 100644
--- a/cpu/ppc4xx/i2c.c
+++ b/cpu/ppc4xx/i2c.c
@@ -1,91 +1,100 @@
-/*****************************************************************************/
-/* I2C Bus interface initialisation and I2C Commands                         */
-/* for PPC405GP		                                                     */
-/* Author : AS HARNOIS                                                       */
-/* Date   : 13.Dec.00                                                        */
-/*****************************************************************************/
+/*
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * based on work by Anne Sophie Harnois <anne-sophie.harnois@nextream.fr>
+ *
+ * (C) Copyright 2001
+ * Bill Hunter,  Wave 7 Optics, williamhunter@mediaone.net
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
 
 #include <common.h>
 #include <ppc4xx.h>
-#if defined(CONFIG_440)
-#   include <440_i2c.h>
-#else
-#   include <405gp_i2c.h>
-#endif
+#include <4xx_i2c.h>
 #include <i2c.h>
+#include <asm-ppc/io.h>
 
 #ifdef CONFIG_HARD_I2C
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#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 */
+#if defined(CONFIG_I2C_MULTI_BUS)
+/* Initialize the bus pointer to whatever one the SPD EEPROM is on.
+ * Default is bus 0.  This is necessary because the DDR initialization
+ * runs from ROM, and we can't switch buses because we can't modify
+ * the global variables.
+ */
+#ifdef CFG_SPD_BUS_NUM
+static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS_NUM;
+#else
+static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0;
+#endif
+#endif /* CONFIG_I2C_MULTI_BUS */
 
-#define IIC_TIMEOUT 1			/* 1 seconde */
-
-
-static void _i2c_bus_reset (void)
+static void _i2c_bus_reset(void)
 {
-	int i, status;
+	int i;
+	u8 dc;
 
 	/* Reset status register */
 	/* write 1 in SCMP and IRQA to clear these fields */
-	out8 (IIC_STS, 0x0A);
+	out_8((u8 *)IIC_STS, 0x0A);
 
 	/* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
-	out8 (IIC_EXTSTS, 0x8F);
-	__asm__ volatile ("eieio");
+	out_8((u8 *)IIC_EXTSTS, 0x8F);
 
-	/*
-	 * 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");
+    	/* Place chip in the reset state */
+	out_8((u8 *)IIC_XTCNTLSS, IIC_XTCNTLSS_SRST);
 
-	/* 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;
+	/* Check if bus is free */
+	dc = in_8((u8 *)IIC_DIRECTCNTL);
+	if (!DIRCTNL_FREE(dc)){
+		/* Try to set bus free state */
+		out_8((u8 *)IIC_DIRECTCNTL, IIC_DIRCNTL_SDAC | IIC_DIRCNTL_SCC);
+
+		/* Wait until we regain bus control */
+		for (i = 0; i < 100; ++i) {
+			dc = in_8((u8 *)IIC_DIRECTCNTL);
+			if (DIRCTNL_FREE(dc))
+				break;
+
+			/* Toggle SCL line */
+			dc ^= IIC_DIRCNTL_SCC;
+			out_8((u8 *)IIC_DIRECTCNTL, dc);
+			udelay(10);
+			dc ^= IIC_DIRCNTL_SCC;
+			out_8((u8 *)IIC_DIRECTCNTL, dc);
 		}
 	}
-	/* 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 */
+
+	/* Remove reset */
+	out_8((u8 *)IIC_XTCNTLSS, 0);
 }
 
-void i2c_init (int speed, int slaveadd)
+void i2c_init(int speed, int slaveadd)
 {
 	sys_info_t sysInfo;
 	unsigned long freqOPB;
 	int val, divisor;
+	int bus;
 
 #ifdef CFG_I2C_INIT_BOARD
 	/* call board specific i2c bus reset routine before accessing the   */
@@ -94,101 +103,100 @@
 	i2c_init_board();
 #endif
 
-	/* Handle possible failed I2C state */
-	/* FIXME: put this into i2c_init_board()? */
-	_i2c_bus_reset ();
+	for (bus = 0; bus < CFG_MAX_I2C_BUS; bus++) {
+		I2C_SET_BUS(bus);
 
-	/* clear lo master address */
-	out8 (IIC_LMADR, 0);
+		/* Handle possible failed I2C state */
+		/* FIXME: put this into i2c_init_board()? */
+		_i2c_bus_reset();
 
-	/* clear hi master address */
-	out8 (IIC_HMADR, 0);
+		/* clear lo master address */
+		out_8((u8 *)IIC_LMADR, 0);
 
-	/* clear lo slave address */
-	out8 (IIC_LSADR, 0);
+		/* clear hi master address */
+		out_8((u8 *)IIC_HMADR, 0);
 
-	/* clear hi slave address */
-	out8 (IIC_HSADR, 0);
+		/* clear lo slave address */
+		out_8((u8 *)IIC_LSADR, 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);
+		/* clear hi slave address */
+		out_8((u8 *)IIC_HSADR, 0);
 
-	/* no interrupts */
-	out8 (IIC_INTRMSK, 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;
+		out_8((u8 *)IIC_CLKDIV, divisor);
 
-	/* clear transfer count */
-	out8 (IIC_XFRCNT, 0);
+		/* no interrupts */
+		out_8((u8 *)IIC_INTRMSK, 0);
 
-	/* clear extended control & stat */
-	/* write 1 in SRC SRS SWC SWS to clear these fields */
-	out8 (IIC_XTCNTLSS, 0xF0);
+		/* clear transfer count */
+		out_8((u8 *)IIC_XFRCNT, 0);
 
-	/* Mode Control Register
-	   Flush Slave/Master data buffer */
-	out8 (IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
-	__asm__ volatile ("eieio");
+		/* clear extended control & stat */
+		/* write 1 in SRC SRS SWC SWS to clear these fields */
+		out_8((u8 *)IIC_XTCNTLSS, 0xF0);
 
+		/* Mode Control Register
+		   Flush Slave/Master data buffer */
+		out_8((u8 *)IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
 
-	val = in8(IIC_MDCNTL);
-	__asm__ volatile ("eieio");
+		val = in_8((u8 *)IIC_MDCNTL);
 
-	/* Ignore General Call, slave transfers are ignored,
-	   disable interrupts, exit unknown bus state, enable hold
-	   SCL
-	   100kHz normaly or FastMode for 400kHz and above
-	*/
+		/* 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;
+		val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL;
+		if (speed >= 400000)
+			val |= IIC_MDCNTL_FSM;
+		out_8((u8 *)IIC_MDCNTL, val);
+
+		/* clear control reg */
+		out_8((u8 *)IIC_CNTL, 0x00);
 	}
-	out8 (IIC_MDCNTL, val);
 
-	/* clear control reg */
-	out8 (IIC_CNTL, 0x00);
-	__asm__ volatile ("eieio");
-
+	/* set to SPD bus as default bus upon powerup */
+	I2C_SET_BUS(CFG_SPD_BUS_NUM);
 }
 
 /*
-  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 )
+ * 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 out_8((u8 *)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;
@@ -198,97 +206,88 @@
 	int i;
 	uchar creg;
 
-	if( data == 0 || data_len == 0 ){
-		/*Don't support data transfer of no length or to address 0*/
+	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 ){
+	if (addr && addr_len) {
 		ptr = addr;
 		cnt = addr_len;
 		reading = 0;
-	}else{
+	} else {
 		ptr = data;
 		cnt = data_len;
 		reading = cmd_type;
 	}
 
-	/*Clear Stop Complete Bit*/
-	out8(IIC_STS,IIC_STS_SCMP);
+	/* Clear Stop Complete Bit */
+	out_8((u8 *)IIC_STS, IIC_STS_SCMP);
 	/* Check init */
-	i=10;
+	i = 10;
 	do {
 		/* Get status */
-		status = in8(IIC_STS);
-		__asm__ volatile("eieio");
+		status = in_8((u8 *)IIC_STS);
 		i--;
-	} while ((status & IIC_STS_PT) && (i>0));
+	} 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*/
+	/* flush the Master/Slave Databuffers */
+	out_8((u8 *)IIC_MDCNTL, ((in_8((u8 *)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");
+	out_8((u8 *)IIC_HMADR, 0);
+	out_8((u8 *)IIC_LMADR, chip);
 
 	tran = 0;
 	result = IIC_OK;
 	creg = 0;
 
-	while ( tran != cnt && (result == IIC_OK)) {
+	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
-		*/
+		 * 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) )
+		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++) {
+		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");
+				out_8((u8 *)IIC_MDBUF, ptr[tran+j]);
+		out_8((u8 *)IIC_CNTL, creg);
 
 		/* 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;
+		 * 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);
+			status = in_8((u8 *)IIC_STS);
+			udelay(10);
 			i--;
-		} while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR)
-			 && (i>0));
+		} while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) && (i > 0));
 
 		if (status & IIC_STS_ERR) {
 			result = IIC_NOK;
-			status = in8 (IIC_EXTSTS);
+			status = in_8((u8 *)IIC_EXTSTS);
 			/* Lost arbitration? */
 			if (status & IIC_EXTSTS_LA)
 				result = IIC_NOK_LA;
@@ -306,34 +305,32 @@
 			/* 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");
-				}
+				 * 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] = in_8((u8 *)IIC_MDBUF);
 			} else
 				result = IIC_NOK_DATA;
 		}
 		creg = 0;
-		tran+=bc;
-		if( ptr == addr && tran == cnt ) {
+		tran += bc;
+		if (ptr == addr && tran == cnt) {
 			ptr = data;
 			cnt = data_len;
 			tran = 0;
 			reading = cmd_type;
-			if( reading )
+			if (reading)
 				creg = IIC_CNTL_RPST;
 		}
 	}
 	return (result);
 }
 
-int i2c_probe (uchar chip)
+int i2c_probe(uchar chip)
 {
 	uchar buf[1];
 
@@ -344,21 +341,21 @@
 	 * 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);
+	return (i2c_transfer(1, chip << 1, 0,0, buf, 1) != 0);
 }
 
 
-int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
+int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len)
 {
 	uchar xaddr[4];
 	int ret;
 
-	if ( alen > 4 ) {
+	if (alen > 4) {
 		printf ("I2C read: addr len %d not supported\n", alen);
 		return 1;
 	}
 
-	if ( alen > 0 ) {
+	if (alen > 0) {
 		xaddr[0] = (addr >> 24) & 0xFF;
 		xaddr[1] = (addr >> 16) & 0xFF;
 		xaddr[2] = (addr >> 8) & 0xFF;
@@ -378,10 +375,10 @@
 	 * still be one byte because the extra address bits are
 	 * hidden in the chip address.
 	 */
-	if( alen > 0 )
+	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 ((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;
@@ -389,16 +386,17 @@
 	return 0;
 }
 
-int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
+int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len)
 {
 	uchar xaddr[4];
 
-	if ( alen > 4 ) {
+	if (alen > 4) {
 		printf ("I2C write: addr len %d not supported\n", alen);
 		return 1;
 
 	}
-	if ( alen > 0 ) {
+
+	if (alen > 0) {
 		xaddr[0] = (addr >> 24) & 0xFF;
 		xaddr[1] = (addr >> 16) & 0xFF;
 		xaddr[2] = (addr >> 8) & 0xFF;
@@ -417,11 +415,11 @@
 	 * still be one byte because the extra address bits are
 	 * hidden in the chip address.
 	 */
-	if( alen > 0 )
+	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);
+	return (i2c_transfer(0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0);
 }
 
 /*-----------------------------------------------------------------------
@@ -433,7 +431,7 @@
 
 	i2c_read(i2c_addr, reg, 1, &buf, 1);
 
-	return(buf);
+	return (buf);
 }
 
 /*-----------------------------------------------------------------------
@@ -443,4 +441,38 @@
 {
 	i2c_write(i2c_addr, reg, 1, &val, 1);
 }
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+/*
+ * Functions for multiple I2C bus handling
+ */
+unsigned int i2c_get_bus_num(void)
+{
+	return i2c_bus_num;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+	if (bus >= CFG_MAX_I2C_BUS)
+		return -1;
+
+	i2c_bus_num = bus;
+
+	return 0;
+}
+
+/* TODO: add 100/400k switching */
+unsigned int i2c_get_bus_speed(void)
+{
+	return CFG_I2C_SPEED;
+}
+
+int i2c_set_bus_speed(unsigned int speed)
+{
+	if (speed != CFG_I2C_SPEED)
+		return -1;
+
+	return 0;
+}
+#endif	/* CONFIG_I2C_MULTI_BUS */
 #endif	/* CONFIG_HARD_I2C */
diff --git a/include/405gp_i2c.h b/include/405gp_i2c.h
deleted file mode 100644
index 5a9a497..0000000
--- a/include/405gp_i2c.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef _405gp_i2c_h_
-#define _405gp_i2c_h_
-
-#define	   I2C_REGISTERS_BASE_ADDRESS 0xEF600500
-#define    IIC_MDBUF	(I2C_REGISTERS_BASE_ADDRESS+IICMDBUF)
-#define    IIC_SDBUF	(I2C_REGISTERS_BASE_ADDRESS+IICSDBUF)
-#define    IIC_LMADR	(I2C_REGISTERS_BASE_ADDRESS+IICLMADR)
-#define    IIC_HMADR	(I2C_REGISTERS_BASE_ADDRESS+IICHMADR)
-#define    IIC_CNTL	(I2C_REGISTERS_BASE_ADDRESS+IICCNTL)
-#define    IIC_MDCNTL	(I2C_REGISTERS_BASE_ADDRESS+IICMDCNTL)
-#define    IIC_STS	(I2C_REGISTERS_BASE_ADDRESS+IICSTS)
-#define    IIC_EXTSTS	(I2C_REGISTERS_BASE_ADDRESS+IICEXTSTS)
-#define    IIC_LSADR	(I2C_REGISTERS_BASE_ADDRESS+IICLSADR)
-#define    IIC_HSADR	(I2C_REGISTERS_BASE_ADDRESS+IICHSADR)
-#define    IIC_CLKDIV	(I2C_REGISTERS_BASE_ADDRESS+IICCLKDIV)
-#define    IIC_INTRMSK	(I2C_REGISTERS_BASE_ADDRESS+IICINTRMSK)
-#define    IIC_XFRCNT	(I2C_REGISTERS_BASE_ADDRESS+IICXFRCNT)
-#define    IIC_XTCNTLSS	(I2C_REGISTERS_BASE_ADDRESS+IICXTCNTLSS)
-#define    IIC_DIRECTCNTL (I2C_REGISTERS_BASE_ADDRESS+IICDIRECTCNTL)
-
-/* MDCNTL Register Bit definition */
-#define    IIC_MDCNTL_HSCL 0x01
-#define    IIC_MDCNTL_EUBS 0x02
-#define    IIC_MDCNTL_EINT 0x04
-#define    IIC_MDCNTL_ESM  0x08
-#define    IIC_MDCNTL_FSM  0x10
-#define    IIC_MDCNTL_EGC  0x20
-#define    IIC_MDCNTL_FMDB 0x40
-#define    IIC_MDCNTL_FSDB 0x80
-
-/* CNTL Register Bit definition */
-#define    IIC_CNTL_PT     0x01
-#define    IIC_CNTL_READ   0x02
-#define    IIC_CNTL_CHT    0x04
-#define    IIC_CNTL_RPST   0x08
-/* bit 2/3 for Transfer count*/
-#define    IIC_CNTL_AMD    0x40
-#define    IIC_CNTL_HMT    0x80
-
-/* STS Register Bit definition */
-#define    IIC_STS_PT	   0X01
-#define    IIC_STS_IRQA    0x02
-#define    IIC_STS_ERR	   0X04
-#define    IIC_STS_SCMP    0x08
-#define    IIC_STS_MDBF    0x10
-#define    IIC_STS_MDBS    0X20
-#define    IIC_STS_SLPR    0x40
-#define    IIC_STS_SSS     0x80
-
-/* EXTSTS Register Bit definition */
-#define    IIC_EXTSTS_XFRA 0X01
-#define    IIC_EXTSTS_ICT  0X02
-#define    IIC_EXTSTS_LA   0X04
-
-/* XTCNTLSS Register Bit definition */
-#define    IIC_XTCNTLSS_SRST  0x01
-#define    IIC_XTCNTLSS_EPI   0x02
-#define    IIC_XTCNTLSS_SDBF  0x04
-#define    IIC_XTCNTLSS_SBDD  0x08
-#define    IIC_XTCNTLSS_SWS   0x10
-#define    IIC_XTCNTLSS_SWC   0x20
-#define    IIC_XTCNTLSS_SRS   0x40
-#define    IIC_XTCNTLSS_SRC   0x80
-#endif
diff --git a/include/440_i2c.h b/include/440_i2c.h
deleted file mode 100644
index 0c2bf36..0000000
--- a/include/440_i2c.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef _440_i2c_h_
-#define _440_i2c_h_
-
-#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
-    defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
-#define    I2C_BASE_ADDR (CFG_PERIPHERAL_BASE + 0x00000700)
-#else
-#define    I2C_BASE_ADDR (CFG_PERIPHERAL_BASE + 0x00000400)
-#endif /*CONFIG_440EP CONFIG_440GR*/
-
-#define	   I2C_REGISTERS_BASE_ADDRESS I2C_BASE_ADDR
-#define    IIC_MDBUF	(I2C_REGISTERS_BASE_ADDRESS+IICMDBUF)
-#define    IIC_SDBUF	(I2C_REGISTERS_BASE_ADDRESS+IICSDBUF)
-#define    IIC_LMADR	(I2C_REGISTERS_BASE_ADDRESS+IICLMADR)
-#define    IIC_HMADR	(I2C_REGISTERS_BASE_ADDRESS+IICHMADR)
-#define    IIC_CNTL	(I2C_REGISTERS_BASE_ADDRESS+IICCNTL)
-#define    IIC_MDCNTL	(I2C_REGISTERS_BASE_ADDRESS+IICMDCNTL)
-#define    IIC_STS	(I2C_REGISTERS_BASE_ADDRESS+IICSTS)
-#define    IIC_EXTSTS	(I2C_REGISTERS_BASE_ADDRESS+IICEXTSTS)
-#define    IIC_LSADR	(I2C_REGISTERS_BASE_ADDRESS+IICLSADR)
-#define    IIC_HSADR	(I2C_REGISTERS_BASE_ADDRESS+IICHSADR)
-#define    IIC_CLKDIV	(I2C_REGISTERS_BASE_ADDRESS+IICCLKDIV)
-#define    IIC_INTRMSK	(I2C_REGISTERS_BASE_ADDRESS+IICINTRMSK)
-#define    IIC_XFRCNT	(I2C_REGISTERS_BASE_ADDRESS+IICXFRCNT)
-#define    IIC_XTCNTLSS	(I2C_REGISTERS_BASE_ADDRESS+IICXTCNTLSS)
-#define    IIC_DIRECTCNTL (I2C_REGISTERS_BASE_ADDRESS+IICDIRECTCNTL)
-
-/* MDCNTL Register Bit definition */
-#define    IIC_MDCNTL_HSCL 0x01
-#define    IIC_MDCNTL_EUBS 0x02
-#define    IIC_MDCNTL_EINT 0x04
-#define    IIC_MDCNTL_ESM  0x08
-#define    IIC_MDCNTL_FSM  0x10
-#define    IIC_MDCNTL_EGC  0x20
-#define    IIC_MDCNTL_FMDB 0x40
-#define    IIC_MDCNTL_FSDB 0x80
-
-/* CNTL Register Bit definition */
-#define    IIC_CNTL_PT     0x01
-#define    IIC_CNTL_READ   0x02
-#define    IIC_CNTL_CHT    0x04
-#define    IIC_CNTL_RPST   0x08
-/* bit 2/3 for Transfer count*/
-#define    IIC_CNTL_AMD    0x40
-#define    IIC_CNTL_HMT    0x80
-
-/* STS Register Bit definition */
-#define    IIC_STS_PT	   0X01
-#define    IIC_STS_IRQA    0x02
-#define    IIC_STS_ERR	   0X04
-#define    IIC_STS_SCMP    0x08
-#define    IIC_STS_MDBF    0x10
-#define    IIC_STS_MDBS    0X20
-#define    IIC_STS_SLPR    0x40
-#define    IIC_STS_SSS     0x80
-
-/* EXTSTS Register Bit definition */
-#define    IIC_EXTSTS_XFRA 0X01
-#define    IIC_EXTSTS_ICT  0X02
-#define    IIC_EXTSTS_LA   0X04
-
-/* XTCNTLSS Register Bit definition */
-#define    IIC_XTCNTLSS_SRST  0x01
-#define    IIC_XTCNTLSS_EPI   0x02
-#define    IIC_XTCNTLSS_SDBF  0x04
-#define    IIC_XTCNTLSS_SBDD  0x08
-#define    IIC_XTCNTLSS_SWS   0x10
-#define    IIC_XTCNTLSS_SWC   0x20
-#define    IIC_XTCNTLSS_SRS   0x40
-#define    IIC_XTCNTLSS_SRC   0x80
-#endif
diff --git a/include/4xx_i2c.h b/include/4xx_i2c.h
new file mode 100644
index 0000000..66b7997
--- /dev/null
+++ b/include/4xx_i2c.h
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2007
+ * 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
+ */
+
+#ifndef _4xx_i2c_h_
+#define _4xx_i2c_h_
+
+#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 second */
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+#define I2C_BUS_OFFS	(i2c_bus_num * 0x100)
+#else
+#define I2C_BUS_OFFS	(0x000)
+#endif /* CONFIG_I2C_MULTI_BUS */
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+#define I2C_BASE_ADDR	(CFG_PERIPHERAL_BASE + 0x00000700 + I2C_BUS_OFFS)
+#elif defined(CONFIG_440)
+/* all remaining 440 variants */
+#define I2C_BASE_ADDR	(CFG_PERIPHERAL_BASE + 0x00000400 + I2C_BUS_OFFS)
+#else
+/* all 405 variants */
+#define I2C_BASE_ADDR	(0xEF600500 + I2C_BUS_OFFS)
+#endif
+
+#define I2C_REGISTERS_BASE_ADDRESS I2C_BASE_ADDR
+#define IIC_MDBUF	(I2C_REGISTERS_BASE_ADDRESS+IICMDBUF)
+#define IIC_SDBUF	(I2C_REGISTERS_BASE_ADDRESS+IICSDBUF)
+#define IIC_LMADR	(I2C_REGISTERS_BASE_ADDRESS+IICLMADR)
+#define IIC_HMADR	(I2C_REGISTERS_BASE_ADDRESS+IICHMADR)
+#define IIC_CNTL	(I2C_REGISTERS_BASE_ADDRESS+IICCNTL)
+#define IIC_MDCNTL	(I2C_REGISTERS_BASE_ADDRESS+IICMDCNTL)
+#define IIC_STS		(I2C_REGISTERS_BASE_ADDRESS+IICSTS)
+#define IIC_EXTSTS	(I2C_REGISTERS_BASE_ADDRESS+IICEXTSTS)
+#define IIC_LSADR	(I2C_REGISTERS_BASE_ADDRESS+IICLSADR)
+#define IIC_HSADR	(I2C_REGISTERS_BASE_ADDRESS+IICHSADR)
+#define IIC_CLKDIV	(I2C_REGISTERS_BASE_ADDRESS+IICCLKDIV)
+#define IIC_INTRMSK	(I2C_REGISTERS_BASE_ADDRESS+IICINTRMSK)
+#define IIC_XFRCNT	(I2C_REGISTERS_BASE_ADDRESS+IICXFRCNT)
+#define IIC_XTCNTLSS	(I2C_REGISTERS_BASE_ADDRESS+IICXTCNTLSS)
+#define IIC_DIRECTCNTL	(I2C_REGISTERS_BASE_ADDRESS+IICDIRECTCNTL)
+
+/* MDCNTL Register Bit definition */
+#define IIC_MDCNTL_HSCL		0x01
+#define IIC_MDCNTL_EUBS		0x02
+#define IIC_MDCNTL_EINT		0x04
+#define IIC_MDCNTL_ESM		0x08
+#define IIC_MDCNTL_FSM		0x10
+#define IIC_MDCNTL_EGC		0x20
+#define IIC_MDCNTL_FMDB		0x40
+#define IIC_MDCNTL_FSDB		0x80
+
+/* CNTL Register Bit definition */
+#define IIC_CNTL_PT		0x01
+#define IIC_CNTL_READ		0x02
+#define IIC_CNTL_CHT		0x04
+#define IIC_CNTL_RPST		0x08
+/* bit 2/3 for Transfer count*/
+#define IIC_CNTL_AMD		0x40
+#define IIC_CNTL_HMT		0x80
+
+/* STS Register Bit definition */
+#define IIC_STS_PT		0x01
+#define IIC_STS_IRQA		0x02
+#define IIC_STS_ERR		0x04
+#define IIC_STS_SCMP		0x08
+#define IIC_STS_MDBF		0x10
+#define IIC_STS_MDBS		0x20
+#define IIC_STS_SLPR		0x40
+#define IIC_STS_SSS		0x80
+
+/* EXTSTS Register Bit definition */
+#define IIC_EXTSTS_XFRA		0x01
+#define IIC_EXTSTS_ICT		0x02
+#define IIC_EXTSTS_LA		0x04
+
+/* XTCNTLSS Register Bit definition */
+#define IIC_XTCNTLSS_SRST	0x01
+#define IIC_XTCNTLSS_EPI	0x02
+#define IIC_XTCNTLSS_SDBF	0x04
+#define IIC_XTCNTLSS_SBDD	0x08
+#define IIC_XTCNTLSS_SWS	0x10
+#define IIC_XTCNTLSS_SWC	0x20
+#define IIC_XTCNTLSS_SRS	0x40
+#define IIC_XTCNTLSS_SRC	0x80
+
+/* IICx_DIRECTCNTL register */
+#define IIC_DIRCNTL_SDAC	0x08
+#define IIC_DIRCNTL_SCC		0x04
+#define IIC_DIRCNTL_MSDA	0x02
+#define IIC_DIRCNTL_MSC		0x01
+
+#define DIRCTNL_FREE(v)		(((v) & 0x0f) == 0x0f)
+#endif
diff --git a/include/i2c.h b/include/i2c.h
index a8f729a..54c6f9f 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -46,6 +46,16 @@
  */
 #define I2C_RXTX_LEN	128	/* maximum tx/rx buffer length */
 
+#if defined(CONFIG_I2C_MULTI_BUS)
+#define CFG_MAX_I2C_BUS		2
+#define I2C_GET_BUS()		i2c_get_bus_num()
+#define I2C_SET_BUS(a)		i2c_set_bus_num(a)
+#else
+#define CFG_MAX_I2C_BUS		1
+#define I2C_GET_BUS()		0
+#define I2C_SET_BUS(a)
+#endif
+
 /*
  * Initialization, must be called once on start up, may be called
  * repeatedly to change the speed and slave addresses.