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