1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/kernel.h>
35#include <linux/module.h>
36#include <linux/types.h>
37#include <linux/init.h>
38#include <linux/errno.h>
39#include <linux/string.h>
40#include <linux/mtd/mtd.h>
41#include <linux/mtd/partitions.h>
42
43#ifndef CONFIG_SA1100_LART
44#error This is for LART architecture only
45#endif
46
47static char module_name[] = "lart";
48
49
50
51
52
53#define FLASH_BLOCKSIZE_PARAM (4096 * BUSWIDTH)
54#define FLASH_NUMBLOCKS_16m_PARAM 8
55#define FLASH_NUMBLOCKS_8m_PARAM 8
56
57
58
59
60
61#define FLASH_BLOCKSIZE_MAIN (32768 * BUSWIDTH)
62#define FLASH_NUMBLOCKS_16m_MAIN 31
63#define FLASH_NUMBLOCKS_8m_MAIN 15
64
65
66
67
68
69
70#define BUSWIDTH 4
71#define FLASH_OFFSET 0xe8000000
72
73
74#define NUM_BLOB_BLOCKS FLASH_NUMBLOCKS_16m_PARAM
75#define PART_BLOB_START 0x00000000
76#define PART_BLOB_LEN (NUM_BLOB_BLOCKS * FLASH_BLOCKSIZE_PARAM)
77
78
79#define NUM_KERNEL_BLOCKS 7
80#define PART_KERNEL_START (PART_BLOB_START + PART_BLOB_LEN)
81#define PART_KERNEL_LEN (NUM_KERNEL_BLOCKS * FLASH_BLOCKSIZE_MAIN)
82
83
84#define NUM_INITRD_BLOCKS 24
85#define PART_INITRD_START (PART_KERNEL_START + PART_KERNEL_LEN)
86#define PART_INITRD_LEN (NUM_INITRD_BLOCKS * FLASH_BLOCKSIZE_MAIN)
87
88
89
90
91#define READ_ARRAY 0x00FF00FF
92#define READ_ID_CODES 0x00900090
93#define ERASE_SETUP 0x00200020
94#define ERASE_CONFIRM 0x00D000D0
95#define PGM_SETUP 0x00400040
96#define STATUS_READ 0x00700070
97#define STATUS_CLEAR 0x00500050
98#define STATUS_BUSY 0x00800080
99#define STATUS_ERASE_ERR 0x00200020
100#define STATUS_PGM_ERR 0x00100010
101
102
103
104
105#define FLASH_MANUFACTURER 0x00890089
106#define FLASH_DEVICE_8mbit_TOP 0x88f188f1
107#define FLASH_DEVICE_8mbit_BOTTOM 0x88f288f2
108#define FLASH_DEVICE_16mbit_TOP 0x88f388f3
109#define FLASH_DEVICE_16mbit_BOTTOM 0x88f488f4
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137#define DATA_TO_FLASH(x) \
138 ( \
139 (((x) & 0x08009000) >> 11) + \
140 (((x) & 0x00002000) >> 10) + \
141 (((x) & 0x04004000) >> 8) + \
142 (((x) & 0x00000010) >> 4) + \
143 (((x) & 0x91000820) >> 3) + \
144 (((x) & 0x22080080) >> 2) + \
145 ((x) & 0x40000400) + \
146 (((x) & 0x00040040) << 1) + \
147 (((x) & 0x00110000) << 4) + \
148 (((x) & 0x00220100) << 5) + \
149 (((x) & 0x00800208) << 6) + \
150 (((x) & 0x00400004) << 9) + \
151 (((x) & 0x00000001) << 12) + \
152 (((x) & 0x00000002) << 13) \
153 )
154
155
156#define FLASH_TO_DATA(x) \
157 ( \
158 (((x) & 0x00010012) << 11) + \
159 (((x) & 0x00000008) << 10) + \
160 (((x) & 0x00040040) << 8) + \
161 (((x) & 0x00000001) << 4) + \
162 (((x) & 0x12200104) << 3) + \
163 (((x) & 0x08820020) << 2) + \
164 ((x) & 0x40000400) + \
165 (((x) & 0x00080080) >> 1) + \
166 (((x) & 0x01100000) >> 4) + \
167 (((x) & 0x04402000) >> 5) + \
168 (((x) & 0x20008200) >> 6) + \
169 (((x) & 0x80000800) >> 9) + \
170 (((x) & 0x00001000) >> 12) + \
171 (((x) & 0x00004000) >> 13) \
172 )
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213#define ADDR_TO_FLASH_U2(x) \
214 ( \
215 (((x) & 0x00000f00) >> 4) + \
216 (((x) & 0x00042000) << 1) + \
217 (((x) & 0x0009c003) << 2) + \
218 (((x) & 0x00021080) << 3) + \
219 (((x) & 0x00000010) << 4) + \
220 (((x) & 0x00000040) << 5) + \
221 (((x) & 0x00000024) << 7) + \
222 (((x) & 0x00000008) << 10) \
223 )
224
225
226#define FLASH_U2_TO_ADDR(x) \
227 ( \
228 (((x) << 4) & 0x00000f00) + \
229 (((x) >> 1) & 0x00042000) + \
230 (((x) >> 2) & 0x0009c003) + \
231 (((x) >> 3) & 0x00021080) + \
232 (((x) >> 4) & 0x00000010) + \
233 (((x) >> 5) & 0x00000040) + \
234 (((x) >> 7) & 0x00000024) + \
235 (((x) >> 10) & 0x00000008) \
236 )
237
238
239#define ADDR_TO_FLASH_U3(x) \
240 ( \
241 (((x) & 0x00000080) >> 3) + \
242 (((x) & 0x00000040) >> 1) + \
243 (((x) & 0x00052020) << 1) + \
244 (((x) & 0x00084f03) << 2) + \
245 (((x) & 0x00029010) << 3) + \
246 (((x) & 0x00000008) << 5) + \
247 (((x) & 0x00000004) << 7) \
248 )
249
250
251#define FLASH_U3_TO_ADDR(x) \
252 ( \
253 (((x) << 3) & 0x00000080) + \
254 (((x) << 1) & 0x00000040) + \
255 (((x) >> 1) & 0x00052020) + \
256 (((x) >> 2) & 0x00084f03) + \
257 (((x) >> 3) & 0x00029010) + \
258 (((x) >> 5) & 0x00000008) + \
259 (((x) >> 7) & 0x00000004) \
260 )
261
262
263
264static __u8 read8 (__u32 offset)
265{
266 volatile __u8 *data = (__u8 *) (FLASH_OFFSET + offset);
267#ifdef LART_DEBUG
268 printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n", __func__, offset, *data);
269#endif
270 return (*data);
271}
272
273static __u32 read32 (__u32 offset)
274{
275 volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset);
276#ifdef LART_DEBUG
277 printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n", __func__, offset, *data);
278#endif
279 return (*data);
280}
281
282static void write32 (__u32 x,__u32 offset)
283{
284 volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset);
285 *data = x;
286#ifdef LART_DEBUG
287 printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, *data);
288#endif
289}
290
291
292
293
294
295
296
297
298
299
300
301static int flash_probe (void)
302{
303 __u32 manufacturer,devtype;
304
305
306 write32 (DATA_TO_FLASH (READ_ID_CODES),0x00000000);
307
308
309
310 manufacturer = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000000)));
311 devtype = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000001)));
312
313
314 write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000);
315
316 return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM));
317}
318
319
320
321
322
323
324
325static inline int erase_block (__u32 offset)
326{
327 __u32 status;
328
329#ifdef LART_DEBUG
330 printk (KERN_DEBUG "%s(): 0x%.8x\n", __func__, offset);
331#endif
332
333
334 write32 (DATA_TO_FLASH (ERASE_SETUP),offset);
335 write32 (DATA_TO_FLASH (ERASE_CONFIRM),offset);
336
337
338 do
339 {
340 write32 (DATA_TO_FLASH (STATUS_READ),offset);
341 status = FLASH_TO_DATA (read32 (offset));
342 }
343 while ((~status & STATUS_BUSY) != 0);
344
345
346 write32 (DATA_TO_FLASH (READ_ARRAY),offset);
347
348
349 if ((status & STATUS_ERASE_ERR))
350 {
351 printk (KERN_WARNING "%s: erase error at address 0x%.8x.\n",module_name,offset);
352 return (0);
353 }
354
355 return (1);
356}
357
358static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
359{
360 __u32 addr,len;
361 int i,first;
362
363#ifdef LART_DEBUG
364 printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len);
365#endif
366
367
368
369
370
371
372
373
374
375
376 for (i = 0; i < mtd->numeraseregions && instr->addr >= mtd->eraseregions[i].offset; i++) ;
377 i--;
378
379
380
381
382
383
384
385 if (i < 0 || (instr->addr & (mtd->eraseregions[i].erasesize - 1)))
386 return -EINVAL;
387
388
389 first = i;
390
391
392
393
394
395
396
397
398 for (; i < mtd->numeraseregions && instr->addr + instr->len >= mtd->eraseregions[i].offset; i++) ;
399 i--;
400
401
402 if (i < 0 || ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)))
403 return -EINVAL;
404
405 addr = instr->addr;
406 len = instr->len;
407
408 i = first;
409
410
411 while (len)
412 {
413 if (!erase_block (addr))
414 return (-EIO);
415
416 addr += mtd->eraseregions[i].erasesize;
417 len -= mtd->eraseregions[i].erasesize;
418
419 if (addr == mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks)) i++;
420 }
421
422 return (0);
423}
424
425static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf)
426{
427#ifdef LART_DEBUG
428 printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len);
429#endif
430
431
432 *retlen = len;
433
434
435 if (from & (BUSWIDTH - 1))
436 {
437 int gap = BUSWIDTH - (from & (BUSWIDTH - 1));
438
439 while (len && gap--) {
440 *buf++ = read8 (from++);
441 len--;
442 }
443 }
444
445
446 while (len >= BUSWIDTH)
447 {
448 *((__u32 *) buf) = read32 (from);
449
450 buf += BUSWIDTH;
451 from += BUSWIDTH;
452 len -= BUSWIDTH;
453 }
454
455
456 if (len & (BUSWIDTH - 1))
457 while (len--) *buf++ = read8 (from++);
458
459 return (0);
460}
461
462
463
464
465
466
467
468static inline int write_dword (__u32 offset,__u32 x)
469{
470 __u32 status;
471
472#ifdef LART_DEBUG
473 printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, x);
474#endif
475
476
477 write32 (DATA_TO_FLASH (PGM_SETUP),offset);
478
479
480 write32 (x,offset);
481
482
483 do
484 {
485 write32 (DATA_TO_FLASH (STATUS_READ),offset);
486 status = FLASH_TO_DATA (read32 (offset));
487 }
488 while ((~status & STATUS_BUSY) != 0);
489
490
491 write32 (DATA_TO_FLASH (READ_ARRAY),offset);
492
493
494 if ((status & STATUS_PGM_ERR) || read32 (offset) != x)
495 {
496 printk (KERN_WARNING "%s: write error at address 0x%.8x.\n",module_name,offset);
497 return (0);
498 }
499
500 return (1);
501}
502
503static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf)
504{
505 __u8 tmp[4];
506 int i,n;
507
508#ifdef LART_DEBUG
509 printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len);
510#endif
511
512
513 if (!len) return (0);
514
515
516 if (to & (BUSWIDTH - 1))
517 {
518 __u32 aligned = to & ~(BUSWIDTH - 1);
519 int gap = to - aligned;
520
521 i = n = 0;
522
523 while (gap--) tmp[i++] = 0xFF;
524 while (len && i < BUSWIDTH) {
525 tmp[i++] = buf[n++];
526 len--;
527 }
528 while (i < BUSWIDTH) tmp[i++] = 0xFF;
529
530 if (!write_dword (aligned,*((__u32 *) tmp))) return (-EIO);
531
532 to += n;
533 buf += n;
534 *retlen += n;
535 }
536
537
538 while (len >= BUSWIDTH)
539 {
540 if (!write_dword (to,*((__u32 *) buf))) return (-EIO);
541
542 to += BUSWIDTH;
543 buf += BUSWIDTH;
544 *retlen += BUSWIDTH;
545 len -= BUSWIDTH;
546 }
547
548
549 if (len & (BUSWIDTH - 1))
550 {
551 i = n = 0;
552
553 while (len--) tmp[i++] = buf[n++];
554 while (i < BUSWIDTH) tmp[i++] = 0xFF;
555
556 if (!write_dword (to,*((__u32 *) tmp))) return (-EIO);
557
558 *retlen += n;
559 }
560
561 return (0);
562}
563
564
565
566static struct mtd_info mtd;
567
568static struct mtd_erase_region_info erase_regions[] = {
569
570 {
571 .offset = 0x00000000,
572 .erasesize = FLASH_BLOCKSIZE_PARAM,
573 .numblocks = FLASH_NUMBLOCKS_16m_PARAM,
574 },
575
576 {
577 .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
578 .erasesize = FLASH_BLOCKSIZE_MAIN,
579 .numblocks = FLASH_NUMBLOCKS_16m_MAIN,
580 }
581};
582
583static const struct mtd_partition lart_partitions[] = {
584
585 {
586 .name = "blob",
587 .offset = PART_BLOB_START,
588 .size = PART_BLOB_LEN,
589 },
590
591 {
592 .name = "kernel",
593 .offset = PART_KERNEL_START,
594 .size = PART_KERNEL_LEN,
595 },
596
597 {
598 .name = "file system",
599 .offset = PART_INITRD_START,
600 .size = PART_INITRD_LEN,
601 }
602};
603#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions)
604
605static int __init lart_flash_init (void)
606{
607 int result;
608 memset (&mtd,0,sizeof (mtd));
609 printk ("MTD driver for LART. Written by Abraham vd Merwe <abraham@2d3d.co.za>\n");
610 printk ("%s: Probing for 28F160x3 flash on LART...\n",module_name);
611 if (!flash_probe ())
612 {
613 printk (KERN_WARNING "%s: Found no LART compatible flash device\n",module_name);
614 return (-ENXIO);
615 }
616 printk ("%s: This looks like a LART board to me.\n",module_name);
617 mtd.name = module_name;
618 mtd.type = MTD_NORFLASH;
619 mtd.writesize = 1;
620 mtd.writebufsize = 4;
621 mtd.flags = MTD_CAP_NORFLASH;
622 mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
623 mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
624 mtd.numeraseregions = ARRAY_SIZE(erase_regions);
625 mtd.eraseregions = erase_regions;
626 mtd._erase = flash_erase;
627 mtd._read = flash_read;
628 mtd._write = flash_write;
629 mtd.owner = THIS_MODULE;
630
631#ifdef LART_DEBUG
632 printk (KERN_DEBUG
633 "mtd.name = %s\n"
634 "mtd.size = 0x%.8x (%uM)\n"
635 "mtd.erasesize = 0x%.8x (%uK)\n"
636 "mtd.numeraseregions = %d\n",
637 mtd.name,
638 mtd.size,mtd.size / (1024*1024),
639 mtd.erasesize,mtd.erasesize / 1024,
640 mtd.numeraseregions);
641
642 if (mtd.numeraseregions)
643 for (result = 0; result < mtd.numeraseregions; result++)
644 printk (KERN_DEBUG
645 "\n\n"
646 "mtd.eraseregions[%d].offset = 0x%.8x\n"
647 "mtd.eraseregions[%d].erasesize = 0x%.8x (%uK)\n"
648 "mtd.eraseregions[%d].numblocks = %d\n",
649 result,mtd.eraseregions[result].offset,
650 result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024,
651 result,mtd.eraseregions[result].numblocks);
652
653 printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions));
654
655 for (result = 0; result < ARRAY_SIZE(lart_partitions); result++)
656 printk (KERN_DEBUG
657 "\n\n"
658 "lart_partitions[%d].name = %s\n"
659 "lart_partitions[%d].offset = 0x%.8x\n"
660 "lart_partitions[%d].size = 0x%.8x (%uK)\n",
661 result,lart_partitions[result].name,
662 result,lart_partitions[result].offset,
663 result,lart_partitions[result].size,lart_partitions[result].size / 1024);
664#endif
665
666 result = mtd_device_register(&mtd, lart_partitions,
667 ARRAY_SIZE(lart_partitions));
668
669 return (result);
670}
671
672static void __exit lart_flash_exit (void)
673{
674 mtd_device_unregister(&mtd);
675}
676
677module_init (lart_flash_init);
678module_exit (lart_flash_exit);
679
680MODULE_LICENSE("GPL");
681MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>");
682MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board");
683