1 From 6b663bce31fb1e1a78dbca22190e98251628fd4f Mon Sep 17 00:00:00 2001
2 From: Thomas Kunze <thommycheck@gmx.de>
3 Date: Mon, 20 Oct 2008 17:48:10 +0200
4 Subject: [PATCH 06/23] add collie flash hack
7 arch/arm/mach-sa1100/collie.c | 2 +-
8 drivers/mtd/chips/Kconfig | 8 +
9 drivers/mtd/chips/Makefile | 1 +
10 drivers/mtd/chips/sharp.c | 645 +++++++++++++++++++++++++++++++++++++++++
11 drivers/mtd/maps/Kconfig | 2 +-
12 5 files changed, 656 insertions(+), 2 deletions(-)
13 create mode 100644 drivers/mtd/chips/sharp.c
15 diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
16 index 8cf267f..ec673b8 100644
17 --- a/arch/arm/mach-sa1100/collie.c
18 +++ b/arch/arm/mach-sa1100/collie.c
19 @@ -222,7 +222,7 @@ static void collie_flash_exit(void)
20 gpio_free(COLLIE_GPIO_VPEN);
22 static struct flash_platform_data collie_flash_data = {
23 - .map_name = "cfi_probe",
24 + .map_name = "sharp",
25 .init = collie_flash_init,
26 .set_vpp = collie_set_vpp,
27 .exit = collie_flash_exit,
28 diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
29 index 9408099..2dcbd03 100644
30 --- a/drivers/mtd/chips/Kconfig
31 +++ b/drivers/mtd/chips/Kconfig
32 @@ -241,5 +241,13 @@ config MTD_XIP
33 used for XIP purposes. If you're not sure what this is all about
37 + tristate "pre-CFI Sharp chip support"
40 + This option enables support for flash chips using Sharp-compatible
41 + commands, including some which are not CFI-compatible and hence
42 + cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
46 diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
47 index 3658241..7283c57 100644
48 --- a/drivers/mtd/chips/Makefile
49 +++ b/drivers/mtd/chips/Makefile
50 @@ -12,4 +12,5 @@ obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o
51 obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o
52 obj-$(CONFIG_MTD_RAM) += map_ram.o
53 obj-$(CONFIG_MTD_ROM) += map_rom.o
54 +obj-$(CONFIG_MTD_SHARP) += sharp.o
55 obj-$(CONFIG_MTD_ABSENT) += map_absent.o
56 diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
58 index 0000000..046b964
60 +++ b/drivers/mtd/chips/sharp.c
63 + * MTD chip driver for pre-CFI Sharp flash chips
65 + * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
66 + * 2000,2001 Lineo, Inc.
68 + * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $
70 + * Devices supported:
71 + * LH28F016SCT Symmetrical block flash memory, 2Mx8
72 + * LH28F008SCT Symmetrical block flash memory, 1Mx8
75 + * http://www.sharpmeg.com/datasheets/memic/flashcmp/
76 + * http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf
80 + * This driver only supports 4x1 arrangement of chips.
81 + * Not tested on anything but PowerPC.
84 +#include <linux/kernel.h>
85 +#include <linux/module.h>
86 +#include <linux/types.h>
87 +#include <linux/sched.h>
88 +#include <linux/errno.h>
89 +#include <linux/init.h>
90 +#include <linux/interrupt.h>
91 +#include <linux/mtd/map.h>
92 +#include <linux/mtd/mtd.h>
93 +#include <linux/mtd/cfi.h>
94 +#include <linux/delay.h>
95 +#include <linux/init.h>
97 +#define CMD_RESET 0xffffffff
98 +#define CMD_READ_ID 0x90909090
99 +#define CMD_READ_STATUS 0x70707070
100 +#define CMD_CLEAR_STATUS 0x50505050
101 +#define CMD_BLOCK_ERASE_1 0x20202020
102 +#define CMD_BLOCK_ERASE_2 0xd0d0d0d0
103 +#define CMD_BYTE_WRITE 0x40404040
104 +#define CMD_SUSPEND 0xb0b0b0b0
105 +#define CMD_RESUME 0xd0d0d0d0
106 +#define CMD_SET_BLOCK_LOCK_1 0x60606060
107 +#define CMD_SET_BLOCK_LOCK_2 0x01010101
108 +#define CMD_SET_MASTER_LOCK_1 0x60606060
109 +#define CMD_SET_MASTER_LOCK_2 0xf1f1f1f1
110 +#define CMD_CLEAR_BLOCK_LOCKS_1 0x60606060
111 +#define CMD_CLEAR_BLOCK_LOCKS_2 0xd0d0d0d0
113 +#define SR_READY 0x80808080 // 1 = ready
114 +#define SR_ERASE_SUSPEND 0x40404040 // 1 = block erase suspended
115 +#define SR_ERROR_ERASE 0x20202020 // 1 = error in block erase or clear lock bits
116 +#define SR_ERROR_WRITE 0x10101010 // 1 = error in byte write or set lock bit
117 +#define SR_VPP 0x08080808 // 1 = Vpp is low
118 +#define SR_WRITE_SUSPEND 0x04040404 // 1 = byte write suspended
119 +#define SR_PROTECT 0x02020202 // 1 = lock bit set
120 +#define SR_RESERVED 0x01010101
122 +#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
124 +#define BLOCK_MASK 0xfffe0000
126 +/* Configuration options */
128 +#define AUTOUNLOCK /* automatically unlocks blocks before erasing */
130 +static struct mtd_info *sharp_probe(struct map_info *);
132 +static int sharp_probe_map(struct map_info *map, struct mtd_info *mtd);
134 +static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
135 + size_t *retlen, u_char *buf);
136 +static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len,
137 + size_t *retlen, const u_char *buf);
138 +static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr);
139 +static void sharp_sync(struct mtd_info *mtd);
140 +static int sharp_suspend(struct mtd_info *mtd);
141 +static void sharp_resume(struct mtd_info *mtd);
142 +static void sharp_destroy(struct mtd_info *mtd);
144 +static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
145 + unsigned long adr, __u32 datum);
146 +static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
147 + unsigned long adr);
149 +static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
150 + unsigned long adr);
155 + struct flchip *chip;
159 + struct flchip chips[1];
162 +static void sharp_destroy(struct mtd_info *mtd);
164 +static struct mtd_chip_driver sharp_chipdrv = {
165 + .probe = sharp_probe,
166 + .destroy = sharp_destroy,
168 + .module = THIS_MODULE
171 +static void sharp_udelay(unsigned long i) {
172 + if (in_interrupt()) {
179 +static struct mtd_info *sharp_probe(struct map_info *map)
181 + struct mtd_info *mtd = NULL;
182 + struct sharp_info *sharp = NULL;
185 + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
189 + sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
195 + width = sharp_probe_map(map,mtd);
203 + mtd->type = MTD_NORFLASH;
204 + mtd->erase = sharp_erase;
205 + mtd->read = sharp_read;
206 + mtd->write = sharp_write;
207 + mtd->sync = sharp_sync;
208 + mtd->suspend = sharp_suspend;
209 + mtd->resume = sharp_resume;
210 + mtd->flags = MTD_CAP_NORFLASH;
211 + mtd->writesize = 1;
212 + mtd->name = map->name;
214 + sharp->chipshift = 24;
215 + sharp->numchips = 1;
216 + sharp->chips[0].start = 0;
217 + sharp->chips[0].state = FL_READY;
218 + sharp->chips[0].mutex = &sharp->chips[0]._spinlock;
219 + sharp->chips[0].word_write_time = 0;
220 + init_waitqueue_head(&sharp->chips[0].wq);
221 + spin_lock_init(&sharp->chips[0]._spinlock);
223 + map->fldrv = &sharp_chipdrv;
224 + map->fldrv_priv = sharp;
226 + __module_get(THIS_MODULE);
230 +static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr)
233 + map_cmd.x[0] = cmd;
234 + map_write(map, map_cmd, adr);
237 +static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
239 + map_word tmp, read0, read4;
240 + unsigned long base = 0;
243 + tmp = map_read(map, base+0);
245 + sharp_send_cmd(map, CMD_READ_ID, base+0);
247 + read0 = map_read(map, base+0);
248 + read4 = map_read(map, base+4);
249 + if (read0.x[0] == 0x00b000b0) {
250 + printk("Sharp chip, %lx, %lx, width = %d\n", read0.x[0], read4.x[0], width);
251 + /* Prints b000b0, b000b0, width = 4 on collie */
252 + switch(read4.x[0]){
255 + /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/
256 + /* a0 - LH28F016SCT-Z4 2Mx8, 32 64k blocks*/
257 + mtd->erasesize = 0x10000 * width;
258 + mtd->size = 0x200000 * width;
261 + /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/
262 + /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/
263 + mtd->erasesize = 0x10000 * width;
264 + mtd->size = 0x100000 * width;
267 + /* a6 - LH28F640BFHE 8 64k * 2 chip blocks*/
268 + mtd->erasesize = 0x10000 * width / 2;
269 + mtd->size = 0x800000 * width / 2;
272 + printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n",
273 + read0.x[0], read4.x[0]);
275 + } else if ((map_read(map, base+0).x[0] == CMD_READ_ID)){
276 + /* RAM, probably */
277 + printk("Looks like RAM\n");
278 + map_write(map, tmp, base+0);
280 + printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n",
281 + read0.x[0], read4.x[0]);
287 +/* This function returns with the chip->mutex lock held. */
288 +static int sharp_wait(struct map_info *map, struct flchip *chip)
291 + unsigned long timeo = jiffies + HZ;
292 + DECLARE_WAITQUEUE(wait, current);
296 + spin_lock_bh(chip->mutex);
298 + switch (chip->state) {
300 + sharp_send_cmd(map, CMD_READ_STATUS, adr);
301 + chip->state = FL_STATUS;
303 + status = map_read(map, adr);
304 + if ((status.x[0] & SR_READY) == SR_READY)
306 + spin_unlock_bh(chip->mutex);
307 + if (time_after(jiffies, timeo)) {
308 + printk("Waiting for chip to be ready timed out in erase\n");
314 + set_current_state(TASK_INTERRUPTIBLE);
315 + add_wait_queue(&chip->wq, &wait);
317 + spin_unlock_bh(chip->mutex);
321 + set_current_state(TASK_RUNNING);
322 + remove_wait_queue(&chip->wq, &wait);
324 + if(signal_pending(current))
327 + timeo = jiffies + HZ;
332 + sharp_send_cmd(map, CMD_RESET, adr);
334 + chip->state = FL_READY;
339 +static void sharp_release(struct flchip *chip)
341 + wake_up(&chip->wq);
342 + spin_unlock_bh(chip->mutex);
345 +static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
346 + size_t *retlen, u_char *buf)
348 + struct map_info *map = mtd->priv;
349 + struct sharp_info *sharp = map->fldrv_priv;
354 + chipnum = (from >> sharp->chipshift);
355 + ofs = from & ((1 << sharp->chipshift)-1);
360 + unsigned long thislen;
362 + if(chipnum>=sharp->numchips)
366 + if(ofs+thislen >= (1<<sharp->chipshift))
367 + thislen = (1<<sharp->chipshift) - ofs;
369 + ret = sharp_wait(map,&sharp->chips[chipnum]);
373 + map_copy_from(map,buf,ofs,thislen);
375 + sharp_release(&sharp->chips[chipnum]);
377 + *retlen += thislen;
387 +static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len,
388 + size_t *retlen, const u_char *buf)
390 + struct map_info *map = mtd->priv;
391 + struct sharp_info *sharp = map->fldrv_priv;
396 + union { u32 l; unsigned char uc[4]; } tbuf;
401 + tbuf.l = 0xffffffff;
402 + chipnum = to >> sharp->chipshift;
403 + ofs = to & ((1<<sharp->chipshift)-1);
406 + for(i=ofs&3;i<4 && len;i++){
413 + sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l);
422 +static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
423 + unsigned long adr, __u32 datum)
428 + map_word data, status;
431 + ret = sharp_wait(map,chip);
435 + for (try=0; try<10; try++) {
438 + sharp_send_cmd(map, CMD_BYTE_WRITE, adr);
439 + /* cpu_to_le32 -> hack to fix the writel be->le conversion */
440 + data.x[0] = cpu_to_le32(datum);
441 + map_write(map, data, adr);
443 + chip->state = FL_WRITING;
444 + timeo = jiffies + (HZ/2);
446 + sharp_send_cmd(map, CMD_READ_STATUS, adr);
447 + for(i=0;i<100;i++){
448 + status = map_read(map, adr);
449 + if((status.x[0] & SR_READY) == SR_READY)
453 + if (status.x[0] & SR_PROTECT) { /* lock block */
454 + sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
455 + sharp_unlock_oneblock(map,chip,adr);
456 + sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
457 + sharp_send_cmd(map, CMD_RESET, adr);
462 + printk("sharp: timed out writing\n");
465 + if (!(status.x[0] & SR_ERRORS))
468 + printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]);
470 + sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
472 + sharp_send_cmd(map, CMD_RESET, adr);
473 + chip->state = FL_READY;
475 + sharp_release(chip);
480 +static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
482 + struct map_info *map = mtd->priv;
483 + struct sharp_info *sharp = map->fldrv_priv;
484 + unsigned long adr,len;
485 + int chipnum, ret=0;
487 + if(instr->addr & (mtd->erasesize - 1))
489 + if(instr->len & (mtd->erasesize - 1))
491 + if(instr->len + instr->addr > mtd->size)
494 + chipnum = instr->addr >> sharp->chipshift;
495 + adr = instr->addr & ((1<<sharp->chipshift)-1);
499 + ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
502 + if (adr >= 0xfe0000) {
503 + adr += mtd->erasesize / 8;
504 + len -= mtd->erasesize / 8;
506 + adr += mtd->erasesize;
507 + len -= mtd->erasesize;
509 + if(adr >> sharp->chipshift){
512 + if(chipnum>=sharp->numchips)
517 + instr->state = MTD_ERASE_DONE;
518 + mtd_erase_callback(instr);
523 +static inline int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
527 + unsigned long timeo;
529 + DECLARE_WAITQUEUE(wait, current);
531 + sharp_send_cmd(map, CMD_READ_STATUS, adr);
532 + status = map_read(map, adr);
534 + timeo = jiffies + HZ * 10;
536 + while (time_before(jiffies, timeo)) {
537 + sharp_send_cmd(map, CMD_READ_STATUS, adr);
538 + status = map_read(map, adr);
539 + if ((status.x[0] & SR_READY) == SR_READY) {
543 + set_current_state(TASK_INTERRUPTIBLE);
544 + add_wait_queue(&chip->wq, &wait);
546 + spin_unlock_bh(chip->mutex);
548 + schedule_timeout(1);
551 + spin_lock_bh(chip->mutex);
553 + remove_wait_queue(&chip->wq, &wait);
554 + set_current_state(TASK_RUNNING);
561 +static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
567 + ret = sharp_wait(map,chip);
572 + /* This seems like a good place to do an unlock */
573 + sharp_unlock_oneblock(map,chip,adr);
576 + sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr);
577 + sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr);
579 + chip->state = FL_ERASING;
581 + ret = sharp_do_wait_for_ready(map,chip,adr);
583 + spin_unlock_bh(chip->mutex);
587 + sharp_send_cmd(map, CMD_READ_STATUS, adr);
588 + status = map_read(map, adr);
590 + if (!(status.x[0] & SR_ERRORS)) {
591 + sharp_send_cmd(map, CMD_RESET, adr);
592 + chip->state = FL_READY;
593 + spin_unlock_bh(chip->mutex);
597 + printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]);
598 + sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
600 + sharp_release(chip);
606 +static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
611 + sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr & BLOCK_MASK);
612 + sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr & BLOCK_MASK);
614 + sharp_do_wait_for_ready(map,chip,adr);
616 + status = map_read(map, adr);
618 + if (!(status.x[0] & SR_ERRORS)) {
619 + sharp_send_cmd(map, CMD_RESET, adr);
620 + chip->state = FL_READY;
624 + printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]);
625 + sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
629 +static void sharp_sync(struct mtd_info *mtd)
633 +static int sharp_suspend(struct mtd_info *mtd)
635 + struct map_info *map = mtd->priv;
636 + struct sharp_info *sharp = map->fldrv_priv;
638 + struct flchip *chip;
641 + for (i = 0; !ret && i < sharp->numchips; i++) {
642 + chip = &sharp->chips[i];
643 + ret = sharp_wait(map,chip);
648 + chip->state = FL_PM_SUSPENDED;
649 + spin_unlock_bh(chip->mutex);
655 +static void sharp_resume(struct mtd_info *mtd)
657 + struct map_info *map = mtd->priv;
658 + struct sharp_info *sharp = map->fldrv_priv;
660 + struct flchip *chip;
662 + for (i = 0; i < sharp->numchips; i++) {
663 + chip = &sharp->chips[i];
665 + spin_lock_bh(chip->mutex);
667 + if (chip->state == FL_PM_SUSPENDED) {
668 + /* We need to force it back to a known state */
669 + sharp_send_cmd(map, CMD_RESET, chip->start);
670 + chip->state = FL_READY;
671 + wake_up(&chip->wq);
674 + spin_unlock_bh(chip->mutex);
678 +static void sharp_destroy(struct mtd_info *mtd)
680 + struct map_info *map = mtd->priv;
681 + struct sharp_info *sharp = map->fldrv_priv;
686 +static int __init sharp_probe_init(void)
688 + printk("MTD Sharp chip driver <ds@lineo.com>\n");
690 + register_mtd_chip_driver(&sharp_chipdrv);
695 +static void __exit sharp_probe_exit(void)
697 + unregister_mtd_chip_driver(&sharp_chipdrv);
700 +module_init(sharp_probe_init);
701 +module_exit(sharp_probe_exit);
704 +MODULE_LICENSE("GPL");
705 +MODULE_AUTHOR("David Schleef <ds@schleef.org>");
706 +MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips");
707 diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
708 index 5ea1693..d523464 100644
709 --- a/drivers/mtd/maps/Kconfig
710 +++ b/drivers/mtd/maps/Kconfig
711 @@ -360,7 +360,7 @@ config MTD_CDB89712
714 tristate "CFI Flash device mapped on StrongARM SA11x0"
715 - depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS
716 + depends on (MTD_CFI || MTD_SHARP) && ARCH_SA1100 && MTD_PARTITIONS
718 This enables access to the flash chips on most platforms based on
719 the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.