onenand_sim.c 13 KB

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