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