1/*====================================================================== 2 3 $Id: doc1000.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $ 4 5======================================================================*/ 6 7 8#include <linux/config.h> 9#include <linux/module.h> 10#include <asm/uaccess.h> 11#include <linux/types.h> 12#include <linux/kernel.h> 13#include <linux/sched.h> 14#include <linux/ptrace.h> 15#include <linux/slab.h> 16#include <linux/string.h> 17#include <linux/timer.h> 18#include <linux/major.h> 19#include <linux/fs.h> 20#include <linux/ioctl.h> 21#include <asm/io.h> 22#include <asm/system.h> 23#include <asm/segment.h> 24#include <stdarg.h> 25#include <linux/delay.h> 26#include <linux/init.h> 27 28#include <linux/mtd/mtd.h> 29#include <linux/mtd/iflash.h> 30 31/* Parameters that can be set with 'insmod' */ 32 33static u_long base = 0xe0000; 34static int erase_timeout = 10*HZ; /* in ticks */ 35static int retry_limit = 4; /* write retries */ 36static u_long max_tries = 4096; /* status polling */ 37 38MODULE_PARM(base,"l"); 39MODULE_PARM(erase_timeout, "i"); 40MODULE_PARM(retry_limit, "i"); 41MODULE_PARM(max_tries, "i"); 42 43#define WINDOW_SIZE 0x2000 44#define WINDOW_MASK (WINDOW_SIZE - 1) 45#define PAGEREG_LO (WINDOW_SIZE) 46#define PAGEREG_HI (WINDOW_SIZE + 2) 47 48static struct mtd_info *mymtd; 49static struct timer_list flashcard_timer; 50 51#define MAX_CELLS 32 52#define MAX_FLASH_DEVICES 8 53 54/* A flash region is composed of one or more "cells", where we allow 55 simultaneous erases if they are in different cells */ 56 57 58 59struct mypriv { 60 u_char *baseaddr; 61 u_short curpage; 62 u_char locked; 63 u_short numdevices; 64 u_char interleave; 65 struct erase_info *cur_erases; 66 wait_queue_head_t wq; 67 u_char devstat[MAX_FLASH_DEVICES]; 68 u_long devshift; 69}; 70 71 72static void flashcard_periodic(u_long data); 73static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr); 74static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); 75static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); 76static void flashcard_sync (struct mtd_info *mtd); 77 78static inline void resume_erase(volatile u_char *addr); 79static inline int suspend_erase(volatile u_char *addr); 80static inline int byte_write (volatile u_char *addr, u_char byte); 81static inline int word_write (volatile u_char *addr, __u16 word); 82static inline int check_write(volatile u_char *addr); 83static inline void block_erase (volatile u_char *addr); 84static inline int check_erase(volatile u_char *addr); 85 86#ifdef CONFIG_SMP 87#warning This is definitely not SMP safe. Lock the paging mechanism. 88#endif 89 90static u_char *pagein(struct mtd_info *mtd, u_long addr) 91{ 92 struct mypriv *priv=mtd->priv; 93 u_short page = addr >> 13; 94 95 priv->baseaddr[PAGEREG_LO] = page & 0xff; 96 priv->baseaddr[PAGEREG_HI] = page >> 8; 97 priv->curpage = page; 98 99 return &priv->baseaddr[addr & WINDOW_MASK]; 100} 101 102 103void flashcard_sync (struct mtd_info *mtd) 104{ 105 struct mypriv *priv=mtd->priv; 106 107 flashcard_periodic((u_long) mtd); 108 printk("sync..."); 109 if (priv->cur_erases) 110 interruptible_sleep_on(&priv->wq); 111 printk("Done.\n"); 112} 113 114int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr) 115{ 116 u_char *pageaddr; 117 struct mypriv *priv=mtd->priv; 118 struct erase_info **tmp=&priv->cur_erases; 119 120 if (instr->len != mtd->erasesize) 121 return -EINVAL; 122 if (instr->addr + instr->len > mtd->size) 123 return -EINVAL; 124 125 pageaddr=pagein(mtd,instr->addr); 126 instr->mtd = mtd; 127 instr->dev = instr->addr >> priv->devshift; 128 instr->cell = (instr->addr - (instr->dev << priv->devshift)) / mtd->erasesize; 129 instr->next = NULL; 130 instr->state = MTD_ERASE_PENDING; 131 132 while (*tmp) 133 { 134 tmp = &((*tmp) -> next); 135 } 136 137 *tmp = instr; 138 flashcard_periodic((u_long)mtd); 139 return 0; 140} 141 142 143int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 144{ 145 u_char *pageaddr=pagein(mtd,from); 146 struct mypriv *priv=mtd->priv; 147 u_char device = from >> priv->devshift; 148 u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize; 149 int ret = 0, timeron = 0; 150 151 if ((from & WINDOW_MASK) + len <= WINDOW_SIZE) 152 *retlen = len; 153 else 154 *retlen = WINDOW_SIZE - (from & WINDOW_MASK); 155 156 if (priv->devstat[device]) 157 { 158 159 /* There is an erase in progress or pending for this device. Stop it */ 160 timeron = del_timer(&flashcard_timer); 161 162 if (priv->cur_erases && priv->cur_erases->cell == cell) 163 164 { 165 /* The erase is on the current cell. Just return all 0xff */ 166 add_timer(&flashcard_timer); 167 168 169 printk("Cell %d currently erasing. Setting to all 0xff\n",cell); 170 memset(buf, 0xff, *retlen); 171 return 0; 172 } 173 if (priv->devstat[device] == MTD_ERASING) 174 { 175 ret = suspend_erase(pageaddr); 176 priv->devstat[device] = MTD_ERASE_SUSPEND; 177 178 if (ret) 179 { 180 printk("flashcard: failed to suspend erase\n"); 181 add_timer (&flashcard_timer); 182 return ret; 183 } 184 } 185 186 } 187 188 writew(IF_READ_ARRAY, (u_long)pageaddr & ~1); 189 190 ret = 0; 191 memcpy (buf, pageaddr, *retlen); 192 193 writew(IF_READ_CSR, (u_long)pageaddr & ~1); 194 195 196 if (priv->devstat[device] & MTD_ERASE_SUSPEND) 197 { 198 resume_erase(pageaddr); 199 priv->devstat[device]=MTD_ERASING; 200 } 201 202 203 if (timeron) add_timer (&flashcard_timer); 204 205 return ret; 206} 207 208 209int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) 210{ 211 struct mypriv *priv = (struct mypriv *)mtd->priv; 212 u_char *endaddr, *startaddr; 213 register u_char *pageaddr; 214 u_char device = to >> priv->devshift; 215/* jiffies_t oldj=jiffies;*/ 216 int ret; 217 218 while (priv->devstat[device]) 219 { 220 flashcard_sync(mtd); 221 } 222 223 if ((to & WINDOW_MASK) + len <= WINDOW_SIZE) 224 *retlen = len; 225 else 226 *retlen = WINDOW_SIZE - (to & WINDOW_MASK); 227 228 pageaddr = pagein(mtd, to); 229 startaddr = (u_char *)((u_long) pageaddr & ~1); 230 endaddr = pageaddr+(*retlen); 231 232 233 234 /* Set up to read */ 235 writew(IF_READ_CSR, startaddr); 236 237 /* Make sure it's aligned by reading the first byte if necessary */ 238 if (to & 1) 239 { 240 /* Unaligned access */ 241 242 u_char cbuf; 243 244 cbuf = *buf; 245 246 if (!((u_long)pageaddr & 0xf)) 247 schedule(); 248 249 ret = byte_write(pageaddr, cbuf); 250 if (ret) return ret; 251 252 pageaddr++; buf++; 253 } 254 255 256 for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2) 257 { 258 /* if ((u_long)pageaddr & 0xf) schedule();*/ 259 260 ret = word_write(pageaddr, *(__u16 *)buf); 261 if (ret) 262 return ret; 263 } 264 265 if (pageaddr != endaddr) 266 { 267 /* One more byte to write at the end. */ 268 u_char cbuf; 269 270 cbuf = *buf; 271 272 ret = byte_write(pageaddr, cbuf); 273 274 if (ret) return ret; 275 } 276 277 return check_write(startaddr); 278/* printk("Time taken in flashcard_write: %lx jiffies\n",jiffies - oldj);*/ 279} 280 281 282 283 284/*====================================================================*/ 285 286static inline int byte_write (volatile u_char *addr, u_char byte) 287{ 288 register u_char status; 289 register u_short i = 0; 290 291 do { 292 status = readb(addr); 293 if (status & CSR_WR_READY) 294 { 295 writeb(IF_WRITE & 0xff, addr); 296 writeb(byte, addr); 297 return 0; 298 } 299 i++; 300 } while(i < max_tries); 301 302 303 printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status); 304 return -EIO; 305} 306 307static inline int word_write (volatile u_char *addr, __u16 word) 308{ 309 register u_short status; 310 register u_short i = 0; 311 312 do { 313 status = readw(addr); 314 if ((status & CSR_WR_READY) == CSR_WR_READY) 315 { 316 writew(IF_WRITE, addr); 317 writew(word, addr); 318 return 0; 319 } 320 i++; 321 } while(i < max_tries); 322 323 printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status); 324 return -EIO; 325} 326 327static inline void block_erase (volatile u_char *addr) 328{ 329 writew(IF_BLOCK_ERASE, addr); 330 writew(IF_CONFIRM, addr); 331} 332 333 334static inline int check_erase(volatile u_char *addr) 335{ 336 __u16 status; 337 338/* writew(IF_READ_CSR, addr);*/ 339 status = readw(addr); 340 341 342 if ((status & CSR_WR_READY) != CSR_WR_READY) 343 return -EBUSY; 344 345 if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) 346 { 347 printk(KERN_NOTICE "flashcard: erase failed, status 0x%x\n", 348 status); 349 return -EIO; 350 } 351 352 return 0; 353} 354 355static inline int suspend_erase(volatile u_char *addr) 356{ 357 __u16 status; 358 u_long i = 0; 359 360 writew(IF_ERASE_SUSPEND, addr); 361 writew(IF_READ_CSR, addr); 362 363 do { 364 status = readw(addr); 365 if ((status & CSR_WR_READY) == CSR_WR_READY) 366 return 0; 367 i++; 368 } while(i < max_tries); 369 370 printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status); 371 return -EIO; 372 373} 374 375static inline void resume_erase(volatile u_char *addr) 376{ 377 __u16 status; 378 379 writew(IF_READ_CSR, addr); 380 status = readw(addr); 381 382 /* Only give resume signal if the erase is really suspended */ 383 if (status & CSR_ERA_SUSPEND) 384 writew(IF_CONFIRM, addr); 385} 386 387static inline void reset_block(volatile u_char *addr) 388{ 389 u_short i; 390 __u16 status; 391 392 writew(IF_CLEAR_CSR, addr); 393 394 for (i = 0; i < 100; i++) { 395 writew(IF_READ_CSR, addr); 396 status = readw(addr); 397 if (status != 0xffff) break; 398 udelay(1000); 399 } 400 401 writew(IF_READ_CSR, addr); 402} 403 404static inline int check_write(volatile u_char *addr) 405{ 406 u_short status, i = 0; 407 408 writew(IF_READ_CSR, addr); 409 410 do { 411 status = readw(addr); 412 if (status & (CSR_WR_ERR | CSR_VPP_LOW)) 413 { 414 printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status); 415 reset_block(addr); 416 return -EIO; 417 } 418 if ((status & CSR_WR_READY) == CSR_WR_READY) 419 return 0; 420 i++; 421 } while (i < max_tries); 422 423 printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status); 424 return -EIO; 425} 426 427 428/*====================================================================*/ 429 430 431 432static void flashcard_periodic(unsigned long data) 433{ 434 register struct mtd_info *mtd = (struct mtd_info *)data; 435 register struct mypriv *priv = mtd->priv; 436 struct erase_info *erase = priv->cur_erases; 437 u_char *pageaddr; 438 439 del_timer (&flashcard_timer); 440 441 if (!erase) 442 return; 443 444 pageaddr = pagein(mtd, erase->addr); 445 446 if (erase->state == MTD_ERASE_PENDING) 447 { 448 block_erase(pageaddr); 449 priv->devstat[erase->dev] = erase->state = MTD_ERASING; 450 erase->time = jiffies; 451 erase->retries = 0; 452 } 453 else if (erase->state == MTD_ERASING) 454 { 455 /* It's trying to erase. Check whether it's finished */ 456 457 int ret = check_erase(pageaddr); 458 459 if (!ret) 460 { 461 /* It's finished OK */ 462 priv->devstat[erase->dev] = 0; 463 priv->cur_erases = erase->next; 464 erase->state = MTD_ERASE_DONE; 465 if (erase->callback) 466 (*(erase->callback))(erase); 467 else 468 kfree(erase); 469 } 470 else if (ret == -EIO) 471 { 472 if (++erase->retries > retry_limit) 473 { 474 printk("Failed too many times. Giving up\n"); 475 priv->cur_erases = erase->next; 476 priv->devstat[erase->dev] = 0; 477 erase->state = MTD_ERASE_FAILED; 478 if (erase->callback) 479 (*(erase->callback))(erase); 480 else 481 kfree(erase); 482 } 483 else 484 priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING; 485 } 486 else if (time_after(jiffies, erase->time + erase_timeout)) 487 { 488 printk("Flash erase timed out. The world is broken.\n"); 489 490 /* Just ignore and hope it goes away. For a while, read ops will give the CSR 491 and writes won't work. */ 492 493 priv->cur_erases = erase->next; 494 priv->devstat[erase->dev] = 0; 495 erase->state = MTD_ERASE_FAILED; 496 if (erase->callback) 497 (*(erase->callback))(erase); 498 else 499 kfree(erase); 500 } 501 } 502 503 if (priv->cur_erases) 504 { 505 flashcard_timer.expires = jiffies + HZ; 506 add_timer (&flashcard_timer); 507 } 508 else 509 wake_up_interruptible(&priv->wq); 510 511} 512 513int __init init_doc1000(void) 514{ 515 struct mypriv *priv; 516 517 if (!base) 518 { 519 printk(KERN_NOTICE "flashcard: No start address for memory device.\n"); 520 return -EINVAL; 521 } 522 523 mymtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); 524 525 if (!mymtd) 526 { 527 printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n"); 528 return -ENOMEM; 529 } 530 531 memset(mymtd,0,sizeof(struct mtd_info)); 532 533 mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL); 534 if (!mymtd->priv) 535 { 536 kfree(mymtd); 537 printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n"); 538 return -ENOMEM; 539 } 540 541 542 543 544 priv=mymtd->priv; 545 init_waitqueue_head(&priv->wq); 546 547 memset (priv,0,sizeof(struct mypriv)); 548 549 priv->baseaddr = phys_to_virt(base); 550 priv->numdevices = 4; 551 552 mymtd->name = "M-Systems DiskOnChip 1000"; 553 554 mymtd->size = 0x100000; 555 mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE; 556 mymtd->erase = flashcard_erase; 557 mymtd->point = NULL; 558 mymtd->unpoint = NULL; 559 mymtd->read = flashcard_read; 560 mymtd->write = flashcard_write; 561 562 mymtd->sync = flashcard_sync; 563 mymtd->erasesize = 0x10000; 564 // mymtd->interleave = 2; 565 priv->devshift = 24; 566 mymtd->type = MTD_NORFLASH; 567 568 if (add_mtd_device(mymtd)) 569 { 570 printk(KERN_NOTICE "MTD device registration failed!\n"); 571 kfree(mymtd->priv); 572 kfree(mymtd); 573 return -EAGAIN; 574 } 575 576 init_timer(&flashcard_timer); 577 flashcard_timer.function = flashcard_periodic; 578 flashcard_timer.data = (u_long)mymtd; 579 return 0; 580} 581 582static void __init cleanup_doc1000(void) 583{ 584 kfree (mymtd->priv); 585 del_mtd_device(mymtd); 586 kfree(mymtd); 587} 588 589module_init(init_doc1000); 590module_exit(cleanup_doc1000); 591 592MODULE_LICENSE("GPL"); 593MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 594MODULE_DESCRIPTION("MTD driver for DiskOnChip 1000"); 595 596