summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMichael Brandt <Michael.Brandt@stericsson.com>2009-12-22 15:06:09 +0100
committerMichael Brandt <Michael.Brandt@stericsson.com>2009-12-22 15:06:09 +0100
commit257e7c347fd32438604da5e7996b902688d9611b (patch)
tree74fe0aa3fcaad4c9a3bd1c3dfc172531400cdd45 /drivers
parent0c9ff2faf4cf516dd6631ba18a4bcc5b739eb4c6 (diff)
parent87d93a1ba2ae23550e1370adb7a3b00af0831165 (diff)
Merge branch 'master' of http://git.denx.de/u-boot
Conflicts: include/usb/musb_udc.h
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bios_emulator/Makefile1
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/bfin-twi_i2c.c74
-rw-r--r--drivers/i2c/omap24xx_i2c.c166
-rw-r--r--drivers/i2c/pca9564_i2c.c189
-rw-r--r--drivers/i2c/s3c24x0_i2c.c6
-rw-r--r--drivers/i2c/soft_i2c.c5
-rw-r--r--drivers/mmc/omap3_mmc.c2
-rw-r--r--drivers/mtd/nand/davinci_nand.c23
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c4
-rw-r--r--drivers/mtd/nand/nand_base.c147
-rw-r--r--drivers/mtd/nand/nand_bbt.c41
-rw-r--r--drivers/mtd/nand/nand_util.c8
-rw-r--r--drivers/mtd/nand/s3c2410_nand.c33
-rw-r--r--drivers/mtd/nand/s3c64xx.c2
-rw-r--r--drivers/mtd/onenand/onenand_base.c742
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c14
-rw-r--r--drivers/mtd/onenand/onenand_uboot.c4
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/dm9000x.c2
-rw-r--r--drivers/net/e1000.c1
-rw-r--r--drivers/net/fec_mxc.c1
-rw-r--r--drivers/net/lan91c96.c452
-rw-r--r--drivers/net/lan91c96.h110
-rw-r--r--drivers/rtc/ftrtc010.c52
-rw-r--r--drivers/rtc/m41t94.c1
-rw-r--r--drivers/rtc/s3c24x0_rtc.c6
-rw-r--r--drivers/serial/s3c64xx.c2
-rw-r--r--drivers/serial/serial_s3c24x0.c6
-rw-r--r--drivers/serial/serial_s5pc1xx.c24
-rw-r--r--drivers/serial/usbtty.h2
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c3
-rw-r--r--drivers/usb/host/s3c64xx-hcd.c2
-rw-r--r--drivers/usb/musb/Makefile2
-rw-r--r--drivers/usb/musb/musb_core.c8
-rw-r--r--drivers/usb/musb/musb_core.h40
-rw-r--r--drivers/usb/musb/musb_debug.h205
-rw-r--r--drivers/usb/musb/musb_hcd.c2
-rw-r--r--drivers/usb/musb/musb_udc.c963
-rw-r--r--drivers/usb/musb/omap3.c134
-rw-r--r--drivers/usb/musb/omap3.h48
-rw-r--r--drivers/usb/phy/Makefile44
-rw-r--r--drivers/usb/phy/twl4030.c189
-rw-r--r--drivers/video/cfb_console.c6
-rw-r--r--drivers/video/mb862xx.c50
46 files changed, 3187 insertions, 634 deletions
diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile
index dd9c102ba..feba4da75 100644
--- a/drivers/bios_emulator/Makefile
+++ b/drivers/bios_emulator/Makefile
@@ -23,6 +23,7 @@ EXTRA_CFLAGS += -I. -I./include -I$(TOPDIR)/include \
CFLAGS += $(EXTRA_CFLAGS)
HOSTCFLAGS += $(EXTRA_CFLAGS)
+CPPFLAGS += $(EXTRA_CFLAGS)
all: $(LIB)
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 4a12976e3..b860e89f8 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -33,6 +33,7 @@ COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP34XX_I2C) += omap24xx_i2c.o
+COBJS-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o
COBJS-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o
COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o
COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o
diff --git a/drivers/i2c/bfin-twi_i2c.c b/drivers/i2c/bfin-twi_i2c.c
index e79063407..73a78d223 100644
--- a/drivers/i2c/bfin-twi_i2c.c
+++ b/drivers/i2c/bfin-twi_i2c.c
@@ -26,6 +26,7 @@
#ifdef TWI0_CLKDIV
#define bfin_write_TWI_CLKDIV(val) bfin_write_TWI0_CLKDIV(val)
+#define bfin_read_TWI_CLKDIV(val) bfin_read_TWI0_CLKDIV(val)
#define bfin_write_TWI_CONTROL(val) bfin_write_TWI0_CONTROL(val)
#define bfin_read_TWI_CONTROL(val) bfin_read_TWI0_CONTROL(val)
#define bfin_write_TWI_MASTER_ADDR(val) bfin_write_TWI0_MASTER_ADDR(val)
@@ -44,8 +45,21 @@
#ifdef CONFIG_TWICLK_KHZ
# error do not define CONFIG_TWICLK_KHZ ... use CONFIG_SYS_I2C_SPEED
#endif
-#if CONFIG_SYS_I2C_SPEED > 400000
-# error The Blackfin I2C hardware can only operate at 400KHz max
+
+/*
+ * The way speed is changed into duty often results in integer truncation
+ * with 50% duty, so we'll force rounding up to the next duty by adding 1
+ * to the max. In practice this will get us a speed of something like
+ * 385 KHz. The other limit is easy to handle as it is only 8 bits.
+ */
+#define I2C_SPEED_MAX 400000
+#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed))
+#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
+#define I2C_DUTY_MIN 0xff /* 8 bit limited */
+#define SYS_I2C_DUTY I2C_SPEED_TO_DUTY(CONFIG_SYS_I2C_SPEED)
+/* Note: duty is inverse of speed, so the comparisons below are correct */
+#if SYS_I2C_DUTY < I2C_DUTY_MAX || SYS_I2C_DUTY > I2C_DUTY_MIN
+# error "The Blackfin I2C hardware can only operate 20KHz - 400KHz"
#endif
/* All transfers are described by this data structure */
@@ -60,6 +74,9 @@ struct i2c_msg {
u8 *abuf; /* addr buffer */
};
+/* Allow msec timeout per ~byte transfer */
+#define I2C_TIMEOUT 10
+
/**
* wait_for_completion - manage the actual i2c transfer
* @msg: the i2c msg
@@ -67,8 +84,9 @@ struct i2c_msg {
static int wait_for_completion(struct i2c_msg *msg)
{
uint16_t int_stat;
+ ulong timebase = get_timer(0);
- while (!ctrlc()) {
+ do {
int_stat = bfin_read_TWI_INT_STAT();
if (int_stat & XMTSERV) {
@@ -103,7 +121,7 @@ static int wait_for_completion(struct i2c_msg *msg)
debugi("processing MERR");
bfin_write_TWI_INT_STAT(MERR);
SSYNC();
- break;
+ return msg->len;
}
if (int_stat & MCOMP) {
debugi("processing MCOMP");
@@ -116,7 +134,12 @@ static int wait_for_completion(struct i2c_msg *msg)
} else
break;
}
- }
+
+ /* If we were able to do something, reset timeout */
+ if (int_stat)
+ timebase = get_timer(0);
+
+ } while (get_timer(timebase) < I2C_TIMEOUT);
return msg->len;
}
@@ -204,7 +227,36 @@ static int i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer, int len,
return ret;
}
-/*
+/**
+ * i2c_set_bus_speed - set i2c bus speed
+ * @speed: bus speed (in HZ)
+ */
+int i2c_set_bus_speed(unsigned int speed)
+{
+ u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
+
+ /* Set TWI interface clock */
+ if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
+ return -1;
+ bfin_write_TWI_CLKDIV((clkdiv << 8) | (clkdiv & 0xff));
+
+ /* Don't turn it on */
+ bfin_write_TWI_MASTER_CTL(speed > 100000 ? FAST : 0);
+
+ return 0;
+}
+
+/**
+ * i2c_get_bus_speed - get i2c bus speed
+ * @speed: bus speed (in HZ)
+ */
+unsigned int i2c_get_bus_speed(void)
+{
+ /* 10 MHz / (2 * CLKDIV) -> 5 MHz / CLKDIV */
+ return 5000000 / (bfin_read_TWI_CLKDIV() & 0xff);
+}
+
+/**
* i2c_init - initialize the i2c bus
* @speed: bus speed (in HZ)
* @slaveaddr: address of device in slave mode (0 - not slave)
@@ -220,15 +272,9 @@ void i2c_init(int speed, int slaveaddr)
bfin_write_TWI_CONTROL(prescale);
/* Set TWI interface clock as specified */
- bfin_write_TWI_CLKDIV(
- ((5 * 1024 / (speed / 1000)) << 8) |
- ((5 * 1024 / (speed / 1000)) & 0xFF)
- );
-
- /* Don't turn it on */
- bfin_write_TWI_MASTER_CTL(speed > 100000 ? FAST : 0);
+ i2c_set_bus_speed(speed);
- /* But enable it */
+ /* Enable it */
bfin_write_TWI_CONTROL(TWI_ENA | prescale);
SSYNC();
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 1a4c8c9ad..ff18991f0 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -29,6 +29,11 @@ static void wait_for_bb (void);
static u16 wait_for_pin (void);
static void flush_fifo(void);
+static struct i2c *i2c_base = (struct i2c *)I2C_DEFAULT_BASE;
+
+static unsigned int bus_initialized[I2C_BUS_MAX];
+static unsigned int current_bus;
+
void i2c_init (int speed, int slaveadd)
{
int psc, fsscll, fssclh;
@@ -95,30 +100,32 @@ void i2c_init (int speed, int slaveadd)
sclh = (unsigned int)fssclh;
}
- writew(0x2, I2C_SYSC); /* for ES2 after soft reset */
+ writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
udelay(1000);
- writew(0x0, I2C_SYSC); /* will probably self clear but */
+ writew(0x0, &i2c_base->sysc); /* will probably self clear but */
- if (readw (I2C_CON) & I2C_CON_EN) {
- writew (0, I2C_CON);
+ if (readw (&i2c_base->con) & I2C_CON_EN) {
+ writew (0, &i2c_base->con);
udelay (50000);
}
- writew(psc, I2C_PSC);
- writew(scll, I2C_SCLL);
- writew(sclh, I2C_SCLH);
+ writew(psc, &i2c_base->psc);
+ writew(scll, &i2c_base->scll);
+ writew(sclh, &i2c_base->sclh);
/* own address */
- writew (slaveadd, I2C_OA);
- writew (I2C_CON_EN, I2C_CON);
+ writew (slaveadd, &i2c_base->oa);
+ writew (I2C_CON_EN, &i2c_base->con);
/* have to enable intrrupts or OMAP i2c module doesn't work */
writew (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
- I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE);
+ I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
udelay (1000);
flush_fifo();
- writew (0xFFFF, I2C_STAT);
- writew (0, I2C_CNT);
+ writew (0xFFFF, &i2c_base->stat);
+ writew (0, &i2c_base->cnt);
+
+ bus_initialized[current_bus] = 1;
}
static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
@@ -130,19 +137,19 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
wait_for_bb ();
/* one byte only */
- writew (1, I2C_CNT);
+ writew (1, &i2c_base->cnt);
/* set slave address */
- writew (devaddr, I2C_SA);
+ writew (devaddr, &i2c_base->sa);
/* no stop bit needed here */
- writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON);
+ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, &i2c_base->con);
status = wait_for_pin ();
if (status & I2C_STAT_XRDY) {
/* Important: have to use byte access */
- writeb (regoffset, I2C_DATA);
+ writeb (regoffset, &i2c_base->data);
udelay (20000);
- if (readw (I2C_STAT) & I2C_STAT_NACK) {
+ if (readw (&i2c_base->stat) & I2C_STAT_NACK) {
i2c_error = 1;
}
} else {
@@ -151,28 +158,28 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
if (!i2c_error) {
/* free bus, otherwise we can't use a combined transction */
- writew (0, I2C_CON);
- while (readw (I2C_STAT) || (readw (I2C_CON) & I2C_CON_MST)) {
+ writew (0, &i2c_base->con);
+ while (readw (&i2c_base->stat) || (readw (&i2c_base->con) & I2C_CON_MST)) {
udelay (10000);
/* Have to clear pending interrupt to clear I2C_STAT */
- writew (0xFFFF, I2C_STAT);
+ writew (0xFFFF, &i2c_base->stat);
}
wait_for_bb ();
/* set slave address */
- writew (devaddr, I2C_SA);
+ writew (devaddr, &i2c_base->sa);
/* read one byte from slave */
- writew (1, I2C_CNT);
+ writew (1, &i2c_base->cnt);
/* need stop bit here */
writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
- I2C_CON);
+ &i2c_base->con);
status = wait_for_pin ();
if (status & I2C_STAT_RRDY) {
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- *value = readb (I2C_DATA);
+ *value = readb (&i2c_base->data);
#else
- *value = readw (I2C_DATA);
+ *value = readw (&i2c_base->data);
#endif
udelay (20000);
} else {
@@ -180,17 +187,17 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
}
if (!i2c_error) {
- writew (I2C_CON_EN, I2C_CON);
- while (readw (I2C_STAT)
- || (readw (I2C_CON) & I2C_CON_MST)) {
+ writew (I2C_CON_EN, &i2c_base->con);
+ while (readw (&i2c_base->stat)
+ || (readw (&i2c_base->con) & I2C_CON_MST)) {
udelay (10000);
- writew (0xFFFF, I2C_STAT);
+ writew (0xFFFF, &i2c_base->stat);
}
}
}
flush_fifo();
- writew (0xFFFF, I2C_STAT);
- writew (0, I2C_CNT);
+ writew (0xFFFF, &i2c_base->stat);
+ writew (0, &i2c_base->cnt);
return i2c_error;
}
@@ -203,12 +210,12 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
wait_for_bb ();
/* two bytes */
- writew (2, I2C_CNT);
+ writew (2, &i2c_base->cnt);
/* set slave address */
- writew (devaddr, I2C_SA);
+ writew (devaddr, &i2c_base->sa);
/* stop bit needed here */
writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
- I2C_CON_STP, I2C_CON);
+ I2C_CON_STP, &i2c_base->con);
/* wait until state change */
status = wait_for_pin ();
@@ -216,24 +223,24 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
if (status & I2C_STAT_XRDY) {
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
/* send out 1 byte */
- writeb (regoffset, I2C_DATA);
- writew (I2C_STAT_XRDY, I2C_STAT);
+ writeb (regoffset, &i2c_base->data);
+ writew (I2C_STAT_XRDY, &i2c_base->stat);
status = wait_for_pin ();
if ((status & I2C_STAT_XRDY)) {
/* send out next 1 byte */
- writeb (value, I2C_DATA);
- writew (I2C_STAT_XRDY, I2C_STAT);
+ writeb (value, &i2c_base->data);
+ writew (I2C_STAT_XRDY, &i2c_base->stat);
} else {
i2c_error = 1;
}
#else
/* send out two bytes */
- writew ((value << 8) + regoffset, I2C_DATA);
+ writew ((value << 8) + regoffset, &i2c_base->data);
#endif
/* must have enough delay to allow BB bit to go low */
udelay (50000);
- if (readw (I2C_STAT) & I2C_STAT_NACK) {
+ if (readw (&i2c_base->stat) & I2C_STAT_NACK) {
i2c_error = 1;
}
} else {
@@ -243,18 +250,18 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
if (!i2c_error) {
int eout = 200;
- writew (I2C_CON_EN, I2C_CON);
- while ((stat = readw (I2C_STAT)) || (readw (I2C_CON) & I2C_CON_MST)) {
+ writew (I2C_CON_EN, &i2c_base->con);
+ while ((stat = readw (&i2c_base->stat)) || (readw (&i2c_base->con) & I2C_CON_MST)) {
udelay (1000);
/* have to read to clear intrrupt */
- writew (0xFFFF, I2C_STAT);
+ writew (0xFFFF, &i2c_base->stat);
if(--eout == 0) /* better leave with error than hang */
break;
}
}
flush_fifo();
- writew (0xFFFF, I2C_STAT);
- writew (0, I2C_CNT);
+ writew (0xFFFF, &i2c_base->stat);
+ writew (0, &i2c_base->cnt);
return i2c_error;
}
@@ -265,14 +272,14 @@ static void flush_fifo(void)
* you get a bus error
*/
while(1){
- stat = readw(I2C_STAT);
+ stat = readw(&i2c_base->stat);
if(stat == I2C_STAT_RRDY){
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- readb(I2C_DATA);
+ readb(&i2c_base->data);
#else
- readw(I2C_DATA);
+ readw(&i2c_base->data);
#endif
- writew(I2C_STAT_RRDY,I2C_STAT);
+ writew(I2C_STAT_RRDY,&i2c_base->stat);
udelay(1000);
}else
break;
@@ -283,7 +290,7 @@ int i2c_probe (uchar chip)
{
int res = 1; /* default = fail */
- if (chip == readw (I2C_OA)) {
+ if (chip == readw (&i2c_base->oa)) {
return res;
}
@@ -291,27 +298,27 @@ int i2c_probe (uchar chip)
wait_for_bb ();
/* try to read one byte */
- writew (1, I2C_CNT);
+ writew (1, &i2c_base->cnt);
/* set slave address */
- writew (chip, I2C_SA);
+ writew (chip, &i2c_base->sa);
/* stop bit needed here */
- writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON);
+ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con);
/* enough delay for the NACK bit set */
udelay (50000);
- if (!(readw (I2C_STAT) & I2C_STAT_NACK)) {
+ if (!(readw (&i2c_base->stat) & I2C_STAT_NACK)) {
res = 0; /* success case */
flush_fifo();
- writew(0xFFFF, I2C_STAT);
+ writew(0xFFFF, &i2c_base->stat);
} else {
- writew(0xFFFF, I2C_STAT); /* failue, clear sources*/
- writew (readw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */
+ writew(0xFFFF, &i2c_base->stat); /* failue, clear sources*/
+ writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con); /* finish up xfer */
udelay(20000);
wait_for_bb ();
}
flush_fifo();
- writew (0, I2C_CNT); /* don't allow any more data in...we don't want it.*/
- writew(0xFFFF, I2C_STAT);
+ writew (0, &i2c_base->cnt); /* don't allow any more data in...we don't want it.*/
+ writew(0xFFFF, &i2c_base->stat);
return res;
}
@@ -370,17 +377,17 @@ static void wait_for_bb (void)
int timeout = 10;
u16 stat;
- writew(0xFFFF, I2C_STAT); /* clear current interruts...*/
- while ((stat = readw (I2C_STAT) & I2C_STAT_BB) && timeout--) {
- writew (stat, I2C_STAT);
+ writew(0xFFFF, &i2c_base->stat); /* clear current interruts...*/
+ while ((stat = readw (&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
+ writew (stat, &i2c_base->stat);
udelay (50000);
}
if (timeout <= 0) {
printf ("timed out in wait_for_bb: I2C_STAT=%x\n",
- readw (I2C_STAT));
+ readw (&i2c_base->stat));
}
- writew(0xFFFF, I2C_STAT); /* clear delayed stuff*/
+ writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
}
static u16 wait_for_pin (void)
@@ -390,7 +397,7 @@ static u16 wait_for_pin (void)
do {
udelay (1000);
- status = readw (I2C_STAT);
+ status = readw (&i2c_base->stat);
} while ( !(status &
(I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
@@ -398,8 +405,33 @@ static u16 wait_for_pin (void)
if (timeout <= 0) {
printf ("timed out in wait_for_pin: I2C_STAT=%x\n",
- readw (I2C_STAT));
- writew(0xFFFF, I2C_STAT);
+ readw (&i2c_base->stat));
+ writew(0xFFFF, &i2c_base->stat);
}
return status;
}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+ if ((bus < 0) || (bus >= I2C_BUS_MAX)) {
+ printf("Bad bus: %d\n", bus);
+ return -1;
+ }
+
+#if I2C_BUS_MAX==3
+ if (bus == 2)
+ i2c_base = (struct i2c *)I2C_BASE3;
+ else
+#endif
+ if (bus == 1)
+ i2c_base = (struct i2c *)I2C_BASE2;
+ else
+ i2c_base = (struct i2c *)I2C_BASE1;
+
+ current_bus = bus;
+
+ if(!bus_initialized[current_bus])
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ return 0;
+}
diff --git a/drivers/i2c/pca9564_i2c.c b/drivers/i2c/pca9564_i2c.c
new file mode 100644
index 000000000..199a9ee39
--- /dev/null
+++ b/drivers/i2c/pca9564_i2c.c
@@ -0,0 +1,189 @@
+/*
+ * File: drivers/i2c/pca9564.c
+ * Based on: drivers/i2c/s3c44b0_i2c.c
+ * Author:
+ *
+ * Created: 2009-06-23
+ * Description: PCA9564 i2c bridge driver
+ *
+ * Modified:
+ * Copyright 2009 CJSC "NII STT", http://www.niistt.ru/
+ *
+ * Bugs:
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <pca9564.h>
+#include <asm/io.h>
+
+#define PCA_STA (CONFIG_PCA9564_BASE + 0)
+#define PCA_TO (CONFIG_PCA9564_BASE + 0)
+#define PCA_DAT (CONFIG_PCA9564_BASE + (1 << 2))
+#define PCA_ADR (CONFIG_PCA9564_BASE + (2 << 2))
+#define PCA_CON (CONFIG_PCA9564_BASE + (3 << 2))
+
+static unsigned char pca_read_reg(unsigned int reg)
+{
+ return readb((void *)reg);
+}
+
+static void pca_write_reg(unsigned int reg, unsigned char value)
+{
+ writeb(value, (void *)reg);
+}
+
+static int pca_wait_busy(void)
+{
+ unsigned int timeout = 10000;
+
+ while (!(pca_read_reg(PCA_CON) & PCA_CON_SI) && --timeout)
+ udelay(1);
+
+ if (timeout == 0)
+ debug("I2C timeout!\n");
+
+ debug("CON = 0x%02x, STA = 0x%02x\n", pca_read_reg(PCA_CON),
+ pca_read_reg(PCA_STA));
+
+ return timeout ? 0 : 1;
+}
+
+/*=====================================================================*/
+/* Public Functions */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO | speed);
+}
+
+/*
+ * Probe the given I2C chip address. Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+
+int i2c_probe(uchar chip)
+{
+ unsigned char res;
+
+ pca_write_reg(PCA_CON, PCA_CON_STA | PCA_CON_ENSIO);
+ pca_wait_busy();
+
+ pca_write_reg(PCA_CON, PCA_CON_STA | PCA_CON_ENSIO);
+
+ pca_write_reg(PCA_DAT, (chip << 1) | 1);
+ res = pca_wait_busy();
+
+ if ((res == 0) && (pca_read_reg(PCA_STA) == 0x48))
+ res = 1;
+
+ pca_write_reg(PCA_CON, PCA_CON_STO | PCA_CON_ENSIO);
+
+ return res;
+}
+
+/*
+ * Read/Write interface:
+ * chip: I2C chip address, range 0..127
+ * addr: Memory (register) address within the chip
+ * alen: Number of bytes to use for addr (typically 1, 2 for larger
+ * memories, 0 for register type devices with only one
+ * register)
+ * buffer: Where to read/write the data
+ * len: How many bytes to read/write
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ int i;
+
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
+ pca_wait_busy();
+
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+
+ pca_write_reg(PCA_DAT, (chip << 1));
+ pca_wait_busy();
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+
+ if (alen > 0) {
+ pca_write_reg(PCA_DAT, addr);
+ pca_wait_busy();
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+ }
+
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STO);
+
+ udelay(500);
+
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
+ pca_wait_busy();
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+
+ pca_write_reg(PCA_DAT, (chip << 1) | 1);
+ pca_wait_busy();
+
+ for (i = 0; i < len; ++i) {
+ if (i == len - 1)
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+ else
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_AA);
+
+ pca_wait_busy();
+ buffer[i] = pca_read_reg(PCA_DAT);
+
+ }
+
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STO);
+
+ return 0;
+}
+
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ int i;
+
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
+ pca_wait_busy();
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+
+ pca_write_reg(PCA_DAT, chip << 1);
+ pca_wait_busy();
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+
+ if (alen > 0) {
+ pca_write_reg(PCA_DAT, addr);
+ pca_wait_busy();
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+ }
+
+ for (i = 0; i < len; ++i) {
+ pca_write_reg(PCA_DAT, buffer[i]);
+ pca_wait_busy();
+ pca_write_reg(PCA_CON, PCA_CON_ENSIO);
+ }
+
+ pca_write_reg(PCA_CON, PCA_CON_STO | PCA_CON_ENSIO);
+
+ return 0;
+}
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index 55c6a12aa..c8371cf73 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -27,11 +27,7 @@
*/
#include <common.h>
-#if defined(CONFIG_S3C2400)
-#include <s3c2400.h>
-#elif defined(CONFIG_S3C2410)
-#include <s3c2410.h>
-#endif
+#include <asm/arch/s3c24x0_cpu.h>
#include <asm/io.h>
#include <i2c.h>
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index 59883a58f..9a4878391 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -34,6 +34,11 @@
#include <asm/io.h>
#include <asm/arch/hardware.h>
#endif
+#ifdef CONFIG_AT91SAM9263 /* only valid for AT91SAM9263 */
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/io.h>
+#endif
#ifdef CONFIG_IXP425 /* only valid for IXP425 */
#include <asm/arch/ixp425.h>
#endif
diff --git a/drivers/mmc/omap3_mmc.c b/drivers/mmc/omap3_mmc.c
index 513dd25b0..96c0e653b 100644
--- a/drivers/mmc/omap3_mmc.c
+++ b/drivers/mmc/omap3_mmc.c
@@ -63,7 +63,9 @@ unsigned char mmc_board_init(void)
{
t2_t *t2_base = (t2_t *)T2_BASE;
+#if defined(CONFIG_TWL4030_POWER)
twl4030_power_mmc_init();
+#endif
writel(readl(&t2_base->pbias_lite) | PBIASLITEPWRDNZ1 |
PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index eabaf3e77..41a95685f 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -182,13 +182,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *
#ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST
static struct nand_ecclayout nand_davinci_4bit_layout_oobfirst = {
-/*
- * TI uses a different layout for 4K page deviecs. Since the
- * eccpos filed can hold only a limited number of entries, adding
- * support for 4K page will result in compilation warnings
- * 4K Support will be added later
- */
-#ifdef CONFIG_SYS_NAND_PAGE_2K
+#if defined(CONFIG_SYS_NAND_PAGE_2K)
.eccbytes = 40,
.eccpos = {
24, 25, 26, 27, 28,
@@ -200,6 +194,21 @@ static struct nand_ecclayout nand_davinci_4bit_layout_oobfirst = {
.oobfree = {
{.offset = 2, .length = 22, },
},
+#elif defined(CONFIG_SYS_NAND_PAGE_4K)
+ .eccbytes = 80,
+ .eccpos = {
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ },
+ .oobfree = {
+ {.offset = 2, .length = 46, },
+ },
#endif
};
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 50cb4aa9d..146e9bf3c 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -766,9 +766,6 @@ int board_nand_init(struct nand_chip *nand)
nand->waitfunc = fsl_elbc_wait;
/* set up nand options */
- /* redirect the pointer of bbt pattern to RAM */
- bbt_main_descr.pattern = bbt_pattern;
- bbt_mirror_descr.pattern = mirror_pattern;
nand->bbt_td = &bbt_main_descr;
nand->bbt_md = &bbt_mirror_descr;
@@ -815,7 +812,6 @@ int board_nand_init(struct nand_chip *nand)
/* Large-page-specific setup */
if (or & OR_FCM_PGS) {
priv->page_size = 1;
- largepage_memorybased.pattern = scan_ff_pattern;
nand->badblock_pattern = &largepage_memorybased;
/* adjust ecc setup if needed */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 426bb95e9..7171bdd51 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -893,6 +893,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
+ *
+ * Not for syndrome calculating ecc controllers, which use a special oob layout
*/
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
@@ -903,10 +906,53 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
+ * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @page: page number to read
+ *
+ * We need a special oob layout and handling even when OOB isn't used.
+ */
+static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page)
+{
+ int eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ uint8_t *oob = chip->oob_poi;
+ int steps, size;
+
+ for (steps = chip->ecc.steps; steps > 0; steps--) {
+ chip->read_buf(mtd, buf, eccsize);
+ buf += eccsize;
+
+ if (chip->ecc.prepad) {
+ chip->read_buf(mtd, oob, chip->ecc.prepad);
+ oob += chip->ecc.prepad;
+ }
+
+ chip->read_buf(mtd, oob, eccbytes);
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->read_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
+ }
+ }
+
+ size = mtd->oobsize - (oob - chip->oob_poi);
+ if (size)
+ chip->read_buf(mtd, oob, size);
+
+ return 0;
+}
+
+/**
* nand_read_page_swecc - [REPLACABLE] software ecc based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*/
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
@@ -946,9 +992,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
* nand_read_subpage - [REPLACABLE] software ecc based sub-page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
- * @dataofs offset of requested data within the page
- * @readlen data length
- * @buf: buffer to store read data
+ * @data_offs: offset of requested data within the page
+ * @readlen: data length
+ * @bufpoi: buffer to store read data
*/
static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
{
@@ -1015,7 +1061,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
int stat;
stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
- if (stat < 0)
+ if (stat == -1)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
@@ -1028,6 +1074,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* Not for syndrome calculating ecc controllers which need a special oob layout
*/
@@ -1059,7 +1106,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- if (stat == -1)
+ if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
@@ -1072,6 +1119,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* Hardware ECC for large page chips, require OOB to be read first.
* For this ECC mode, the write_page method is re-used from ECC_HW.
@@ -1120,6 +1168,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* The hw generator calculates the error syndrome automatically. Therefor
* we need a special oob layout and handling.
@@ -1677,6 +1726,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
+ *
+ * Not for syndrome calculating ecc controllers, which use a special oob layout
*/
static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf)
@@ -1686,6 +1737,44 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
+ * nand_write_page_raw_syndrome - [Intern] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ *
+ * We need a special oob layout and handling even when ECC isn't checked.
+ */
+static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ uint8_t *oob = chip->oob_poi;
+ int steps, size;
+
+ for (steps = chip->ecc.steps; steps > 0; steps--) {
+ chip->write_buf(mtd, buf, eccsize);
+ buf += eccsize;
+
+ if (chip->ecc.prepad) {
+ chip->write_buf(mtd, oob, chip->ecc.prepad);
+ oob += chip->ecc.prepad;
+ }
+
+ chip->read_buf(mtd, oob, eccbytes);
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->write_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
+ }
+ }
+
+ size = mtd->oobsize - (oob - chip->oob_poi);
+ if (size)
+ chip->write_buf(mtd, oob, size);
+}
+/**
* nand_write_page_swecc - [REPLACABLE] software ecc based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
@@ -2211,13 +2300,15 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt)
{
- int page, len, status, pages_per_block, ret, chipnr;
+ int page, status, pages_per_block, ret, chipnr;
struct nand_chip *chip = mtd->priv;
- int rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS]={0};
+ loff_t rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS] = {0};
unsigned int bbt_masked_page = 0xffffffff;
+ loff_t len;
- MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
- (unsigned int) instr->addr, (unsigned int) instr->len);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, "
+ "len = %llu\n", (unsigned long long) instr->addr,
+ (unsigned long long) instr->len);
/* Start address must align on block boundary */
if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
@@ -2313,7 +2404,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "
"Failed erase, page 0x%08x\n", page);
instr->state = MTD_ERASE_FAILED;
- instr->fail_addr = (page << chip->page_shift);
+ instr->fail_addr = ((loff_t)page << chip->page_shift);
goto erase_exit;
}
@@ -2323,7 +2414,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
*/
if (bbt_masked_page != 0xffffffff &&
(page & BBT_PAGE_MASK) == bbt_masked_page)
- rewrite_bbt[chipnr] = (page << chip->page_shift);
+ rewrite_bbt[chipnr] =
+ ((loff_t)page << chip->page_shift);
/* Increment page address and decrement length */
len -= (1 << chip->phys_erase_shift);
@@ -2370,8 +2462,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
continue;
/* update the BBT for chip */
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
- "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
- chip->bbt_td->pages[chipnr]);
+ "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
+ chip->bbt_td->pages[chipnr]);
nand_update_bbt(mtd, rewrite_bbt[chipnr]);
}
@@ -2566,7 +2658,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (!mtd->name)
mtd->name = type->name;
- chip->chipsize = type->chipsize << 20;
+ chip->chipsize = (uint64_t)type->chipsize << 20;
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
@@ -2624,7 +2716,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
- chip->chip_shift = ffs(chip->chipsize) - 1;
+ if (chip->chipsize & 0xffffffff)
+ chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
+ else
+ chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
/* Set the bad block position */
chip->badblockpos = mtd->writesize > 512 ?
@@ -2722,7 +2817,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
- * @maxchips: Number of chips to scan for
*
* This is the second phase of the normal nand_scan() function. It
* fills out all the uninitialized function pointers with the defaults
@@ -2761,7 +2855,6 @@ int nand_scan_tail(struct mtd_info *mtd)
default:
printk(KERN_WARNING "No oob scheme defined for "
"oobsize %d\n", mtd->oobsize);
-/* BUG(); */
}
}
@@ -2772,10 +2865,6 @@ int nand_scan_tail(struct mtd_info *mtd)
* check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
*/
- if (!chip->ecc.read_page_raw)
- chip->ecc.read_page_raw = nand_read_page_raw;
- if (!chip->ecc.write_page_raw)
- chip->ecc.write_page_raw = nand_write_page_raw;
switch (chip->ecc.mode) {
case NAND_ECC_HW_OOB_FIRST:
@@ -2795,6 +2884,10 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_page = nand_read_page_hwecc;
if (!chip->ecc.write_page)
chip->ecc.write_page = nand_write_page_hwecc;
+ if (!chip->ecc.read_page_raw)
+ chip->ecc.read_page_raw = nand_read_page_raw;
+ if (!chip->ecc.write_page_raw)
+ chip->ecc.write_page_raw = nand_write_page_raw;
if (!chip->ecc.read_oob)
chip->ecc.read_oob = nand_read_oob_std;
if (!chip->ecc.write_oob)
@@ -2816,6 +2909,10 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_page = nand_read_page_syndrome;
if (!chip->ecc.write_page)
chip->ecc.write_page = nand_write_page_syndrome;
+ if (!chip->ecc.read_page_raw)
+ chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
+ if (!chip->ecc.write_page_raw)
+ chip->ecc.write_page_raw = nand_write_page_raw_syndrome;
if (!chip->ecc.read_oob)
chip->ecc.read_oob = nand_read_oob_syndrome;
if (!chip->ecc.write_oob)
@@ -2834,6 +2931,8 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_page = nand_read_page_swecc;
chip->ecc.read_subpage = nand_read_subpage;
chip->ecc.write_page = nand_write_page_swecc;
+ chip->ecc.read_page_raw = nand_read_page_raw;
+ chip->ecc.write_page_raw = nand_write_page_raw;
chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = 256;
@@ -2846,6 +2945,8 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_page = nand_read_page_raw;
chip->ecc.write_page = nand_write_page_raw;
chip->ecc.read_oob = nand_read_oob_std;
+ chip->ecc.read_page_raw = nand_read_page_raw;
+ chip->ecc.write_page_raw = nand_write_page_raw;
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = mtd->writesize;
chip->ecc.bytes = 0;
@@ -2862,7 +2963,8 @@ int nand_scan_tail(struct mtd_info *mtd)
* the out of band area
*/
chip->ecc.layout->oobavail = 0;
- for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
+ for (i = 0; chip->ecc.layout->oobfree[i].length
+ && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
chip->ecc.layout->oobavail +=
chip->ecc.layout->oobfree[i].length;
mtd->oobavail = chip->ecc.layout->oobavail;
@@ -2890,6 +2992,7 @@ int nand_scan_tail(struct mtd_info *mtd)
break;
case 4:
case 8:
+ case 16:
mtd->subpage_sft = 2;
break;
}
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index d68a315f1..2fe68abe1 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -182,16 +182,19 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
if (tmp == msk)
continue;
if (reserved_block_code && (tmp == reserved_block_code)) {
- printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
- ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",
+ (loff_t)((offs << 2) +
+ (act >> 1)) <<
+ this->bbt_erase_shift);
this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
mtd->ecc_stats.bbtblocks++;
continue;
}
/* Leave it for now, if its matured we can move this
* message to MTD_DEBUG_LEVEL0 */
- printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
- ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",
+ (loff_t)((offs << 2) + (act >> 1)) <<
+ this->bbt_erase_shift);
/* Factory marked bad or worn out ? */
if (tmp == 0)
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -295,8 +298,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
- scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,
- mtd->writesize);
+ scan_read_raw(mtd, buf, (loff_t)td->pages[0] <<
+ this->page_shift, mtd->writesize);
td->version[0] = buf[mtd->writesize + td->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
td->pages[0], td->version[0]);
@@ -304,8 +307,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the mirror version, if available */
if (md && (md->options & NAND_BBT_VERSION)) {
- scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,
- mtd->writesize);
+ scan_read_raw(mtd, buf, (loff_t)md->pages[0] <<
+ this->page_shift, mtd->writesize);
md->version[0] = buf[mtd->writesize + md->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
md->pages[0], md->version[0]);
@@ -422,7 +425,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
startblock = chip * numblocks;
numblocks += startblock;
- from = startblock << (this->bbt_erase_shift - 1);
+ from = (loff_t)startblock << (this->bbt_erase_shift - 1);
}
for (i = startblock; i < numblocks;) {
@@ -440,8 +443,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
if (ret) {
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
MTDDEBUG (MTD_DEBUG_LEVEL0,
- "Bad eraseblock %d at 0x%08x\n",
- i >> 1, (unsigned int)from);
+ "Bad eraseblock %d at 0x%012llx\n",
+ i >> 1, (unsigned long long)from);
mtd->ecc_stats.badblocks++;
}
@@ -507,7 +510,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
for (block = 0; block < td->maxblocks; block++) {
int actblock = startblock + dir * block;
- loff_t offs = actblock << this->bbt_erase_shift;
+ loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
/* Read first page */
scan_read_raw(mtd, buf, offs, mtd->writesize);
@@ -731,7 +734,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
memset(&einfo, 0, sizeof(einfo));
einfo.mtd = mtd;
- einfo.addr = (unsigned long)to;
+ einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
if (res < 0)
@@ -741,8 +744,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
if (res < 0)
goto outerr;
- printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
- "0x%02X\n", (unsigned int)to, td->version[chip]);
+ printk(KERN_DEBUG "Bad block table written to 0x%012llx, "
+ "version 0x%02X\n", (unsigned long long)to,
+ td->version[chip]);
/* Mark it as used */
td->pages[chip] = page;
@@ -922,7 +926,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
newval = oldval | (0x2 << (block & 0x06));
this->bbt[(block >> 3)] = newval;
if ((oldval != newval) && td->reserved_block_code)
- nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)block <<
+ (this->bbt_erase_shift - 1));
continue;
}
update = 0;
@@ -943,7 +948,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
new ones have been marked, then we need to update the stored
bbts. This should only happen once. */
if (update && td->reserved_block_code)
- nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)(block - 2) <<
+ (this->bbt_erase_shift - 1));
}
}
@@ -1039,7 +1045,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
if (!this->bbt || !td)
return -EINVAL;
- len = mtd->size >> (this->bbt_erase_shift + 2);
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
len += (len >> this->page_shift) * mtd->oobsize;
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 7085d42cc..29c42f73b 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -41,10 +41,6 @@
#include <nand.h>
#include <jffs2/jffs2.h>
-#if !defined(CONFIG_SYS_64BIT_VSPRINTF)
-#warning Please define CONFIG_SYS_64BIT_VSPRINTF for correct output!
-#endif
-
typedef struct erase_info erase_info_t;
typedef struct mtd_info mtd_info_t;
@@ -490,7 +486,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
len_incl_bad = get_len_incl_bad (nand, offset, *length);
- if ((offset + len_incl_bad) >= nand->size) {
+ if ((offset + len_incl_bad) > nand->size) {
printf ("Attempt to write outside the flash area\n");
return -EINVAL;
}
@@ -562,7 +558,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
len_incl_bad = get_len_incl_bad (nand, offset, *length);
- if ((offset + len_incl_bad) >= nand->size) {
+ if ((offset + len_incl_bad) > nand->size) {
printf ("Attempt to read outside the flash area\n");
return -EINVAL;
}
diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c
index f2f3e722e..a27d47e5f 100644
--- a/drivers/mtd/nand/s3c2410_nand.c
+++ b/drivers/mtd/nand/s3c2410_nand.c
@@ -21,7 +21,7 @@
#include <common.h>
#include <nand.h>
-#include <s3c2410.h>
+#include <asm/arch/s3c24x0_cpu.h>
#include <asm/io.h>
#define S3C2410_NFCONF_EN (1<<15)
@@ -36,6 +36,21 @@
#define S3C2410_ADDR_NALE 4
#define S3C2410_ADDR_NCLE 8
+#ifdef CONFIG_NAND_SPL
+
+/* in the early stage of NAND flash booting, printf() is not available */
+#define printf(fmt, args...)
+
+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ int i;
+ struct nand_chip *this = mtd->priv;
+
+ for (i = 0; i < len; i++)
+ buf[i] = readb(this->IO_ADDR_R);
+}
+#endif
+
static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
@@ -83,9 +98,10 @@ void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
{
- ecc_code[0] = NFECC0;
- ecc_code[1] = NFECC1;
- ecc_code[2] = NFECC2;
+ struct s3c2410_nand *nand = s3c2410_get_base_nand();
+ ecc_code[0] = readb(&nand->NFECC);
+ ecc_code[1] = readb(&nand->NFECC + 1);
+ ecc_code[2] = readb(&nand->NFECC + 2);
debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
@@ -130,8 +146,13 @@ int board_nand_init(struct nand_chip *nand)
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
+ nand->select_chip = NULL;
+
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
+#ifdef CONFIG_NAND_SPL
+ nand->read_buf = nand_read_buf;
+#endif
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2410_hwcontrol;
@@ -142,7 +163,9 @@ int board_nand_init(struct nand_chip *nand)
nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
nand->ecc.calculate = s3c2410_nand_calculate_ecc;
nand->ecc.correct = s3c2410_nand_correct_data;
- nand->ecc.mode = NAND_ECC_HW3_512;
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
+ nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
diff --git a/drivers/mtd/nand/s3c64xx.c b/drivers/mtd/nand/s3c64xx.c
index edaf55a14..084e47564 100644
--- a/drivers/mtd/nand/s3c64xx.c
+++ b/drivers/mtd/nand/s3c64xx.c
@@ -28,7 +28,7 @@
#include <common.h>
#include <nand.h>
-#include <s3c6400.h>
+#include <asm/arch/s3c6400.h>
#include <asm/io.h>
#include <asm/errno.h>
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 368fa6ef6..f9273ab97 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -9,6 +9,11 @@
* auto-placement support, read-while load support, various fixes
* Copyright (C) Nokia Corporation, 2007
*
+ * Rohit Hagargundgi <h.rohit at samsung.com>,
+ * Amul Kumar Saha <amul.saha@samsung.com>:
+ * Flex-OneNAND support
+ * Copyright (C) Samsung Electronics, 2009
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -24,7 +29,7 @@
#include <malloc.h>
/* It should access 16-bit instead of 8-bit */
-static inline void *memcpy_16(void *dst, const void *src, unsigned int len)
+static void *memcpy_16(void *dst, const void *src, unsigned int len)
{
void *ret = dst;
short *d = dst;
@@ -37,6 +42,27 @@ static inline void *memcpy_16(void *dst, const void *src, unsigned int len)
}
/**
+ * onenand_oob_128 - oob info for Flex-Onenand with 4KB page
+ * For now, we expose only 64 out of 80 ecc bytes
+ */
+static struct nand_ecclayout onenand_oob_128 = {
+ .eccbytes = 64,
+ .eccpos = {
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 102, 103, 104, 105
+ },
+ .oobfree = {
+ {2, 4}, {18, 4}, {34, 4}, {50, 4},
+ {66, 4}, {82, 4}, {98, 4}, {114, 4}
+ }
+};
+
+/**
* onenand_oob_64 - oob info for large (2KB) page
*/
static struct nand_ecclayout onenand_oob_64 = {
@@ -74,6 +100,14 @@ static const unsigned char ffchars[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 */
};
/**
@@ -180,6 +214,85 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
}
/**
+ * flexonenand_block - Return block number for flash address
+ * @param this - OneNAND device structure
+ * @param addr - Address for which block number is needed
+ */
+static unsigned int flexonenand_block(struct onenand_chip *this, loff_t addr)
+{
+ unsigned int boundary, blk, die = 0;
+
+ if (ONENAND_IS_DDP(this) && addr >= this->diesize[0]) {
+ die = 1;
+ addr -= this->diesize[0];
+ }
+
+ boundary = this->boundary[die];
+
+ blk = addr >> (this->erase_shift - 1);
+ if (blk > boundary)
+ blk = (blk + boundary + 1) >> 1;
+
+ blk += die ? this->density_mask : 0;
+ return blk;
+}
+
+unsigned int onenand_block(struct onenand_chip *this, loff_t addr)
+{
+ if (!FLEXONENAND(this))
+ return addr >> this->erase_shift;
+ return flexonenand_block(this, addr);
+}
+
+/**
+ * flexonenand_addr - Return address of the block
+ * @this: OneNAND device structure
+ * @block: Block number on Flex-OneNAND
+ *
+ * Return address of the block
+ */
+static loff_t flexonenand_addr(struct onenand_chip *this, int block)
+{
+ loff_t ofs = 0;
+ int die = 0, boundary;
+
+ if (ONENAND_IS_DDP(this) && block >= this->density_mask) {
+ block -= this->density_mask;
+ die = 1;
+ ofs = this->diesize[0];
+ }
+
+ boundary = this->boundary[die];
+ ofs += (loff_t) block << (this->erase_shift - 1);
+ if (block > (boundary + 1))
+ ofs += (loff_t) (block - boundary - 1)
+ << (this->erase_shift - 1);
+ return ofs;
+}
+
+loff_t onenand_addr(struct onenand_chip *this, int block)
+{
+ if (!FLEXONENAND(this))
+ return (loff_t) block << this->erase_shift;
+ return flexonenand_addr(this, block);
+}
+
+/**
+ * flexonenand_region - [Flex-OneNAND] Return erase region of addr
+ * @param mtd MTD device structure
+ * @param addr address whose erase region needs to be identified
+ */
+int flexonenand_region(struct mtd_info *mtd, loff_t addr)
+{
+ int i;
+
+ for (i = 0; i < mtd->numeraseregions; i++)
+ if (addr < mtd->eraseregions[i].offset)
+ break;
+ return i - 1;
+}
+
+/**
* onenand_get_density - [DEFAULT] Get OneNAND density
* @param dev_id OneNAND device ID
*
@@ -205,10 +318,11 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
size_t len)
{
struct onenand_chip *this = mtd->priv;
- int value, readcmd = 0;
+ int value;
int block, page;
+
/* Now we use page size operation */
- int sectors = 4, count = 4;
+ int sectors = 0, count = 0;
/* Address translation */
switch (cmd) {
@@ -220,15 +334,28 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
page = -1;
break;
+ case FLEXONENAND_CMD_PI_ACCESS:
+ /* addr contains die index */
+ block = addr * this->density_mask;
+ page = -1;
+ break;
+
case ONENAND_CMD_ERASE:
case ONENAND_CMD_BUFFERRAM:
- block = (int)(addr >> this->erase_shift);
+ block = onenand_block(this, addr);
page = -1;
break;
+ case FLEXONENAND_CMD_READ_PI:
+ cmd = ONENAND_CMD_READ;
+ block = addr * this->density_mask;
+ page = 0;
+ break;
+
default:
- block = (int)(addr >> this->erase_shift);
- page = (int)(addr >> this->page_shift);
+ block = onenand_block(this, addr);
+ page = (int) (addr
+ - onenand_addr(this, block)) >> this->page_shift;
page &= this->page_mask;
break;
}
@@ -240,8 +367,11 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
this->write_word(value,
this->base + ONENAND_REG_START_ADDRESS2);
- /* Switch to the next data buffer */
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (ONENAND_IS_MLC(this))
+ ONENAND_SET_BUFFERRAM0(this);
+ else
+ /* Switch to the next data buffer */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
return 0;
}
@@ -252,7 +382,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
this->write_word(value,
this->base + ONENAND_REG_START_ADDRESS1);
- /* Write 'DFS, FBA' of Flash */
+ /* Select DataRAM for DDP */
value = onenand_bufferram_address(this, block);
this->write_word(value,
this->base + ONENAND_REG_START_ADDRESS2);
@@ -262,10 +392,14 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
int dataram;
switch (cmd) {
+ case FLEXONENAND_CMD_RECOVER_LSB:
case ONENAND_CMD_READ:
case ONENAND_CMD_READOOB:
- dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
- readcmd = 1;
+ if (ONENAND_IS_MLC(this))
+ dataram = ONENAND_SET_BUFFERRAM0(this);
+ else
+ dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
+
break;
default:
@@ -292,6 +426,29 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
}
/**
+ * onenand_read_ecc - return ecc status
+ * @param this onenand chip structure
+ */
+static int onenand_read_ecc(struct onenand_chip *this)
+{
+ int ecc, i;
+
+ if (!FLEXONENAND(this))
+ return this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+
+ for (i = 0; i < 4; i++) {
+ ecc = this->read_word(this->base
+ + ((ONENAND_REG_ECC_STATUS + i) << 1));
+ if (likely(!ecc))
+ continue;
+ if (ecc & FLEXONENAND_UNCORRECTABLE_ERROR)
+ return ONENAND_ECC_2BIT_ALL;
+ }
+
+ return 0;
+}
+
+/**
* onenand_wait - [DEFAULT] wait until the command is done
* @param mtd MTD device structure
* @param state state to select the max. timeout value
@@ -305,7 +462,7 @@ static int onenand_wait(struct mtd_info *mtd, int state)
struct onenand_chip *this = mtd->priv;
unsigned int flags = ONENAND_INT_MASTER;
unsigned int interrupt = 0;
- unsigned int ctrl, ecc;
+ unsigned int ctrl;
while (1) {
interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
@@ -315,6 +472,14 @@ static int onenand_wait(struct mtd_info *mtd, int state)
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+ if (interrupt & ONENAND_INT_READ) {
+ int ecc = onenand_read_ecc(this);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk("onenand_wait: ECC error = 0x%04x\n", ecc);
+ return -EBADMSG;
+ }
+ }
+
if (ctrl & ONENAND_CTRL_ERROR) {
printk("onenand_wait: controller error = 0x%04x\n", ctrl);
if (ctrl & ONENAND_CTRL_LOCK)
@@ -324,14 +489,6 @@ static int onenand_wait(struct mtd_info *mtd, int state)
return -EIO;
}
- if (interrupt & ONENAND_INT_READ) {
- ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
- if (ecc & ONENAND_ECC_2BIT_ALL) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_wait: ECC error = 0x%04x\n", ecc);
- return -EBADMSG;
- }
- }
return 0;
}
@@ -499,7 +656,7 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
if (found && ONENAND_IS_DDP(this)) {
/* Select DataRAM for DDP */
- int block = (int) (addr >> this->erase_shift);
+ int block = onenand_block(this, addr);
int value = onenand_bufferram_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
}
@@ -632,6 +789,45 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
}
/**
+ * onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data
+ * @param mtd MTD device structure
+ * @param addr address to recover
+ * @param status return value from onenand_wait
+ *
+ * MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has
+ * lower page address and MSB page has higher page address in paired pages.
+ * If power off occurs during MSB page program, the paired LSB page data can
+ * become corrupt. LSB page recovery read is a way to read LSB page though page
+ * data are corrupted. When uncorrectable error occurs as a result of LSB page
+ * read after power up, issue LSB page recovery read.
+ */
+static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
+{
+ struct onenand_chip *this = mtd->priv;
+ int i;
+
+ /* Recovery is only for Flex-OneNAND */
+ if (!FLEXONENAND(this))
+ return status;
+
+ /* check if we failed due to uncorrectable error */
+ if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
+ return status;
+
+ /* check if address lies in MLC region */
+ i = flexonenand_region(mtd, addr);
+ if (mtd->eraseregions[i].erasesize < (1 << this->erase_shift))
+ return status;
+
+ printk("onenand_recover_lsb:"
+ "Attempting to recover from uncorrectable read\n");
+
+ /* Issue the LSB page recovery command */
+ this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr, this->writesize);
+ return this->wait(mtd, FL_READING);
+}
+
+/**
* onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
* @param mtd MTD device structure
* @param from offset to read from
@@ -673,6 +869,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats;
/* Read-while-load method */
+ /* Note: We can't use this feature in MLC */
/* Do first load to bufferRAM */
if (read < len) {
@@ -680,6 +877,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
this->main_buf = buf;
this->command(mtd, ONENAND_CMD_READ, from, writesize);
ret = this->wait(mtd, FL_READING);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
onenand_update_bufferram(mtd, from, !ret);
if (ret == -EBADMSG)
ret = 0;
@@ -694,7 +893,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
while (!ret) {
/* If there is more to load then start next load */
from += thislen;
- if (read + thislen < len) {
+ if (!ONENAND_IS_MLC(this) && read + thislen < len) {
this->main_buf = buf + thislen;
this->command(mtd, ONENAND_CMD_READ, from, writesize);
/*
@@ -728,6 +927,16 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
oobcolumn = 0;
}
+ if (ONENAND_IS_MLC(this) && (read + thislen < len)) {
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
+ ret = this->wait(mtd, FL_READING);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
+ onenand_update_bufferram(mtd, from, !ret);
+ if (ret == -EBADMSG)
+ ret = 0;
+ }
+
/* See if we are done */
read += thislen;
if (read == len)
@@ -735,16 +944,19 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
/* Set up for next read from bufferRAM */
if (unlikely(boundary))
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (!ONENAND_IS_MLC(this))
+ ONENAND_SET_NEXT_BUFFERRAM(this);
buf += thislen;
thislen = min_t(int, writesize, len - read);
column = 0;
- /* Now wait for load */
- ret = this->wait(mtd, FL_READING);
- onenand_update_bufferram(mtd, from, !ret);
- if (ret == -EBADMSG)
- ret = 0;
+ if (!ONENAND_IS_MLC(this)) {
+ /* Now wait for load */
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+ if (ret == -EBADMSG)
+ ret = 0;
+ }
}
/*
@@ -781,7 +993,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
size_t len = ops->ooblen;
mtd_oob_mode_t mode = ops->mode;
u_char *buf = ops->oobbuf;
- int ret = 0;
+ int ret = 0, readcmd;
from += ops->ooboffs;
@@ -812,16 +1024,21 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats;
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
while (read < len) {
thislen = oobsize - column;
thislen = min_t(int, thislen, len);
this->spare_buf = buf;
- this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+ this->command(mtd, readcmd, from, mtd->oobsize);
onenand_update_bufferram(mtd, from, 0);
ret = this->wait(mtd, FL_READING);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
+
if (ret && ret != -EBADMSG) {
printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
break;
@@ -945,9 +1162,12 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
if (interrupt & ONENAND_INT_READ) {
- int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
- if (ecc & ONENAND_ECC_2BIT_ALL)
+ int ecc = onenand_read_ecc(this);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x"
+ ", controller = 0x%04x\n", ecc, ctrl);
return ONENAND_BBT_READ_ERROR;
+ }
} else {
printk(KERN_ERR "onenand_bbt_wait: read timeout!"
"ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
@@ -976,12 +1196,14 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
{
struct onenand_chip *this = mtd->priv;
int read = 0, thislen, column;
- int ret = 0;
+ int ret = 0, readcmd;
size_t len = ops->ooblen;
u_char *buf = ops->oobbuf;
MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
/* Initialize return value */
ops->oobretlen = 0;
@@ -1002,11 +1224,14 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
thislen = min_t(int, thislen, len);
this->spare_buf = buf;
- this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+ this->command(mtd, readcmd, from, mtd->oobsize);
onenand_update_bufferram(mtd, from, 0);
ret = this->bbt_wait(mtd, FL_READING);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
+
if (ret)
break;
@@ -1044,9 +1269,11 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
{
struct onenand_chip *this = mtd->priv;
u_char *oob_buf = this->oob_buf;
- int status, i;
+ int status, i, readcmd;
- this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
+ this->command(mtd, readcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
status = this->wait(mtd, FL_READING);
if (status)
@@ -1291,7 +1518,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
{
struct onenand_chip *this = mtd->priv;
int column, ret = 0, oobsize;
- int written = 0;
+ int written = 0, oobcmd;
u_char *oobbuf;
size_t len = ops->ooblen;
const u_char *buf = ops->oobbuf;
@@ -1333,6 +1560,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
oobbuf = this->oob_buf;
+ oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
+
/* Loop until all data write */
while (written < len) {
int thislen = min_t(int, oobsize, len - written);
@@ -1348,7 +1577,14 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
memcpy(oobbuf + column, buf, thislen);
this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
- this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
+ if (ONENAND_IS_MLC(this)) {
+ /* Set main area of DataRAM to 0xff*/
+ memset(this->page_buf, 0xff, mtd->writesize);
+ this->write_bufferram(mtd, 0, ONENAND_DATARAM,
+ this->page_buf, 0, mtd->writesize);
+ }
+
+ this->command(mtd, oobcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
if (ONENAND_IS_2PLANE(this)) {
@@ -1475,34 +1711,54 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct onenand_chip *this = mtd->priv;
unsigned int block_size;
- loff_t addr;
- int len;
- int ret = 0;
-
- MTDDEBUG (MTD_DEBUG_LEVEL3,
- "onenand_erase: start = 0x%08x, len = %i\n",
- (unsigned int)instr->addr, (unsigned int)instr->len);
+ loff_t addr = instr->addr;
+ unsigned int len = instr->len;
+ int ret = 0, i;
+ struct mtd_erase_region_info *region = NULL;
+ unsigned int region_end = 0;
- block_size = (1 << this->erase_shift);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
+ (unsigned int) addr, len);
- /* Start address must align on block boundary */
- if (unlikely(instr->addr & (block_size - 1))) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Unaligned address\n");
+ /* Do not allow erase past end of device */
+ if (unlikely((len + addr) > mtd->size)) {
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
+ "Erase past end of device\n");
return -EINVAL;
}
- /* Length must align on block boundary */
- if (unlikely(instr->len & (block_size - 1))) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Length not block aligned\n");
- return -EINVAL;
+ if (FLEXONENAND(this)) {
+ /* Find the eraseregion of this address */
+ i = flexonenand_region(mtd, addr);
+ region = &mtd->eraseregions[i];
+
+ block_size = region->erasesize;
+ region_end = region->offset
+ + region->erasesize * region->numblocks;
+
+ /* Start address within region must align on block boundary.
+ * Erase region's start offset is always block start address.
+ */
+ if (unlikely((addr - region->offset) & (block_size - 1))) {
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
+ " Unaligned address\n");
+ return -EINVAL;
+ }
+ } else {
+ block_size = 1 << this->erase_shift;
+
+ /* Start address must align on block boundary */
+ if (unlikely(addr & (block_size - 1))) {
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
+ "Unaligned address\n");
+ return -EINVAL;
+ }
}
- /* Do not allow erase past end of device */
- if (unlikely((instr->len + instr->addr) > mtd->size)) {
+ /* Length must align on block boundary */
+ if (unlikely(len & (block_size - 1))) {
MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Erase past end of device\n");
+ "onenand_erase: Length not block aligned\n");
return -EINVAL;
}
@@ -1512,9 +1768,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
onenand_get_device(mtd, FL_ERASING);
/* Loop throught the pages */
- len = instr->len;
- addr = instr->addr;
-
instr->state = MTD_ERASING;
while (len) {
@@ -1541,14 +1794,7 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
else
MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
"Failed erase, block %d\n",
- (unsigned)(addr >> this->erase_shift));
- if (ret == -EPERM)
- printk("onenand_erase: "
- "Device is write protected!!!\n");
- else
- printk("onenand_erase: "
- "Failed erase, block %d\n",
- (unsigned)(addr >> this->erase_shift));
+ onenand_block(this, addr));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
@@ -1557,6 +1803,23 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
len -= block_size;
addr += block_size;
+
+ if (addr == region_end) {
+ if (!len)
+ break;
+ region++;
+
+ block_size = region->erasesize;
+ region_end = region->offset
+ + region->erasesize * region->numblocks;
+
+ if (len & (block_size - 1)) {
+ /* This has been checked at MTD
+ * partitioning level. */
+ printk("onenand_erase: Unaligned address\n");
+ goto erase_exit;
+ }
+ }
}
instr->state = MTD_ERASE_DONE;
@@ -1634,7 +1897,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
int block;
/* Get block number */
- block = ((int) ofs) >> bbm->bbt_erase_shift;
+ block = onenand_block(this, ofs);
if (bbm->bbt)
bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
@@ -1682,8 +1945,8 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
int start, end, block, value, status;
int wp_status_mask;
- start = ofs >> this->erase_shift;
- end = len >> this->erase_shift;
+ start = onenand_block(this, ofs);
+ end = onenand_block(this, ofs + len);
if (cmd == ONENAND_CMD_LOCK)
wp_status_mask = ONENAND_WP_LS;
@@ -1718,7 +1981,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
}
/* Block lock scheme */
- for (block = start; block < start + end; block++) {
+ for (block = start; block < end; block++) {
/* Set block address */
value = onenand_block_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
@@ -1831,7 +2094,7 @@ static void onenand_unlock_all(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
loff_t ofs = 0;
- size_t len = this->chipsize;
+ size_t len = mtd->size;
if (this->options & ONENAND_HAS_UNLOCK_ALL) {
/* Set start block address */
@@ -1847,14 +2110,12 @@ static void onenand_unlock_all(struct mtd_info *mtd)
& ONENAND_CTRL_ONGO)
continue;
- return;
-
/* Check lock status */
if (onenand_check_lock_status(this))
return;
/* Workaround for all block unlock in DDP */
- if (ONENAND_IS_DDP(this)) {
+ if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
/* All blocks on another chip */
ofs = this->chipsize >> 1;
len = this->chipsize >> 1;
@@ -1906,6 +2167,14 @@ static void onenand_check_features(struct mtd_info *mtd)
break;
}
+ if (ONENAND_IS_MLC(this))
+ this->options &= ~ONENAND_HAS_2PLANE;
+
+ if (FLEXONENAND(this)) {
+ this->options &= ~ONENAND_HAS_CONT_LOCK;
+ this->options |= ONENAND_HAS_UNLOCK_ALL;
+ }
+
if (this->options & ONENAND_HAS_CONT_LOCK)
printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
if (this->options & ONENAND_HAS_UNLOCK_ALL)
@@ -1922,16 +2191,18 @@ static void onenand_check_features(struct mtd_info *mtd)
*/
char *onenand_print_device_info(int device, int version)
{
- int vcc, demuxed, ddp, density;
+ int vcc, demuxed, ddp, density, flexonenand;
char *dev_info = malloc(80);
char *p = dev_info;
vcc = device & ONENAND_DEVICE_VCC_MASK;
demuxed = device & ONENAND_DEVICE_IS_DEMUX;
ddp = device & ONENAND_DEVICE_IS_DDP;
- density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
- p += sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
+ density = onenand_get_density(device);
+ flexonenand = device & DEVICE_IS_FLEXONENAND;
+ p += sprintf(dev_info, "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
demuxed ? "" : "Muxed ",
+ flexonenand ? "Flex-" : "",
ddp ? "(DDP)" : "",
(16 << density), vcc ? "2.65/3.3" : "1.8", device);
@@ -1957,7 +2228,7 @@ static int onenand_check_maf(int manuf)
char *name;
int i;
- for (i = 0; size; i++)
+ for (i = 0; i < size; i++)
if (manuf == onenand_manuf_ids[i].id)
break;
@@ -1974,6 +2245,265 @@ static int onenand_check_maf(int manuf)
}
/**
+* flexonenand_get_boundary - Reads the SLC boundary
+* @param onenand_info - onenand info structure
+*
+* Fill up boundary[] field in onenand_chip
+**/
+static int flexonenand_get_boundary(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned int die, bdry;
+ int ret, syscfg, locked;
+
+ /* Disable ECC */
+ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
+ this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
+
+ for (die = 0; die < this->dies; die++) {
+ this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
+ this->wait(mtd, FL_SYNCING);
+
+ this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
+ ret = this->wait(mtd, FL_READING);
+
+ bdry = this->read_word(this->base + ONENAND_DATARAM);
+ if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
+ locked = 0;
+ else
+ locked = 1;
+ this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
+
+ this->command(mtd, ONENAND_CMD_RESET, 0, 0);
+ ret = this->wait(mtd, FL_RESETING);
+
+ printk(KERN_INFO "Die %d boundary: %d%s\n", die,
+ this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
+ }
+
+ /* Enable ECC */
+ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
+ return 0;
+}
+
+/**
+ * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
+ * boundary[], diesize[], mtd->size, mtd->erasesize,
+ * mtd->eraseregions
+ * @param mtd - MTD device structure
+ */
+static void flexonenand_get_size(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ int die, i, eraseshift, density;
+ int blksperdie, maxbdry;
+ loff_t ofs;
+
+ density = onenand_get_density(this->device_id);
+ blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
+ blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
+ maxbdry = blksperdie - 1;
+ eraseshift = this->erase_shift - 1;
+
+ mtd->numeraseregions = this->dies << 1;
+
+ /* This fills up the device boundary */
+ flexonenand_get_boundary(mtd);
+ die = 0;
+ ofs = 0;
+ i = -1;
+ for (; die < this->dies; die++) {
+ if (!die || this->boundary[die-1] != maxbdry) {
+ i++;
+ mtd->eraseregions[i].offset = ofs;
+ mtd->eraseregions[i].erasesize = 1 << eraseshift;
+ mtd->eraseregions[i].numblocks =
+ this->boundary[die] + 1;
+ ofs += mtd->eraseregions[i].numblocks << eraseshift;
+ eraseshift++;
+ } else {
+ mtd->numeraseregions -= 1;
+ mtd->eraseregions[i].numblocks +=
+ this->boundary[die] + 1;
+ ofs += (this->boundary[die] + 1) << (eraseshift - 1);
+ }
+ if (this->boundary[die] != maxbdry) {
+ i++;
+ mtd->eraseregions[i].offset = ofs;
+ mtd->eraseregions[i].erasesize = 1 << eraseshift;
+ mtd->eraseregions[i].numblocks = maxbdry ^
+ this->boundary[die];
+ ofs += mtd->eraseregions[i].numblocks << eraseshift;
+ eraseshift--;
+ } else
+ mtd->numeraseregions -= 1;
+ }
+
+ /* Expose MLC erase size except when all blocks are SLC */
+ mtd->erasesize = 1 << this->erase_shift;
+ if (mtd->numeraseregions == 1)
+ mtd->erasesize >>= 1;
+
+ printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
+ for (i = 0; i < mtd->numeraseregions; i++)
+ printk(KERN_INFO "[offset: 0x%08llx, erasesize: 0x%05x,"
+ " numblocks: %04u]\n", mtd->eraseregions[i].offset,
+ mtd->eraseregions[i].erasesize,
+ mtd->eraseregions[i].numblocks);
+
+ for (die = 0, mtd->size = 0; die < this->dies; die++) {
+ this->diesize[die] = (loff_t) (blksperdie << this->erase_shift);
+ this->diesize[die] -= (loff_t) (this->boundary[die] + 1)
+ << (this->erase_shift - 1);
+ mtd->size += this->diesize[die];
+ }
+}
+
+/**
+ * flexonenand_check_blocks_erased - Check if blocks are erased
+ * @param mtd_info - mtd info structure
+ * @param start - first erase block to check
+ * @param end - last erase block to check
+ *
+ * Converting an unerased block from MLC to SLC
+ * causes byte values to change. Since both data and its ECC
+ * have changed, reads on the block give uncorrectable error.
+ * This might lead to the block being detected as bad.
+ *
+ * Avoid this by ensuring that the block to be converted is
+ * erased.
+ */
+static int flexonenand_check_blocks_erased(struct mtd_info *mtd,
+ int start, int end)
+{
+ struct onenand_chip *this = mtd->priv;
+ int i, ret;
+ int block;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OOB_PLACE,
+ .ooboffs = 0,
+ .ooblen = mtd->oobsize,
+ .datbuf = NULL,
+ .oobbuf = this->oob_buf,
+ };
+ loff_t addr;
+
+ printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
+
+ for (block = start; block <= end; block++) {
+ addr = flexonenand_addr(this, block);
+ if (onenand_block_isbad_nolock(mtd, addr, 0))
+ continue;
+
+ /*
+ * Since main area write results in ECC write to spare,
+ * it is sufficient to check only ECC bytes for change.
+ */
+ ret = onenand_read_oob_nolock(mtd, addr, &ops);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < mtd->oobsize; i++)
+ if (this->oob_buf[i] != 0xff)
+ break;
+
+ if (i != mtd->oobsize) {
+ printk(KERN_WARNING "Block %d not erased.\n", block);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * flexonenand_set_boundary - Writes the SLC boundary
+ * @param mtd - mtd info structure
+ */
+int flexonenand_set_boundary(struct mtd_info *mtd, int die,
+ int boundary, int lock)
+{
+ struct onenand_chip *this = mtd->priv;
+ int ret, density, blksperdie, old, new, thisboundary;
+ loff_t addr;
+
+ if (die >= this->dies)
+ return -EINVAL;
+
+ if (boundary == this->boundary[die])
+ return 0;
+
+ density = onenand_get_density(this->device_id);
+ blksperdie = ((16 << density) << 20) >> this->erase_shift;
+ blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
+
+ if (boundary >= blksperdie) {
+ printk("flexonenand_set_boundary:"
+ "Invalid boundary value. "
+ "Boundary not changed.\n");
+ return -EINVAL;
+ }
+
+ /* Check if converting blocks are erased */
+ old = this->boundary[die] + (die * this->density_mask);
+ new = boundary + (die * this->density_mask);
+ ret = flexonenand_check_blocks_erased(mtd, min(old, new)
+ + 1, max(old, new));
+ if (ret) {
+ printk(KERN_ERR "flexonenand_set_boundary: Please erase blocks before boundary change\n");
+ return ret;
+ }
+
+ this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
+ this->wait(mtd, FL_SYNCING);
+
+ /* Check is boundary is locked */
+ this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
+ ret = this->wait(mtd, FL_READING);
+
+ thisboundary = this->read_word(this->base + ONENAND_DATARAM);
+ if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
+ printk(KERN_ERR "flexonenand_set_boundary: boundary locked\n");
+ goto out;
+ }
+
+ printk(KERN_INFO "flexonenand_set_boundary: Changing die %d boundary: %d%s\n",
+ die, boundary, lock ? "(Locked)" : "(Unlocked)");
+
+ boundary &= FLEXONENAND_PI_MASK;
+ boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
+
+ addr = die ? this->diesize[0] : 0;
+ this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
+ ret = this->wait(mtd, FL_ERASING);
+ if (ret) {
+ printk("flexonenand_set_boundary:"
+ "Failed PI erase for Die %d\n", die);
+ goto out;
+ }
+
+ this->write_word(boundary, this->base + ONENAND_DATARAM);
+ this->command(mtd, ONENAND_CMD_PROG, addr, 0);
+ ret = this->wait(mtd, FL_WRITING);
+ if (ret) {
+ printk("flexonenand_set_boundary:"
+ "Failed PI write for Die %d\n", die);
+ goto out;
+ }
+
+ this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
+ ret = this->wait(mtd, FL_WRITING);
+out:
+ this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
+ this->wait(mtd, FL_RESETING);
+ if (!ret)
+ /* Recalculate device size on boundary change*/
+ flexonenand_get_size(mtd);
+
+ return ret;
+}
+
+/**
* onenand_probe - [OneNAND Interface] Probe the OneNAND device
* @param mtd MTD device structure
*
@@ -2016,48 +2546,69 @@ static int onenand_probe(struct mtd_info *mtd)
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
+ this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
/* Check OneNAND device */
if (maf_id != bram_maf_id || dev_id != bram_dev_id)
return -ENXIO;
- /* FIXME : Current OneNAND MTD doesn't support Flex-OneNAND */
- if (dev_id & (1 << 9)) {
- printk("Not yet support Flex-OneNAND\n");
- return -ENXIO;
- }
-
/* Flash device information */
mtd->name = onenand_print_device_info(dev_id, ver_id);
this->device_id = dev_id;
this->version_id = ver_id;
density = onenand_get_density(dev_id);
+ if (FLEXONENAND(this)) {
+ this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
+ /* Maximum possible erase regions */
+ mtd->numeraseregions = this->dies << 1;
+ mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info)
+ * (this->dies << 1));
+ if (!mtd->eraseregions)
+ return -ENOMEM;
+ }
+
+ /*
+ * For Flex-OneNAND, chipsize represents maximum possible device size.
+ * mtd->size represents the actual device size.
+ */
this->chipsize = (16 << density) << 20;
- /* Set density mask. it is used for DDP */
- if (ONENAND_IS_DDP(this))
- this->density_mask = (1 << (density + 6));
- else
- this->density_mask = 0;
/* OneNAND page size & block size */
/* The data buffer size is equal to page size */
mtd->writesize =
this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
+ /* We use the full BufferRAM */
+ if (ONENAND_IS_MLC(this))
+ mtd->writesize <<= 1;
+
mtd->oobsize = mtd->writesize >> 5;
/* Pagers per block is always 64 in OneNAND */
mtd->erasesize = mtd->writesize << 6;
+ /*
+ * Flex-OneNAND SLC area has 64 pages per block.
+ * Flex-OneNAND MLC area has 128 pages per block.
+ * Expose MLC erase size to find erase_shift and page_mask.
+ */
+ if (FLEXONENAND(this))
+ mtd->erasesize <<= 1;
this->erase_shift = ffs(mtd->erasesize) - 1;
this->page_shift = ffs(mtd->writesize) - 1;
this->ppb_shift = (this->erase_shift - this->page_shift);
this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
+ /* Set density mask. it is used for DDP */
+ if (ONENAND_IS_DDP(this))
+ this->density_mask = this->chipsize >> (this->erase_shift + 1);
/* It's real page size */
this->writesize = mtd->writesize;
/* REVIST: Multichip handling */
- mtd->size = this->chipsize;
+ if (FLEXONENAND(this))
+ flexonenand_get_size(mtd);
+ else
+ mtd->size = this->chipsize;
/* Check OneNAND features */
onenand_check_features(mtd);
@@ -2149,6 +2700,11 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
* Allow subpage writes up to oobsize.
*/
switch (mtd->oobsize) {
+ case 128:
+ this->ecclayout = &onenand_oob_128;
+ mtd->subpage_sft = 0;
+ break;
+
case 64:
this->ecclayout = &onenand_oob_64;
mtd->subpage_sft = 2;
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index d538f9582..135487772 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -69,6 +69,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
loff_t from;
size_t readlen, ooblen;
struct mtd_oob_ops ops;
+ int rgn;
printk(KERN_INFO "Scanning device for bad blocks\n");
@@ -82,7 +83,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
/* Note that numblocks is 2 * (real numblocks) here;
* see i += 2 below as it makses shifting and masking less painful
*/
- numblocks = mtd->size >> (bbm->bbt_erase_shift - 1);
+ numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1);
startblock = 0;
from = 0;
@@ -115,7 +116,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
}
}
i += 2;
- from += (1 << bbm->bbt_erase_shift);
+
+ if (FLEXONENAND(this)) {
+ rgn = flexonenand_region(mtd, from);
+ from += mtd->eraseregions[rgn].erasesize;
+ } else
+ from += (1 << bbm->bbt_erase_shift);
}
return 0;
@@ -152,7 +158,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
uint8_t res;
/* Get block number * 2 */
- block = (int)(offs >> (bbm->bbt_erase_shift - 1));
+ block = (int) (onenand_block(this, offs) << 1);
res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
MTDDEBUG (MTD_DEBUG_LEVEL2,
@@ -191,7 +197,7 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
struct bbm_info *bbm = this->bbm;
int len, ret = 0;
- len = mtd->size >> (this->erase_shift + 2);
+ len = this->chipsize >> (this->erase_shift + 2);
/* Allocate memory (2bit per block) */
bbm->bbt = malloc(len);
if (!bbm->bbt) {
diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c
index 9823b5b47..c642016c2 100644
--- a/drivers/mtd/onenand/onenand_uboot.c
+++ b/drivers/mtd/onenand/onenand_uboot.c
@@ -40,8 +40,10 @@ void onenand_init(void)
onenand_scan(&onenand_mtd, 1);
+ if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND)
+ puts("Flex-");
puts("OneNAND: ");
- print_size(onenand_mtd.size, "\n");
+ print_size(onenand_chip.chipsize, "\n");
#ifdef CONFIG_MTD_DEVICE
/*
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fc9887b51..904727e1b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -44,7 +44,7 @@ COBJS-$(CONFIG_GRETH) += greth.o
COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
COBJS-$(CONFIG_KIRKWOOD_EGIGA) += kirkwood_egiga.o
COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
-COBJS-$(CONFIG_DRIVER_LAN91C96) += lan91c96.o
+COBJS-$(CONFIG_LAN91C96) += lan91c96.o
COBJS-$(CONFIG_MACB) += macb.o
COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c
index 73dd33572..a7fef5603 100644
--- a/drivers/net/dm9000x.c
+++ b/drivers/net/dm9000x.c
@@ -75,7 +75,7 @@ TODO: external MII is not functional, only internal at the moment.
#define DM9000_DMP_PACKET(func,packet,length) \
do { \
int i; \
- printf(func ": length: %d\n", length); \
+ printf("%s: length: %d\n", func, length); \
for (i = 0; i < length; i++) { \
if (i % 8 == 0) \
printf("\n%s: %02x: ", func, i); \
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 7f9f783c4..2825342ff 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -79,6 +79,7 @@ static struct pci_device_id supported[] = {
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_COPPER},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546GB_COPPER},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541GI_LF},
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index ad073077c..19116f253 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -450,6 +450,7 @@ static int fec_init(struct eth_device *dev, bd_t* bd)
*/
if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) {
free(fec->base_ptr);
+ fec->base_ptr = NULL;
return -ENOMEM;
}
fec_tbd_init(fec);
diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c
index 65565bcb0..90e400249 100644
--- a/drivers/net/lan91c96.c
+++ b/drivers/net/lan91c96.c
@@ -60,6 +60,7 @@
#include <common.h>
#include <command.h>
+#include <malloc.h>
#include "lan91c96.h"
#include <net.h>
@@ -108,11 +109,7 @@
*
*------------------------------------------------------------------------
*/
-#define CARDNAME "LAN91C96"
-
-#define SMC_BASE_ADDRESS CONFIG_LAN91C96_BASE
-
-#define SMC_DEV_NAME "LAN91C96"
+#define DRIVER_NAME "LAN91C96"
#define SMC_ALLOC_MAX_TRY 5
#define SMC_TX_TIMEOUT 30
@@ -124,64 +121,12 @@
#undef USE_32_BIT
#endif
-/*-----------------------------------------------------------------
- *
- * The driver can be entered at any of the following entry points.
- *
- *-----------------------------------------------------------------
- */
-
-extern int eth_init (bd_t * bd);
-extern void eth_halt (void);
-extern int eth_rx (void);
-extern int eth_send (volatile void *packet, int length);
-#if 0
-static int smc_hw_init (void);
-#endif
-
-/*
- * This is called by register_netdev(). It is responsible for
- * checking the portlist for the SMC9000 series chipset. If it finds
- * one, then it will initialize the device, find the hardware information,
- * and sets up the appropriate device parameters.
- * NOTE: Interrupts are *OFF* when this procedure is called.
- *
- * NB:This shouldn't be static since it is referred to externally.
- */
-int smc_init (void);
-
-/*
- * This is called by unregister_netdev(). It is responsible for
- * cleaning up before the driver is finally unregistered and discarded.
- */
-void smc_destructor (void);
-
-/*
- * The kernel calls this function when someone wants to use the device,
- * typically 'ifconfig ethX up'.
- */
-static int smc_open (bd_t *bd);
-
-
-/*
- * This is called by the kernel in response to 'ifconfig ethX down'. It
- * is responsible for cleaning up everything that the open routine
- * does, and maybe putting the card into a powerdown state.
- */
-static int smc_close (void);
-
-/*
- * This is a separate procedure to handle the receipt of a packet, to
- * leave the interrupt code looking slightly cleaner
- */
-static int smc_rcv (void);
-
/* See if a MAC address is defined in the current environment. If so use it. If not
. print a warning and set the environment and other globals with the default.
. If an EEPROM is present it really should be consulted.
*/
-int smc_get_ethaddr(bd_t *bd);
-int get_rom_mac(unsigned char *v_rom_mac);
+static int smc_get_ethaddr(bd_t *bd, struct eth_device *dev);
+static int get_rom_mac(struct eth_device *dev, unsigned char *v_rom_mac);
/* ------------------------------------------------------------
* Internal routines
@@ -195,7 +140,7 @@ static unsigned char smc_mac_addr[] = { 0xc0, 0x00, 0x00, 0x1b, 0x62, 0x9c };
* the default mac address.
*/
-void smc_set_mac_addr (const unsigned char *addr)
+static void smc_set_mac_addr(const unsigned char *addr)
{
int i;
@@ -204,45 +149,21 @@ void smc_set_mac_addr (const unsigned char *addr)
}
}
-/*
- * smc_get_macaddr is no longer used. If you want to override the default
- * mac address, call smc_get_mac_addr as a part of the board initialisation.
- */
-
-#if 0
-void smc_get_macaddr (byte * addr)
-{
- /* MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10 */
- unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010);
- int i;
-
-
- for (i = 0; i < 6; i++) {
- addr[0] = *(dnp1110_mac + 0);
- addr[1] = *(dnp1110_mac + 1);
- addr[2] = *(dnp1110_mac + 2);
- addr[3] = *(dnp1110_mac + 3);
- addr[4] = *(dnp1110_mac + 4);
- addr[5] = *(dnp1110_mac + 5);
- }
-}
-#endif /* 0 */
-
/***********************************************
* Show available memory *
***********************************************/
-void dump_memory_info (void)
+void dump_memory_info(struct eth_device *dev)
{
word mem_info;
word old_bank;
- old_bank = SMC_inw (LAN91C96_BANK_SELECT) & 0xF;
+ old_bank = SMC_inw(dev, LAN91C96_BANK_SELECT) & 0xF;
- SMC_SELECT_BANK (0);
- mem_info = SMC_inw (LAN91C96_MIR);
+ SMC_SELECT_BANK(dev, 0);
+ mem_info = SMC_inw(dev, LAN91C96_MIR);
PRINTK2 ("Memory: %4d available\n", (mem_info >> 8) * 2048);
- SMC_SELECT_BANK (old_bank);
+ SMC_SELECT_BANK(dev, old_bank);
}
/*
@@ -252,28 +173,15 @@ void dump_memory_info (void)
static void print_packet (byte *, int);
#endif
-/* #define tx_done(dev) 1 */
-
-
-/* this does a soft reset on the device */
-static void smc_reset (void);
-
-/* Enable Interrupts, Receive, and Transmit */
-static void smc_enable (void);
-
-/* this puts the device in an inactive state */
-static void smc_shutdown (void);
-
-
-static int poll4int (byte mask, int timeout)
+static int poll4int (struct eth_device *dev, byte mask, int timeout)
{
int tmo = get_timer (0) + timeout * CONFIG_SYS_HZ;
int is_timeout = 0;
- word old_bank = SMC_inw (LAN91C96_BANK_SELECT);
+ word old_bank = SMC_inw(dev, LAN91C96_BANK_SELECT);
PRINTK2 ("Polling...\n");
- SMC_SELECT_BANK (2);
- while ((SMC_inw (LAN91C96_INT_STATS) & mask) == 0) {
+ SMC_SELECT_BANK(dev, 2);
+ while ((SMC_inw(dev, LAN91C96_INT_STATS) & mask) == 0) {
if (get_timer (0) >= tmo) {
is_timeout = 1;
break;
@@ -281,7 +189,7 @@ static int poll4int (byte mask, int timeout)
}
/* restore old bank selection */
- SMC_SELECT_BANK (old_bank);
+ SMC_SELECT_BANK(dev, old_bank);
if (is_timeout)
return 1;
@@ -290,7 +198,7 @@ static int poll4int (byte mask, int timeout)
}
/*
- * Function: smc_reset( void )
+ * Function: smc_reset
* Purpose:
* This sets the SMC91111 chip to its normal state, hopefully from whatever
* mess that any other DOS driver has put it in.
@@ -306,28 +214,28 @@ static int poll4int (byte mask, int timeout)
* 5. clear all interrupts
*
*/
-static void smc_reset (void)
+static void smc_reset(struct eth_device *dev)
{
- PRINTK2 ("%s:smc_reset\n", SMC_DEV_NAME);
+ PRINTK2("%s:smc_reset\n", dev->name);
/* This resets the registers mostly to defaults, but doesn't
affect EEPROM. That seems unnecessary */
- SMC_SELECT_BANK (0);
- SMC_outw (LAN91C96_RCR_SOFT_RST, LAN91C96_RCR);
+ SMC_SELECT_BANK(dev, 0);
+ SMC_outw(dev, LAN91C96_RCR_SOFT_RST, LAN91C96_RCR);
udelay (10);
/* Disable transmit and receive functionality */
- SMC_outw (0, LAN91C96_RCR);
- SMC_outw (0, LAN91C96_TCR);
+ SMC_outw(dev, 0, LAN91C96_RCR);
+ SMC_outw(dev, 0, LAN91C96_TCR);
/* set the control register */
- SMC_SELECT_BANK (1);
- SMC_outw (SMC_inw (LAN91C96_CONTROL) | LAN91C96_CTR_BIT_8,
+ SMC_SELECT_BANK(dev, 1);
+ SMC_outw(dev, SMC_inw(dev, LAN91C96_CONTROL) | LAN91C96_CTR_BIT_8,
LAN91C96_CONTROL);
/* Disable all interrupts */
- SMC_outb (0, LAN91C96_INT_MASK);
+ SMC_outb(dev, 0, LAN91C96_INT_MASK);
}
/*
@@ -338,24 +246,24 @@ static void smc_reset (void)
* 2. Enable the transmitter
* 3. Enable the receiver
*/
-static void smc_enable ()
+static void smc_enable(struct eth_device *dev)
{
- PRINTK2 ("%s:smc_enable\n", SMC_DEV_NAME);
- SMC_SELECT_BANK (0);
+ PRINTK2("%s:smc_enable\n", dev->name);
+ SMC_SELECT_BANK(dev, 0);
/* Initialize the Memory Configuration Register. See page
49 of the LAN91C96 data sheet for details. */
- SMC_outw (LAN91C96_MCR_TRANSMIT_PAGES, LAN91C96_MCR);
+ SMC_outw(dev, LAN91C96_MCR_TRANSMIT_PAGES, LAN91C96_MCR);
/* Initialize the Transmit Control Register */
- SMC_outw (LAN91C96_TCR_TXENA, LAN91C96_TCR);
+ SMC_outw(dev, LAN91C96_TCR_TXENA, LAN91C96_TCR);
/* Initialize the Receive Control Register
* FIXME:
* The promiscuous bit set because I could not receive ARP reply
* packets from the server when I send a ARP request. It only works
* when I set the promiscuous bit
*/
- SMC_outw (LAN91C96_RCR_RXEN | LAN91C96_RCR_PRMS, LAN91C96_RCR);
+ SMC_outw(dev, LAN91C96_RCR_RXEN | LAN91C96_RCR_PRMS, LAN91C96_RCR);
}
/*
@@ -372,18 +280,18 @@ static void smc_enable ()
* the manual says that it will wake up in response to any I/O requests
* in the register space. Empirical results do not show this working.
*/
-static void smc_shutdown ()
+static void smc_shutdown(struct eth_device *dev)
{
- PRINTK2 (CARDNAME ":smc_shutdown\n");
+ PRINTK2("%s:smc_shutdown\n", dev->name);
/* no more interrupts for me */
- SMC_SELECT_BANK (2);
- SMC_outb (0, LAN91C96_INT_MASK);
+ SMC_SELECT_BANK(dev, 2);
+ SMC_outb(dev, 0, LAN91C96_INT_MASK);
/* and tell the card to stay away from that nasty outside world */
- SMC_SELECT_BANK (0);
- SMC_outb (0, LAN91C96_RCR);
- SMC_outb (0, LAN91C96_TCR);
+ SMC_SELECT_BANK(dev, 0);
+ SMC_outb(dev, 0, LAN91C96_RCR);
+ SMC_outb(dev, 0, LAN91C96_TCR);
}
@@ -405,7 +313,8 @@ static void smc_shutdown ()
* Enable the transmit interrupt, so I know if it failed
* Free the kernel data if I actually sent it.
*/
-static int smc_send_packet (volatile void *packet, int packet_length)
+static int smc_send_packet(struct eth_device *dev, volatile void *packet,
+ int packet_length)
{
byte packet_no;
unsigned long ioaddr;
@@ -417,7 +326,7 @@ static int smc_send_packet (volatile void *packet, int packet_length)
byte status;
- PRINTK3 ("%s:smc_hardware_send_packet\n", SMC_DEV_NAME);
+ PRINTK3("%s:smc_hardware_send_packet\n", dev->name);
length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
@@ -437,30 +346,31 @@ static int smc_send_packet (volatile void *packet, int packet_length)
numPages >>= 8; /* Divide by 256 */
if (numPages > 7) {
- printf ("%s: Far too big packet error. \n", SMC_DEV_NAME);
+ printf("%s: Far too big packet error. \n", dev->name);
return 0;
}
/* now, try to allocate the memory */
- SMC_SELECT_BANK (2);
- SMC_outw (LAN91C96_MMUCR_ALLOC_TX | numPages, LAN91C96_MMU);
+ SMC_SELECT_BANK(dev, 2);
+ SMC_outw(dev, LAN91C96_MMUCR_ALLOC_TX | numPages, LAN91C96_MMU);
again:
try++;
time_out = MEMORY_WAIT_TIME;
do {
- status = SMC_inb (LAN91C96_INT_STATS);
+ status = SMC_inb(dev, LAN91C96_INT_STATS);
if (status & LAN91C96_IST_ALLOC_INT) {
- SMC_outb (LAN91C96_IST_ALLOC_INT, LAN91C96_INT_STATS);
+ SMC_outb(dev, LAN91C96_IST_ALLOC_INT,
+ LAN91C96_INT_STATS);
break;
}
} while (--time_out);
if (!time_out) {
PRINTK2 ("%s: memory allocation, try %d failed ...\n",
- SMC_DEV_NAME, try);
+ dev->name, try);
if (try < SMC_ALLOC_MAX_TRY)
goto again;
else
@@ -468,30 +378,30 @@ static int smc_send_packet (volatile void *packet, int packet_length)
}
PRINTK2 ("%s: memory allocation, try %d succeeded ...\n",
- SMC_DEV_NAME, try);
+ dev->name, try);
/* I can send the packet now.. */
- ioaddr = SMC_BASE_ADDRESS;
+ ioaddr = dev->iobase;
buf = (byte *) packet;
/* If I get here, I _know_ there is a packet slot waiting for me */
- packet_no = SMC_inb (LAN91C96_ARR);
+ packet_no = SMC_inb(dev, LAN91C96_ARR);
if (packet_no & LAN91C96_ARR_FAILED) {
/* or isn't there? BAD CHIP! */
- printf ("%s: Memory allocation failed. \n", SMC_DEV_NAME);
+ printf("%s: Memory allocation failed. \n", dev->name);
return 0;
}
/* we have a packet address, so tell the card to use it */
- SMC_outb (packet_no, LAN91C96_PNR);
+ SMC_outb(dev, packet_no, LAN91C96_PNR);
/* point to the beginning of the packet */
- SMC_outw (LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
+ SMC_outw(dev, LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
- PRINTK3 ("%s: Trying to xmit packet of length %x\n",
- SMC_DEV_NAME, length);
+ PRINTK3("%s: Trying to xmit packet of length %x\n",
+ dev->name, length);
#if SMC_DEBUG > 2
printf ("Transmitting Packet\n");
@@ -501,11 +411,11 @@ static int smc_send_packet (volatile void *packet, int packet_length)
/* send the packet length ( +6 for status, length and ctl byte )
and the status word ( set to zeros ) */
#ifdef USE_32_BIT
- SMC_outl ((length + 6) << 16, LAN91C96_DATA_HIGH);
+ SMC_outl(dev, (length + 6) << 16, LAN91C96_DATA_HIGH);
#else
- SMC_outw (0, LAN91C96_DATA_HIGH);
+ SMC_outw(dev, 0, LAN91C96_DATA_HIGH);
/* send the packet length ( +6 for status words, length, and ctl */
- SMC_outw ((length + 6), LAN91C96_DATA_HIGH);
+ SMC_outw(dev, (length + 6), LAN91C96_DATA_HIGH);
#endif /* USE_32_BIT */
/* send the actual data
@@ -516,54 +426,52 @@ static int smc_send_packet (volatile void *packet, int packet_length)
* almost as much time as is saved?
*/
#ifdef USE_32_BIT
- SMC_outsl (LAN91C96_DATA_HIGH, buf, length >> 2);
+ SMC_outsl(dev, LAN91C96_DATA_HIGH, buf, length >> 2);
if (length & 0x2)
- SMC_outw (*((word *) (buf + (length & 0xFFFFFFFC))),
+ SMC_outw(dev, *((word *) (buf + (length & 0xFFFFFFFC))),
LAN91C96_DATA_HIGH);
#else
- SMC_outsw (LAN91C96_DATA_HIGH, buf, (length) >> 1);
+ SMC_outsw(dev, LAN91C96_DATA_HIGH, buf, (length) >> 1);
#endif /* USE_32_BIT */
/* Send the last byte, if there is one. */
if ((length & 1) == 0) {
- SMC_outw (0, LAN91C96_DATA_HIGH);
+ SMC_outw(dev, 0, LAN91C96_DATA_HIGH);
} else {
- SMC_outw (buf[length - 1] | 0x2000, LAN91C96_DATA_HIGH);
+ SMC_outw(dev, buf[length - 1] | 0x2000, LAN91C96_DATA_HIGH);
}
/* and let the chipset deal with it */
- SMC_outw (LAN91C96_MMUCR_ENQUEUE, LAN91C96_MMU);
+ SMC_outw(dev, LAN91C96_MMUCR_ENQUEUE, LAN91C96_MMU);
/* poll for TX INT */
- if (poll4int (LAN91C96_MSK_TX_INT, SMC_TX_TIMEOUT)) {
+ if (poll4int (dev, LAN91C96_MSK_TX_INT, SMC_TX_TIMEOUT)) {
/* sending failed */
- PRINTK2 ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME);
+ PRINTK2("%s: TX timeout, sending failed...\n", dev->name);
/* release packet */
- SMC_outw (LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+ SMC_outw(dev, LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
/* wait for MMU getting ready (low) */
- while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY) {
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
udelay (10);
- }
- PRINTK2 ("MMU ready\n");
+ PRINTK2("MMU ready\n");
return 0;
} else {
/* ack. int */
- SMC_outw (LAN91C96_IST_TX_INT, LAN91C96_INT_STATS);
+ SMC_outw(dev, LAN91C96_IST_TX_INT, LAN91C96_INT_STATS);
- PRINTK2 ("%s: Sent packet of length %d \n", SMC_DEV_NAME, length);
+ PRINTK2("%s: Sent packet of length %d \n", dev->name, length);
/* release packet */
- SMC_outw (LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+ SMC_outw(dev, LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
/* wait for MMU getting ready (low) */
- while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY) {
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
udelay (10);
- }
PRINTK2 ("MMU ready\n");
}
@@ -571,20 +479,6 @@ static int smc_send_packet (volatile void *packet, int packet_length)
return length;
}
-/*-------------------------------------------------------------------------
- * smc_destructor( struct net_device * dev )
- * Input parameters:
- * dev, pointer to the device structure
- *
- * Output:
- * None.
- *--------------------------------------------------------------------------
- */
-void smc_destructor ()
-{
- PRINTK2 (CARDNAME ":smc_destructor\n");
-}
-
/*
* Open and Initialize the board
@@ -592,20 +486,20 @@ void smc_destructor ()
* Set up everything, reset the card, etc ..
*
*/
-static int smc_open (bd_t *bd)
+static int smc_open(bd_t *bd, struct eth_device *dev)
{
int i, err; /* used to set hw ethernet address */
- PRINTK2 ("%s:smc_open\n", SMC_DEV_NAME);
+ PRINTK2("%s:smc_open\n", dev->name);
/* reset the hardware */
- smc_reset ();
- smc_enable ();
-
- SMC_SELECT_BANK (1);
+ smc_reset(dev);
+ smc_enable(dev);
- err = smc_get_ethaddr (bd); /* set smc_mac_addr, and sync it with u-boot globals */
+ SMC_SELECT_BANK(dev, 1);
+ /* set smc_mac_addr, and sync it with u-boot globals */
+ err = smc_get_ethaddr(bd, dev);
if (err < 0)
return -1;
#ifdef USE_32_BIT
@@ -614,11 +508,11 @@ static int smc_open (bd_t *bd)
address = smc_mac_addr[i + 1] << 8;
address |= smc_mac_addr[i];
- SMC_outw (address, LAN91C96_IA0 + i);
+ SMC_outw(dev, address, LAN91C96_IA0 + i);
}
#else
for (i = 0; i < 6; i++)
- SMC_outb (smc_mac_addr[i], LAN91C96_IA0 + i);
+ SMC_outb(dev, smc_mac_addr[i], LAN91C96_IA0 + i);
#endif
return 0;
}
@@ -635,7 +529,7 @@ static int smc_open (bd_t *bd)
* o otherwise, read in the packet
*-------------------------------------------------------------
*/
-static int smc_rcv ()
+static int smc_rcv(struct eth_device *dev)
{
int packet_number;
word status;
@@ -647,26 +541,26 @@ static int smc_rcv ()
#endif
- SMC_SELECT_BANK (2);
- packet_number = SMC_inw (LAN91C96_FIFO);
+ SMC_SELECT_BANK(dev, 2);
+ packet_number = SMC_inw(dev, LAN91C96_FIFO);
if (packet_number & LAN91C96_FIFO_RXEMPTY) {
return 0;
}
- PRINTK3 ("%s:smc_rcv\n", SMC_DEV_NAME);
+ PRINTK3("%s:smc_rcv\n", dev->name);
/* start reading from the start of the packet */
- SMC_outw (LAN91C96_PTR_READ | LAN91C96_PTR_RCV |
+ SMC_outw(dev, LAN91C96_PTR_READ | LAN91C96_PTR_RCV |
LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
/* First two words are status and packet_length */
#ifdef USE_32_BIT
- stat_len = SMC_inl (LAN91C96_DATA_HIGH);
+ stat_len = SMC_inl(dev, LAN91C96_DATA_HIGH);
status = stat_len & 0xffff;
packet_length = stat_len >> 16;
#else
- status = SMC_inw (LAN91C96_DATA_HIGH);
- packet_length = SMC_inw (LAN91C96_DATA_HIGH);
+ status = SMC_inw(dev, LAN91C96_DATA_HIGH);
+ packet_length = SMC_inw(dev, LAN91C96_DATA_HIGH);
#endif
packet_length &= 0x07ff; /* mask off top bits */
@@ -690,13 +584,14 @@ static int smc_rcv ()
to send the DWORDs or the bytes first, or some
mixture. A mixture might improve already slow PIO
performance */
- SMC_insl (LAN91C96_DATA_HIGH, NetRxPackets[0], packet_length >> 2);
+ SMC_insl(dev, LAN91C96_DATA_HIGH, NetRxPackets[0],
+ packet_length >> 2);
/* read the left over bytes */
if (packet_length & 3) {
int i;
byte *tail = (byte *) (NetRxPackets[0] + (packet_length & ~3));
- dword leftover = SMC_inl (LAN91C96_DATA_HIGH);
+ dword leftover = SMC_inl(dev, LAN91C96_DATA_HIGH);
for (i = 0; i < (packet_length & 3); i++)
*tail++ = (byte) (leftover >> (8 * i)) & 0xff;
@@ -704,13 +599,14 @@ static int smc_rcv ()
#else
PRINTK3 (" Reading %d words and %d byte(s) \n",
(packet_length >> 1), packet_length & 1);
- SMC_insw (LAN91C96_DATA_HIGH, NetRxPackets[0], packet_length >> 1);
+ SMC_insw(dev, LAN91C96_DATA_HIGH, NetRxPackets[0],
+ packet_length >> 1);
#endif /* USE_32_BIT */
#if SMC_DEBUG > 2
printf ("Receiving Packet\n");
- print_packet (NetRxPackets[0], packet_length);
+ print_packet((byte *)NetRxPackets[0], packet_length);
#endif
} else {
/* error ... */
@@ -718,13 +614,13 @@ static int smc_rcv ()
is_error = 1;
}
- while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
udelay (1); /* Wait until not busy */
/* error or good, tell the card to get rid of this packet */
- SMC_outw (LAN91C96_MMUCR_RELEASE_RX, LAN91C96_MMU);
+ SMC_outw(dev, LAN91C96_MMUCR_RELEASE_RX, LAN91C96_MMU);
- while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
udelay (1); /* Wait until not busy */
if (!is_error) {
@@ -745,18 +641,18 @@ static int smc_rcv ()
* an 'ifconfig ethX down'
*
-----------------------------------------------------*/
-static int smc_close ()
+static int smc_close(struct eth_device *dev)
{
- PRINTK2 ("%s:smc_close\n", SMC_DEV_NAME);
+ PRINTK2("%s:smc_close\n", dev->name);
/* clear everything */
- smc_shutdown ();
+ smc_shutdown(dev);
return 0;
}
#if SMC_DEBUG > 2
-static void print_packet (byte * buf, int length)
+static void print_packet(byte *buf, int length)
{
#if 0
int i;
@@ -792,86 +688,40 @@ static void print_packet (byte * buf, int length)
}
#endif /* SMC_DEBUG > 2 */
-int eth_init (bd_t * bd)
-{
- return (smc_open(bd));
-}
-
-void eth_halt ()
+static int lan91c96_init(struct eth_device *dev, bd_t *bd)
{
- smc_close ();
+ return smc_open(bd, dev);
}
-int eth_rx ()
+static void lan91c96_halt(struct eth_device *dev)
{
- return smc_rcv ();
+ smc_close(dev);
}
-int eth_send (volatile void *packet, int length)
+static int lan91c96_recv(struct eth_device *dev)
{
- return smc_send_packet (packet, length);
+ return smc_rcv(dev);
}
-
-#if 0
-/*-------------------------------------------------------------------------
- * smc_hw_init()
- *
- * Function:
- * Reset and enable the device, check if the I/O space location
- * is correct
- *
- * Input parameters:
- * None
- *
- * Output:
- * 0 --> success
- * 1 --> error
- *--------------------------------------------------------------------------
- */
-static int smc_hw_init ()
+static int lan91c96_send(struct eth_device *dev, volatile void *packet,
+ int length)
{
- unsigned short status_test;
-
- /* The attribute register of the LAN91C96 is located at address
- 0x0e000000 on the lubbock platform */
- volatile unsigned *attaddr = (unsigned *) (0x0e000000);
-
- /* first reset, then enable the device. Sequence is critical */
- attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_SRESET;
- udelay (100);
- attaddr[LAN91C96_ECOR] &= ~LAN91C96_ECOR_SRESET;
- attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_ENABLE;
-
- /* force 16-bit mode */
- attaddr[LAN91C96_ECSR] &= ~LAN91C96_ECSR_IOIS8;
- udelay (100);
-
- /* check if the I/O address is correct, the upper byte of the
- bank select register should read 0x33 */
-
- status_test = SMC_inw (LAN91C96_BANK_SELECT);
- if ((status_test & 0xFF00) != 0x3300) {
- printf ("Failed to initialize ethernetchip\n");
- return 1;
- }
- return 0;
+ return smc_send_packet(dev, packet, length);
}
-#endif /* 0 */
-/* smc_get_ethaddr (bd_t * bd)
+/* smc_get_ethaddr
*
* This checks both the environment and the ROM for an ethernet address. If
* found, the environment takes precedence.
*/
-int smc_get_ethaddr (bd_t * bd)
+static int smc_get_ethaddr(bd_t *bd, struct eth_device *dev)
{
uchar v_mac[6];
if (!eth_getenv_enetaddr("ethaddr", v_mac)) {
/* get ROM mac value if any */
- if (!get_rom_mac(v_mac)) {
+ if (!get_rom_mac(dev, v_mac)) {
printf("\n*** ERROR: ethaddr is NOT set !!\n");
return -1;
}
@@ -888,7 +738,7 @@ int smc_get_ethaddr (bd_t * bd)
* Note, this has omly been tested for the OMAP730 P2.
*/
-int get_rom_mac (unsigned char *v_rom_mac)
+static int get_rom_mac(struct eth_device *dev, unsigned char *v_rom_mac)
{
#ifdef HARDCODE_MAC /* used for testing or to supress run time warnings */
char hw_mac_addr[] = { 0x02, 0x80, 0xad, 0x20, 0x31, 0xb8 };
@@ -897,11 +747,75 @@ int get_rom_mac (unsigned char *v_rom_mac)
return (1);
#else
int i;
- SMC_SELECT_BANK (1);
+ SMC_SELECT_BANK(dev, 1);
for (i=0; i<6; i++)
{
- v_rom_mac[i] = SMC_inb (LAN91C96_IA0 + i);
+ v_rom_mac[i] = SMC_inb(dev, LAN91C96_IA0 + i);
}
return (1);
#endif
}
+
+/* Structure to detect the device IDs */
+struct id_type {
+ u8 id;
+ char *name;
+};
+static struct id_type supported_chips[] = {
+ {0, ""}, /* Dummy entry to prevent id check failure */
+ {9, "LAN91C110"},
+ {8, "LAN91C100FD"},
+ {7, "LAN91C100"},
+ {5, "LAN91C95"},
+ {4, "LAN91C94/LAN91C96"},
+ {3, "LAN91C90/LAN91C92"},
+};
+/* lan91c96_detect_chip
+ * See:
+ * http://www.embeddedsys.com/subpages/resources/images/documents/LAN91C96_datasheet.pdf
+ * page 71 - that is the closest we get to detect this device
+ */
+static int lan91c96_detect_chip(struct eth_device *dev)
+{
+ u8 chip_id;
+ int r;
+ SMC_SELECT_BANK(dev, 3);
+ chip_id = SMC_inw(dev, 0xA) & LAN91C96_REV_REVID;
+ SMC_SELECT_BANK(dev, 0);
+ for (r = 0; r < sizeof(supported_chips) / sizeof(struct id_type); r++)
+ if (chip_id == supported_chips[r].id)
+ return r;
+ return 0;
+}
+
+int lan91c96_initialize(u8 dev_num, int base_addr)
+{
+ struct eth_device *dev;
+ int r = 0;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ free(dev);
+ return 0;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ dev->iobase = base_addr;
+
+ /* Try to detect chip. Will fail if not present. */
+ r = lan91c96_detect_chip(dev);
+ if (!r) {
+ free(dev);
+ return 0;
+ }
+ get_rom_mac(dev, dev->enetaddr);
+
+ dev->init = lan91c96_init;
+ dev->halt = lan91c96_halt;
+ dev->send = lan91c96_send;
+ dev->recv = lan91c96_recv;
+ sprintf(dev->name, "%s-%hu", supported_chips[r].name, dev_num);
+
+ eth_register(dev);
+ return 0;
+}
diff --git a/drivers/net/lan91c96.h b/drivers/net/lan91c96.h
index 5beddda04..6fbb0e3cb 100644
--- a/drivers/net/lan91c96.h
+++ b/drivers/net/lan91c96.h
@@ -46,14 +46,6 @@
#include <asm/io.h>
#include <config.h>
-/*
- * This function may be called by the board specific initialisation code
- * in order to override the default mac address.
- */
-
-void smc_set_mac_addr(const unsigned char *addr);
-
-
/* I want some simple types */
typedef unsigned char byte;
@@ -86,66 +78,71 @@ typedef unsigned long int dword;
#define SMC_IO_SHIFT 0
#endif
-#define SMCREG(r) (SMC_BASE_ADDRESS+((r)<<SMC_IO_SHIFT))
+#define SMCREG(edev, r) ((edev)->iobase+((r)<<SMC_IO_SHIFT))
-#define SMC_inl(r) (*((volatile dword *)SMCREG(r)))
-#define SMC_inw(r) (*((volatile word *)SMCREG(r)))
-#define SMC_inb(p) ({ \
+#define SMC_inl(edev, r) (*((volatile dword *)SMCREG(edev, r)))
+#define SMC_inw(edev, r) (*((volatile word *)SMCREG(edev, r)))
+#define SMC_inb(edev, p) ({ \
unsigned int __p = p; \
- unsigned int __v = SMC_inw(__p & ~1); \
+ unsigned int __v = SMC_inw(edev, __p & ~1); \
if (__p & 1) __v >>= 8; \
else __v &= 0xff; \
__v; })
-#define SMC_outl(d,r) (*((volatile dword *)SMCREG(r)) = d)
-#define SMC_outw(d,r) (*((volatile word *)SMCREG(r)) = d)
-#define SMC_outb(d,r) ({ word __d = (byte)(d); \
- word __w = SMC_inw((r)&~1); \
+#define SMC_outl(edev, d, r) (*((volatile dword *)SMCREG(edev, r)) = d)
+#define SMC_outw(edev, d, r) (*((volatile word *)SMCREG(edev, r)) = d)
+#define SMC_outb(edev, d, r) ({ word __d = (byte)(d); \
+ word __w = SMC_inw(edev, (r)&~1); \
__w &= ((r)&1) ? 0x00FF : 0xFF00; \
__w |= ((r)&1) ? __d<<8 : __d; \
- SMC_outw(__w,(r)&~1); \
+ SMC_outw(edev, __w, (r)&~1); \
})
-#define SMC_outsl(r,b,l) ({ int __i; \
+#define SMC_outsl(edev, r, b, l) ({ int __i; \
dword *__b2; \
__b2 = (dword *) b; \
for (__i = 0; __i < l; __i++) { \
- SMC_outl( *(__b2 + __i), r ); \
+ SMC_outl(edev, *(__b2 + __i),\
+ r); \
} \
})
-#define SMC_outsw(r,b,l) ({ int __i; \
+#define SMC_outsw(edev, r, b, l) ({ int __i; \
word *__b2; \
__b2 = (word *) b; \
for (__i = 0; __i < l; __i++) { \
- SMC_outw( *(__b2 + __i), r ); \
+ SMC_outw(edev, *(__b2 + __i),\
+ r); \
} \
})
-#define SMC_insl(r,b,l) ({ int __i ; \
+#define SMC_insl(edev, r, b, l) ({ int __i ; \
dword *__b2; \
__b2 = (dword *) b; \
for (__i = 0; __i < l; __i++) { \
- *(__b2 + __i) = SMC_inl(r); \
- SMC_inl(0); \
+ *(__b2 + __i) = SMC_inl(edev,\
+ r); \
+ SMC_inl(edev, 0); \
}; \
})
-#define SMC_insw(r,b,l) ({ int __i ; \
+#define SMC_insw(edev, r, b, l) ({ int __i ; \
word *__b2; \
__b2 = (word *) b; \
for (__i = 0; __i < l; __i++) { \
- *(__b2 + __i) = SMC_inw(r); \
- SMC_inw(0); \
+ *(__b2 + __i) = SMC_inw(edev,\
+ r); \
+ SMC_inw(edev, 0); \
}; \
})
-#define SMC_insb(r,b,l) ({ int __i ; \
+#define SMC_insb(edev, r, b, l) ({ int __i ; \
byte *__b2; \
__b2 = (byte *) b; \
for (__i = 0; __i < l; __i++) { \
- *(__b2 + __i) = SMC_inb(r); \
- SMC_inb(0); \
+ *(__b2 + __i) = SMC_inb(edev,\
+ r); \
+ SMC_inb(edev, 0); \
}; \
})
@@ -155,40 +152,35 @@ typedef unsigned long int dword;
* We have only 16 Bit PCMCIA access on Socket 0
*/
-#define SMC_inw(r) (*((volatile word *)(SMC_BASE_ADDRESS+(r))))
-#define SMC_inb(r) (((r)&1) ? SMC_inw((r)&~1)>>8 : SMC_inw(r)&0xFF)
+#define SMC_inw(edev, r) (*((volatile word *)((edev)->iobase+(r))))
+#define SMC_inb(edev, r) (((r)&1) ? SMC_inw(edev, (r)&~1)>>8 :\
+ SMC_inw(edev, r)&0xFF)
-#define SMC_outw(d,r) (*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d)
-#define SMC_outb(d,r) ({ word __d = (byte)(d); \
- word __w = SMC_inw((r)&~1); \
+#define SMC_outw(edev, d, r) (*((volatile word *)((edev)->iobase+(r))) = d)
+#define SMC_outb(edev, d, r) ({ word __d = (byte)(d); \
+ word __w = SMC_inw(edev, (r)&~1); \
__w &= ((r)&1) ? 0x00FF : 0xFF00; \
__w |= ((r)&1) ? __d<<8 : __d; \
- SMC_outw(__w,(r)&~1); \
+ SMC_outw(edev, __w, (r)&~1); \
})
-#if 0
-#define SMC_outsw(r,b,l) outsw(SMC_BASE_ADDRESS+(r), (b), (l))
-#else
-#define SMC_outsw(r,b,l) ({ int __i; \
+#define SMC_outsw(edev, r, b, l) ({ int __i; \
word *__b2; \
__b2 = (word *) b; \
for (__i = 0; __i < l; __i++) { \
- SMC_outw( *(__b2 + __i), r); \
+ SMC_outw(edev, *(__b2 + __i),\
+ r); \
} \
})
-#endif
-#if 0
-#define SMC_insw(r,b,l) insw(SMC_BASE_ADDRESS+(r), (b), (l))
-#else
-#define SMC_insw(r,b,l) ({ int __i ; \
+#define SMC_insw(edev, r, b, l) ({ int __i ; \
word *__b2; \
__b2 = (word *) b; \
for (__i = 0; __i < l; __i++) { \
- *(__b2 + __i) = SMC_inw(r); \
- SMC_inw(0); \
+ *(__b2 + __i) = SMC_inw(edev,\
+ r); \
+ SMC_inw(edev, 0); \
}; \
})
-#endif
#endif
@@ -608,25 +600,25 @@ typedef unsigned long int dword;
/* select a register bank, 0 to 3 */
-#define SMC_SELECT_BANK(x) { SMC_outw( x, LAN91C96_BANK_SELECT ); }
+#define SMC_SELECT_BANK(edev, x) { SMC_outw(edev, x, LAN91C96_BANK_SELECT); }
/* this enables an interrupt in the interrupt mask register */
-#define SMC_ENABLE_INT(x) {\
+#define SMC_ENABLE_INT(edev, x) {\
unsigned char mask;\
- SMC_SELECT_BANK(2);\
- mask = SMC_inb( LAN91C96_INT_MASK );\
+ SMC_SELECT_BANK(edev, 2);\
+ mask = SMC_inb(edev, LAN91C96_INT_MASK);\
mask |= (x);\
- SMC_outb( mask, LAN91C96_INT_MASK ); \
+ SMC_outb(edev, mask, LAN91C96_INT_MASK); \
}
/* this disables an interrupt from the interrupt mask register */
-#define SMC_DISABLE_INT(x) {\
+#define SMC_DISABLE_INT(edev, x) {\
unsigned char mask;\
- SMC_SELECT_BANK(2);\
- mask = SMC_inb( LAN91C96_INT_MASK );\
+ SMC_SELECT_BANK(edev, 2);\
+ mask = SMC_inb(edev, LAN91C96_INT_MASK);\
mask &= ~(x);\
- SMC_outb( mask, LAN91C96_INT_MASK ); \
+ SMC_outb(edev, mask, LAN91C96_INT_MASK); \
}
/*----------------------------------------------------------------------
diff --git a/drivers/rtc/ftrtc010.c b/drivers/rtc/ftrtc010.c
index c3c0bc2f5..7738a7aca 100644
--- a/drivers/rtc/ftrtc010.c
+++ b/drivers/rtc/ftrtc010.c
@@ -47,15 +47,15 @@ struct ftrtc010 {
static struct ftrtc010 *rtc = (struct ftrtc010 *)CONFIG_FTRTC010_BASE;
-static void ftrtc010_enable (void)
+static void ftrtc010_enable(void)
{
- writel (FTRTC010_CR_ENABLE, &rtc->cr);
+ writel(FTRTC010_CR_ENABLE, &rtc->cr);
}
/*
* return current time in seconds
*/
-static unsigned long ftrtc010_time (void)
+static unsigned long ftrtc010_time(void)
{
unsigned long day;
unsigned long hour;
@@ -64,11 +64,11 @@ static unsigned long ftrtc010_time (void)
unsigned long second2;
do {
- second = readl (&rtc->sec);
- day = readl (&rtc->day);
- hour = readl (&rtc->hour);
- minute = readl (&rtc->min);
- second2 = readl (&rtc->sec);
+ second = readl(&rtc->sec);
+ day = readl(&rtc->day);
+ hour = readl(&rtc->hour);
+ minute = readl(&rtc->min);
+ second2 = readl(&rtc->sec);
} while (second != second2);
return day * 24 * 60 * 60 + hour * 60 * 60 + minute * 60 + second;
@@ -78,16 +78,16 @@ static unsigned long ftrtc010_time (void)
* Get the current time from the RTC
*/
-int rtc_get (struct rtc_time *tmp)
+int rtc_get(struct rtc_time *tmp)
{
unsigned long now;
- debug ("%s(): record register: %x\n",
- __func__, readl (&rtc->record));
+ debug("%s(): record register: %x\n",
+ __func__, readl(&rtc->record));
- now = ftrtc010_time () + readl (&rtc->record);
+ now = ftrtc010_time() + readl(&rtc->record);
- to_tm (now, tmp);
+ to_tm(now, tmp);
return 0;
}
@@ -95,30 +95,30 @@ int rtc_get (struct rtc_time *tmp)
/*
* Set the RTC
*/
-int rtc_set (struct rtc_time *tmp)
+int rtc_set(struct rtc_time *tmp)
{
unsigned long new;
unsigned long now;
- debug ("%s(): DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
- __func__,
- tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ debug("%s(): DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ __func__,
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- new = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour,
- tmp->tm_min, tmp->tm_sec);
+ new = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour,
+ tmp->tm_min, tmp->tm_sec);
- now = ftrtc010_time ();
+ now = ftrtc010_time();
- debug ("%s(): write %lx to record register\n", __func__, new - now);
+ debug("%s(): write %lx to record register\n", __func__, new - now);
- writel (new - now, &rtc->record);
+ writel(new - now, &rtc->record);
return 0;
}
-void rtc_reset (void)
+void rtc_reset(void)
{
- debug ("%s()\n", __func__);
- ftrtc010_enable ();
+ debug("%s()\n", __func__);
+ ftrtc010_enable();
}
diff --git a/drivers/rtc/m41t94.c b/drivers/rtc/m41t94.c
index 02b41d91b..5b665bb01 100644
--- a/drivers/rtc/m41t94.c
+++ b/drivers/rtc/m41t94.c
@@ -120,5 +120,4 @@ void rtc_reset(void)
* Could not be tested as the reset pin is not wired on
* the sbc35-ag20 board
*/
- return 0;
}
diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c
index 1ce34e38d..04de5ca54 100644
--- a/drivers/rtc/s3c24x0_rtc.c
+++ b/drivers/rtc/s3c24x0_rtc.c
@@ -30,11 +30,7 @@
#if (defined(CONFIG_CMD_DATE))
-#if defined(CONFIG_S3C2400)
-#include <s3c2400.h>
-#elif defined(CONFIG_S3C2410)
-#include <s3c2410.h>
-#endif
+#include <asm/arch/s3c24x0_cpu.h>
#include <rtc.h>
#include <asm/io.h>
diff --git a/drivers/serial/s3c64xx.c b/drivers/serial/s3c64xx.c
index 1b974e04f..6d22df7cf 100644
--- a/drivers/serial/s3c64xx.c
+++ b/drivers/serial/s3c64xx.c
@@ -23,7 +23,7 @@
#include <common.h>
-#include <s3c6400.h>
+#include <asm/arch/s3c6400.h>
#ifdef CONFIG_SERIAL1
#define UART_NR S3C64XX_UART0
diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c
index c2c72e456..5dd4dd816 100644
--- a/drivers/serial/serial_s3c24x0.c
+++ b/drivers/serial/serial_s3c24x0.c
@@ -19,11 +19,7 @@
*/
#include <common.h>
-#if defined(CONFIG_S3C2400) || defined(CONFIG_TRAB)
-#include <s3c2400.h>
-#elif defined(CONFIG_S3C2410)
-#include <s3c2410.h>
-#endif
+#include <asm/arch/s3c24x0_cpu.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/serial/serial_s5pc1xx.c b/drivers/serial/serial_s5pc1xx.c
index 68c06a919..73669a9f1 100644
--- a/drivers/serial/serial_s5pc1xx.c
+++ b/drivers/serial/serial_s5pc1xx.c
@@ -98,14 +98,24 @@ int serial_init_dev(const int dev_index)
return 0;
}
-static int serial_err_check(const int dev_index)
+static int serial_err_check(const int dev_index, int op)
{
struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index);
+ unsigned int mask;
+
+ /*
+ * UERSTAT
+ * Break Detect [3]
+ * Frame Err [2] : receive operation
+ * Parity Err [1] : receive operation
+ * Overrun Err [0] : receive operation
+ */
+ if (op)
+ mask = 0x8;
+ else
+ mask = 0xf;
- if (readl(&uart->uerstat) & 0xf)
- return 1;
-
- return 0;
+ return readl(&uart->uerstat) & mask;
}
/*
@@ -119,7 +129,7 @@ int serial_getc_dev(const int dev_index)
/* wait for character to arrive */
while (!(readl(&uart->utrstat) & 0x1)) {
- if (serial_err_check(dev_index))
+ if (serial_err_check(dev_index, 0))
return 0;
}
@@ -135,7 +145,7 @@ void serial_putc_dev(const char c, const int dev_index)
/* wait for room in the tx FIFO */
while (!(readl(&uart->utrstat) & 0x2)) {
- if (serial_err_check(dev_index))
+ if (serial_err_check(dev_index, 1))
return;
}
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index c693dd5f0..adb7685a6 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -31,6 +31,8 @@
#include <usb/musb_udc.h>
#elif defined(CONFIG_OMAP1510)
#include <usb/omap1510_udc.h>
+#elif defined(CONFIG_MUSB_UDC)
+#include <usb/musb_udc.h>
#elif defined(CONFIG_PXA27X)
#include <usb/pxa27x_udc.h>
#endif
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 324c308f4..ba85991e8 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -96,7 +96,7 @@ static struct descriptor {
* UE_DIR_IN | EHCI_INTR_ENDPT
*/
3, /* bmAttributes: UE_INTERRUPT */
- 8, 0, /* wMaxPacketSize */
+ 8, /* wMaxPacketSize */
255 /* bInterval */
},
};
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 67d478f87..b03a60044 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -65,8 +65,7 @@
#endif
#if defined(CONFIG_ARM920T) || \
- defined(CONFIG_S3C2400) || \
- defined(CONFIG_S3C2410) || \
+ defined(CONFIG_S3C24X0) || \
defined(CONFIG_S3C6400) || \
defined(CONFIG_440EP) || \
defined(CONFIG_PCI_OHCI) || \
diff --git a/drivers/usb/host/s3c64xx-hcd.c b/drivers/usb/host/s3c64xx-hcd.c
index 274a4ed30..cd295dabb 100644
--- a/drivers/usb/host/s3c64xx-hcd.c
+++ b/drivers/usb/host/s3c64xx-hcd.c
@@ -25,7 +25,7 @@
*/
#include <common.h>
-#include <s3c6400.h>
+#include <asm/arch/s3c6400.h>
int usb_cpu_init(void)
{
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 09e0a5f32..f2ccd9fe0 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_musb.a
COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
+COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o
COBJS-$(CONFIG_USB_DAVINCI) += davinci.o
+COBJS-$(CONFIG_USB_OMAP3) += omap3.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index ec57fc811..22f3dba0c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -32,7 +32,9 @@ struct musb_regs *musbr;
*/
void musb_start(void)
{
+#if defined(CONFIG_MUSB_HCD)
u8 devctl;
+#endif
/* disable all interrupts */
writew(0, &musbr->intrtxe);
@@ -74,9 +76,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->txfifosz);
writew(fifoaddr >> 3, &musbr->txfifoadd);
+
+ csr = readw(&musbr->txcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->txcsr);
writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
#endif
/* Flush fifo if required */
@@ -87,9 +90,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->rxfifosz);
writew(fifoaddr >> 3, &musbr->rxfifoadd);
+
+ csr = readw(&musbr->rxcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->rxcsr);
writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
#endif
/* Flush fifo if required */
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index f9da3f0b2..15c7f49a3 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -40,6 +40,36 @@
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+/* EP0 */
+struct musb_ep0_regs {
+ u16 reserved4;
+ u16 csr0;
+ u16 reserved5;
+ u16 reserved6;
+ u16 count0;
+ u8 host_type0;
+ u8 host_naklimit0;
+ u8 reserved7;
+ u8 reserved8;
+ u8 reserved9;
+ u8 configdata;
+};
+
+/* EP 1-15 */
+struct musb_epN_regs {
+ u16 txmaxp;
+ u16 txcsr;
+ u16 rxmaxp;
+ u16 rxcsr;
+ u16 rxcount;
+ u8 txtype;
+ u8 txinterval;
+ u8 rxtype;
+ u8 rxinterval;
+ u8 reserved0;
+ u8 fifosize;
+};
+
/* Mentor USB core register overlay structure */
struct musb_regs {
/* common registers */
@@ -97,6 +127,16 @@ struct musb_regs {
u8 rxhubaddr;
u8 rxhubport;
} tar[16];
+ /*
+ * end point registers
+ * ep0 elements are valid when array index is 0
+ * otherwise epN is valid
+ */
+ union musb_ep_regs {
+ struct musb_ep0_regs ep0;
+ struct musb_epN_regs epN;
+ } ep[16];
+
} __attribute__((aligned(32)));
/*
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
new file mode 100644
index 000000000..62380ffc6
--- /dev/null
+++ b/drivers/usb/musb/musb_debug.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Define MUSB_DEBUG before including this file to get debug macros */
+#ifdef MUSB_DEBUG
+
+#define MUSB_FLAGS_PRINT(v, x, y) \
+ if (((v) & MUSB_##x##_##y)) \
+ serial_printf("\t\t"#y"\n")
+
+static inline void musb_print_pwr(u8 b)
+{
+ serial_printf("\tpower 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE);
+ MUSB_FLAGS_PRINT(b, POWER, SOFTCONN);
+ MUSB_FLAGS_PRINT(b, POWER, HSENAB);
+ MUSB_FLAGS_PRINT(b, POWER, HSMODE);
+ MUSB_FLAGS_PRINT(b, POWER, RESET);
+ MUSB_FLAGS_PRINT(b, POWER, RESUME);
+ MUSB_FLAGS_PRINT(b, POWER, SUSPENDM);
+ MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND);
+}
+
+static inline void musb_print_csr0(u16 w)
+{
+ serial_printf("\tcsr0 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY);
+}
+
+static inline void musb_print_intrusb(u8 b)
+{
+ serial_printf("\tintrusb 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, INTR, VBUSERROR);
+ MUSB_FLAGS_PRINT(b, INTR, SESSREQ);
+ MUSB_FLAGS_PRINT(b, INTR, DISCONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, CONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, SOF);
+ MUSB_FLAGS_PRINT(b, INTR, RESUME);
+ MUSB_FLAGS_PRINT(b, INTR, SUSPEND);
+
+ if (b & MUSB_INTR_BABBLE)
+ serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n");
+
+}
+
+static inline void musb_print_intrtx(u16 w)
+{
+ serial_printf("\tintrtx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_intrrx(u16 w)
+{
+ serial_printf("\tintrx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_devctl(u8 b)
+{
+ serial_printf("\tdevctl 0x%2.2x\n", b);
+ if (b & MUSB_DEVCTL_BDEVICE)
+ serial_printf("\t\tB device\n");
+ else
+ serial_printf("\t\tA device\n");
+ if (b & MUSB_DEVCTL_FSDEV)
+ serial_printf("\t\tFast Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_LSDEV)
+ serial_printf("\t\tSlow Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_HM)
+ serial_printf("\t\tHost mode\n");
+ else
+ serial_printf("\t\tPeripherial mode\n");
+ if (b & MUSB_DEVCTL_HR)
+ serial_printf("\t\tHost request started(B device)\n");
+ else
+ serial_printf("\t\tHost request finished(B device)\n");
+ if (b & MUSB_DEVCTL_BDEVICE) {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(B device)\n");
+ else
+ serial_printf("\t\tEnd of session(B device)\n");
+ } else {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(A device)\n");
+ else
+ serial_printf("\t\tEnd of session(A device)\n");
+ }
+}
+
+static inline void musb_print_config(u8 b)
+{
+ serial_printf("\tconfig 0x%2.2x\n", b);
+ if (b & MUSB_CONFIGDATA_MPRXE)
+ serial_printf("\t\tAuto combine rx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_MPTXE)
+ serial_printf("\t\tAuto split tx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_BIGENDIAN)
+ serial_printf("\t\tBig Endian ordering\n");
+ else
+ serial_printf("\t\tLittle Endian ordering\n");
+ if (b & MUSB_CONFIGDATA_HBRXE)
+ serial_printf("\t\tHigh speed rx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_HBTXE)
+ serial_printf("\t\tHigh speed tx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_DYNFIFO)
+ serial_printf("\t\tDynamic fifo sizing\n");
+ if (b & MUSB_CONFIGDATA_SOFTCONE)
+ serial_printf("\t\tSoft Connect\n");
+ if (b & MUSB_CONFIGDATA_UTMIDW)
+ serial_printf("\t\t16 bit data width\n");
+ else
+ serial_printf("\t\t8 bit data width\n");
+}
+
+static inline void musb_print_rxmaxp(u16 w)
+{
+ serial_printf("\trxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_rxcsr(u16 w)
+{
+ serial_printf("\trxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB);
+ MUSB_FLAGS_PRINT(w, RXCSR, DISNYET);
+ MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE);
+ MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR);
+ MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL);
+ MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN);
+
+ if (w & MUSB_RXCSR_P_ISO)
+ serial_printf("\t\tiso mode\n");
+ else
+ serial_printf("\t\tbulk mode\n");
+
+}
+
+static inline void musb_print_txmaxp(u16 w)
+{
+ serial_printf("\ttxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_txcsr(u16 w)
+{
+ serial_printf("\ttxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL);
+
+ if (w & MUSB_TXCSR_MODE)
+ serial_printf("\t\tTX mode\n");
+ else
+ serial_printf("\t\tRX mode\n");
+}
+
+#else
+
+/* stubs */
+
+#define musb_print_pwr(b)
+#define musb_print_csr0(w)
+#define musb_print_intrusb(b)
+#define musb_print_intrtx(w)
+#define musb_print_intrrx(w)
+#define musb_print_devctl(b)
+#define musb_print_config(b)
+#define musb_print_rxmaxp(w)
+#define musb_print_rxcsr(w)
+#define musb_print_txmaxp(w)
+#define musb_print_txcsr(w)
+
+#endif /* MUSB_DEBUG */
diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c
index 4ca94cb31..555d2dc1b 100644
--- a/drivers/usb/musb/musb_hcd.c
+++ b/drivers/usb/musb/musb_hcd.c
@@ -803,7 +803,7 @@ void usb_event_poll()
{
struct stdio_dev *dev;
struct usb_device *usb_kbd_dev;
- struct usb_interface_descriptor *iface;
+ struct usb_interface *iface;
struct usb_endpoint_descriptor *ep;
int pipe;
int maxp;
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
new file mode 100644
index 000000000..fc43cf4f0
--- /dev/null
+++ b/drivers/usb/musb/musb_udc.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is a rewrite of the usb device part of
+ * repository git.omapzoom.org/repo/u-boot.git, branch master,
+ * file cpu/omap3/fastboot.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * -------------------------------------------------------------------------
+ *
+ * The details of connecting the device to the uboot usb device subsystem
+ * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
+ * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 Texas Instruments Incorporated.
+ *
+ * Based on
+ * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
+ * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
+ *
+ * Author: Diego Dompe (diego.dompe@ridgerun.com)
+ * Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * -------------------------------------------------------------------------
+ *
+ * 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 <usb/musb_udc.h>
+#include "../gadget/ep0.h"
+#include "musb_core.h"
+#if defined(CONFIG_USB_OMAP3)
+#include "omap3.h"
+#elif defined(CONFIG_USB_DAVINCI)
+#include "davinci.h"
+#endif
+
+/* Define MUSB_DEBUG for debugging */
+/* #define MUSB_DEBUG */
+#include "musb_debug.h"
+
+#define MAX_ENDPOINT 15
+
+#define GET_ENDPOINT(dev,ep) \
+(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
+
+#define SET_EP0_STATE(s) \
+do { \
+ if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
+ if ((s) != ep0_state) { \
+ if ((debug_setup) && (debug_level > 1)) \
+ serial_printf("INFO : Changing state " \
+ "from %s to %s in %s at " \
+ "line %d\n", \
+ ep0_state_strings[ep0_state],\
+ ep0_state_strings[s], \
+ __PRETTY_FUNCTION__, \
+ __LINE__); \
+ ep0_state = s; \
+ } \
+ } else { \
+ if (debug_level > 0) \
+ serial_printf("Error at %s %d with setting " \
+ "state %d is invalid\n", \
+ __PRETTY_FUNCTION__, __LINE__, s); \
+ } \
+} while (0)
+
+/* static implies these initialized to 0 or NULL */
+static int debug_setup;
+static int debug_level;
+static struct musb_epinfo epinfo[MAX_ENDPOINT * 2];
+static enum ep0_state_enum {
+ IDLE = 0,
+ TX,
+ RX,
+ SET_ADDRESS
+} ep0_state = IDLE;
+static char *ep0_state_strings[4] = {
+ "IDLE",
+ "TX",
+ "RX",
+ "SET_ADDRESS",
+};
+
+static struct urb *ep0_urb;
+struct usb_endpoint_instance *ep0_endpoint;
+static struct usb_device_instance *udc_device;
+static int enabled;
+
+#ifdef MUSB_DEBUG
+static void musb_db_regs(void)
+{
+ u8 b;
+ u16 w;
+
+ b = readb(&musbr->faddr);
+ serial_printf("\tfaddr 0x%2.2x\n", b);
+
+ b = readb(&musbr->power);
+ musb_print_pwr(b);
+
+ w = readw(&musbr->ep[0].ep0.csr0);
+ musb_print_csr0(w);
+
+ b = readb(&musbr->devctl);
+ musb_print_devctl(b);
+
+ b = readb(&musbr->ep[0].ep0.configdata);
+ musb_print_config(b);
+
+ w = readw(&musbr->frame);
+ serial_printf("\tframe 0x%4.4x\n", w);
+
+ b = readb(&musbr->index);
+ serial_printf("\tindex 0x%2.2x\n", b);
+
+ w = readw(&musbr->ep[1].epN.rxmaxp);
+ musb_print_rxmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.rxcsr);
+ musb_print_rxcsr(w);
+
+ w = readw(&musbr->ep[1].epN.txmaxp);
+ musb_print_txmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.txcsr);
+ musb_print_txcsr(w);
+}
+#else
+#define musb_db_regs()
+#endif /* DEBUG_MUSB */
+
+static void musb_peri_softconnect(void)
+{
+ u8 power, devctl;
+ u8 intrusb;
+ u16 intrrx, intrtx;
+
+ /* Power off MUSB */
+ power = readb(&musbr->power);
+ power &= ~MUSB_POWER_SOFTCONN;
+ writeb(power, &musbr->power);
+
+ /* Read intr to clear */
+ intrusb = readb(&musbr->intrusb);
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ udelay(1000 * 1000); /* 1 sec */
+
+ /* Power on MUSB */
+ power = readb(&musbr->power);
+ power |= MUSB_POWER_SOFTCONN;
+ /*
+ * The usb device interface is usb 1.1
+ * Disable 2.0 high speed by clearring the hsenable bit.
+ */
+ power &= ~MUSB_POWER_HSENAB;
+ writeb(power, &musbr->power);
+
+ /* Check if device is in b-peripheral mode */
+ devctl = readb(&musbr->devctl);
+ if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
+ (devctl & MUSB_DEVCTL_HM)) {
+ serial_printf("ERROR : Unsupport USB mode\n");
+ serial_printf("Check that mini-B USB cable is attached "
+ "to the device\n");
+ }
+
+ if (debug_setup && (debug_level > 1))
+ musb_db_regs();
+}
+
+static void musb_peri_reset(void)
+{
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
+
+ if (ep0_endpoint)
+ ep0_endpoint->endpoint_address = 0xff;
+
+ /* Sync sw and hw addresses */
+ writeb(udc_device->address, &musbr->faddr);
+
+ SET_EP0_STATE(IDLE);
+}
+
+static void musb_peri_resume(void)
+{
+ /* noop */
+}
+
+static void musb_peri_ep0_stall(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SENDSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
+}
+
+static void musb_peri_ep0_ack_req(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_TXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready_and_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND);
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_DATAEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_set_address(void)
+{
+ u8 faddr;
+ writeb(udc_device->address, &musbr->faddr);
+
+ /* Verify */
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address == faddr) {
+ SET_EP0_STATE(IDLE);
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Address set to %d\n",
+ __PRETTY_FUNCTION__, udc_device->address);
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Address missmatch "
+ "sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ }
+}
+
+static void musb_peri_rx_ack(unsigned int ep)
+{
+ u16 peri_rxcsr;
+
+ peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
+ peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
+}
+
+static void musb_peri_tx_ready(unsigned int ep)
+{
+ u16 peri_txcsr;
+
+ peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+ peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+}
+
+static void musb_peri_ep0_zero_data_request(int err)
+{
+ musb_peri_ep0_ack_req();
+
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+
+ musb_peri_ep0_last();
+
+ /* USBD state */
+ switch (ep0_urb->device_request.bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s received set "
+ "address\n", __PRETTY_FUNCTION__);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Configured\n",
+ __PRETTY_FUNCTION__);
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ break;
+ }
+
+ /* EP0 state */
+ if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
+ SET_EP0_STATE(SET_ADDRESS);
+ } else {
+ SET_EP0_STATE(IDLE);
+ }
+ }
+}
+
+static void musb_peri_ep0_rx_data_request(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ */
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->rcv_urb = ep0_urb;
+ ep0_urb->actual_length = 0;
+ SET_EP0_STATE(RX);
+}
+
+static void musb_peri_ep0_tx_data_request(int err)
+{
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->tx_urb = ep0_urb;
+ ep0_endpoint->sent = 0;
+ SET_EP0_STATE(TX);
+ }
+}
+
+static void musb_peri_ep0_idle(void)
+{
+ u16 count0;
+ int err;
+ u16 csr0;
+
+ /*
+ * Verify addresses
+ * A lot of confusion can be caused if the address
+ * in software, udc layer, does not agree with the
+ * hardware. Since the setting of the hardware address
+ * must be set after the set address request, the
+ * usb state machine is out of sync for a few frame.
+ * It is a good idea to run this check when changes
+ * are made to the state machine.
+ */
+ if ((debug_level > 0) &&
+ (ep0_state != SET_ADDRESS)) {
+ u8 faddr;
+
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address != faddr) {
+ serial_printf("ERROR : %s addresses do not"
+ "match sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ udelay(1000 * 1000);
+ hang();
+ }
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ goto end;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+ if (count0 == 0)
+ goto end;
+
+ if (count0 != 8) {
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN : %s SETUP incorrect size %d\n",
+ __PRETTY_FUNCTION__, count0);
+ musb_peri_ep0_stall();
+ goto end;
+ }
+
+ read_fifo(0, count0, &ep0_urb->device_request);
+
+ if (debug_level > 2)
+ print_usb_device_request(&ep0_urb->device_request);
+
+ if (ep0_urb->device_request.wLength == 0) {
+ err = ep0_recv_setup(ep0_urb);
+
+ /* Zero data request */
+ musb_peri_ep0_zero_data_request(err);
+ } else {
+ /* Is data coming or going ? */
+ u8 reqType = ep0_urb->device_request.bmRequestType;
+
+ if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
+ err = ep0_recv_setup(ep0_urb);
+ /* Device to host */
+ musb_peri_ep0_tx_data_request(err);
+ } else {
+ /*
+ * Host to device
+ *
+ * The RX routine will call ep0_recv_setup
+ * when the data packet has arrived.
+ */
+ musb_peri_ep0_rx_data_request();
+ }
+ }
+
+end:
+ return;
+}
+
+static void musb_peri_ep0_rx(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ * Pass the data back to driver ep0_recv_setup which
+ * should give the cdc_recv_setup the chance to handle
+ * the rx
+ */
+ u16 csr0;
+ u16 count0;
+
+ if (debug_level > 3) {
+ if (0 != ep0_urb->actual_length) {
+ serial_printf("%s finished ? %d of %d\n",
+ __PRETTY_FUNCTION__,
+ ep0_urb->actual_length,
+ ep0_urb->device_request.wLength);
+ }
+ }
+
+ if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
+ musb_peri_ep0_last();
+ SET_EP0_STATE(IDLE);
+ ep0_recv_setup(ep0_urb);
+ return;
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ return;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+
+ if (count0) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = ep0_endpoint;
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (count0 > remaining_space)
+ length = remaining_space;
+ else
+ length = count0;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(0, length, data);
+
+ musb_peri_ep0_ack_req();
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s no space in "
+ "rcv buffer\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s with nothing to do\n",
+ __PRETTY_FUNCTION__);
+ }
+}
+
+static void musb_peri_ep0_tx(void)
+{
+ u16 csr0;
+ int transfer_size = 0;
+ unsigned int p, pm;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Check for pending tx */
+ if (csr0 & MUSB_CSR0_TXPKTRDY)
+ goto end;
+
+ /* Check if this is the last packet sent */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length) {
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
+ /* Is the transfer size negative ? */
+ if (transfer_size <= 0) {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with the"
+ " transfer size %d\n",
+ __PRETTY_FUNCTION__,
+ transfer_size);
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ /* Truncate large transfers to the fifo size */
+ if (transfer_size > ep0_endpoint->tx_packetSize)
+ transfer_size = ep0_endpoint->tx_packetSize;
+
+ write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
+ ep0_endpoint->sent += transfer_size;
+
+ /* Done or more to send ? */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length)
+ musb_ep0_tx_ready_and_last();
+ else
+ musb_ep0_tx_ready();
+
+ /* Wait a bit */
+ pm = 10;
+ for (p = 0; p < pm; p++) {
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(csr0 & MUSB_CSR0_TXPKTRDY))
+ break;
+
+ /* Double the delay. */
+ udelay(1 << pm);
+ }
+
+ if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm))
+ SET_EP0_STATE(IDLE);
+
+end:
+ return;
+}
+
+static void musb_peri_ep0(void)
+{
+ u16 csr0;
+
+ if (SET_ADDRESS == ep0_state)
+ return;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Error conditions */
+ if (MUSB_CSR0_P_SENTSTALL & csr0) {
+ csr0 &= ~MUSB_CSR0_P_SENTSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ }
+ if (MUSB_CSR0_P_SETUPEND & csr0) {
+ csr0 |= MUSB_CSR0_P_SVDSETUPEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN: %s SETUPEND\n",
+ __PRETTY_FUNCTION__);
+ }
+
+ /* Normal states */
+ if (IDLE == ep0_state)
+ musb_peri_ep0_idle();
+
+ if (TX == ep0_state)
+ musb_peri_ep0_tx();
+
+ if (RX == ep0_state)
+ musb_peri_ep0_rx();
+}
+
+static void musb_peri_rx_ep(unsigned int ep)
+{
+ u16 peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
+
+ if (peri_rxcount) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = GET_ENDPOINT(udc_device, ep);
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (peri_rxcount > remaining_space)
+ length = remaining_space;
+ else
+ length = peri_rxcount;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(ep, length, data);
+
+ musb_peri_rx_ack(ep);
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d no space "
+ "in rcv buffer\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d with nothing to do\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+}
+
+static void musb_peri_rx(u16 intr)
+{
+ unsigned int ep;
+
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0();
+
+ for (ep = 1; ep < 16; ep++) {
+ if ((1 << ep) & intr)
+ musb_peri_rx_ep(ep);
+ }
+}
+
+static void musb_peri_tx(u16 intr)
+{
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0_tx();
+
+ /*
+ * Use this in the future when handling epN tx
+ *
+ * u8 ep;
+ *
+ * for (ep = 1; ep < 16; ep++) {
+ * if ((1 << ep) & intr) {
+ * / * handle tx for this endpoint * /
+ * }
+ * }
+ */
+}
+
+void udc_irq(void)
+{
+ /* This is a high freq called function */
+ if (enabled) {
+ u8 intrusb;
+
+ intrusb = readb(&musbr->intrusb);
+
+ /*
+ * See drivers/usb/gadget/mpc8xx_udc.c for
+ * state diagram going from detached through
+ * configuration.
+ */
+ if (MUSB_INTR_RESUME & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ musb_peri_ep0();
+
+ if (MUSB_INTR_RESET & intrusb) {
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ }
+
+ if (MUSB_INTR_DISCONNECT & intrusb) {
+ /* cable unplugged from hub/host */
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+ }
+
+ if (MUSB_INTR_SOF & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ if (MUSB_INTR_SUSPEND & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_INACTIVE, 0);
+ }
+
+ if (ep0_state != SET_ADDRESS) {
+ u16 intrrx, intrtx;
+
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ if (intrrx)
+ musb_peri_rx(intrrx);
+
+ if (intrtx)
+ musb_peri_tx(intrtx);
+ } else {
+ if (MUSB_INTR_SOF & intrusb) {
+ u8 faddr;
+ faddr = readb(&musbr->faddr);
+ /*
+ * Setting of the address can fail.
+ * Normally it succeeds the second time.
+ */
+ if (udc_device->address != faddr)
+ musb_peri_ep0_set_address();
+ }
+ }
+ }
+}
+
+void udc_set_nak(int ep_num)
+{
+ /* noop */
+}
+
+void udc_unset_nak(int ep_num)
+{
+ /* noop */
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+ int ret = 0;
+
+ /* Transmit only if the hardware is available */
+ if (endpoint->tx_urb && endpoint->state == 0) {
+ unsigned int ep = endpoint->endpoint_address &
+ USB_ENDPOINT_NUMBER_MASK;
+
+ u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+
+ /* Error conditions */
+ if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
+ peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+ }
+
+ if (debug_level > 1)
+ musb_print_txcsr(peri_txcsr);
+
+ /* Check if a packet is waiting to be sent */
+ if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
+ u32 length;
+ u8 *data;
+ struct urb *urb = endpoint->tx_urb;
+ unsigned int remaining_packet = urb->actual_length -
+ endpoint->sent;
+
+ if (endpoint->tx_packetSize < remaining_packet)
+ length = endpoint->tx_packetSize;
+ else
+ length = remaining_packet;
+
+ data = (u8 *) urb->buffer;
+ data += endpoint->sent;
+
+ /* common musb fifo function */
+ write_fifo(ep, length, data);
+
+ musb_peri_tx_ready(ep);
+
+ endpoint->last = length;
+ /* usbd_tx_complete will take care of updating 'sent' */
+ usbd_tx_complete(endpoint);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Problem with urb %p "
+ "or ep state %d\n",
+ __PRETTY_FUNCTION__,
+ endpoint->tx_urb, endpoint->state);
+ }
+
+ return ret;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint)
+{
+ if (0 == id) {
+ /* EP0 */
+ ep0_endpoint = endpoint;
+ ep0_endpoint->endpoint_address = 0xff;
+ ep0_urb = usbd_alloc_urb(device, endpoint);
+ } else if (MAX_ENDPOINT >= id) {
+ int ep_addr;
+
+ /* Check the direction */
+ ep_addr = endpoint->endpoint_address;
+ if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) {
+ /* IN */
+ epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
+ } else {
+ /* OUT */
+ epinfo[id * 2].epsize = endpoint->rcv_packetSize;
+ }
+
+ musb_configure_ep(&epinfo[0],
+ sizeof(epinfo) / sizeof(struct musb_epinfo));
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s endpoint request %d "
+ "exceeds maximum %d\n",
+ __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
+ }
+}
+
+void udc_connect(void)
+{
+ /* noop */
+}
+
+void udc_disconnect(void)
+{
+ /* noop */
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+ /* Save the device structure pointer */
+ udc_device = device;
+
+ enabled = 1;
+}
+
+void udc_disable(void)
+{
+ enabled = 0;
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+ /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+ usbd_device_event_irq(device, DEVICE_INIT, 0);
+
+ /*
+ * The DEVICE_CREATE event puts the USB device in the state
+ * STATE_ATTACHED.
+ */
+ usbd_device_event_irq(device, DEVICE_CREATE, 0);
+
+ /* Resets the address to 0 */
+ usbd_device_event_irq(device, DEVICE_RESET, 0);
+
+ udc_enable(device);
+}
+
+int udc_init(void)
+{
+ int ret;
+ int ep_loop;
+
+ ret = musb_platform_init();
+ if (ret < 0)
+ goto end;
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musbr = musb_cfg.regs;
+
+ /* Initialize the endpoints */
+ for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) {
+ epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
+ epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
+ epinfo[ep_loop].epsize = 0;
+ }
+
+ musb_peri_softconnect();
+
+ ret = 0;
+end:
+
+ return ret;
+}
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
new file mode 100644
index 000000000..ea98c3cac
--- /dev/null
+++ b/drivers/usb/musb/omap3.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2009 Texas Instruments
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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 <twl4030.h>
+#include "omap3.h"
+
+static int platform_needs_initialization = 1;
+
+struct musb_config musb_cfg = {
+ (struct musb_regs *)MENTOR_USB0_BASE,
+ OMAP3_USB_TIMEOUT,
+ 0
+};
+
+/*
+ * OMAP3 USB OTG registers.
+ */
+struct omap3_otg_regs {
+ u32 revision;
+ u32 sysconfig;
+ u32 sysstatus;
+ u32 interfsel;
+ u32 simenable;
+ u32 forcestdby;
+};
+
+static struct omap3_otg_regs *otg;
+
+#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000
+#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000
+#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010
+#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008
+#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004
+#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002
+#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001
+
+#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001
+
+#define OMAP3_OTG_INTERFSEL_OMAP 0x0001
+
+#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001
+
+
+#ifdef DEBUG_MUSB_OMAP3
+static void musb_db_otg_regs(void)
+{
+ u32 l;
+ l = readl(&otg->revision);
+ serial_printf("OTG_REVISION 0x%x\n", l);
+ l = readl(&otg->sysconfig);
+ serial_printf("OTG_SYSCONFIG 0x%x\n", l);
+ l = readl(&otg->sysstatus);
+ serial_printf("OTG_SYSSTATUS 0x%x\n", l);
+ l = readl(&otg->interfsel);
+ serial_printf("OTG_INTERFSEL 0x%x\n", l);
+ l = readl(&otg->forcestdby);
+ serial_printf("OTG_FORCESTDBY 0x%x\n", l);
+}
+#endif
+
+int musb_platform_init(void)
+{
+ int ret = -1;
+
+ if (platform_needs_initialization) {
+ u32 stdby;
+
+ /*
+ * OMAP3EVM uses ISP1504 phy and so
+ * twl4030 related init is not required.
+ */
+#ifdef CONFIG_TWL4030_USB
+ if (twl4030_usb_ulpi_init()) {
+ serial_printf("ERROR: %s Could not initialize PHY\n",
+ __PRETTY_FUNCTION__);
+ goto end;
+ }
+#endif
+ otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
+
+ /* Set OTG to always be on */
+ writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
+ OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
+
+ /* Set the interface */
+ writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
+
+ /* Clear force standby */
+ stdby = readl(&otg->forcestdby);
+ stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
+ writel(stdby, &otg->forcestdby);
+
+ platform_needs_initialization = 0;
+ }
+
+ ret = platform_needs_initialization;
+end:
+ return ret;
+
+}
+
+void musb_platform_deinit(void)
+{
+ /* noop */
+}
diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h
new file mode 100644
index 000000000..20fc9d294
--- /dev/null
+++ b/drivers/usb/musb/omap3.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is based on the file drivers/usb/musb/davinci.h
+ *
+ * This is the unique part of its copyright:
+ *
+ * --------------------------------------------------------------------
+ *
+ * Copyright (c) 2008 Texas Instruments
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ *
+ * --------------------------------------------------------------------
+ *
+ * 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 _MUSB_OMAP3_H_
+#define _MUSB_OMAP3_H_
+
+#include "musb_core.h"
+
+/* Base address of MUSB registers */
+#define MENTOR_USB0_BASE (OMAP34XX_CORE_L4_IO_BASE + 0xAB000)
+
+/* Base address of OTG registers */
+#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400)
+
+/* Timeout for USB module */
+#define OMAP3_USB_TIMEOUT 0x3FFFFFF
+
+int musb_platform_init(void);
+
+#endif /* _MUSB_OMAP3_H */
+
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
new file mode 100644
index 000000000..200b907d9
--- /dev/null
+++ b/drivers/usb/phy/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2009 Wind River Systems, Inc.
+# Tom Rix <Tom.Rix@windriver.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libusb_phy.a
+
+COBJS-$(CONFIG_TWL4030_USB) += twl4030.o
+COBJS-y := twl4030.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/usb/phy/twl4030.c b/drivers/usb/phy/twl4030.c
new file mode 100644
index 000000000..54d2e615c
--- /dev/null
+++ b/drivers/usb/phy/twl4030.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/gadget/twl4030_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * * (C) Copyright 2009 Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * Based on: twl4030_usb.c in linux 2.6 (drivers/i2c/chips/twl4030_usb.c)
+ * Copyright (C) 2004-2007 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * Author: Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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 <twl4030.h>
+
+/* Defines for bits in registers */
+#define OPMODE_MASK (3 << 3)
+#define XCVRSELECT_MASK (3 << 0)
+#define CARKITMODE (1 << 2)
+#define OTG_ENAB (1 << 5)
+#define PHYPWD (1 << 0)
+#define CLOCKGATING_EN (1 << 2)
+#define CLK32K_EN (1 << 1)
+#define REQ_PHY_DPLL_CLK (1 << 0)
+#define PHY_DPLL_CLK (1 << 0)
+
+static int twl4030_usb_write(u8 address, u8 data)
+{
+ int ret;
+
+ ret = twl4030_i2c_write_u8(TWL4030_CHIP_USB, data, address);
+ if (ret != 0)
+ printf("TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
+
+ return ret;
+}
+
+static int twl4030_usb_read(u8 address)
+{
+ u8 data;
+ int ret;
+
+ ret = twl4030_i2c_read_u8(TWL4030_CHIP_USB, &data, address);
+ if (ret == 0)
+ ret = data;
+ else
+ printf("TWL4030:USB:Read[0x%x] Error %d\n", address, ret);
+
+ return ret;
+}
+
+static void twl4030_usb_ldo_init(void)
+{
+ /* Enable writing to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 0xC0,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 0x0C,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+
+ /* put VUSB3V1 LDO in active state */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB_DEDICATED2);
+
+ /* input to VUSB3V1 LDO is from VBAT, not VBUS */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x14,
+ TWL4030_PM_RECEIVER_VUSB_DEDICATED1);
+
+ /* turn on 3.1V regulator */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x20,
+ TWL4030_PM_RECEIVER_VUSB3V1_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB3V1_TYPE);
+
+ /* turn on 1.5V regulator */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x20,
+ TWL4030_PM_RECEIVER_VUSB1V5_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB1V5_TYPE);
+
+ /* turn on 1.8V regulator */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x20,
+ TWL4030_PM_RECEIVER_VUSB1V8_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB1V8_TYPE);
+
+ /* disable access to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 0x00,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+}
+
+static void twl4030_phy_power(void)
+{
+ u8 pwr, clk;
+
+ /* Power the PHY */
+ pwr = twl4030_usb_read(TWL4030_USB_PHY_PWR_CTRL);
+ pwr &= ~PHYPWD;
+ twl4030_usb_write(TWL4030_USB_PHY_PWR_CTRL, pwr);
+ /* Enable clocks */
+ clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+ clk |= CLOCKGATING_EN | CLK32K_EN;
+ twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+}
+
+/*
+ * Initiaze the ULPI interface
+ * ULPI : Universal Transceiver Macrocell Low Pin Interface
+ * An interface between the USB link controller like musb and the
+ * the PHY or transceiver that drives the actual bus.
+ */
+int twl4030_usb_ulpi_init(void)
+{
+ long timeout = 1000 * 1000; /* 1 sec */;
+ u8 clk, sts, pwr;
+
+ /* twl4030 ldo init */
+ twl4030_usb_ldo_init();
+
+ /* Enable the twl4030 phy */
+ twl4030_phy_power();
+
+ /* Enable DPLL to access PHY registers over I2C */
+ clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+ clk |= REQ_PHY_DPLL_CLK;
+ twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+
+ /* Check if the PHY DPLL is locked */
+ sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+ while (!(sts & PHY_DPLL_CLK) && 0 < timeout) {
+ udelay(10);
+ sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+ timeout -= 10;
+ }
+
+ /* Final check */
+ sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+ if (!(sts & PHY_DPLL_CLK)) {
+ printf("Error:TWL4030:USB Timeout setting PHY DPLL clock\n");
+ return -1;
+ }
+
+ /*
+ * There are two circuit blocks attached to the PHY,
+ * Carkit and USB OTG. Disable Carkit and enable USB OTG
+ */
+ twl4030_usb_write(TWL4030_USB_IFC_CTRL_CLR, CARKITMODE);
+ pwr = twl4030_usb_read(TWL4030_USB_POWER_CTRL);
+ pwr |= OTG_ENAB;
+ twl4030_usb_write(TWL4030_USB_POWER_CTRL_SET, pwr);
+
+ /* Clear the opmode bits to ensure normal encode */
+ twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, OPMODE_MASK);
+
+ /* Clear the xcvrselect bits to enable the high speed transeiver */
+ twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, XCVRSELECT_MASK);
+
+ /* Let ULPI control the DPLL clock */
+ clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+ clk &= ~REQ_PHY_DPLL_CLK;
+ twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+
+ return 0;
+}
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index fbc4df9f6..c07a26e3c 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -146,9 +146,11 @@ CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability of the
#ifdef CONFIG_VIDEO_CORALP
#define VIDEO_FB_LITTLE_ENDIAN
#endif
+#ifdef CONFIG_VIDEO_MB862xx_ACCEL
#define VIDEO_HW_RECTFILL
#define VIDEO_HW_BITBLT
#endif
+#endif
/*****************************************************************************/
/* Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc */
@@ -319,7 +321,7 @@ void console_cursor (int state);
#else
#define SWAP16(x) (x)
#define SWAP32(x) (x)
-#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
+#if defined(VIDEO_FB_16BPP_WORD_SWAP)
#define SHORTSWAP32(x) ( ((x) >> 16) | ((x) << 16) )
#else
#define SHORTSWAP32(x) (x)
@@ -401,8 +403,6 @@ static const int video_font_draw_table32[16][4] = {
{ 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff } };
-int gunzip(void *, int, unsigned char *, unsigned long *);
-
/******************************************************************************/
static void video_drawchars (int xx, int yy, unsigned char *s, int count)
diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c
index a8676cc64..edf34aa06 100644
--- a/drivers/video/mb862xx.c
+++ b/drivers/video/mb862xx.c
@@ -89,6 +89,7 @@ unsigned int fr_div[] = { 0x00000f00, 0x00000900, 0x00000500 };
(GC_DISP_BASE | GC_L0PAL0) + \
((idx) << 2)), (val))
+#if defined(CONFIG_VIDEO_MB862xx_ACCEL)
static void gdc_sw_reset (void)
{
GraphicDevice *dev = &mb862xx;
@@ -129,6 +130,7 @@ static void de_wait_slots (int slots)
break;
}
}
+#endif
#if !defined(CONFIG_VIDEO_CORALP)
static void board_disp_init (void)
@@ -144,11 +146,13 @@ static void board_disp_init (void)
#endif
/*
- * Init drawing engine
+ * Init drawing engine if accel enabled.
+ * Also clears visible framebuffer.
*/
static void de_init (void)
{
GraphicDevice *dev = &mb862xx;
+#if defined(CONFIG_VIDEO_MB862xx_ACCEL)
int cf = (dev->gdfBytesPP == 1) ? 0x0000 : 0x8000;
dev->dprBase = dev->frameAdrs + GC_DRAW_BASE;
@@ -174,6 +178,14 @@ static void de_init (void)
DE_WR_FIFO (dev->winSizeY << 16 | dev->winSizeX);
/* sync with SW access to framebuffer */
de_wait ();
+#else
+ unsigned int i, *p;
+
+ i = dev->winSizeX * dev->winSizeY;
+ p = (unsigned int *)dev->frameAdrs;
+ while (i--)
+ *p++ = 0;
+#endif
}
#if defined(CONFIG_VIDEO_CORALP)
@@ -340,6 +352,30 @@ unsigned int card_init (void)
}
#endif
+
+#if !defined(CONFIG_VIDEO_CORALP)
+int mb862xx_probe(unsigned int addr)
+{
+ GraphicDevice *dev = &mb862xx;
+ unsigned int reg;
+
+ dev->frameAdrs = addr;
+ dev->dprBase = dev->frameAdrs + GC_DRAW_BASE;
+
+ /* Try to access GDC ID/Revision registers */
+ reg = HOST_RD_REG (GC_CID);
+ reg = HOST_RD_REG (GC_CID);
+ if (reg == 0x303) {
+ reg = DE_RD_REG(GC_REV);
+ reg = DE_RD_REG(GC_REV);
+ if ((reg & ~0xff) == 0x20050100)
+ return MB862XX_TYPE_LIME;
+ }
+
+ return 0;
+}
+#endif
+
void *video_hw_init (void)
{
GraphicDevice *dev = &mb862xx;
@@ -359,8 +395,16 @@ void *video_hw_init (void)
if ((dev->frameAdrs = board_video_init ()) == 0) {
puts ("Controller not found!\n");
return NULL;
- } else
+ } else {
puts ("Lime\n");
+
+ /* Set Change of Clock Frequency Register */
+ HOST_WR_REG (GC_CCF, CONFIG_SYS_MB862xx_CCF);
+ /* Delay required */
+ udelay(300);
+ /* Set Memory I/F Mode Register) */
+ HOST_WR_REG (GC_MMR, CONFIG_SYS_MB862xx_MMR);
+ }
#endif
de_init ();
@@ -389,6 +433,7 @@ void video_set_lut (unsigned int index, unsigned char r,
L0PAL_WR_REG (index, (r << 16) | (g << 8) | (b));
}
+#if defined(CONFIG_VIDEO_MB862xx_ACCEL)
/*
* Drawing engine Fill and BitBlt screen region
*/
@@ -430,3 +475,4 @@ void video_hw_bitblt (unsigned int bpp, unsigned int src_x,
DE_WR_FIFO ((height << 16) | width);
de_wait (); /* sync */
}
+#endif