Blame view
drivers/mtd/maps/dc21285.c
5.41 KB
1da177e4c
|
1 2 3 |
/* * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip) * |
2f82af08f
|
4 |
* (C) 2000 Nicolas Pitre <nico@fluxnic.net> |
1da177e4c
|
5 6 |
* * This code is GPL |
1da177e4c
|
7 |
*/ |
1da177e4c
|
8 9 10 11 12 |
#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> |
4e57b6817
|
13 |
#include <linux/slab.h> |
1da177e4c
|
14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> #include <asm/io.h> #include <asm/hardware/dec21285.h> #include <asm/mach-types.h> static struct mtd_info *dc21285_mtd; #ifdef CONFIG_ARCH_NETWINDER |
69f34c98c
|
27 |
/* |
1da177e4c
|
28 |
* This is really ugly, but it seams to be the only |
69f34c98c
|
29 |
* realiable way to do it, as the cpld state machine |
1da177e4c
|
30 31 32 33 34 |
* is unpredictible. So we have a 25us penalty per * write access. */ static void nw_en_write(void) { |
1da177e4c
|
35 36 37 38 39 40 |
unsigned long flags; /* * we want to write a bit pattern XXX1 to Xilinx to enable * the write gate, which will be open for about the next 2ms. */ |
70d13e083
|
41 42 43 |
spin_lock_irqsave(&nw_gpio_lock, flags); nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE); spin_unlock_irqrestore(&nw_gpio_lock, flags); |
1da177e4c
|
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
/* * let the ISA bus to catch on... */ udelay(25); } #else #define nw_en_write() do { } while (0) #endif static map_word dc21285_read8(struct map_info *map, unsigned long ofs) { map_word val; val.x[0] = *(uint8_t*)(map->virt + ofs); return val; } static map_word dc21285_read16(struct map_info *map, unsigned long ofs) { map_word val; val.x[0] = *(uint16_t*)(map->virt + ofs); return val; } static map_word dc21285_read32(struct map_info *map, unsigned long ofs) { map_word val; val.x[0] = *(uint32_t*)(map->virt + ofs); return val; } static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { memcpy(to, (void*)(map->virt + from), len); } static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr) { if (machine_is_netwinder()) nw_en_write(); *CSR_ROMWRITEREG = adr & 3; adr &= ~3; *(uint8_t*)(map->virt + adr) = d.x[0]; } static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr) { if (machine_is_netwinder()) nw_en_write(); *CSR_ROMWRITEREG = adr & 3; adr &= ~3; *(uint16_t*)(map->virt + adr) = d.x[0]; } static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr) { if (machine_is_netwinder()) nw_en_write(); *(uint32_t*)(map->virt + adr) = d.x[0]; } static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len) { while (len > 0) { map_word d; |
75b84e94a
|
109 |
d.x[0] = *((uint32_t*)from); |
1da177e4c
|
110 |
dc21285_write32(map, d, to); |
75b84e94a
|
111 |
from += 4; |
1da177e4c
|
112 113 114 115 116 117 118 119 120 |
to += 4; len -= 4; } } static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len) { while (len > 0) { map_word d; |
75b84e94a
|
121 |
d.x[0] = *((uint16_t*)from); |
1da177e4c
|
122 |
dc21285_write16(map, d, to); |
75b84e94a
|
123 |
from += 2; |
1da177e4c
|
124 125 126 127 128 129 130 131 |
to += 2; len -= 2; } } static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len) { map_word d; |
75b84e94a
|
132 |
d.x[0] = *((uint8_t*)from); |
1da177e4c
|
133 |
dc21285_write8(map, d, to); |
75b84e94a
|
134 |
from++; |
1da177e4c
|
135 136 137 138 139 140 141 142 143 144 |
to++; len--; } static struct map_info dc21285_map = { .name = "DC21285 flash", .phys = NO_XIP, .size = 16*1024*1024, .copy_from = dc21285_copy_from, }; |
1da177e4c
|
145 |
/* Partition stuff */ |
0984c8910
|
146 |
static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; |
69f34c98c
|
147 |
|
1da177e4c
|
148 149 |
static int __init init_dc21285(void) { |
1da177e4c
|
150 151 |
/* Determine bankwidth */ switch (*CSR_SA110_CNTL & (3<<14)) { |
69f34c98c
|
152 |
case SA110_CNTL_ROMWIDTH_8: |
1da177e4c
|
153 154 155 156 157 |
dc21285_map.bankwidth = 1; dc21285_map.read = dc21285_read8; dc21285_map.write = dc21285_write8; dc21285_map.copy_to = dc21285_copy_to_8; break; |
69f34c98c
|
158 159 |
case SA110_CNTL_ROMWIDTH_16: dc21285_map.bankwidth = 2; |
1da177e4c
|
160 161 162 163 |
dc21285_map.read = dc21285_read16; dc21285_map.write = dc21285_write16; dc21285_map.copy_to = dc21285_copy_to_16; break; |
69f34c98c
|
164 165 |
case SA110_CNTL_ROMWIDTH_32: dc21285_map.bankwidth = 4; |
1da177e4c
|
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
dc21285_map.read = dc21285_read32; dc21285_map.write = dc21285_write32; dc21285_map.copy_to = dc21285_copy_to_32; break; default: printk (KERN_ERR "DC21285 flash: undefined bankwidth "); return -ENXIO; } printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth) ", dc21285_map.bankwidth*8); /* Let's map the flash area */ dc21285_map.virt = ioremap(DC21285_FLASH, 16*1024*1024); if (!dc21285_map.virt) { printk("Failed to ioremap "); return -EIO; } if (machine_is_ebsa285()) { dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map); } else { dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map); } if (!dc21285_mtd) { iounmap(dc21285_map.virt); return -ENXIO; |
69f34c98c
|
196 |
} |
1da177e4c
|
197 |
dc21285_mtd->owner = THIS_MODULE; |
42d7fbe22
|
198 |
mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0); |
69f34c98c
|
199 |
|
1da177e4c
|
200 |
if(machine_is_ebsa285()) { |
69f34c98c
|
201 |
/* |
1da177e4c
|
202 203 204 205 206 207 208 209 210 211 212 213 |
* Flash timing is determined with bits 19-16 of the * CSR_SA110_CNTL. The value is the number of wait cycles, or * 0 for 16 cycles (the default). Cycles are 20 ns. * Here we use 7 for 140 ns flash chips. */ /* access time */ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); /* burst time */ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); /* tristate time */ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); } |
69f34c98c
|
214 |
|
1da177e4c
|
215 216 217 218 219 |
return 0; } static void __exit cleanup_dc21285(void) { |
bc2ffddc4
|
220 |
mtd_device_unregister(dc21285_mtd); |
1da177e4c
|
221 222 223 224 225 226 227 228 229 |
map_destroy(dc21285_mtd); iounmap(dc21285_map.virt); } module_init(init_dc21285); module_exit(cleanup_dc21285); MODULE_LICENSE("GPL"); |
2f82af08f
|
230 |
MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>"); |
1da177e4c
|
231 |
MODULE_DESCRIPTION("MTD map driver for DC21285 boards"); |