From 3814ea4f0002536ac592480b2cdafa319a16e329 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 14 Oct 2009 19:27:26 -0400 Subject: Blackfin: TWI/I2C: add timeout to transfer The current transfer code relies on ctrlc() to abort transfers, but this requires user interactivity. Naturalize the process with a timeout. Signed-off-by: Mike Frysinger --- drivers/i2c/bfin-twi_i2c.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/bfin-twi_i2c.c b/drivers/i2c/bfin-twi_i2c.c index e790634..5ef30be 100644 --- a/drivers/i2c/bfin-twi_i2c.c +++ b/drivers/i2c/bfin-twi_i2c.c @@ -60,6 +60,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 +70,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 +107,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 +120,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; } -- cgit v1.1 From 08a1c6258c2a04cead33eac50d96ea89979dcb94 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 14 Oct 2009 19:27:27 -0400 Subject: Blackfin: TWI/I2C: implement bus speed get/set functions While we're here, improve the speed calculation a bit to match the HRM. Signed-off-by: Mike Frysinger --- drivers/i2c/bfin-twi_i2c.c | 59 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/bfin-twi_i2c.c b/drivers/i2c/bfin-twi_i2c.c index 5ef30be..73a78d2 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 */ @@ -213,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) @@ -229,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(); -- cgit v1.1 From 08ea550eef310e9d59d83f3cfd57a902373bf17f Mon Sep 17 00:00:00 2001 From: Valentin Yakovenkov Date: Mon, 26 Oct 2009 18:49:06 -0400 Subject: new PCA9564 i2c bridge driver Signed-off-by: Valentin Yakovenkov Signed-off-by: Mike Frysinger --- drivers/i2c/Makefile | 1 + drivers/i2c/pca9564_i2c.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 drivers/i2c/pca9564_i2c.c (limited to 'drivers') diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 4a12976..b860e89 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/pca9564_i2c.c b/drivers/i2c/pca9564_i2c.c new file mode 100644 index 0000000..199a9ee --- /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 +#include +#include +#include + +#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; +} -- cgit v1.1 From c28d3bbe963f4c57937d6fdc1dd63cd3562c147c Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 23 Oct 2009 12:03:13 +0200 Subject: video: mb862xx: improve board-specific Lime configuration To avoid board-specific code accessing the mb862xx registers directly, the public function mb862xx_probe() has been introduced. Furthermore, the "Change of Clock Frequency" and "Set Memory I/F Mode" registers are now defined by CONFIG_SYS_MB862xx_CCF and CONFIG_SYS_MB862xx__MMR, respectively. The BSPs for the socrates and lwmon5 boards have been adapted accordingly. Signed-off-by: Wolfgang Grandegger --- drivers/video/mb862xx.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c index a8676cc..bb212a8 100644 --- a/drivers/video/mb862xx.c +++ b/drivers/video/mb862xx.c @@ -340,6 +340,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 +383,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 (); -- cgit v1.1 From 5d16ca87100ea58c93c46b9f0264981eaed49568 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 23 Oct 2009 12:03:14 +0200 Subject: video: mb862xx: add option CONFIG_VIDEO_MB862xx_ACCEL for 32bpp mode The new IPEK01 board can use the 32 bpp mode for the Lime graphics controller. For this mode, video accelaration does not work. This patch makes the accelaration configurable via CONFIG_VIDEO_MB862xx_ACCEL, which is enabled for the lwmon5 and the socrates board for backward compatibility. Signed-off-by: Anatolij Gustschin Signed-off-by: Wolfgang Grandegger --- drivers/video/cfb_console.c | 2 ++ drivers/video/mb862xx.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index fbc4df9..0df321c 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 */ diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c index bb212a8..edf34aa 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) @@ -421,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 */ @@ -462,3 +475,4 @@ void video_hw_bitblt (unsigned int bpp, unsigned int src_x, DE_WR_FIFO ((height << 16) | width); de_wait (); /* sync */ } +#endif -- cgit v1.1 From 229b6dce675c729ee0ea2d7b61fbcda89b23b6b8 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 23 Oct 2009 12:03:15 +0200 Subject: video: mb862xx: add option VIDEO_FB_16BPP_WORD_SWAP for IPEK01 In 16 bpp mode, the new IPEK01 board only requires swapping of D16 words for D32 accesses due to the diffferent connecting to the GDC bus. This patch introduces the configuration option VIDEO_FB_16BPP_WORD_SWAP, which should be set for all board using the mb862xx in 16 bpp mode. For the IPEK01, VIDEO_FB_16BPP_PIXEL_SWAP should not be set. Signed-off-by: Wolfgang Grandegger --- drivers/video/cfb_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 0df321c..16d6689 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -321,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) -- cgit v1.1 From aaa8eec532876c47acfd31bf9b573a00eaad92ae Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Fri, 30 Oct 2009 13:51:23 -0400 Subject: NAND: Update to support 64 bit device size This patch adds support for NANDs greater than 2 GB. Patch is based on the MTD NAND driver in the kernel. Signed-off-by: Sandeep Paulraj Signed-off-by: Scott Wood --- drivers/mtd/nand/nand_base.c | 26 ++++++++++++++++---------- drivers/mtd/nand/nand_bbt.c | 41 +++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 426bb95..30a3e9e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2211,13 +2211,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 +2315,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 +2325,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 +2373,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 +2569,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 +2627,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(chip->chipsize) - 1; + else + chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31; /* Set the bad block position */ chip->badblockpos = mtd->writesize > 512 ? diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index d68a315f..2fe68ab 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; -- cgit v1.1 From 4f41e7ea1a17ba7207ca41379bf344b317e72c12 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Sat, 7 Nov 2009 14:24:06 -0500 Subject: NAND: Correct the "chip_shift" calculation This patch updates the "chip_shift" calculation in the NAND driver. This is being done to sync up the NAND driver with the kernel NAND driver. Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 30a3e9e..d5c53fe 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2628,7 +2628,7 @@ 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; if (chip->chipsize & 0xffffffff) - chip->chip_shift = ffs(chip->chipsize) - 1; + chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; else chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31; -- cgit v1.1 From 36e0b98ec832bb5ec42d6e249058d5b84f75dff8 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Sat, 7 Nov 2009 14:24:20 -0500 Subject: NAND: Remove commented out code Patch removes already commented out dead code Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/nand_base.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d5c53fe..7446634 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2767,7 +2767,6 @@ int nand_scan_tail(struct mtd_info *mtd) default: printk(KERN_WARNING "No oob scheme defined for " "oobsize %d\n", mtd->oobsize); -/* BUG(); */ } } -- cgit v1.1 From aad4a28b2518e1d24ee606d9ea31f9b4dd029777 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Sat, 7 Nov 2009 14:24:34 -0500 Subject: NAND: Subpage shift for ecc_steps equal to 16 This was originally part of Thomas Gleixner's patch for adding support for 4KiB pages. This is not part of the U-Boot NAND driver so updating the driver with this to sync up with the kernel NAND driver. Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/nand_base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7446634..b3b2be2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2895,6 +2895,7 @@ int nand_scan_tail(struct mtd_info *mtd) break; case 4: case 8: + case 16: mtd->subpage_sft = 2; break; } -- cgit v1.1 From e25ee0396226fb56679702d0361cf2645504e7f6 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Sat, 7 Nov 2009 14:24:50 -0500 Subject: NAND: Updating comments/explanations in the NAND driver Patch updates the comments and explanations for the arguments to various functions. Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/nand_base.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b3b2be2..cfd582a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -893,6 +893,7 @@ 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 */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -907,6 +908,7 @@ static int nand_read_page_raw(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 */ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -946,9 +948,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) { @@ -1028,6 +1030,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 */ @@ -1072,6 +1075,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 +1124,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. @@ -2728,7 +2733,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 -- cgit v1.1 From 18b5a4b43af3c8359cb568f4fa32d6b9dcebbf26 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Sat, 7 Nov 2009 14:25:03 -0500 Subject: NAND: Update check condition for nand_read_page_hwecc API The patch updates the check condition for determining whether the ECC corrections has failed. This makes it similar to what is in the kernel NAND driver. Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index cfd582a..52b0c1a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1062,7 +1062,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; -- cgit v1.1 From 5df3c2b62cebaa0ddb2817364f93726e5dbe3525 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Sat, 7 Nov 2009 14:25:18 -0500 Subject: NAND: Don't walk past end of oobfree[] When computing oobavail from the list of free areas in the OOB, don't assume there will always be an unused slot at the end. This syncs up with the kernel NAND driver. Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/nand_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 52b0c1a..cf032a6 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2871,7 +2871,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; -- cgit v1.1 From 7e86661cd777eec1e81c5e57c468e81138fda983 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 Nov 2009 16:27:01 -0500 Subject: NAND: fix "raw" reads with ECC syndrome layouts The syndrome based page read/write routines store ECC, and possibly other "OOB" data, right after each chunk of ECC'd data. With ECC chunk size of 512 bytes and a large page (2KiB) NAND, the layout is: data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines use a traditional layout -- data OOB, disregarding the prepad and postpad values -- so when they're used with that type of ECC hardware, those calls mix up the data and OOB. Which means, in particular, that bad block tables won't be found on startup, with data corruption and related chaos ensuing. The current syndrome-based drivers in mainline all seem to use one chunk per page; presumably they haven't noticed such bugs. Fix this, by adding read/write page_raw_syndrome() routines as siblings of the existing non-raw routines; "raw" just means to bypass the ECC computations, not change data and OOB layout. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 100 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index cf032a6..6da261c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -894,6 +894,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this) * @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) @@ -904,6 +906,48 @@ 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 @@ -1682,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) @@ -1691,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 @@ -2781,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: @@ -2804,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) @@ -2825,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) @@ -2843,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; @@ -2855,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; -- cgit v1.1 From 35209cbceebe212a8c5ec17d552960f8bd4725f3 Mon Sep 17 00:00:00 2001 From: Mingkai Hu Date: Tue, 20 Oct 2009 16:58:17 +0800 Subject: fsl_elbc_nand: remove the bbt descriptors relocation fixup The commit 66372fe2 manually relocated the bbt pattern pointer, which can be removed by using full relocation. Signed-off-by: Mingkai Hu --- drivers/mtd/nand/fsl_elbc_nand.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 50cb4aa..146e9bf 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 */ -- cgit v1.1 From cacbe919584193f64e74088e03f068e52775bb86 Mon Sep 17 00:00:00 2001 From: Amul Kumar Saha Date: Fri, 6 Nov 2009 17:15:31 +0530 Subject: Flex-OneNAND driver support This patch adds support for Flex-OneNAND devices. Signed-off-by: Rohit Hagargundgi Signed-off-by: Amul Kumar Saha --- drivers/mtd/onenand/onenand_base.c | 742 +++++++++++++++++++++++++++++++----- drivers/mtd/onenand/onenand_bbt.c | 14 +- drivers/mtd/onenand/onenand_uboot.c | 4 +- 3 files changed, 662 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 368fa6e..f9273ab 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 , + * Amul Kumar Saha : + * 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 /* 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 d538f95..1354877 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 9823b5b..c642016 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 /* -- cgit v1.1 From 1d2e96de56cc57e25a19bc40d297f36c4c4443a2 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 2 Nov 2009 20:36:26 +0100 Subject: OMAP2/3: I2C: Add support for second and third bus Add support to use second and third I2C bus, too. Bus 0 is still the default, but by calling i2c_set_bus_num(1/2) before doing I2C accesses, code can switch to bus 1 and 2, too. Don't forget to switch back afterwards, then. Signed-off-by: Dirk Behme --- drivers/i2c/omap24xx_i2c.c | 166 +++++++++++++++++++++++++++------------------ 1 file changed, 99 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 1a4c8c9..ff18991 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; +} -- cgit v1.1 From 6cd752f927e515e63a038fa363edceec5a59c028 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Mon, 16 Nov 2009 13:32:01 -0500 Subject: NAND: Update read_read_subpage API check This patch updates a check condition in the NAND driver. The check condition is similat to what is in linux/next. Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6da261c..7171bdd 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1061,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; -- cgit v1.1 From 5e1ded558b7cc28a62c14598f6437023b6262444 Mon Sep 17 00:00:00 2001 From: "Hui.Tang" Date: Wed, 18 Nov 2009 16:24:04 +0800 Subject: S3C2410 NAND Flash Add Missing Function This patch add nand_read_buf() for S3C2410 NAND SPL. In nand_spl/nand_boot.c, nand_boot() will check nand->select_chip, so nand->select_chip should also be initialized. Signed-off-by: Hui.Tang --- drivers/mtd/nand/s3c2410_nand.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c index f2f3e72..815c78e 100644 --- a/drivers/mtd/nand/s3c2410_nand.c +++ b/drivers/mtd/nand/s3c2410_nand.c @@ -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 -- cgit v1.1 From 10a5a7991258019af155bc19b3b246aaa708b0e2 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Thu, 19 Nov 2009 23:04:42 -0500 Subject: NAND: Add Support for 4K page size in DaVinci NAND driver This patch adds support for NAND devices with a page size of 4K in the DaVinci NAND driver. The layout matches the layout that TI uses for 4K page size NAND devices in the kernel NAND driver. Signed-off-by: Sandeep Paulraj --- drivers/mtd/nand/davinci_nand.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index eabaf3e..41a9568 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 }; -- cgit v1.1 From 4e574c4e2d3776d9db62dca4ca3c73be1574af43 Mon Sep 17 00:00:00 2001 From: Daniel Gorsulowski Date: Mon, 18 May 2009 13:20:54 +0200 Subject: at91: Extended soft_i2c driver for AT91SAM9263 SoC While hard_i2c support is not available (see http://lists.denx.de/pipermail/u-boot/2009-March/049751.html), this patch enables soft_i2c on AT91SAM9263 SoC. Signed-off-by: Daniel Gorsulowski --- drivers/i2c/soft_i2c.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index 59883a5..9a48783 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -34,6 +34,11 @@ #include #include #endif +#ifdef CONFIG_AT91SAM9263 /* only valid for AT91SAM9263 */ +#include +#include +#include +#endif #ifdef CONFIG_IXP425 /* only valid for IXP425 */ #include #endif -- cgit v1.1 From 9829cabbaa0474e94075bf7d62c99bdba996518b Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Wed, 28 Oct 2009 19:16:43 -0400 Subject: Fix for Void function returning value in sbc35-a9g20 Void function was returning 0 in the m41t94 rtc driver. This makes it similar to m41t62 rtc driver. Signed-off-by: Sandeep Paulraj --- drivers/rtc/m41t94.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/m41t94.c b/drivers/rtc/m41t94.c index 02b41d9..5b665bb 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; } -- cgit v1.1 From 492fb1fdbcdd5e21be0b6742c15f76c648f0653b Mon Sep 17 00:00:00 2001 From: "kevin.morfitt@fearnside-systems.co.uk" Date: Tue, 3 Nov 2009 18:08:41 +0900 Subject: Move s3c24x0 header files to asm-arm/arch-s3c24x0/ This patch moves the s3c24x0 header files from include/ to include/asm-arm/arch-s3c24x0/. checkpatch.pl showed 2 errors and 3 warnings. The 2 errors were both due to a non-UTF8 character in David M?ller's name: ERROR: Invalid UTF-8, patch and commit message should be encoded in UTF-8 #489: FILE: include/asm-arm/arch-s3c24x0/s3c2410.h:3: + * David M?ller ELSOFT AG Switzerland. d.mueller@elsoft.ch As David's name correctly contains a non-UTF8 character I haven't fixed these errors. The 3 warnings were all because of the use of 'volatile' in s3c24x0.h: WARNING: Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt #673: FILE: include/asm-arm/arch-s3c24x0/s3c24x0.h:35: +typedef volatile u8 S3C24X0_REG8; +typedef volatile u16 S3C24X0_REG16; +typedef volatile u32 S3C24X0_REG32; I'll fix these errors in another patch. Tested by running MAKEALL for ARM8 targets and ensuring there were no new errors or warnings. Signed-off-by: Kevin Morfitt Signed-off-by: Minkyu Kang --- drivers/i2c/s3c24x0_i2c.c | 4 ++-- drivers/mtd/nand/s3c2410_nand.c | 2 +- drivers/rtc/s3c24x0_rtc.c | 4 ++-- drivers/serial/serial_s3c24x0.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 55c6a12..8fecc6e 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -28,9 +28,9 @@ #include #if defined(CONFIG_S3C2400) -#include +#include #elif defined(CONFIG_S3C2410) -#include +#include #endif #include diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c index 815c78e..2f89b8c 100644 --- a/drivers/mtd/nand/s3c2410_nand.c +++ b/drivers/mtd/nand/s3c2410_nand.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #define S3C2410_NFCONF_EN (1<<15) diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c index 1ce34e3..2d78f93 100644 --- a/drivers/rtc/s3c24x0_rtc.c +++ b/drivers/rtc/s3c24x0_rtc.c @@ -31,9 +31,9 @@ #if (defined(CONFIG_CMD_DATE)) #if defined(CONFIG_S3C2400) -#include +#include #elif defined(CONFIG_S3C2410) -#include +#include #endif #include diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c index c2c72e4..914d07c 100644 --- a/drivers/serial/serial_s3c24x0.c +++ b/drivers/serial/serial_s3c24x0.c @@ -20,9 +20,9 @@ #include #if defined(CONFIG_S3C2400) || defined(CONFIG_TRAB) -#include +#include #elif defined(CONFIG_S3C2410) -#include +#include #endif DECLARE_GLOBAL_DATA_PTR; -- cgit v1.1 From 47e801bec360e69e4b087a141d015b318e1b0212 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Wed, 4 Nov 2009 16:07:59 +0900 Subject: s3c64xx: move s3c64xx header files to asm-arm/arch-s3c64xx This patch moves the s3c64xx header files from include/ to include/asm-arm/arch-s3c64xx Signed-off-by: Minkyu Kang --- drivers/mtd/nand/s3c64xx.c | 2 +- drivers/serial/s3c64xx.c | 2 +- drivers/usb/host/s3c64xx-hcd.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/s3c64xx.c b/drivers/mtd/nand/s3c64xx.c index edaf55a..084e475 100644 --- a/drivers/mtd/nand/s3c64xx.c +++ b/drivers/mtd/nand/s3c64xx.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/serial/s3c64xx.c b/drivers/serial/s3c64xx.c index 1b974e0..6d22df7 100644 --- a/drivers/serial/s3c64xx.c +++ b/drivers/serial/s3c64xx.c @@ -23,7 +23,7 @@ #include -#include +#include #ifdef CONFIG_SERIAL1 #define UART_NR S3C64XX_UART0 diff --git a/drivers/usb/host/s3c64xx-hcd.c b/drivers/usb/host/s3c64xx-hcd.c index 274a4ed..cd295da 100644 --- a/drivers/usb/host/s3c64xx-hcd.c +++ b/drivers/usb/host/s3c64xx-hcd.c @@ -25,7 +25,7 @@ */ #include -#include +#include int usb_cpu_init(void) { -- cgit v1.1 From 940032260914076b1594906334b2e3f7af6fb7cf Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Tue, 10 Nov 2009 20:23:50 +0900 Subject: s5pc1xx: serial: fix the error check logic Because of Frame error, Parity error and Overrun error are occured only receive operation, need to masking when error checking. Signed-off-by: Minkyu Kang --- drivers/serial/serial_s5pc1xx.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_s5pc1xx.c b/drivers/serial/serial_s5pc1xx.c index 68c06a9..73669a9 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; } -- cgit v1.1 From ac67804fbb2d82a19170066c02af7053d474ce8d Mon Sep 17 00:00:00 2001 From: "kevin.morfitt@fearnside-systems.co.uk" Date: Tue, 17 Nov 2009 18:30:34 +0900 Subject: Add a unified s3c24x0 header file This patch adds a unified s3c24x0 cpu header file that selects the header file for the specific s3c24x0 cpu from the SOC and CPU configs defined in board config file. This removes the current chain of s3c24-type #ifdef's from the s3c24x0 code. Signed-off-by: Kevin Morfitt Signed-off-by: Minkyu Kang --- drivers/i2c/s3c24x0_i2c.c | 6 +----- drivers/mtd/nand/s3c2410_nand.c | 2 +- drivers/rtc/s3c24x0_rtc.c | 6 +----- drivers/serial/serial_s3c24x0.c | 6 +----- drivers/usb/host/ohci-hcd.c | 3 +-- 5 files changed, 5 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 8fecc6e..c8371cf 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,11 +27,7 @@ */ #include -#if defined(CONFIG_S3C2400) -#include -#elif defined(CONFIG_S3C2410) -#include -#endif +#include #include #include diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c index 2f89b8c..a27d47e 100644 --- a/drivers/mtd/nand/s3c2410_nand.c +++ b/drivers/mtd/nand/s3c2410_nand.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #define S3C2410_NFCONF_EN (1<<15) diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c index 2d78f93..04de5ca 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 -#elif defined(CONFIG_S3C2410) -#include -#endif +#include #include #include diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c index 914d07c..5dd4dd8 100644 --- a/drivers/serial/serial_s3c24x0.c +++ b/drivers/serial/serial_s3c24x0.c @@ -19,11 +19,7 @@ */ #include -#if defined(CONFIG_S3C2400) || defined(CONFIG_TRAB) -#include -#elif defined(CONFIG_S3C2410) -#include -#endif +#include DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 67d478f..b03a600 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) || \ -- cgit v1.1 From 39ba774f9b02c44b8fd4df44afac932800c18662 Mon Sep 17 00:00:00 2001 From: Po-Yu Chuang Date: Wed, 11 Nov 2009 17:26:00 +0800 Subject: arm: A320: driver for FTRTC010 real time clock This patch adds an FTRTC010 driver for Faraday A320 evaluation board. Signed-off-by: Po-Yu Chuang --- drivers/rtc/Makefile | 1 + drivers/rtc/ftrtc010.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 drivers/rtc/ftrtc010.c (limited to 'drivers') diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index ea7d899..772a49a 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -40,6 +40,7 @@ COBJS-$(CONFIG_RTC_DS1556) += ds1556.o COBJS-$(CONFIG_RTC_DS164x) += ds164x.o COBJS-$(CONFIG_RTC_DS174x) += ds174x.o COBJS-$(CONFIG_RTC_DS3231) += ds3231.o +COBJS-$(CONFIG_RTC_FTRTC010) += ftrtc010.o COBJS-$(CONFIG_RTC_ISL1208) += isl1208.o COBJS-$(CONFIG_RTC_M41T11) += m41t11.o COBJS-$(CONFIG_RTC_M41T60) += m41t60.o diff --git a/drivers/rtc/ftrtc010.c b/drivers/rtc/ftrtc010.c new file mode 100644 index 0000000..7738a7a --- /dev/null +++ b/drivers/rtc/ftrtc010.c @@ -0,0 +1,124 @@ +/* + * Faraday FTRTC010 Real Time Clock + * + * (C) Copyright 2009 Faraday Technology + * Po-Yu Chuang + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +struct ftrtc010 { + unsigned int sec; /* 0x00 */ + unsigned int min; /* 0x04 */ + unsigned int hour; /* 0x08 */ + unsigned int day; /* 0x0c */ + unsigned int alarm_sec; /* 0x10 */ + unsigned int alarm_min; /* 0x14 */ + unsigned int alarm_hour; /* 0x18 */ + unsigned int record; /* 0x1c */ + unsigned int cr; /* 0x20 */ +}; + +/* + * RTC Control Register + */ +#define FTRTC010_CR_ENABLE (1 << 0) +#define FTRTC010_CR_INTERRUPT_SEC (1 << 1) /* per second irq */ +#define FTRTC010_CR_INTERRUPT_MIN (1 << 2) /* per minute irq */ +#define FTRTC010_CR_INTERRUPT_HR (1 << 3) /* per hour irq */ +#define FTRTC010_CR_INTERRUPT_DAY (1 << 4) /* per day irq */ + +static struct ftrtc010 *rtc = (struct ftrtc010 *)CONFIG_FTRTC010_BASE; + +static void ftrtc010_enable(void) +{ + writel(FTRTC010_CR_ENABLE, &rtc->cr); +} + +/* + * return current time in seconds + */ +static unsigned long ftrtc010_time(void) +{ + unsigned long day; + unsigned long hour; + unsigned long minute; + unsigned long second; + unsigned long second2; + + do { + 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; +} + +/* + * Get the current time from the RTC + */ + +int rtc_get(struct rtc_time *tmp) +{ + unsigned long now; + + debug("%s(): record register: %x\n", + __func__, readl(&rtc->record)); + + now = ftrtc010_time() + readl(&rtc->record); + + to_tm(now, tmp); + + return 0; +} + +/* + * Set the RTC + */ +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); + + new = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour, + tmp->tm_min, tmp->tm_sec); + + now = ftrtc010_time(); + + debug("%s(): write %lx to record register\n", __func__, new - now); + + writel(new - now, &rtc->record); + + return 0; +} + +void rtc_reset(void) +{ + debug("%s()\n", __func__); + ftrtc010_enable(); +} -- cgit v1.1 From 7c15121f4007751af8c45c978c4ad7d6c5ff11f9 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 23 Nov 2009 16:36:05 +0530 Subject: omap3_mmc: Encapsulate twl4030 under option CONFIG_TWL4030_POWER Fixes the build/compilation error if we try to re-use the omap3_mmc code without TWL4030_POWER. Signed-off-by: Vaibhav Hiremath --- drivers/mmc/omap3_mmc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/omap3_mmc.c b/drivers/mmc/omap3_mmc.c index 513dd25..96c0e65 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, -- cgit v1.1 From 4b142febff71eabdb7ddbb125c7b583b24ddc434 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Thu, 3 Dec 2009 11:21:21 +0100 Subject: common: delete CONFIG_SYS_64BIT_VSPRINTF and CONFIG_SYS_64BIT_STRTOUL There is more and more usage of printing 64bit values, so enable this feature generally, and delete the CONFIG_SYS_64BIT_VSPRINTF and CONFIG_SYS_64BIT_STRTOUL defines. Signed-off-by: Heiko Schocher --- drivers/mtd/nand/nand_util.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 7085d42..df7f140 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -41,10 +41,6 @@ #include #include -#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; -- cgit v1.1