1 /*
2 * Handle mapping of the flash memory access routines
3 * on TQM8xxL based devices.
4 *
5 * $Id: tqm8xxl.c,v 1.4 2002/06/20 13:41:20 mag Exp $
6 *
7 * based on rpxlite.c
8 *
9 * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw>
10 *
11 * This code is GPLed
12 *
13 */
14
15 /*
16 * According to TQM8xxL hardware manual, TQM8xxL series have
17 * following flash memory organisations:
18 * | capacity | | chip type | | bank0 | | bank1 |
19 * 2MiB 512Kx16 2MiB 0
20 * 4MiB 1Mx16 4MiB 0
21 * 8MiB 1Mx16 4MiB 4MiB
22 * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at
23 * kernel configuration.
24 */
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/types.h>
28 #include <linux/kernel.h>
29 #include <asm/io.h>
30
31 #include <linux/mtd/mtd.h>
32 #include <linux/mtd/map.h>
33 #include <linux/mtd/partitions.h>
34
35 #define FLASH_ADDR 0x40000000
36 #define FLASH_SIZE 0x00800000
37 #define FLASH_BANK_MAX 4
38
39 // trivial struct to describe partition information
40 struct mtd_part_def
41 {
42 int nums;
43 unsigned char *type;
44 struct mtd_partition* mtd_part;
45 };
46
47 //static struct mtd_info *mymtd;
48 static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
49 static struct map_info* map_banks[FLASH_BANK_MAX];
50 static struct mtd_part_def part_banks[FLASH_BANK_MAX];
51 static unsigned long num_banks;
52 static unsigned long start_scan_addr;
53
tqm8xxl_read8(struct map_info * map,unsigned long ofs)54 __u8 tqm8xxl_read8(struct map_info *map, unsigned long ofs)
55 {
56 return *((__u8 *)(map->map_priv_1 + ofs));
57 }
58
tqm8xxl_read16(struct map_info * map,unsigned long ofs)59 __u16 tqm8xxl_read16(struct map_info *map, unsigned long ofs)
60 {
61 return *((__u16 *)(map->map_priv_1 + ofs));
62 }
63
tqm8xxl_read32(struct map_info * map,unsigned long ofs)64 __u32 tqm8xxl_read32(struct map_info *map, unsigned long ofs)
65 {
66 return *((__u32 *)(map->map_priv_1 + ofs));
67 }
68
tqm8xxl_copy_from(struct map_info * map,void * to,unsigned long from,ssize_t len)69 void tqm8xxl_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
70 {
71 memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
72 }
73
tqm8xxl_write8(struct map_info * map,__u8 d,unsigned long adr)74 void tqm8xxl_write8(struct map_info *map, __u8 d, unsigned long adr)
75 {
76 *((__u8 *)(map->map_priv_1 + adr)) = d;
77 }
78
tqm8xxl_write16(struct map_info * map,__u16 d,unsigned long adr)79 void tqm8xxl_write16(struct map_info *map, __u16 d, unsigned long adr)
80 {
81 *((__u16 *)( map->map_priv_1 + adr)) = d;
82 }
83
tqm8xxl_write32(struct map_info * map,__u32 d,unsigned long adr)84 void tqm8xxl_write32(struct map_info *map, __u32 d, unsigned long adr)
85 {
86 *((__u32 *)(map->map_priv_1 + adr)) = d;
87 }
88
tqm8xxl_copy_to(struct map_info * map,unsigned long to,const void * from,ssize_t len)89 void tqm8xxl_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
90 {
91 memcpy_toio((void *)(map->map_priv_1 + to), from, len);
92 }
93
94 /*
95 * Here are partition information for all known TQM8xxL series devices.
96 * See include/linux/mtd/partitions.h for definition of the mtd_partition
97 * structure.
98 *
99 * The *_max_flash_size is the maximum possible mapped flash size which
100 * is not necessarily the actual flash size. It must correspond to the
101 * value specified in the mapping definition defined by the
102 * "struct map_desc *_io_desc" for the corresponding machine.
103 */
104
105 #ifdef CONFIG_MTD_PARTITIONS
106 /* Currently, TQM8xxL has upto 8MiB flash */
107 static unsigned long tqm8xxl_max_flash_size = 0x00800000;
108
109 /* partition definition for first flash bank
110 * also ref. to "drivers\char\flash_config.c"
111 */
112 static struct mtd_partition tqm8xxl_partitions[] = {
113 {
114 name: "ppcboot",
115 offset: 0x00000000,
116 size: 0x00020000, /* 128KB */
117 mask_flags: MTD_WRITEABLE, /* force read-only */
118 },
119 {
120 name: "kernel", /* default kernel image */
121 offset: 0x00020000,
122 size: 0x000e0000,
123 mask_flags: MTD_WRITEABLE, /* force read-only */
124 },
125 {
126 name: "user",
127 offset: 0x00100000,
128 size: 0x00100000,
129 },
130 {
131 name: "initrd",
132 offset: 0x00200000,
133 size: 0x00200000,
134 }
135 };
136 /* partition definition for second flahs bank */
137 static struct mtd_partition tqm8xxl_fs_partitions[] = {
138 {
139 name: "cramfs",
140 offset: 0x00000000,
141 size: 0x00200000,
142 },
143 {
144 name: "jffs",
145 offset: 0x00200000,
146 size: 0x00200000,
147 //size: MTDPART_SIZ_FULL,
148 }
149 };
150 #endif
151
152 #define NB_OF(x) (sizeof(x)/sizeof(x[0]))
153
init_tqm_mtd(void)154 int __init init_tqm_mtd(void)
155 {
156 int idx = 0, ret = 0;
157 unsigned long flash_addr, flash_size, mtd_size = 0;
158 /* pointer to TQM8xxL board info data */
159 bd_t *bd = (bd_t *)__res;
160
161 flash_addr = bd->bi_flashstart;
162 flash_size = bd->bi_flashsize;
163 //request maximum flash size address spzce
164 start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
165 if (!start_scan_addr) {
166 //printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, FLASH_ADDR);
167 printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
168 return -EIO;
169 }
170 for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
171 {
172 if(mtd_size >= flash_size)
173 break;
174
175 printk("%s: chip probing count %d\n", __FUNCTION__, idx);
176
177 map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
178 if(map_banks[idx] == NULL)
179 {
180 //return -ENOMEM;
181 ret = -ENOMEM;
182 goto error_mem;
183 }
184 memset((void *)map_banks[idx], 0, sizeof(struct map_info));
185 map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
186 if(map_banks[idx]->name == NULL)
187 {
188 //return -ENOMEM;
189 ret = -ENOMEM;
190 goto error_mem;
191 }
192 memset((void *)map_banks[idx]->name, 0, 16);
193
194 sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
195 map_banks[idx]->size = flash_size;
196 map_banks[idx]->buswidth = 4;
197 map_banks[idx]->read8 = tqm8xxl_read8;
198 map_banks[idx]->read16 = tqm8xxl_read16;
199 map_banks[idx]->read32 = tqm8xxl_read32;
200 map_banks[idx]->copy_from = tqm8xxl_copy_from;
201 map_banks[idx]->write8 = tqm8xxl_write8;
202 map_banks[idx]->write16 = tqm8xxl_write16;
203 map_banks[idx]->write32 = tqm8xxl_write32;
204 map_banks[idx]->copy_to = tqm8xxl_copy_to;
205 map_banks[idx]->map_priv_1 =
206 start_scan_addr + ((idx > 0) ?
207 (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
208 //start to probe flash chips
209 mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
210 if(mtd_banks[idx])
211 {
212 mtd_banks[idx]->module = THIS_MODULE;
213 mtd_size += mtd_banks[idx]->size;
214 num_banks++;
215 printk("%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
216 mtd_banks[idx]->name, mtd_banks[idx]->size);
217 }
218 }
219
220 /* no supported flash chips found */
221 if(!num_banks)
222 {
223 printk("TQM8xxL: No support flash chips found!\n");
224 ret = -ENXIO;
225 goto error_mem;
226 }
227
228 #ifdef CONFIG_MTD_PARTITIONS
229 /*
230 * Select Static partition definitions
231 */
232 part_banks[0].mtd_part = tqm8xxl_partitions;
233 part_banks[0].type = "Static image";
234 part_banks[0].nums = NB_OF(tqm8xxl_partitions);
235 part_banks[1].mtd_part = tqm8xxl_fs_partitions;
236 part_banks[1].type = "Static file system";
237 part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions);
238 for(idx = 0; idx < num_banks ; idx++)
239 {
240 if (part_banks[idx].nums == 0) {
241 printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx);
242 add_mtd_device(mtd_banks[idx]);
243 } else {
244 printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n",
245 idx, part_banks[idx].type);
246 add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part,
247 part_banks[idx].nums);
248 }
249 }
250 #else
251 printk(KERN_NOTICE "TQM flash: registering %d whole flash banks at once\n", num_banks);
252 for(idx = 0 ; idx < num_banks ; idx++)
253 add_mtd_device(mtd_banks[idx]);
254 #endif
255 return 0;
256 error_mem:
257 for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
258 {
259 if(map_banks[idx] != NULL)
260 {
261 if(map_banks[idx]->name != NULL)
262 {
263 kfree(map_banks[idx]->name);
264 map_banks[idx]->name = NULL;
265 }
266 kfree(map_banks[idx]);
267 map_banks[idx] = NULL;
268 }
269 }
270 //return -ENOMEM;
271 error:
272 iounmap((void *)start_scan_addr);
273 //return -ENXIO;
274 return ret;
275 }
276
cleanup_tqm_mtd(void)277 static void __exit cleanup_tqm_mtd(void)
278 {
279 unsigned int idx = 0;
280 for(idx = 0 ; idx < num_banks ; idx++)
281 {
282 /* destroy mtd_info previously allocated */
283 if (mtd_banks[idx]) {
284 del_mtd_partitions(mtd_banks[idx]);
285 map_destroy(mtd_banks[idx]);
286 }
287 /* release map_info not used anymore */
288 kfree(map_banks[idx]->name);
289 kfree(map_banks[idx]);
290 }
291 if (start_scan_addr) {
292 iounmap((void *)start_scan_addr);
293 start_scan_addr = 0;
294 }
295 }
296
297 module_init(init_tqm_mtd);
298 module_exit(cleanup_tqm_mtd);
299
300 MODULE_LICENSE("GPL");
301 MODULE_AUTHOR("Kirk Lee <kirk@hpc.ee.ntu.edu.tw>");
302 MODULE_DESCRIPTION("MTD map driver for TQM8xxL boards");
303