diff options
author | David Woodhouse <dwmw2@infradead.org> | 2008-02-03 02:31:04 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2008-02-03 02:31:04 -0500 |
commit | b7e23d913aafc93fc5f119e1be17620073cc3811 (patch) | |
tree | 0f76a32d5b22cf12f6f822cf0c04481f3bb227fb | |
parent | c1f3ee120bb61045b1c0a3ead620d1d65af47130 (diff) | |
parent | 69d79186dc48ca22a0ce69511bef8ef6c2465ada (diff) |
Merge git://git.infradead.org/~kmpark/onenand-mtd-2.6
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 59 | ||||
-rw-r--r-- | include/linux/mtd/onenand_regs.h | 1 |
2 files changed, 29 insertions, 31 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ed9f9c061ac5..b281b116aaeb 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -170,6 +170,18 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) | |||
170 | } | 170 | } |
171 | 171 | ||
172 | /** | 172 | /** |
173 | * onenand_get_density - [DEFAULT] Get OneNAND density | ||
174 | * @param dev_id OneNAND device ID | ||
175 | * | ||
176 | * Get OneNAND density from device ID | ||
177 | */ | ||
178 | static inline int onenand_get_density(int dev_id) | ||
179 | { | ||
180 | int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
181 | return (density & ONENAND_DEVICE_DENSITY_MASK); | ||
182 | } | ||
183 | |||
184 | /** | ||
173 | * onenand_command - [DEFAULT] Send command to OneNAND device | 185 | * onenand_command - [DEFAULT] Send command to OneNAND device |
174 | * @param mtd MTD device structure | 186 | * @param mtd MTD device structure |
175 | * @param cmd the command to be sent | 187 | * @param cmd the command to be sent |
@@ -182,8 +194,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) | |||
182 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) | 194 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) |
183 | { | 195 | { |
184 | struct onenand_chip *this = mtd->priv; | 196 | struct onenand_chip *this = mtd->priv; |
185 | int value, readcmd = 0, block_cmd = 0; | 197 | int value, block, page; |
186 | int block, page; | ||
187 | 198 | ||
188 | /* Address translation */ | 199 | /* Address translation */ |
189 | switch (cmd) { | 200 | switch (cmd) { |
@@ -198,7 +209,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
198 | case ONENAND_CMD_ERASE: | 209 | case ONENAND_CMD_ERASE: |
199 | case ONENAND_CMD_BUFFERRAM: | 210 | case ONENAND_CMD_BUFFERRAM: |
200 | case ONENAND_CMD_OTP_ACCESS: | 211 | case ONENAND_CMD_OTP_ACCESS: |
201 | block_cmd = 1; | ||
202 | block = (int) (addr >> this->erase_shift); | 212 | block = (int) (addr >> this->erase_shift); |
203 | page = -1; | 213 | page = -1; |
204 | break; | 214 | break; |
@@ -240,11 +250,9 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
240 | value = onenand_block_address(this, block); | 250 | value = onenand_block_address(this, block); |
241 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | 251 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); |
242 | 252 | ||
243 | if (block_cmd) { | 253 | /* Select DataRAM for DDP */ |
244 | /* Select DataRAM for DDP */ | 254 | value = onenand_bufferram_address(this, block); |
245 | value = onenand_bufferram_address(this, block); | 255 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); |
246 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
247 | } | ||
248 | } | 256 | } |
249 | 257 | ||
250 | if (page != -1) { | 258 | if (page != -1) { |
@@ -256,7 +264,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
256 | case ONENAND_CMD_READ: | 264 | case ONENAND_CMD_READ: |
257 | case ONENAND_CMD_READOOB: | 265 | case ONENAND_CMD_READOOB: |
258 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); | 266 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); |
259 | readcmd = 1; | ||
260 | break; | 267 | break; |
261 | 268 | ||
262 | default: | 269 | default: |
@@ -273,12 +280,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
273 | /* Write 'BSA, BSC' of DataRAM */ | 280 | /* Write 'BSA, BSC' of DataRAM */ |
274 | value = onenand_buffer_address(dataram, sectors, count); | 281 | value = onenand_buffer_address(dataram, sectors, count); |
275 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); | 282 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); |
276 | |||
277 | if (readcmd) { | ||
278 | /* Select DataRAM for DDP */ | ||
279 | value = onenand_bufferram_address(this, block); | ||
280 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
281 | } | ||
282 | } | 283 | } |
283 | 284 | ||
284 | /* Interrupt clear */ | 285 | /* Interrupt clear */ |
@@ -1118,12 +1119,10 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
1118 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 1119 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
1119 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 1120 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
1120 | 1121 | ||
1122 | /* Initial bad block case: 0x2400 or 0x0400 */ | ||
1121 | if (ctrl & ONENAND_CTRL_ERROR) { | 1123 | if (ctrl & ONENAND_CTRL_ERROR) { |
1122 | printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); | 1124 | printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); |
1123 | /* Initial bad block case */ | 1125 | return ONENAND_BBT_READ_ERROR; |
1124 | if (ctrl & ONENAND_CTRL_LOAD) | ||
1125 | return ONENAND_BBT_READ_ERROR; | ||
1126 | return ONENAND_BBT_READ_FATAL_ERROR; | ||
1127 | } | 1126 | } |
1128 | 1127 | ||
1129 | if (interrupt & ONENAND_INT_READ) { | 1128 | if (interrupt & ONENAND_INT_READ) { |
@@ -1218,7 +1217,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | |||
1218 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) | 1217 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) |
1219 | { | 1218 | { |
1220 | struct onenand_chip *this = mtd->priv; | 1219 | struct onenand_chip *this = mtd->priv; |
1221 | char oobbuf[64]; | 1220 | u_char *oob_buf = this->oob_buf; |
1222 | int status, i; | 1221 | int status, i; |
1223 | 1222 | ||
1224 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); | 1223 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); |
@@ -1227,9 +1226,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
1227 | if (status) | 1226 | if (status) |
1228 | return status; | 1227 | return status; |
1229 | 1228 | ||
1230 | this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | 1229 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); |
1231 | for (i = 0; i < mtd->oobsize; i++) | 1230 | for (i = 0; i < mtd->oobsize; i++) |
1232 | if (buf[i] != 0xFF && buf[i] != oobbuf[i]) | 1231 | if (buf[i] != 0xFF && buf[i] != oob_buf[i]) |
1233 | return -EBADMSG; | 1232 | return -EBADMSG; |
1234 | 1233 | ||
1235 | return 0; | 1234 | return 0; |
@@ -1431,7 +1430,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1431 | } | 1430 | } |
1432 | 1431 | ||
1433 | /* Only check verify write turn on */ | 1432 | /* Only check verify write turn on */ |
1434 | ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); | 1433 | ret = onenand_verify(mtd, buf, to, thislen); |
1435 | if (ret) { | 1434 | if (ret) { |
1436 | printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); | 1435 | printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); |
1437 | break; | 1436 | break; |
@@ -1447,9 +1446,6 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1447 | buf += thislen; | 1446 | buf += thislen; |
1448 | } | 1447 | } |
1449 | 1448 | ||
1450 | /* Deselect and wake up anyone waiting on the device */ | ||
1451 | onenand_release_device(mtd); | ||
1452 | |||
1453 | ops->retlen = written; | 1449 | ops->retlen = written; |
1454 | 1450 | ||
1455 | return ret; | 1451 | return ret; |
@@ -2160,7 +2156,7 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, | |||
2160 | 2156 | ||
2161 | *retlen = 0; | 2157 | *retlen = 0; |
2162 | 2158 | ||
2163 | density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2159 | density = onenand_get_density(this->device_id); |
2164 | if (density < ONENAND_DEVICE_DENSITY_512Mb) | 2160 | if (density < ONENAND_DEVICE_DENSITY_512Mb) |
2165 | otp_pages = 20; | 2161 | otp_pages = 20; |
2166 | else | 2162 | else |
@@ -2311,7 +2307,8 @@ static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from, | |||
2311 | static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, | 2307 | static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, |
2312 | size_t len) | 2308 | size_t len) |
2313 | { | 2309 | { |
2314 | unsigned char oob_buf[64]; | 2310 | struct onenand_chip *this = mtd->priv; |
2311 | u_char *oob_buf = this->oob_buf; | ||
2315 | size_t retlen; | 2312 | size_t retlen; |
2316 | int ret; | 2313 | int ret; |
2317 | 2314 | ||
@@ -2351,7 +2348,7 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
2351 | unsigned int density, process; | 2348 | unsigned int density, process; |
2352 | 2349 | ||
2353 | /* Lock scheme depends on density and process */ | 2350 | /* Lock scheme depends on density and process */ |
2354 | density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2351 | density = onenand_get_density(this->device_id); |
2355 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; | 2352 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; |
2356 | 2353 | ||
2357 | /* Lock scheme */ | 2354 | /* Lock scheme */ |
@@ -2400,7 +2397,7 @@ static void onenand_print_device_info(int device, int version) | |||
2400 | vcc = device & ONENAND_DEVICE_VCC_MASK; | 2397 | vcc = device & ONENAND_DEVICE_VCC_MASK; |
2401 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; | 2398 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; |
2402 | ddp = device & ONENAND_DEVICE_IS_DDP; | 2399 | ddp = device & ONENAND_DEVICE_IS_DDP; |
2403 | density = device >> ONENAND_DEVICE_DENSITY_SHIFT; | 2400 | density = onenand_get_density(device); |
2404 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", | 2401 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", |
2405 | demuxed ? "" : "Muxed ", | 2402 | demuxed ? "" : "Muxed ", |
2406 | ddp ? "(DDP)" : "", | 2403 | ddp ? "(DDP)" : "", |
@@ -2492,7 +2489,7 @@ static int onenand_probe(struct mtd_info *mtd) | |||
2492 | this->device_id = dev_id; | 2489 | this->device_id = dev_id; |
2493 | this->version_id = ver_id; | 2490 | this->version_id = ver_id; |
2494 | 2491 | ||
2495 | density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2492 | density = onenand_get_density(dev_id); |
2496 | this->chipsize = (16 << density) << 20; | 2493 | this->chipsize = (16 << density) << 20; |
2497 | /* Set density mask. it is used for DDP */ | 2494 | /* Set density mask. it is used for DDP */ |
2498 | if (ONENAND_IS_DDP(this)) | 2495 | if (ONENAND_IS_DDP(this)) |
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h index c46161f4eee3..d1b310c92eb4 100644 --- a/include/linux/mtd/onenand_regs.h +++ b/include/linux/mtd/onenand_regs.h | |||
@@ -67,6 +67,7 @@ | |||
67 | /* | 67 | /* |
68 | * Device ID Register F001h (R) | 68 | * Device ID Register F001h (R) |
69 | */ | 69 | */ |
70 | #define ONENAND_DEVICE_DENSITY_MASK (0xf) | ||
70 | #define ONENAND_DEVICE_DENSITY_SHIFT (4) | 71 | #define ONENAND_DEVICE_DENSITY_SHIFT (4) |
71 | #define ONENAND_DEVICE_IS_DDP (1 << 3) | 72 | #define ONENAND_DEVICE_IS_DDP (1 << 3) |
72 | #define ONENAND_DEVICE_IS_DEMUX (1 << 2) | 73 | #define ONENAND_DEVICE_IS_DEMUX (1 << 2) |