source: src/linux/universal/linux-3.5/drivers/mtd/devices/ar7240_flash.c @ 31672

Last change on this file since 31672 was 31672, checked in by brainslayer, 5 months ago

fix fs detection

File size: 12.3 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] == 0x004d594c) {
123                        printk(KERN_EMERG "compex mylo detected\n");
124                        return i * 4;   // compex, lzma image
125                }
126                if (ofs[i] == 0x32303033) {
127                        printk(KERN_EMERG "WNR2000 uboot detected\n");
128                        return 0x50000; // uboot, lzma image
129                }
130                if (ofs[i] == 0x32323030) {
131                        printk(KERN_EMERG "WNR2200 uboot detected\n");
132                        return 0x50000; // uboot, lzma image
133                }
134                if (ofs[i] == 0x01000000 && ofs[i+1] == 0x44442d57) {
135                        printk(KERN_EMERG "tplink uboot detected\n");
136                        return i * 4;   // uboot, lzma image
137                }
138                if (ofs[i + 15] == 0x27051956) {
139                        printk(KERN_EMERG "WRT160NL uboot detected\n");
140                        return i * 4;   // uboot, lzma image
141                }
142                if (ofs[i] == SQUASHFS_MAGIC_SWAP) {
143                        printk(KERN_EMERG "ZCom quirk found\n");
144                        zcom=1;
145                        for (a = i; a < maxscan; a += 16384) {
146                                        if (ofs[a] == 0x27051956) {
147                                            printk(KERN_EMERG "ZCom quirk kernel offset %d\n",a*4);
148                                            zcomoffset = a * 4;
149                                        }
150       
151                        }
152                        return i * 4;   // filesys starts earlier
153                }
154               
155        }
156        return -1;
157}
158
159static unsigned int guessflashsize(void *base)
160{
161        unsigned int size;
162        unsigned int *guess = (unsigned int *)base;
163        unsigned int max = 16 << 20;
164//check 3 patterns since we can't write.
165        unsigned int p1 = guess[0];
166        unsigned int p2 = guess[4096];
167        unsigned int p3 = guess[8192];
168        unsigned int c1;
169        unsigned int c2;
170        unsigned int c3;
171        for (size = 2 << 20; size <= (max >> 1); size <<= 1) {
172                unsigned int ofs = size / 4;
173                c1 = guess[ofs];
174                c2 = guess[ofs + 4096];
175                c3 = guess[ofs + 8192];
176                if (p1 == c1 && p2 == c2 && p3 == c3)   // mirror found
177                {
178                        break;
179                }
180        }
181        printk(KERN_EMERG "guessed flashsize = %dM\n", size >> 20);
182        return size;
183
184}
185
186static int ar7240_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
187{
188        int nsect, s_curr, s_last;
189        uint64_t  res;
190        if (instr->addr + instr->len > mtd->size)
191                return (-EINVAL);
192
193        ar7240_flash_spi_down();
194
195        res = instr->len;
196        do_div(res, mtd->erasesize);
197        nsect = res;
198        if (((uint32_t)instr->len) % mtd->erasesize)
199                nsect++;
200
201        res = instr->addr;
202        do_div(res,mtd->erasesize);
203        s_curr = res;
204        s_last = s_curr + nsect;
205
206        do {
207                ar7240_spi_sector_erase(s_curr * AR7240_SPI_SECTOR_SIZE);
208        } while (++s_curr < s_last);
209
210        ar7240_spi_done();
211
212        ar7240_flash_spi_up();
213
214        if (instr->callback) {
215                instr->state = MTD_ERASE_DONE;
216                instr->callback(instr);
217        }
218        return 0;
219}
220
221static int
222ar7240_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
223                  size_t *retlen, u_char * buf)
224{
225        uint32_t addr = from | 0xbf000000;
226
227//      printk(KERN_EMERG "read block %X:%X\n",from,len);
228        if (!len)
229                return (0);
230        if (from + len > mtd->size)
231                return (-EINVAL);
232
233//      ar7240_flash_spi_down();
234
235        memcpy(buf, (uint8_t *) (addr), len);
236        *retlen = len;
237
238//      ar7240_flash_spi_up();
239//      printk(KERN_EMERG "read block %X:%X done\n",from,len);
240
241        return 0;
242}
243
244static int
245ar7240_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
246                   size_t *retlen, const u_char * buf)
247{
248        int total = 0, len_this_lp, bytes_this_page;
249        uint32_t addr = 0;
250        u_char *mem;
251//      printk(KERN_EMERG "write block %X:%X\n",to,len);
252
253        ar7240_flash_spi_down();
254
255        while (total < len) {
256                mem = buf + total;
257                addr = to + total;
258                bytes_this_page =
259                    AR7240_SPI_PAGE_SIZE - (addr % AR7240_SPI_PAGE_SIZE);
260                len_this_lp = min((len - total), bytes_this_page);
261
262                ar7240_spi_write_page(addr, mem, len_this_lp);
263                total += len_this_lp;
264        }
265
266        ar7240_spi_done();
267
268        ar7240_flash_spi_up();
269
270        *retlen = len;
271        return 0;
272}
273
274static struct mtd_partition dir_parts[] = {
275#ifdef CONFIG_MTD_FLASH_16MB
276      {name: "RedBoot", offset: 0x30000, size:0x10000,},
277        //, mask_flags: MTD_WRITEABLE, },
278      {name: "linux", offset: 0x50000, size:0xf90000,},
279#elif CONFIG_MTD_FLASH_8MB
280      {name: "RedBoot", offset: 0x30000, size:0x10000,},
281        //, mask_flags: MTD_WRITEABLE, },
282      {name: "linux", offset: 0x50000, size:0x790000,},
283#else
284      {name: "RedBoot", offset: 0, size:0x40000,},
285        //, mask_flags: MTD_WRITEABLE, },
286      {name: "linux", offset: 0x40000, size:0x3a0000,},
287#endif
288      {name: "rootfs", offset: 0x0, size:0x2b0000,},
289        //must be detected
290      {name: "ddwrt", offset: 0x0, size:0x2b0000,},
291        //must be detected
292      {name: "nvram", offset: 0x3d0000, size:0x10000,},
293      {name: "board_config", offset: 0x3f0000, size:0x10000,},
294      {name: "fullflash", offset: 0x3f0000, size:0x10000,},
295      {name: "fullboot", offset: 0, size:0x30000,},
296      {name:NULL,},
297};
298
299struct fis_image_desc {
300        unsigned char name[16]; // Null terminated name
301        unsigned long flash_base;       // Address within FLASH of image
302        unsigned long mem_base; // Address in memory where it executes
303        unsigned long size;     // Length of image
304        unsigned long entry_point;      // Execution entry point
305        unsigned long data_length;      // Length of actual data
306        unsigned char _pad[256 - (16 + 7 * sizeof(unsigned long))];
307        unsigned long desc_cksum;       // Checksum over image descriptor
308        unsigned long file_cksum;       // Checksum over image data
309};
310
311/*
312 * sets up flash_info and returns size of FLASH (bytes)
313 */
314static int __init ar7240_flash_init(void)
315{
316        int i;
317        ar7240_flash_geom_t *geom;
318        struct mtd_info *mtd;
319        uint8_t index;
320        int result = -1;
321        char *buf;
322        int offset = 0;
323        struct squashfs_super_block *sb;
324        size_t rootsize;
325        size_t len;
326        int fsize;
327        init_MUTEX(&ar7240_flash_sem);
328
329        ar7240_reg_wr_nf(AR7240_SPI_CLOCK, 0x43);
330        buf = (char *)0xbf000000;
331        fsize = guessflashsize(buf);
332        for (i = 0; i < AR7240_FLASH_MAX_BANKS; i++) {
333
334                index = ar7240_flash_probe();
335                geom = &flash_geom_tbl[index];
336
337                /* set flash size to value from bootloader if it passed valid value */
338                /* otherwise use the default 4MB.                                   */
339                //if (__ath_flash_size >= 4 && __ath_flash_size <= 16)
340                //    geom->size = __ath_flash_size * 1024 * 1024;
341
342                mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
343                if (!mtd) {
344                        printk("Cant allocate mtd stuff\n");
345                        return -1;
346                }
347                memset(mtd, 0, sizeof(struct mtd_info));
348
349                mtd->name = AR7240_FLASH_NAME;
350                mtd->type = MTD_NORFLASH;
351                mtd->flags = (MTD_CAP_NORFLASH | MTD_WRITEABLE);
352                mtd->size = fsize;
353                mtd->erasesize = geom->sector_size;
354                mtd->numeraseregions = 0;
355                mtd->eraseregions = NULL;
356                mtd->owner = THIS_MODULE;
357                mtd->_erase = ar7240_flash_erase;
358                mtd->_read = ar7240_flash_read;
359                mtd->_write = ar7240_flash_write;
360
361                printk(KERN_EMERG "scanning for root partition\n");
362
363                offset = 0;
364
365                int guess = guessbootsize(buf, mtd->size);
366                if (guess > 0) {
367                        printk(KERN_EMERG "guessed bootloader size = %X\n",
368                               guess);
369                        dir_parts[0].offset = 0;
370                        dir_parts[0].size = guess;                     
371                        dir_parts[7].size = guess;                     
372                        dir_parts[1].offset = guess;
373                        dir_parts[1].size = 0;
374                }
375                while ((offset + mtd->erasesize) < mtd->size) {
376//                      printk(KERN_EMERG "[0x%08X] = [0x%08X]!=[0x%08X]\n",offset,*((unsigned int *) buf),SQUASHFS_MAGIC);
377                        if (*((__u32 *)buf) == SQUASHFS_MAGIC_SWAP) {
378                                printk(KERN_EMERG "\nfound squashfs at %X\n",
379                                       offset);
380                                sb = (struct squashfs_super_block *)buf;
381                                dir_parts[2].offset = offset;
382
383                                dir_parts[2].size = le64_to_cpu(sb->bytes_used);;
384                                len = dir_parts[2].offset + dir_parts[2].size;
385                                len += (mtd->erasesize - 1);
386                                len &= ~(mtd->erasesize - 1);
387                                dir_parts[2].size =
388                                    (len & 0x1ffffff) - dir_parts[2].offset;
389                                dir_parts[3].offset =
390                                    dir_parts[2].offset + dir_parts[2].size;
391
392                                dir_parts[5].offset = mtd->size - mtd->erasesize;       //fis config
393                                dir_parts[5].size = mtd->erasesize;
394                                #if defined(CONFIG_DIR825C1) && !defined(CONFIG_WDR4300)
395                                dir_parts[4].offset = dir_parts[5].offset - (mtd->erasesize*2); //nvram
396                                dir_parts[4].size = mtd->erasesize;
397                                #else
398                                dir_parts[4].offset = dir_parts[5].offset - (mtd->erasesize - (nocalibration * mtd->erasesize));        //nvram
399                                dir_parts[4].size = mtd->erasesize;
400                                #endif
401                                dir_parts[3].size =
402                                    dir_parts[4].offset - dir_parts[3].offset;
403                                rootsize = dir_parts[4].offset - offset;        //size of rootfs aligned to nvram offset
404                                dir_parts[1].size =
405                                    (dir_parts[2].offset -
406                                     dir_parts[1].offset) + rootsize;
407                                //now scan for linux offset
408                                break;
409                        }
410                        offset += 4096;
411                        buf += 4096;
412                }
413                dir_parts[6].offset = 0;        // linux + nvram = phy size
414                dir_parts[6].size = mtd->size;  // linux + nvram = phy size
415                result = add_mtd_partitions(mtd, dir_parts, 8);
416        }
417
418        return 0;
419}
420
421static void __exit ar7240_flash_exit(void)
422{
423        /*
424         * nothing to do
425         */
426}
427
428/*
429 * Primitives to implement flash operations
430 */
431static void ar7240_spi_write_enable()
432{
433        ar7240_reg_wr_nf(AR7240_SPI_FS, 1);
434        ar7240_reg_wr_nf(AR7240_SPI_WRITE, AR7240_SPI_CS_DIS);
435        ar7240_spi_bit_banger(AR7240_SPI_CMD_WREN);
436        ar7240_spi_go();
437}
438
439static void ar7240_spi_poll()
440{
441        int rd;
442
443        do {
444                ar7240_reg_wr_nf(AR7240_SPI_WRITE, AR7240_SPI_CS_DIS);
445                ar7240_spi_bit_banger(AR7240_SPI_CMD_RD_STATUS);
446                ar7240_spi_delay_8();
447                rd = (ar7240_reg_rd(AR7240_SPI_RD_STATUS) & 1);
448        } while (rd);
449}
450
451static void ar7240_spi_write_page(uint32_t addr, uint8_t * data, int len)
452{
453        int i;
454        uint8_t ch;
455
456        ar7240_spi_write_enable();
457        ar7240_spi_bit_banger(AR7240_SPI_CMD_PAGE_PROG);
458        ar7240_spi_send_addr(addr);
459
460        for (i = 0; i < len; i++) {
461                ch = *(data + i);
462                ar7240_spi_bit_banger(ch);
463        }
464
465        ar7240_spi_go();
466        ar7240_spi_poll();
467}
468
469static void ar7240_spi_sector_erase(uint32_t addr)
470{
471        ar7240_spi_write_enable();
472        ar7240_spi_bit_banger(AR7240_SPI_CMD_SECTOR_ERASE);
473        ar7240_spi_send_addr(addr);
474        ar7240_spi_go();
475//    display(0x7d);
476        ar7240_spi_poll();
477}
478
479module_init(ar7240_flash_init);
480module_exit(ar7240_flash_exit);
Note: See TracBrowser for help on using the repository browser.