source: src/linux/universal/linux-3.2/drivers/mtd/devices/ar7240_flash.c @ 31660

Last change on this file since 31660 was 31660, checked in by brainslayer, 13 days ago

use new squashfs in all kernels

File size: 12.1 KB
Line 
1/*
2 * This file contains glue for Atheros ar7100 spi flash interface
3 * Primitives are ar7100_spi_*
4 * mtd flash implements are ar7100_flash_*
5 */
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/types.h>
9#include <linux/errno.h>
10#include <linux/slab.h>
11#include <linux/mtd/mtd.h>
12#include <linux/mtd/partitions.h>
13#include "../mtdcore.h"
14#include <asm/delay.h>
15#include <asm/io.h>
16#include <linux/semaphore.h>
17#include <linux/squashfs_fs.h>
18
19#include "ar7240.h"
20#include "ar7240_flash.h"
21
22/* this is passed in as a boot parameter by bootloader */
23//extern int __ath_flash_size;
24
25/*
26 * statics
27 */
28static void ar7240_spi_write_enable(void);
29static void ar7240_spi_poll(void);
30static void ar7240_spi_write_page(uint32_t addr, uint8_t * data, int len);
31static void ar7240_spi_sector_erase(uint32_t addr);
32
33#define down mutex_lock
34#define up mutex_unlock
35#define init_MUTEX mutex_init
36#define DECLARE_MUTEX(a) struct mutex a
37
38static DECLARE_MUTEX(ar7240_flash_sem);
39
40/* GLOBAL FUNCTIONS */
41void ar7240_flash_spi_down(void)
42{
43//printk(KERN_EMERG "spi down\n");
44        down(&ar7240_flash_sem);
45}
46
47void ar7240_flash_spi_up(void)
48{
49//printk(KERN_EMERG "spi up\n");
50        up(&ar7240_flash_sem);
51}
52
53EXPORT_SYMBOL(ar7240_flash_spi_down);
54EXPORT_SYMBOL(ar7240_flash_spi_up);
55
56#define AR7240_FLASH_SIZE_2MB          (2*1024*1024)
57#define AR7240_FLASH_SIZE_4MB          (4*1024*1024)
58#define AR7240_FLASH_SIZE_8MB          (8*1024*1024)
59#define AR7240_FLASH_SIZE_16MB          (16*1024*1024)
60#ifndef ST25P28
61#define AR7240_FLASH_SECTOR_SIZE_64KB  (64*1024)
62#else
63#define AR7240_FLASH_SECTOR_SIZE_256KB  (256*1024)
64#endif
65#define AR7240_FLASH_SECTOR_SIZE_64KB  (64*1024)
66#define AR7240_FLASH_PG_SIZE_256B       256
67#define AR7240_FLASH_NAME               "ar7240-nor0"
68/*
69 * bank geometry
70 */
71typedef struct ar7240_flash_geom {
72        uint32_t size;
73        uint32_t sector_size;
74        uint32_t nsectors;
75        uint32_t pgsize;
76} ar7240_flash_geom_t;
77
78ar7240_flash_geom_t flash_geom_tbl[AR7240_FLASH_MAX_BANKS] = {
79        {
80#ifdef CONFIG_MTD_FLASH_16MB
81         .size = AR7240_FLASH_SIZE_16MB,
82#elif CONFIG_MTD_FLASH_8MB
83         .size = AR7240_FLASH_SIZE_8MB,
84#else
85         .size = AR7240_FLASH_SIZE_4MB,
86#endif
87         .sector_size = AR7240_FLASH_SECTOR_SIZE_64KB,
88         .pgsize = AR7240_FLASH_PG_SIZE_256B}
89};
90
91static int ar7240_flash_probe()
92{
93        return 0;
94}
95
96static int zcom=0;
97static int nocalibration=0;
98static unsigned int zcomoffset = 0;
99int guessbootsize(void *offset, unsigned int maxscan)
100{
101        unsigned int i,a;
102        unsigned char *ofsb = (unsigned char *)offset;
103        unsigned int *ofs = (unsigned int *)offset;
104        maxscan -= 0x20000;
105        maxscan /= 4;
106        zcom=0;
107        if (!strncmp((char *)(ofsb + 0x29da), "myloram.bin", 11) || !strncmp((char *)(ofsb + 0x2aba), "myloram.bin", 11)) {
108                printk(KERN_EMERG "compex WP72E detected\n");
109                nocalibration=1;
110                return 0x30000; // compex, lzma image
111        }
112
113        for (i = 0; i < maxscan; i += 16384) {
114                if (ofs[i] == 0x6d000080) {
115                        printk(KERN_EMERG "redboot or compatible detected\n");
116                        return i * 4;   // redboot, lzma image
117                }
118                if (ofs[i] == 0x27051956) {
119                        printk(KERN_EMERG "uboot detected\n");
120                        return i * 4;   // uboot, lzma image
121                }
122                if (ofs[i] == 0x32303033) {
123                        printk(KERN_EMERG "WNR2000 uboot detected\n");
124                        return 0x50000; // uboot, lzma image
125                }
126                if (ofs[i] == 0x32323030) {
127                        printk(KERN_EMERG "WNR2200 uboot detected\n");
128                        return 0x50000; // uboot, lzma image
129                }
130                if (ofs[i] == 0x01000000 && ofs[i+1] == 0x44442d57) {
131                        printk(KERN_EMERG "tplink uboot detected\n");
132                        return i * 4;   // uboot, lzma image
133                }
134                if (ofs[i + 15] == 0x27051956) {
135                        printk(KERN_EMERG "WRT160NL uboot detected\n");
136                        return i * 4;   // uboot, lzma image
137                }
138                if (ofs[i] == SQUASHFS_MAGIC_SWAP) {
139                        printk(KERN_EMERG "ZCom quirk found\n");
140                        zcom=1;
141                        for (a = i; a < maxscan; a += 16384) {
142                                        if (ofs[a] == 0x27051956) {
143                                            printk(KERN_EMERG "ZCom quirk kernel offset %d\n",a*4);
144                                            zcomoffset = a * 4;
145                                        }
146       
147                        }
148                        return i * 4;   // filesys starts earlier
149                }
150               
151        }
152        return -1;
153}
154
155static unsigned int guessflashsize(void *base)
156{
157        unsigned int size;
158        unsigned int *guess = (unsigned int *)base;
159        unsigned int max = 16 << 20;
160//check 3 patterns since we can't write.
161        unsigned int p1 = guess[0];
162        unsigned int p2 = guess[4096];
163        unsigned int p3 = guess[8192];
164        unsigned int c1;
165        unsigned int c2;
166        unsigned int c3;
167        for (size = 2 << 20; size <= (max >> 1); size <<= 1) {
168                unsigned int ofs = size / 4;
169                c1 = guess[ofs];
170                c2 = guess[ofs + 4096];
171                c3 = guess[ofs + 8192];
172                if (p1 == c1 && p2 == c2 && p3 == c3)   // mirror found
173                {
174                        break;
175                }
176        }
177        printk(KERN_EMERG "guessed flashsize = %dM\n", size >> 20);
178        return size;
179
180}
181
182static int ar7240_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
183{
184        int nsect, s_curr, s_last;
185        uint64_t  res;
186        if (instr->addr + instr->len > mtd->size)
187                return (-EINVAL);
188
189        ar7240_flash_spi_down();
190
191        res = instr->len;
192        do_div(res, mtd->erasesize);
193        nsect = res;
194        if (((uint32_t)instr->len) % mtd->erasesize)
195                nsect++;
196
197        res = instr->addr;
198        do_div(res,mtd->erasesize);
199        s_curr = res;
200        s_last = s_curr + nsect;
201
202        do {
203                ar7240_spi_sector_erase(s_curr * AR7240_SPI_SECTOR_SIZE);
204        } while (++s_curr < s_last);
205
206        ar7240_spi_done();
207
208        ar7240_flash_spi_up();
209
210        if (instr->callback) {
211                instr->state = MTD_ERASE_DONE;
212                instr->callback(instr);
213        }
214        return 0;
215}
216
217static int
218ar7240_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
219                  size_t *retlen, u_char * buf)
220{
221        uint32_t addr = from | 0xbf000000;
222
223//      printk(KERN_EMERG "read block %X:%X\n",from,len);
224        if (!len)
225                return (0);
226        if (from + len > mtd->size)
227                return (-EINVAL);
228
229//      ar7240_flash_spi_down();
230
231        memcpy(buf, (uint8_t *) (addr), len);
232        *retlen = len;
233
234//      ar7240_flash_spi_up();
235//      printk(KERN_EMERG "read block %X:%X done\n",from,len);
236
237        return 0;
238}
239
240static int
241ar7240_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
242                   size_t *retlen, const u_char * buf)
243{
244        int total = 0, len_this_lp, bytes_this_page;
245        uint32_t addr = 0;
246        u_char *mem;
247//      printk(KERN_EMERG "write block %X:%X\n",to,len);
248
249        ar7240_flash_spi_down();
250
251        while (total < len) {
252                mem = buf + total;
253                addr = to + total;
254                bytes_this_page =
255                    AR7240_SPI_PAGE_SIZE - (addr % AR7240_SPI_PAGE_SIZE);
256                len_this_lp = min((len - total), bytes_this_page);
257
258                ar7240_spi_write_page(addr, mem, len_this_lp);
259                total += len_this_lp;
260        }
261
262        ar7240_spi_done();
263
264        ar7240_flash_spi_up();
265
266        *retlen = len;
267        return 0;
268}
269
270static struct mtd_partition dir_parts[] = {
271#ifdef CONFIG_MTD_FLASH_16MB
272      {name: "RedBoot", offset: 0x30000, size:0x10000,},
273        //, mask_flags: MTD_WRITEABLE, },
274      {name: "linux", offset: 0x50000, size:0xf90000,},
275#elif CONFIG_MTD_FLASH_8MB
276      {name: "RedBoot", offset: 0x30000, size:0x10000,},
277        //, mask_flags: MTD_WRITEABLE, },
278      {name: "linux", offset: 0x50000, size:0x790000,},
279#else
280      {name: "RedBoot", offset: 0, size:0x40000,},
281        //, mask_flags: MTD_WRITEABLE, },
282      {name: "linux", offset: 0x40000, size:0x3a0000,},
283#endif
284      {name: "rootfs", offset: 0x0, size:0x2b0000,},
285        //must be detected
286      {name: "ddwrt", offset: 0x0, size:0x2b0000,},
287        //must be detected
288      {name: "nvram", offset: 0x3d0000, size:0x10000,},
289      {name: "board_config", offset: 0x3f0000, size:0x10000,},
290      {name: "fullflash", offset: 0x3f0000, size:0x10000,},
291      {name: "fullboot", offset: 0, size:0x30000,},
292      {name:NULL,},
293};
294
295struct fis_image_desc {
296        unsigned char name[16]; // Null terminated name
297        unsigned long flash_base;       // Address within FLASH of image
298        unsigned long mem_base; // Address in memory where it executes
299        unsigned long size;     // Length of image
300        unsigned long entry_point;      // Execution entry point
301        unsigned long data_length;      // Length of actual data
302        unsigned char _pad[256 - (16 + 7 * sizeof(unsigned long))];
303        unsigned long desc_cksum;       // Checksum over image descriptor
304        unsigned long file_cksum;       // Checksum over image data
305};
306
307/*
308 * sets up flash_info and returns size of FLASH (bytes)
309 */
310static int __init ar7240_flash_init(void)
311{
312        int i;
313        ar7240_flash_geom_t *geom;
314        struct mtd_info *mtd;
315        uint8_t index;
316        int result = -1;
317        char *buf;
318        int offset = 0;
319        struct squashfs_super_block *sb;
320        size_t rootsize;
321        size_t len;
322        int fsize;
323        init_MUTEX(&ar7240_flash_sem);
324
325        ar7240_reg_wr_nf(AR7240_SPI_CLOCK, 0x43);
326        buf = (char *)0xbf000000;
327        fsize = guessflashsize(buf);
328        for (i = 0; i < AR7240_FLASH_MAX_BANKS; i++) {
329
330                index = ar7240_flash_probe();
331                geom = &flash_geom_tbl[index];
332
333                /* set flash size to value from bootloader if it passed valid value */
334                /* otherwise use the default 4MB.                                   */
335                //if (__ath_flash_size >= 4 && __ath_flash_size <= 16)
336                //    geom->size = __ath_flash_size * 1024 * 1024;
337
338                mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
339                if (!mtd) {
340                        printk("Cant allocate mtd stuff\n");
341                        return -1;
342                }
343                memset(mtd, 0, sizeof(struct mtd_info));
344
345                mtd->name = AR7240_FLASH_NAME;
346                mtd->type = MTD_NORFLASH;
347                mtd->flags = (MTD_CAP_NORFLASH | MTD_WRITEABLE);
348                mtd->size = fsize;
349                mtd->erasesize = geom->sector_size;
350                mtd->numeraseregions = 0;
351                mtd->eraseregions = NULL;
352                mtd->owner = THIS_MODULE;
353                mtd->erase = ar7240_flash_erase;
354                mtd->read = ar7240_flash_read;
355                mtd->write = ar7240_flash_write;
356
357                printk(KERN_EMERG "scanning for root partition\n");
358
359                offset = 0;
360
361                int guess = guessbootsize(buf, mtd->size);
362                if (guess > 0) {
363                        printk(KERN_EMERG "guessed bootloader size = %X\n",
364                               guess);
365                        dir_parts[0].offset = 0;
366                        dir_parts[0].size = guess;                     
367                        dir_parts[7].size = guess;                     
368                        dir_parts[1].offset = guess;
369                        dir_parts[1].size = 0;
370                }
371                while ((offset + mtd->erasesize) < mtd->size) {
372//                      printk(KERN_EMERG "[0x%08X] = [0x%08X]!=[0x%08X]\n",offset,*((unsigned int *) buf),SQUASHFS_MAGIC);
373                        if (*((__u32 *)buf) == SQUASHFS_MAGIC_SWAP) {
374                                printk(KERN_EMERG "\nfound squashfs at %X\n",
375                                       offset);
376                                sb = (struct squashfs_super_block *)buf;
377                                dir_parts[2].offset = offset;
378
379                                dir_parts[2].size = sb->bytes_used;
380                                len = dir_parts[2].offset + dir_parts[2].size;
381                                len += (mtd->erasesize - 1);
382                                len &= ~(mtd->erasesize - 1);
383                                dir_parts[2].size =
384                                    (len & 0x1ffffff) - dir_parts[2].offset;
385                                dir_parts[3].offset =
386                                    dir_parts[2].offset + dir_parts[2].size;
387
388                                dir_parts[5].offset = mtd->size - mtd->erasesize;       //fis config
389                                dir_parts[5].size = mtd->erasesize;
390                                #ifdef CONFIG_DIR825C1
391                                dir_parts[4].offset = dir_parts[5].offset - (mtd->erasesize*2); //nvram
392                                dir_parts[4].size = mtd->erasesize;
393                                #else
394                                dir_parts[4].offset = dir_parts[5].offset - (mtd->erasesize - (nocalibration * mtd->erasesize));        //nvram
395                                dir_parts[4].size = mtd->erasesize;
396                                #endif
397                                dir_parts[3].size =
398                                    dir_parts[4].offset - dir_parts[3].offset;
399                                rootsize = dir_parts[4].offset - offset;        //size of rootfs aligned to nvram offset
400                                dir_parts[1].size =
401                                    (dir_parts[2].offset -
402                                     dir_parts[1].offset) + rootsize;
403                                //now scan for linux offset
404                                break;
405                        }
406                        offset += 4096;
407                        buf += 4096;
408                }
409                dir_parts[6].offset = 0;        // linux + nvram = phy size
410                dir_parts[6].size = mtd->size;  // linux + nvram = phy size
411                result = add_mtd_partitions(mtd, dir_parts, 8);
412        }
413
414        return 0;
415}
416
417static void __exit ar7240_flash_exit(void)
418{
419        /*
420         * nothing to do
421         */
422}
423
424/*
425 * Primitives to implement flash operations
426 */
427static void ar7240_spi_write_enable()
428{
429        ar7240_reg_wr_nf(AR7240_SPI_FS, 1);
430        ar7240_reg_wr_nf(AR7240_SPI_WRITE, AR7240_SPI_CS_DIS);
431        ar7240_spi_bit_banger(AR7240_SPI_CMD_WREN);
432        ar7240_spi_go();
433}
434
435static void ar7240_spi_poll()
436{
437        int rd;
438
439        do {
440                ar7240_reg_wr_nf(AR7240_SPI_WRITE, AR7240_SPI_CS_DIS);
441                ar7240_spi_bit_banger(AR7240_SPI_CMD_RD_STATUS);
442                ar7240_spi_delay_8();
443                rd = (ar7240_reg_rd(AR7240_SPI_RD_STATUS) & 1);
444        } while (rd);
445}
446
447static void ar7240_spi_write_page(uint32_t addr, uint8_t * data, int len)
448{
449        int i;
450        uint8_t ch;
451
452        ar7240_spi_write_enable();
453        ar7240_spi_bit_banger(AR7240_SPI_CMD_PAGE_PROG);
454        ar7240_spi_send_addr(addr);
455
456        for (i = 0; i < len; i++) {
457                ch = *(data + i);
458                ar7240_spi_bit_banger(ch);
459        }
460
461        ar7240_spi_go();
462        ar7240_spi_poll();
463}
464
465static void ar7240_spi_sector_erase(uint32_t addr)
466{
467        ar7240_spi_write_enable();
468        ar7240_spi_bit_banger(AR7240_SPI_CMD_SECTOR_ERASE);
469        ar7240_spi_send_addr(addr);
470        ar7240_spi_go();
471//    display(0x7d);
472        ar7240_spi_poll();
473}
474
475module_init(ar7240_flash_init);
476module_exit(ar7240_flash_exit);
Note: See TracBrowser for help on using the repository browser.