1/* 2 * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip) 3 * 4 * (C) 2000 Nicolas Pitre <nico@cam.org> 5 * 6 * This code is GPL 7 * 8 * $Id: dc21285.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $ 9 */ 10 11#include <linux/module.h> 12#include <linux/types.h> 13#include <linux/kernel.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 22 23static struct mtd_info *mymtd; 24 25__u8 dc21285_read8(struct map_info *map, unsigned long ofs) 26{ 27 return *(__u8*)(map->map_priv_1 + ofs); 28} 29 30__u16 dc21285_read16(struct map_info *map, unsigned long ofs) 31{ 32 return *(__u16*)(map->map_priv_1 + ofs); 33} 34 35__u32 dc21285_read32(struct map_info *map, unsigned long ofs) 36{ 37 return *(__u32*)(map->map_priv_1 + ofs); 38} 39 40void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 41{ 42 memcpy(to, (void*)(map->map_priv_1 + from), len); 43} 44 45void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr) 46{ 47 *CSR_ROMWRITEREG = adr & 3; 48 adr &= ~3; 49 *(__u8*)(map->map_priv_1 + adr) = d; 50} 51 52void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr) 53{ 54 *CSR_ROMWRITEREG = adr & 3; 55 adr &= ~3; 56 *(__u16*)(map->map_priv_1 + adr) = d; 57} 58 59void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr) 60{ 61 *(__u32*)(map->map_priv_1 + adr) = d; 62} 63 64void dc21285_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 65{ 66 switch (map->buswidth) { 67 case 4: 68 while (len > 0) { 69 __u32 d = *((__u32*)from)++; 70 dc21285_write32(map, d, to); 71 to += 4; 72 len -= 4; 73 } 74 break; 75 case 2: 76 while (len > 0) { 77 __u16 d = *((__u16*)from)++; 78 dc21285_write16(map, d, to); 79 to += 2; 80 len -= 2; 81 } 82 break; 83 case 1: 84 while (len > 0) { 85 __u8 d = *((__u8*)from)++; 86 dc21285_write8(map, d, to); 87 to++; 88 len--; 89 } 90 break; 91 } 92} 93 94struct map_info dc21285_map = { 95 name: "DC21285 flash", 96 size: 16*1024*1024, 97 read8: dc21285_read8, 98 read16: dc21285_read16, 99 read32: dc21285_read32, 100 copy_from: dc21285_copy_from, 101 write8: dc21285_write8, 102 write16: dc21285_write16, 103 write32: dc21285_write32, 104 copy_to: dc21285_copy_to 105}; 106 107 108/* Partition stuff */ 109static struct mtd_partition *dc21285_parts; 110 111extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); 112 113int __init init_dc21285(void) 114{ 115 /* Determine buswidth */ 116 switch (*CSR_SA110_CNTL & (3<<14)) { 117 case SA110_CNTL_ROMWIDTH_8: 118 dc21285_map.buswidth = 1; 119 break; 120 case SA110_CNTL_ROMWIDTH_16: 121 dc21285_map.buswidth = 2; 122 break; 123 case SA110_CNTL_ROMWIDTH_32: 124 dc21285_map.buswidth = 4; 125 break; 126 default: 127 printk (KERN_ERR "DC21285 flash: undefined buswidth\n"); 128 return -ENXIO; 129 } 130 printk (KERN_NOTICE "DC21285 flash support (%d-bit buswidth)\n", 131 dc21285_map.buswidth*8); 132 133 /* Let's map the flash area */ 134 dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0); 135 if (!dc21285_map.map_priv_1) { 136 printk("Failed to ioremap\n"); 137 return -EIO; 138 } 139 140 mymtd = do_map_probe("cfi_probe", &dc21285_map); 141 if (mymtd) { 142 int nrparts; 143 144 mymtd->module = THIS_MODULE; 145 146 /* partition fixup */ 147 148 nrparts = parse_redboot_partitions(mymtd, &dc21285_parts); 149 if (nrparts <=0) { 150 printk(KERN_NOTICE "RedBoot partition table failed\n"); 151 iounmap((void *)dc21285_map.map_priv_1); 152 return -ENXIO; 153 } 154 155 add_mtd_partitions(mymtd, dc21285_parts, nrparts); 156 157 /* 158 * Flash timing is determined with bits 19-16 of the 159 * CSR_SA110_CNTL. The value is the number of wait cycles, or 160 * 0 for 16 cycles (the default). Cycles are 20 ns. 161 * Here we use 7 for 140 ns flash chips. 162 */ 163 /* access time */ 164 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); 165 /* burst time */ 166 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); 167 /* tristate time */ 168 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); 169 170 return 0; 171 } 172 173 iounmap((void *)dc21285_map.map_priv_1); 174 return -ENXIO; 175} 176 177static void __exit cleanup_dc21285(void) 178{ 179 if (mymtd) { 180 del_mtd_device(mymtd); 181 map_destroy(mymtd); 182 mymtd = NULL; 183 } 184 if (dc21285_map.map_priv_1) { 185 iounmap((void *)dc21285_map.map_priv_1); 186 dc21285_map.map_priv_1 = 0; 187 } 188 if(dc21285_parts) 189 kfree(dc21285_parts); 190} 191 192module_init(init_dc21285); 193module_exit(cleanup_dc21285); 194 195 196MODULE_LICENSE("GPL"); 197MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); 198MODULE_DESCRIPTION("MTD map driver for DC21285 boards"); 199