source: src/linux/universal/linux-3.2/drivers/mtd/devices/ar9100_pflash.c @ 31672

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

fix fs detection

File size: 12.9 KB
Line 
1/*
2 * This file contains glue for Atheros ar9100 pf flash interface
3 * Primitives are ar9100_pf_*
4 * mtd flash implements are ar9100_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
18#include "ar7100.h"
19#include "ar9100_pflash.h"
20#include <linux/squashfs_fs.h>
21
22/* this is passed in as a boot parameter by bootloader */
23extern int __ath_flash_size;
24extern void ar9100_write(uint32_t, CFG_FLASH_WORD_SIZE);
25extern CFG_FLASH_WORD_SIZE ar9100_read(uint32_t offset);
26
27/*
28 * bank geometry
29 */
30typedef struct ar9100_flash_geom {
31    uint16_t vendor_id;
32    uint16_t device_id;
33    char *name;
34    uint32_t sector_size;
35    uint32_t size;
36} ar9100_flash_geom_t;
37
38
39/*
40 * statics
41 */
42static int ar9100_pflash_erase(ar9100_flash_geom_t *geom,int s_first, int s_last);
43static int ar9100_pflash_write_word(ar9100_flash_geom_t *geom,unsigned long dest, unsigned long data);
44static int ar9100_pflash_write_buff(ar9100_flash_geom_t *geom,u_char * src, unsigned long addr, unsigned long cnt);
45static int ar9100_flash_probe(void);
46
47static const char *part_probes[] __initdata =
48    { "cmdlinepart", "RedBoot", NULL };
49
50#define down mutex_lock
51#define up mutex_unlock
52#define init_MUTEX mutex_init
53#define DECLARE_MUTEX(a) struct mutex a
54
55static DECLARE_MUTEX(ar9100_flash_sem);
56static DECLARE_MUTEX(ar7100_flash_sem);
57
58/* GLOBAL FUNCTIONS */
59void ar9100_pflash_down(void)
60{
61    down(&ar9100_flash_sem);
62}
63
64void ar9100_pflash_up(void)
65{
66    up(&ar9100_flash_sem);
67}
68
69/* For spi flash controller */
70void ar7100_flash_spi_down(void)
71{
72    down(&ar7100_flash_sem);
73}
74
75void ar7100_flash_spi_up(void)
76{
77    up(&ar7100_flash_sem);
78}
79
80EXPORT_SYMBOL(ar7100_flash_spi_down);
81EXPORT_SYMBOL(ar7100_flash_spi_up);
82
83ar9100_flash_geom_t flash_geom_tbl[] = {
84    {0x00bf, 0x2780, "SST-39VF400", 0x01000, 0x080000}, /* 512KB */
85    {0x00bf, 0x2782, "SST-39VF160", 0x01000, 0x200000}, /* 2MB */
86    {0x00bf, 0x236b, "SST-39VF6401", 0x01000, 0x800000},
87    {0x00bf, 0x236a, "SST-39VF6402", 0x01000, 0x800000},
88    {0x00bf, 0x236d, "SST-39VF6402", 0x01000, 0x800000},
89    {0x0001, 0x227e, "AMD-SPANSION", 0x02000, 0x2000000},  /* 32 MB  */
90    {0x00c2, 0x227e, "AMD-SPANSION", 0x02000, 0x2000000},  /* 32 MB  */
91    {0xffff, 0xffff, NULL, 0, 0}        /* end list */
92};
93
94static int ar9100_flash_probe()
95{
96    uint16_t venid, devid, i;
97
98    /* issue JEDEC query */
99
100    ar9100_write(CFG_FLASH_ADDR0, FLASH_Setup_Code1);
101    ar9100_write(CFG_FLASH_ADDR1, FLASH_Setup_Code2);
102    ar9100_write(CFG_FLASH_ADDR0, FLASH_Jedec_Query);
103
104    udelay(10000);
105
106    venid = ar9100_read(0);
107    devid = ar9100_read(1);
108
109    /* issue software exit */
110    ar9100_write(CFG_FLASH_ADDR0, FLASH_Setup_Code1);
111    ar9100_write(CFG_FLASH_ADDR1, FLASH_Setup_Code2);
112    ar9100_write(CFG_FLASH_ADDR0, FLASH_Soft_Exit);
113
114    udelay(10000);
115
116    for (i = 0; flash_geom_tbl[i].name != NULL; i++) {
117        if ((venid == flash_geom_tbl[i].vendor_id) &&
118            (devid == flash_geom_tbl[i].device_id)) {
119            break;
120        }
121    }
122if (flash_geom_tbl[i].name==NULL)
123    {
124    printk(KERN_EMERG "use default mapping for vendor %X, dev %X\n",venid,devid);
125    i=5;
126    }
127    printk("FLASH ID: %s ", flash_geom_tbl[i].name);
128
129    if (flash_geom_tbl[i].size >= 0x100000)
130        printk("SIZE: (%d MB)\n", flash_geom_tbl[i].size >> 20);
131    else
132        printk("SIZE: (%d KB)\n", flash_geom_tbl[i].size >> 10);
133
134    return i;
135}
136
137static int ar9100_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
138{
139    int nsect, s_curr, s_last;
140        uint64_t  res;
141 
142    if (instr->addr + instr->len > mtd->size) return (-EINVAL);
143
144    ar9100_pflash_down();
145
146        res = instr->len;
147        do_div(res, mtd->erasesize);
148        nsect = res;
149        if (((uint32_t)instr->len) % mtd->erasesize)
150                nsect++;
151
152        res = instr->addr;
153        do_div(res,mtd->erasesize);
154        s_curr = res;
155    s_last  = s_curr + nsect;
156
157    ar9100_pflash_erase((ar9100_flash_geom_t *)mtd->priv,s_curr, s_last);
158
159    ar9100_pflash_up();
160
161    if (instr->callback) {
162        instr->state = MTD_ERASE_DONE;
163        instr->callback(instr);
164    }
165
166    return 0;
167}
168
169static int
170ar9100_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
171          size_t * retlen, u_char * buf)
172{
173    uint32_t addr = from | AR9100_PFLASH_CTRLR;
174
175    if (!len)
176        return (0);
177   
178    if (from + len > mtd->size)
179        return (-EINVAL);
180
181    ar9100_pflash_down();
182   
183    memcpy(buf, (uint8_t *) (addr), len);
184    *retlen = len;
185
186    ar9100_pflash_up();
187
188    return 0;
189}
190
191static int
192ar9100_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
193           size_t * retlen, const u_char * buf)
194{
195
196//printk(KERN_EMERG "%s", __func__);
197
198    ar9100_pflash_down();
199
200    if (mtd->size < to + len)
201        return ENOSPC;
202
203    to += AR9100_PFLASH_CTRLR;
204    ar9100_pflash_write_buff((ar9100_flash_geom_t *)mtd->priv, (u_char *) buf, to, len);
205
206    ar9100_pflash_up();
207
208    *retlen = len;
209
210    return 0;
211}
212
213static struct mtd_partition dir_parts[] = {
214        { name: "RedBoot", offset: 0, size: 0x60000, },//, mask_flags: MTD_WRITEABLE, },
215        { name: "linux", offset: 0x60000, size: 0x390000, },
216        { name: "rootfs", offset: 0x0, size: 0x2b0000,}, //must be detected
217        { name: "ddwrt", offset: 0x0, size: 0x2b0000,}, //must be detected
218        { name: "nvram", offset: 0x3d0000, size: 0x10000, },
219        { name: "board_config", offset: 0x3f0000, size: 0x10000, },
220        { name: "fullflash", offset: 0x3f0000, size: 0x10000, },
221        { name: NULL, },
222};
223
224/*
225 * sets up flash_info and returns size of FLASH (bytes)
226 */
227static int
228__init ar9100_flash_init(void)
229{
230    int np;
231    ar9100_flash_geom_t *geom;
232    struct mtd_info *mtd;
233    struct mtd_partition *mtd_parts;
234    uint8_t index;
235        char *buf;
236        unsigned char *p;
237        int offset=0;
238        struct squashfs_super_block *sb;
239        size_t rootsize;
240        size_t len;
241
242    init_MUTEX(&ar9100_flash_sem);
243
244    index = ar9100_flash_probe();
245    geom = &flash_geom_tbl[index];
246
247    /* set flash size to value from bootloader if it passed valid value */
248    /* otherwise use the default 4MB.                                   */
249    if (__ath_flash_size >= 4 && __ath_flash_size <= 32)
250        geom->size = __ath_flash_size * 1024 * 1024;
251
252    mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
253    if (!mtd) {
254        printk("Cant allocate mtd stuff\n");
255        return -1;
256    }
257    memset(mtd, 0, sizeof(struct mtd_info));
258
259    mtd->name = AR9100_FLASH_NAME;
260    mtd->type = MTD_NORFLASH;
261    mtd->flags = (MTD_CAP_NORFLASH | MTD_WRITEABLE);
262    mtd->size = geom->size;
263    mtd->erasesize = (geom->sector_size * 16);  /* Erase block size */
264    mtd->numeraseregions = 0;
265    mtd->eraseregions = NULL;
266    mtd->owner = THIS_MODULE;
267    mtd->erase = ar9100_flash_erase;
268    mtd->read = ar9100_flash_read;
269    mtd->write = ar9100_flash_write;
270    mtd->priv = (void *)(&flash_geom_tbl[index]);
271
272        printk(KERN_EMERG "scanning for root partition\n");
273       
274        offset = 0;
275        buf = 0xbe000000;
276        while((offset+mtd->erasesize)<mtd->size)
277            {
278            //printk(KERN_EMERG "[0x%08X] = [0x%08X]!=[0x%08X]\n",offset,*((unsigned int *) buf),SQUASHFS_MAGIC);
279            if (*((__u32 *) buf) == SQUASHFS_MAGIC_SWAP)
280                {
281                printk(KERN_EMERG "\nfound squashfs at %X\n",offset);
282                sb = (struct squashfs_super_block *) buf;
283                dir_parts[2].offset = offset;
284                dir_parts[2].size = le64_to_cpu(sb->bytes_used);
285                len = dir_parts[2].offset + dir_parts[2].size;
286                len +=  (mtd->erasesize - 1);
287                len &= ~(mtd->erasesize - 1);
288                dir_parts[2].size = (len&0x1ffffff) - dir_parts[2].offset;
289                dir_parts[3].offset = dir_parts[2].offset + dir_parts[2].size;
290                dir_parts[5].offset = mtd->size-mtd->erasesize; // board config
291                dir_parts[5].size = mtd->erasesize;
292                dir_parts[4].offset = dir_parts[5].offset-mtd->erasesize; //nvram
293                dir_parts[4].size = mtd->erasesize;
294                dir_parts[3].size = dir_parts[4].offset - dir_parts[3].offset;
295                rootsize = dir_parts[4].offset-offset; //size of rootfs aligned to nvram offset
296
297                dir_parts[1].offset=dir_parts[0].size;
298                dir_parts[1].size=(dir_parts[2].offset-dir_parts[0].size)+rootsize;
299                break;
300                }
301                //now scan for linux offset
302            offset+=4096;
303            buf+=4096;
304            }
305        def:;
306        dir_parts[6].offset=0; // linux + nvram = phy size
307        dir_parts[6].size=mtd->size; // linux + nvram = phy size
308        add_mtd_partitions(mtd, dir_parts, 7);
309    return 0;
310}
311
312
313static void
314__exit ar9100_flash_exit(void)
315{
316    /*
317     * nothing to do
318     */
319}
320
321/*
322 * Primitives to implement flash operations
323 */
324
325static int
326ar9100_pflash_write_buff(ar9100_flash_geom_t *geom, u_char * src, unsigned long addr, unsigned long cnt)
327{
328    unsigned long cp, wp, data;
329    int i, l, rc;
330//printk(KERN_EMERG "%s", __func__);
331
332    wp = (addr & ~3);   /* get lower word aligned address */
333
334    /*
335     * handle unaligned start bytes
336     */
337    if ((l = addr - wp) != 0) {
338        data = 0;
339        for (i = 0, cp = wp; i < l; ++i, ++cp) {
340            data = (data << 8) | (*(unsigned char *) cp);
341        }
342        for (; i < 4 && cnt > 0; ++i) {
343            data = (data << 8) | *src++;
344            --cnt;
345            ++cp;
346        }
347        for (; cnt == 0 && i < 4; ++i, ++cp) {
348            data = (data << 8) | (*(unsigned char *) cp);
349        }
350
351        if ((rc = ar9100_pflash_write_word(geom, wp, data)) != 0) {
352            return (rc);
353        }
354        wp += 4;
355    }
356    /*
357     * handle word aligned part
358     *
359     */
360    while (cnt >= 4) {
361        data = 0;
362        for (i = 0; i < 4; ++i) {
363            data = (data << 8) | *src++;
364        }
365        if ((rc = ar9100_pflash_write_word(geom, wp, data)) != 0) {
366            return (rc);
367        }
368        wp += 4;
369        cnt -= 4;
370    }
371
372    if (cnt == 0) {
373        return (0);
374    }
375
376    /*
377     * handle unaligned tail bytes
378     */
379    data = 0;
380    for (i = 0, cp = wp; i < 4 && cnt > 0; ++i, ++cp) {
381        data = (data << 8) | *src++;
382        --cnt;
383    }
384    for (; i < 4; ++i, ++cp) {
385        data = (data << 8) | (*(unsigned char *) cp);
386    }
387    return (ar9100_pflash_write_word(geom, wp, data));
388}
389
390static int ar9100_pflash_write_word(ar9100_flash_geom_t *geom, unsigned long dest, unsigned long data)
391{
392//printk(KERN_EMERG "%s", __func__);
393
394
395    volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *) dest;
396    unsigned long data_addr;
397
398    data_addr = (unsigned long) &data;
399    CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *) data_addr;
400    int i;
401
402    /* Check if Flash is (sufficiently) erased */
403    if ((*((unsigned long *) dest) & data) != data) {
404        return (2);
405    }
406
407    for (i = 0; i < 4 / sizeof(CFG_FLASH_WORD_SIZE); i++) {
408        CFG_FLASH_WORD_SIZE state, prev_state;
409        int timeout;
410
411        ar9100_write(CFG_FLASH_ADDR0, FLASH_Setup_Code1);
412        ar9100_write(CFG_FLASH_ADDR1, FLASH_Setup_Code2);
413        ar9100_write(CFG_FLASH_ADDR0, FLASH_Program);
414        dest2[i] = data2[i];
415
416#if 1
417            timeout = 10000000;
418            while (timeout) {
419                if (dest2[i] == data2[i]) {
420                         break;
421                }
422                timeout--;
423            }
424#else
425        /*  Wait for completion (bit 6 stops toggling) */
426                timeout = 5000000;
427                prev_state = (dest2[i] & FLASH_Busy);
428                while (timeout) {
429                        state = (dest2[i] & FLASH_Busy);
430                        if (prev_state == state) {
431                                break;
432                        }
433                timeout--;
434                prev_state = state;
435                }
436#endif
437                if (!timeout)
438                        return -1;
439     }
440
441    return (0);
442}
443
444static int ar9100_pflash_erase(ar9100_flash_geom_t *geom, int s_first, int s_last)
445{
446//printk(KERN_EMERG "%s", __func__);
447
448    int i;
449    int timeout;
450
451    for (i = s_first; i < s_last; i++) {
452        CFG_FLASH_WORD_SIZE state, prev_state,rd_data;
453
454         f_ptr addr_ptr = (f_ptr) (AR9100_PFLASH_CTRLR + (i * geom->sector_size * 16));
455//      printk(KERN_EMERG "%s %d", __func__,i);
456
457        /* Program data [byte] - 6 step sequence */
458        ar9100_write(CFG_FLASH_ADDR0, FLASH_Setup_Code1);
459        ar9100_write(CFG_FLASH_ADDR1, FLASH_Setup_Code2);
460        ar9100_write(CFG_FLASH_ADDR0, FLASH_Setup_Erase);
461        ar9100_write(CFG_FLASH_ADDR0, FLASH_Setup_Code1);
462        ar9100_write(CFG_FLASH_ADDR1, FLASH_Setup_Code2);
463
464        *addr_ptr = FLASH_Block_Erase;
465#if 1
466        // Wait for erase completion.
467        timeout = 10000000;
468        while (timeout) {
469                state = *addr_ptr;
470                if (FLASHWORD(0xffff) == state) {
471                        break;
472                }
473                timeout--;
474            }
475#else
476        /*  Wait for completion (bit 6 stops toggling) */
477                timeout = 5000000;
478                prev_state = (*addr_ptr & FLASH_Busy);
479                while (timeout) {
480                        rd_data = *addr_ptr;
481                        state = rd_data & FLASH_Busy;
482                        if ((prev_state == state) && (rd_data == FLASHWORD(0xffff))) {
483                                break;
484                        }
485                        timeout--;
486                        prev_state = state;
487                }
488#endif
489        if (!timeout) {
490                printk("Erase operation failed\n");
491                return -1;
492        }
493     }
494         return 0;
495}
496
497module_init(ar9100_flash_init);
498module_exit(ar9100_flash_exit);
Note: See TracBrowser for help on using the repository browser.