Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
onenand_sim.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/mtd/onenand/onenand_sim.c
3  *
4  * The OneNAND simulator
5  *
6  * Copyright © 2005-2007 Samsung Electronics
7  * Kyungmin Park <[email protected]>
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 
56 static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER;
59 static int technology_id = CONFIG_ONENAND_SIM_TECHNOLOGY_ID;
60 static int boundary[] = {
63 };
64 
65 struct 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)
88 static 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 
96 static 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  */
107 struct onenand_info {
108  struct mtd_info mtd;
110  struct onenand_chip onenand;
112 };
113 
114 static struct onenand_info *info;
115 
116 #define DPRINTK(format, args...) \
117 do { \
118  printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \
119  __LINE__, ##args); \
120 } while (0)
121 
130 static 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:
141  if (block_lock_scheme)
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)
150  else
151  ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this);
152  break;
153 
155  if (block_lock_scheme)
157  else
158  ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this);
159  break;
160 
161  default:
162  break;
163  }
164 }
165 
173 static 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 
195 static void onenand_update_interrupt(struct onenand_chip *this, int cmd)
196 {
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 
235 static 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 
260 static 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) {
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 happened 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 happened 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 
370 static 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:
381  onenand_lock_handle(this, cmd);
382  break;
383 
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 
399  page = (page >> ONENAND_FPA_SHIFT);
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 
425 static 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 
447 static 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 
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);
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 
492 static void flash_exit(struct onenand_flash *flash)
493 {
494  vfree(ONENAND_CORE(flash));
495  kfree(flash->base);
496 }
497 
498 static int __init onenand_sim_init(void)
499 {
500  /* Allocate all 0xff chars pointer */
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  mtd_device_register(&info->mtd, info->parts,
543  ARRAY_SIZE(os_partitions));
544 
545  return 0;
546 }
547 
548 static void __exit onenand_sim_exit(void)
549 {
550  struct onenand_chip *this = info->mtd.priv;
551  struct onenand_flash *flash = this->priv;
552 
553  onenand_release(&info->mtd);
554  flash_exit(flash);
555  kfree(ffchars);
556  kfree(info);
557 }
558 
559 module_init(onenand_sim_init);
560 module_exit(onenand_sim_exit);
561 
562 MODULE_AUTHOR("Kyungmin Park <[email protected]>");
563 MODULE_DESCRIPTION("The OneNAND flash simulator");
564 MODULE_LICENSE("GPL");