0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/delay.h>
0013 #include <linux/slab.h>
0014
0015 #include <linux/mtd/mtd.h>
0016 #include <linux/mtd/map.h>
0017 #include <linux/mtd/partitions.h>
0018
0019 #include <asm/io.h>
0020 #include <asm/hardware/dec21285.h>
0021 #include <asm/mach-types.h>
0022
0023
0024 static struct mtd_info *dc21285_mtd;
0025
0026 #ifdef CONFIG_ARCH_NETWINDER
0027
0028
0029
0030
0031
0032
0033 static void nw_en_write(void)
0034 {
0035 unsigned long flags;
0036
0037
0038
0039
0040
0041 raw_spin_lock_irqsave(&nw_gpio_lock, flags);
0042 nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
0043 raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
0044
0045
0046
0047
0048 udelay(25);
0049 }
0050 #else
0051 #define nw_en_write() do { } while (0)
0052 #endif
0053
0054 static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
0055 {
0056 map_word val;
0057 val.x[0] = *(uint8_t*)(map->virt + ofs);
0058 return val;
0059 }
0060
0061 static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
0062 {
0063 map_word val;
0064 val.x[0] = *(uint16_t*)(map->virt + ofs);
0065 return val;
0066 }
0067
0068 static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
0069 {
0070 map_word val;
0071 val.x[0] = *(uint32_t*)(map->virt + ofs);
0072 return val;
0073 }
0074
0075 static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
0076 {
0077 memcpy(to, (void*)(map->virt + from), len);
0078 }
0079
0080 static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr)
0081 {
0082 if (machine_is_netwinder())
0083 nw_en_write();
0084 *CSR_ROMWRITEREG = adr & 3;
0085 adr &= ~3;
0086 *(uint8_t*)(map->virt + adr) = d.x[0];
0087 }
0088
0089 static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr)
0090 {
0091 if (machine_is_netwinder())
0092 nw_en_write();
0093 *CSR_ROMWRITEREG = adr & 3;
0094 adr &= ~3;
0095 *(uint16_t*)(map->virt + adr) = d.x[0];
0096 }
0097
0098 static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr)
0099 {
0100 if (machine_is_netwinder())
0101 nw_en_write();
0102 *(uint32_t*)(map->virt + adr) = d.x[0];
0103 }
0104
0105 static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
0106 {
0107 while (len > 0) {
0108 map_word d;
0109 d.x[0] = *((uint32_t*)from);
0110 dc21285_write32(map, d, to);
0111 from += 4;
0112 to += 4;
0113 len -= 4;
0114 }
0115 }
0116
0117 static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
0118 {
0119 while (len > 0) {
0120 map_word d;
0121 d.x[0] = *((uint16_t*)from);
0122 dc21285_write16(map, d, to);
0123 from += 2;
0124 to += 2;
0125 len -= 2;
0126 }
0127 }
0128
0129 static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
0130 {
0131 map_word d;
0132 d.x[0] = *((uint8_t*)from);
0133 dc21285_write8(map, d, to);
0134 from++;
0135 to++;
0136 len--;
0137 }
0138
0139 static struct map_info dc21285_map = {
0140 .name = "DC21285 flash",
0141 .phys = NO_XIP,
0142 .size = 16*1024*1024,
0143 .copy_from = dc21285_copy_from,
0144 };
0145
0146
0147 static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
0148
0149 static int __init init_dc21285(void)
0150 {
0151
0152 switch (*CSR_SA110_CNTL & (3<<14)) {
0153 case SA110_CNTL_ROMWIDTH_8:
0154 dc21285_map.bankwidth = 1;
0155 dc21285_map.read = dc21285_read8;
0156 dc21285_map.write = dc21285_write8;
0157 dc21285_map.copy_to = dc21285_copy_to_8;
0158 break;
0159 case SA110_CNTL_ROMWIDTH_16:
0160 dc21285_map.bankwidth = 2;
0161 dc21285_map.read = dc21285_read16;
0162 dc21285_map.write = dc21285_write16;
0163 dc21285_map.copy_to = dc21285_copy_to_16;
0164 break;
0165 case SA110_CNTL_ROMWIDTH_32:
0166 dc21285_map.bankwidth = 4;
0167 dc21285_map.read = dc21285_read32;
0168 dc21285_map.write = dc21285_write32;
0169 dc21285_map.copy_to = dc21285_copy_to_32;
0170 break;
0171 default:
0172 printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
0173 return -ENXIO;
0174 }
0175 printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
0176 dc21285_map.bankwidth*8);
0177
0178
0179 dc21285_map.virt = ioremap(DC21285_FLASH, 16*1024*1024);
0180 if (!dc21285_map.virt) {
0181 printk("Failed to ioremap\n");
0182 return -EIO;
0183 }
0184
0185 if (machine_is_ebsa285()) {
0186 dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
0187 } else {
0188 dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
0189 }
0190
0191 if (!dc21285_mtd) {
0192 iounmap(dc21285_map.virt);
0193 return -ENXIO;
0194 }
0195
0196 dc21285_mtd->owner = THIS_MODULE;
0197
0198 mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0);
0199
0200 if(machine_is_ebsa285()) {
0201
0202
0203
0204
0205
0206
0207
0208 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
0209
0210 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
0211
0212 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
0213 }
0214
0215 return 0;
0216 }
0217
0218 static void __exit cleanup_dc21285(void)
0219 {
0220 mtd_device_unregister(dc21285_mtd);
0221 map_destroy(dc21285_mtd);
0222 iounmap(dc21285_map.virt);
0223 }
0224
0225 module_init(init_dc21285);
0226 module_exit(cleanup_dc21285);
0227
0228
0229 MODULE_LICENSE("GPL");
0230 MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>");
0231 MODULE_DESCRIPTION("MTD map driver for DC21285 boards");