1/* 2 * linux/drivers/mtd/onenand/onenand_sim.c 3 * 4 * The OneNAND simulator 5 * 6 * Copyright �� 2005-2007 Samsung Electronics 7 * Kyungmin Park <kyungmin.park@samsung.com> 8 * 9 * Vishak G <vishak.g at samsung.com>, Rohit Hagargundgi <h.rohit at samsung.com> 10 * Flex-OneNAND simulator support 11 * Copyright (C) Samsung Electronics, 2008 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License version 2 as 15 * published by the Free Software Foundation. 16 */ 17 18#include <linux/kernel.h> 19#include <linux/slab.h> 20#include <linux/module.h> 21#include <linux/init.h> 22#include <linux/vmalloc.h> 23#include <linux/mtd/mtd.h> 24#include <linux/mtd/partitions.h> 25#include <linux/mtd/onenand.h> 26 27#include <linux/io.h> 28 29#ifndef CONFIG_ONENAND_SIM_MANUFACTURER 30#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec 31#endif 32 33#ifndef CONFIG_ONENAND_SIM_DEVICE_ID 34#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04 35#endif 36 37#define CONFIG_FLEXONENAND ((CONFIG_ONENAND_SIM_DEVICE_ID >> 9) & 1) 38 39#ifndef CONFIG_ONENAND_SIM_VERSION_ID 40#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e 41#endif 42 43#ifndef CONFIG_ONENAND_SIM_TECHNOLOGY_ID 44#define CONFIG_ONENAND_SIM_TECHNOLOGY_ID CONFIG_FLEXONENAND 45#endif 46 47/* Initial boundary values for Flex-OneNAND Simulator */ 48#ifndef CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY 49#define CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY 0x01 50#endif 51 52#ifndef CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY 53#define CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY 0x01 54#endif 55 56static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER; 57static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID; 58static int version_id = CONFIG_ONENAND_SIM_VERSION_ID; 59static int technology_id = CONFIG_ONENAND_SIM_TECHNOLOGY_ID; 60static int boundary[] = { 61 CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY, 62 CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY, 63}; 64 65struct onenand_flash { 66 void __iomem *base; 67 void __iomem *data; 68}; 69 70#define ONENAND_CORE(flash) (flash->data) 71#define ONENAND_CORE_SPARE(flash, this, offset) \ 72 ((flash->data) + (this->chipsize) + (offset >> 5)) 73 74#define ONENAND_MAIN_AREA(this, offset) \ 75 (this->base + ONENAND_DATARAM + offset) 76 77#define ONENAND_SPARE_AREA(this, offset) \ 78 (this->base + ONENAND_SPARERAM + offset) 79 80#define ONENAND_GET_WP_STATUS(this) \ 81 (readw(this->base + ONENAND_REG_WP_STATUS)) 82 83#define ONENAND_SET_WP_STATUS(v, this) \ 84 (writew(v, this->base + ONENAND_REG_WP_STATUS)) 85 86/* It has all 0xff chars */ 87#define MAX_ONENAND_PAGESIZE (4096 + 128) 88static unsigned char *ffchars; 89 90#if CONFIG_FLEXONENAND 91#define PARTITION_NAME "Flex-OneNAND simulator partition" 92#else 93#define PARTITION_NAME "OneNAND simulator partition" 94#endif 95 96static struct mtd_partition os_partitions[] = { 97 { 98 .name = PARTITION_NAME, 99 .offset = 0, 100 .size = MTDPART_SIZ_FULL, 101 }, 102}; 103 104/* 105 * OneNAND simulator mtd 106 */ 107struct onenand_info { 108 struct mtd_info mtd; 109 struct mtd_partition *parts; 110 struct onenand_chip onenand; 111 struct onenand_flash flash; 112}; 113 114static struct onenand_info *info; 115 116#define DPRINTK(format, args...) \ 117do { \ 118 printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \ 119 __LINE__, ##args); \ 120} while (0) 121 122/** 123 * onenand_lock_handle - Handle Lock scheme 124 * @this: OneNAND device structure 125 * @cmd: The command to be sent 126 * 127 * Send lock command to OneNAND device. 128 * The lock scheme depends on chip type. 129 */ 130static void onenand_lock_handle(struct onenand_chip *this, int cmd) 131{ 132 int block_lock_scheme; 133 int status; 134 135 status = ONENAND_GET_WP_STATUS(this); 136 block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK); 137 138 switch (cmd) { 139 case ONENAND_CMD_UNLOCK: 140 case ONENAND_CMD_UNLOCK_ALL: 141 if (block_lock_scheme) 142 ONENAND_SET_WP_STATUS(ONENAND_WP_US, this); 143 else 144 ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this); 145 break; 146 147 case ONENAND_CMD_LOCK: 148 if (block_lock_scheme) 149 ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this); 150 else 151 ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this); 152 break; 153 154 case ONENAND_CMD_LOCK_TIGHT: 155 if (block_lock_scheme) 156 ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this); 157 else 158 ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this); 159 break; 160 161 default: 162 break; 163 } 164} 165 166/** 167 * onenand_bootram_handle - Handle BootRAM area 168 * @this: OneNAND device structure 169 * @cmd: The command to be sent 170 * 171 * Emulate BootRAM area. It is possible to do basic operation using BootRAM. 172 */ 173static void onenand_bootram_handle(struct onenand_chip *this, int cmd) 174{ 175 switch (cmd) { 176 case ONENAND_CMD_READID: 177 writew(manuf_id, this->base); 178 writew(device_id, this->base + 2); 179 writew(version_id, this->base + 4); 180 break; 181 182 default: 183 /* REVIST: Handle other commands */ 184 break; 185 } 186} 187 188/** 189 * onenand_update_interrupt - Set interrupt register 190 * @this: OneNAND device structure 191 * @cmd: The command to be sent 192 * 193 * Update interrupt register. The status depends on command. 194 */ 195static void onenand_update_interrupt(struct onenand_chip *this, int cmd) 196{ 197 int interrupt = ONENAND_INT_MASTER; 198 199 switch (cmd) { 200 case ONENAND_CMD_READ: 201 case ONENAND_CMD_READOOB: 202 interrupt |= ONENAND_INT_READ; 203 break; 204 205 case ONENAND_CMD_PROG: 206 case ONENAND_CMD_PROGOOB: 207 interrupt |= ONENAND_INT_WRITE; 208 break; 209 210 case ONENAND_CMD_ERASE: 211 interrupt |= ONENAND_INT_ERASE; 212 break; 213 214 case ONENAND_CMD_RESET: 215 interrupt |= ONENAND_INT_RESET; 216 break; 217 218 default: 219 break; 220 } 221 222 writew(interrupt, this->base + ONENAND_REG_INTERRUPT); 223} 224 225/** 226 * onenand_check_overwrite - Check if over-write happened 227 * @dest: The destination pointer 228 * @src: The source pointer 229 * @count: The length to be check 230 * 231 * Returns: 0 on same, otherwise 1 232 * 233 * Compare the source with destination 234 */ 235static int onenand_check_overwrite(void *dest, void *src, size_t count) 236{ 237 unsigned int *s = (unsigned int *) src; 238 unsigned int *d = (unsigned int *) dest; 239 int i; 240 241 count >>= 2; 242 for (i = 0; i < count; i++) 243 if ((*s++ ^ *d++) != 0) 244 return 1; 245 246 return 0; 247} 248 249/** 250 * onenand_data_handle - Handle OneNAND Core and DataRAM 251 * @this: OneNAND device structure 252 * @cmd: The command to be sent 253 * @dataram: Which dataram used 254 * @offset: The offset to OneNAND Core 255 * 256 * Copy data from OneNAND Core to DataRAM (read) 257 * Copy data from DataRAM to OneNAND Core (write) 258 * Erase the OneNAND Core (erase) 259 */ 260static void onenand_data_handle(struct onenand_chip *this, int cmd, 261 int dataram, unsigned int offset) 262{ 263 struct mtd_info *mtd = &info->mtd; 264 struct onenand_flash *flash = this->priv; 265 int main_offset, spare_offset, die = 0; 266 void __iomem *src; 267 void __iomem *dest; 268 unsigned int i; 269 static int pi_operation; 270 int erasesize, rgn; 271 272 if (dataram) { 273 main_offset = mtd->writesize; 274 spare_offset = mtd->oobsize; 275 } else { 276 main_offset = 0; 277 spare_offset = 0; 278 } 279 280 if (pi_operation) { 281 die = readw(this->base + ONENAND_REG_START_ADDRESS2); 282 die >>= ONENAND_DDP_SHIFT; 283 } 284 285 switch (cmd) { 286 case FLEXONENAND_CMD_PI_ACCESS: 287 pi_operation = 1; 288 break; 289 290 case ONENAND_CMD_RESET: 291 pi_operation = 0; 292 break; 293 294 case ONENAND_CMD_READ: 295 src = ONENAND_CORE(flash) + offset; 296 dest = ONENAND_MAIN_AREA(this, main_offset); 297 if (pi_operation) { 298 writew(boundary[die], this->base + ONENAND_DATARAM); 299 break; 300 } 301 memcpy(dest, src, mtd->writesize); 302 /* Fall through */ 303 304 case ONENAND_CMD_READOOB: 305 src = ONENAND_CORE_SPARE(flash, this, offset); 306 dest = ONENAND_SPARE_AREA(this, spare_offset); 307 memcpy(dest, src, mtd->oobsize); 308 break; 309 310 case ONENAND_CMD_PROG: 311 src = ONENAND_MAIN_AREA(this, main_offset); 312 dest = ONENAND_CORE(flash) + offset; 313 if (pi_operation) { 314 boundary[die] = readw(this->base + ONENAND_DATARAM); 315 break; 316 } 317 /* To handle partial write */ 318 for (i = 0; i < (1 << mtd->subpage_sft); i++) { 319 int off = i * this->subpagesize; 320 if (!memcmp(src + off, ffchars, this->subpagesize)) 321 continue; 322 if (memcmp(dest + off, ffchars, this->subpagesize) && 323 onenand_check_overwrite(dest + off, src + off, this->subpagesize)) 324 printk(KERN_ERR "over-write happend at 0x%08x\n", offset); 325 memcpy(dest + off, src + off, this->subpagesize); 326 } 327 /* Fall through */ 328 329 case ONENAND_CMD_PROGOOB: 330 src = ONENAND_SPARE_AREA(this, spare_offset); 331 /* Check all data is 0xff chars */ 332 if (!memcmp(src, ffchars, mtd->oobsize)) 333 break; 334 335 dest = ONENAND_CORE_SPARE(flash, this, offset); 336 if (memcmp(dest, ffchars, mtd->oobsize) && 337 onenand_check_overwrite(dest, src, mtd->oobsize)) 338 printk(KERN_ERR "OOB: over-write happend at 0x%08x\n", 339 offset); 340 memcpy(dest, src, mtd->oobsize); 341 break; 342 343 case ONENAND_CMD_ERASE: 344 if (pi_operation) 345 break; 346 347 if (FLEXONENAND(this)) { 348 rgn = flexonenand_region(mtd, offset); 349 erasesize = mtd->eraseregions[rgn].erasesize; 350 } else 351 erasesize = mtd->erasesize; 352 353 memset(ONENAND_CORE(flash) + offset, 0xff, erasesize); 354 memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff, 355 (erasesize >> 5)); 356 break; 357 358 default: 359 break; 360 } 361} 362 363/** 364 * onenand_command_handle - Handle command 365 * @this: OneNAND device structure 366 * @cmd: The command to be sent 367 * 368 * Emulate OneNAND command. 369 */ 370static void onenand_command_handle(struct onenand_chip *this, int cmd) 371{ 372 unsigned long offset = 0; 373 int block = -1, page = -1, bufferram = -1; 374 int dataram = 0; 375 376 switch (cmd) { 377 case ONENAND_CMD_UNLOCK: 378 case ONENAND_CMD_LOCK: 379 case ONENAND_CMD_LOCK_TIGHT: 380 case ONENAND_CMD_UNLOCK_ALL: 381 onenand_lock_handle(this, cmd); 382 break; 383 384 case ONENAND_CMD_BUFFERRAM: 385 /* Do nothing */ 386 return; 387 388 default: 389 block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1); 390 if (block & (1 << ONENAND_DDP_SHIFT)) { 391 block &= ~(1 << ONENAND_DDP_SHIFT); 392 /* The half of chip block */ 393 block += this->chipsize >> (this->erase_shift + 1); 394 } 395 if (cmd == ONENAND_CMD_ERASE) 396 break; 397 398 page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8); 399 page = (page >> ONENAND_FPA_SHIFT); 400 bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER); 401 bufferram >>= ONENAND_BSA_SHIFT; 402 bufferram &= ONENAND_BSA_DATARAM1; 403 dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0; 404 break; 405 } 406 407 if (block != -1) 408 offset = onenand_addr(this, block); 409 410 if (page != -1) 411 offset += page << this->page_shift; 412 413 onenand_data_handle(this, cmd, dataram, offset); 414 415 onenand_update_interrupt(this, cmd); 416} 417 418/** 419 * onenand_writew - [OneNAND Interface] Emulate write operation 420 * @value: value to write 421 * @addr: address to write 422 * 423 * Write OneNAND register with value 424 */ 425static void onenand_writew(unsigned short value, void __iomem * addr) 426{ 427 struct onenand_chip *this = info->mtd.priv; 428 429 /* BootRAM handling */ 430 if (addr < this->base + ONENAND_DATARAM) { 431 onenand_bootram_handle(this, value); 432 return; 433 } 434 /* Command handling */ 435 if (addr == this->base + ONENAND_REG_COMMAND) 436 onenand_command_handle(this, value); 437 438 writew(value, addr); 439} 440 441/** 442 * flash_init - Initialize OneNAND simulator 443 * @flash: OneNAND simulator data strucutres 444 * 445 * Initialize OneNAND simulator. 446 */ 447static int __init flash_init(struct onenand_flash *flash) 448{ 449 int density, size; 450 int buffer_size; 451 452 flash->base = kzalloc(131072, GFP_KERNEL); 453 if (!flash->base) { 454 printk(KERN_ERR "Unable to allocate base address.\n"); 455 return -ENOMEM; 456 } 457 458 density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT; 459 density &= ONENAND_DEVICE_DENSITY_MASK; 460 size = ((16 << 20) << density); 461 462 ONENAND_CORE(flash) = vmalloc(size + (size >> 5)); 463 if (!ONENAND_CORE(flash)) { 464 printk(KERN_ERR "Unable to allocate nand core address.\n"); 465 kfree(flash->base); 466 return -ENOMEM; 467 } 468 469 memset(ONENAND_CORE(flash), 0xff, size + (size >> 5)); 470 471 /* Setup registers */ 472 writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID); 473 writew(device_id, flash->base + ONENAND_REG_DEVICE_ID); 474 writew(version_id, flash->base + ONENAND_REG_VERSION_ID); 475 writew(technology_id, flash->base + ONENAND_REG_TECHNOLOGY); 476 477 if (density < 2 && (!CONFIG_FLEXONENAND)) 478 buffer_size = 0x0400; /* 1KiB page */ 479 else 480 buffer_size = 0x0800; /* 2KiB page */ 481 writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE); 482 483 return 0; 484} 485 486/** 487 * flash_exit - Clean up OneNAND simulator 488 * @flash: OneNAND simulator data structures 489 * 490 * Clean up OneNAND simulator. 491 */ 492static void flash_exit(struct onenand_flash *flash) 493{ 494 vfree(ONENAND_CORE(flash)); 495 kfree(flash->base); 496} 497 498static int __init onenand_sim_init(void) 499{ 500 /* Allocate all 0xff chars pointer */ 501 ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL); 502 if (!ffchars) { 503 printk(KERN_ERR "Unable to allocate ff chars.\n"); 504 return -ENOMEM; 505 } 506 memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE); 507 508 /* Allocate OneNAND simulator mtd pointer */ 509 info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); 510 if (!info) { 511 printk(KERN_ERR "Unable to allocate core structures.\n"); 512 kfree(ffchars); 513 return -ENOMEM; 514 } 515 516 /* Override write_word function */ 517 info->onenand.write_word = onenand_writew; 518 519 if (flash_init(&info->flash)) { 520 printk(KERN_ERR "Unable to allocate flash.\n"); 521 kfree(ffchars); 522 kfree(info); 523 return -ENOMEM; 524 } 525 526 info->parts = os_partitions; 527 528 info->onenand.base = info->flash.base; 529 info->onenand.priv = &info->flash; 530 531 info->mtd.name = "OneNAND simulator"; 532 info->mtd.priv = &info->onenand; 533 info->mtd.owner = THIS_MODULE; 534 535 if (onenand_scan(&info->mtd, 1)) { 536 flash_exit(&info->flash); 537 kfree(ffchars); 538 kfree(info); 539 return -ENXIO; 540 } 541 542 add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions)); 543 544 return 0; 545} 546 547static void __exit onenand_sim_exit(void) 548{ 549 struct onenand_chip *this = info->mtd.priv; 550 struct onenand_flash *flash = this->priv; 551 552 onenand_release(&info->mtd); 553 flash_exit(flash); 554 kfree(ffchars); 555 kfree(info); 556} 557 558module_init(onenand_sim_init); 559module_exit(onenand_sim_exit); 560 561MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); 562MODULE_DESCRIPTION("The OneNAND flash simulator"); 563MODULE_LICENSE("GPL"); 564