source: src/linux/universal/linux-3.10/drivers/mtd/maps/ixp4xx.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: 14.0 KB
Line 
1/*
2 * $Id: ixp4xx.c,v 1.13 2005/11/16 16:23:21 dvrabel Exp $
3 *
4 * drivers/mtd/maps/ixp4xx.c
5 *
6 * MTD Map file for IXP4XX based systems. Please do not make per-board
7 * changes in here. If your board needs special setup, do it in your
8 * platform level code in arch/arm/mach-ixp4xx/board-setup.c
9 *
10 * Original Author: Intel Corporation
11 * Maintainer: Deepak Saxena <dsaxena@mvista.com>
12 *
13 * Copyright (C) 2002 Intel Corporation
14 * Copyright (C) 2003-2004 MontaVista Software, Inc.
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/types.h>
20#include <linux/init.h>
21#include <linux/kernel.h>
22#include <linux/string.h>
23#include <linux/slab.h>
24#include <linux/ioport.h>
25#include <linux/device.h>
26#include <linux/platform_device.h>
27
28#include <linux/mtd/mtd.h>
29#include <linux/mtd/map.h>
30#include <linux/mtd/partitions.h>
31#include "../mtdcore.h"
32#include <linux/vmalloc.h>
33#include <linux/squashfs_fs.h>
34
35#include <asm/io.h>
36#include <asm/mach/flash.h>
37
38#include <linux/reboot.h>
39
40/*
41 * Read/write a 16 bit word from flash address 'addr'.
42 *
43 * When the cpu is in little-endian mode it swizzles the address lines
44 * ('address coherency') so we need to undo the swizzling to ensure commands
45 * and the like end up on the correct flash address.
46 *
47 * To further complicate matters, due to the way the expansion bus controller
48 * handles 32 bit reads, the byte stream ABCD is stored on the flash as:
49 *     D15    D0
50 *     +---+---+
51 *     | A | B | 0
52 *     +---+---+
53 *     | C | D | 2
54 *     +---+---+
55 * This means that on LE systems each 16 bit word must be swapped. Note that
56 * this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to 'unswap' the CFI
57 * data and other flash commands which are always in D7-D0.
58 */
59#ifndef __ARMEB__
60#ifndef CONFIG_MTD_CFI_BE_BYTE_SWAP
61#  error CONFIG_MTD_CFI_BE_BYTE_SWAP required
62#endif
63
64static inline u16 flash_read16(void __iomem *addr)
65{
66        return be16_to_cpu(__raw_readw((void __iomem *)((unsigned long)addr ^ 0x2)));
67}
68
69static inline void flash_write16(u16 d, void __iomem *addr)
70{
71        __raw_writew(cpu_to_be16(d), (void __iomem *)((unsigned long)addr ^ 0x2));
72}
73
74#define BYTE0(h)        ((h) & 0xFF)
75#define BYTE1(h)        (((h) >> 8) & 0xFF)
76
77#else
78
79static inline u16 flash_read16(const void __iomem *addr)
80{
81        return __raw_readw(addr);
82}
83
84static inline void flash_write16(u16 d, void __iomem *addr)
85{
86        __raw_writew(d, addr);
87}
88
89#define BYTE0(h)        (((h) >> 8) & 0xFF)
90#define BYTE1(h)        ((h) & 0xFF)
91#endif
92
93static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
94{
95        map_word val;
96        val.x[0] = flash_read16(map->virt + ofs);
97        return val;
98}
99
100/*
101 * The IXP4xx expansion bus only allows 16-bit wide acceses
102 * when attached to a 16-bit wide device (such as the 28F128J3A),
103 * so we can't just memcpy_fromio().
104 */
105static void ixp4xx_copy_from(struct map_info *map, void *to,
106                             unsigned long from, ssize_t len)
107{
108        u8 *dest = (u8 *) to;
109        void __iomem *src = map->virt + from;
110
111        if (len <= 0)
112                return;
113
114        if (from & 1) {
115                *dest++ = BYTE1(flash_read16(src));
116                src++;
117                --len;
118        }
119
120        while (len >= 2) {
121                u16 data = flash_read16(src);
122                *dest++ = BYTE0(data);
123                *dest++ = BYTE1(data);
124                src += 2;
125                len -= 2;
126        }
127
128        if (len > 0)
129                *dest++ = BYTE0(flash_read16(src));
130}
131
132/*
133 * Unaligned writes are ignored, causing the 8-bit
134 * probe to fail and proceed to the 16-bit probe (which succeeds).
135 */
136static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
137{
138        if (!(adr & 1))
139                flash_write16(d.x[0], map->virt + adr);
140}
141
142/*
143 * Fast write16 function without the probing check above
144 */
145static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
146{
147        flash_write16(d.x[0], map->virt + adr);
148}
149
150struct ixp4xx_flash_info {
151        struct mtd_info *mtd;
152        struct map_info map;
153        struct mtd_partition *partitions;
154        struct resource *res;
155};
156
157static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
158
159struct fis_image_desc {
160    unsigned char name[16];      // Null terminated name
161    unsigned long flash_base;    // Address within FLASH of image
162    unsigned long mem_base;      // Address in memory where it executes
163    unsigned long size;          // Length of image
164    unsigned long entry_point;   // Execution entry point
165    unsigned long data_length;   // Length of actual data
166    unsigned char _pad[256-(16+7*sizeof(unsigned long))];
167    unsigned long desc_cksum;    // Checksum over image descriptor
168    unsigned long file_cksum;    // Checksum over image data
169};
170
171
172static struct mtd_partition dir_parts[] = {
173        { name: "RedBoot", offset: 0, size: 0x30000, },//, mask_flags: MTD_WRITEABLE, },
174        { name: "linux", offset: 0x30000, size: 0x390000, },
175        { name: "rootfs", offset: 0x0, size: 0x2b0000,}, //must be detected
176        { name: "ddwrt", offset: 0x0, size: 0x2b0000,}, //must be detected
177        { name: "mampf", offset: 0x3d0000, size: 0x10000, },
178        { name: "nvram", offset: 0x3d0000, size: 0x10000, },
179        { name: "FIS directory", offset: 0x3e0000, size: 0x10000, },
180        { name: "RedBoot config", offset: 0x3e0000, size: 0x10000, },
181        { name: "fullflash", offset: 0x3e0000, size: 0x10000, },
182        { name: NULL, },
183};
184
185/*static struct mtd_partition ixp_parts[] = {
186        { name: "boot", offset: 0, size: 0x80000, },//, mask_flags: MTD_WRITEABLE, },
187        { name: "linux", offset: 0x80000, size: 0x390000, },
188        { name: "rootfs", offset: 0x140000, size: 0x2b0000,},
189        { name: "mampf", offset: 0x140000, size: 0x20000,},
190        { name: "nvram", offset: 0x3f0000, size: 0x20000, },
191        { name: NULL, },
192};
193*/
194static int ixp4xx_flash_remove(struct platform_device *dev)
195{
196        struct flash_platform_data *plat = dev->dev.platform_data;
197        struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
198
199        platform_set_drvdata(dev, NULL);
200
201        if(!info)
202                return 0;
203
204        if (info->mtd) {
205                del_mtd_partitions(info->mtd);
206                map_destroy(info->mtd);
207        }
208        if (info->map.virt)
209                iounmap(info->map.virt);
210
211        kfree(info->partitions);
212
213        if (info->res) {
214                release_resource(info->res);
215                kfree(info->res);
216        }
217
218        if (plat->exit)
219                plat->exit();
220
221        return 0;
222}
223
224/*static struct mtd_partition ap71_parts[] = {
225        { name: "RedBoot", offset: 0, size: 0x80000, },//, mask_flags: MTD_WRITEABLE, },
226        { name: "linux", offset: 0x80000, size: 0xd20000, },
227        { name: "ramdisk", offset: 0x280000, size: 0xd00000,},
228        { name: "mampf", offset: 0xf80000, size: 0x20000, },
229        { name: "nvram", offset: 0xfa0000, size: 0x20000, },
230        { name: "RedBoot config", offset: 0xfc0000, size: 0x01000, },
231        { name: "FIS directory", offset: 0xfe0000, size: 0x20000, },
232        { name: NULL, },
233};*/
234
235#define AP71_MTDP_NUM 7
236
237
238static int ixp4xx_flash_probe(struct platform_device *dev)
239{
240        struct flash_platform_data *plat = dev->dev.platform_data;
241        struct ixp4xx_flash_info *info;
242        int result = -1;
243        struct mtd_info *mtd;
244        int err = -1;
245        int offset=0;
246        char *buf;
247        unsigned char *p;
248        struct fis_image_desc *fis; 
249
250        if (!plat)
251                return -ENODEV;
252
253        if (plat->init) {
254                err = plat->init();
255                if (err)
256                        return err;
257        }
258
259        info = kmalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL);
260        if(!info) {
261                err = -ENOMEM;
262                goto Error;
263        }
264        memset(info,0,sizeof(struct ixp4xx_flash_info));
265
266        platform_set_drvdata(dev, info);
267
268        /*
269         * Tell the MTD layer we're not 1:1 mapped so that it does
270         * not attempt to do a direct access on us.
271         */
272        info->map.phys = NO_XIP;
273        info->map.size = dev->resource->end - dev->resource->start + 1;
274
275        /*
276         * We only support 16-bit accesses for now. If and when
277         * any board use 8-bit access, we'll fixup the driver to
278         * handle that.
279         */
280        info->map.bankwidth = 2;
281        info->map.name = dev_name(&dev->dev);
282        info->map.read = ixp4xx_read16,
283        info->map.write = ixp4xx_probe_write16,
284        info->map.copy_from = ixp4xx_copy_from,
285        printk(KERN_ERR "try to reserve 0x%08X with size of 0x%08X\n",dev->resource->start,dev->resource->end - dev->resource->start + 1);
286        info->res = request_mem_region(dev->resource->start,
287                        dev->resource->end - dev->resource->start + 1,
288                        "IXP4XXFlash");
289        if (!info->res) {
290                printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
291                err = -ENOMEM;
292                goto Error;
293        }
294
295        info->map.virt = ioremap(dev->resource->start,
296                                 dev->resource->end - dev->resource->start + 1);
297        if (!info->map.virt) {
298                printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
299                err = -EIO;
300                goto Error;
301        }
302
303        info->mtd = do_map_probe(plat->map_name, &info->map);
304        if (!info->mtd) {
305                printk(KERN_ERR "IXP4XXFlash: map_probe failed\n");
306                err = -ENXIO;
307                goto Error;
308        }
309        info->mtd->owner = THIS_MODULE;
310
311        /* Use the fast version */
312        info->map.write = ixp4xx_write16,
313
314        printk(KERN_EMERG "scanning for root partition\n");
315        mtd = info->mtd;
316        offset = 0;
317        buf = info->map.virt;
318        int foundconfig=0;
319        int foundfis=0;
320        int filesyssize=0;
321        int tmplen;
322        int erasesize = mtd->erasesize;
323        #ifdef CONFIG_TONZE
324        erasesize=0x20000;
325        #endif
326        #ifdef CONFIG_NOP8670
327        erasesize=0x20000;
328        #endif
329        while((offset+erasesize)<mtd->size)
330            {
331            printk(KERN_EMERG "[0x%08X]\r",offset);
332            if (*((__u32 *) buf) == SQUASHFS_MAGIC_SWAP || *((__u16 *) buf) == 0x1985)
333                {
334                struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
335                if (*((__u16 *) buf) != 0x1985)
336                        {
337                        filesyssize = sb->bytes_used;
338                        tmplen = offset + filesyssize;
339                        tmplen +=  (erasesize - 1);
340                        tmplen &= ~(erasesize - 1);
341                        filesyssize = tmplen - offset;
342                        }
343
344
345                printk(KERN_EMERG "\nfound squashfs/jffs2 at %X\n",offset);
346                dir_parts[2].offset = offset;
347                //detect now compex board
348                //printk(KERN_EMERG "id = %s\n",(char*)(info->map.virt+0x23d6));
349                if (!strncmp((char*)(info->map.virt+0x23d6),"myloram.bin",11))
350                    {
351                    printk(KERN_EMERG "Compex WP188 detected!\n");
352                    dir_parts[0].size=0x40000;
353                    dir_parts[0].offset=0;
354                    dir_parts[7].size=0x1000;
355                    dir_parts[7].offset = mtd->size-0x1000;
356                    dir_parts[6].size=erasesize;
357                    dir_parts[6].offset = mtd->size-erasesize;
358
359                    long highest=dir_parts[6].offset;
360                    #ifdef CONFIG_TONZE
361                    highest&= ~(erasesize-1);
362                    #endif
363                    dir_parts[2].size=(highest - (erasesize*2)) - dir_parts[2].offset;
364                    dir_parts[4].offset=highest - erasesize*2;
365                    dir_parts[4].size=erasesize;
366                    dir_parts[5].offset=highest - erasesize;
367                    dir_parts[5].size=erasesize;
368                    dir_parts[1].offset=0x40000;
369                    dir_parts[1].size=dir_parts[2].offset-dir_parts[1].offset+dir_parts[2].size;
370                    goto def;
371                    }
372               
373               
374               
375                //now scan for linux offset
376#ifdef CONFIG_NOP8670
377                p=(unsigned char*)(info->map.virt+mtd->size-erasesize);
378#elif CONFIG_TONZE
379                p=(unsigned char*)(info->map.virt+mtd->size-0x8000);
380#else
381                p=(unsigned char*)(info->map.virt+mtd->size-erasesize);
382#endif
383                fis = (struct fis_image_desc*)p;
384                printk(KERN_EMERG "scan redboot from %p\n",fis);
385                while(1)
386                {
387                if (fis->name[0]==0xff)
388                    {
389                    goto def;
390                    }
391                if (!strncmp(fis->name,"RedBoot",7) && strncmp(fis->name,"RedBoot config",14))
392                    {
393                    printk(KERN_EMERG "found RedBoot partition at [0x%08lX]\n",fis->flash_base);
394                    dir_parts[0].size=fis->size;
395                    }
396                if (!strncmp(fis->name,"RedBoot config",14))
397                    {
398                    printk(KERN_EMERG "found RedBoot config partition at [0x%08lX]\n",fis->flash_base);
399                    dir_parts[7].size=mtd->erasesize;
400                    dir_parts[7].offset=fis->flash_base&(mtd->size-1);
401#ifdef CONFIG_TONZE
402                    dir_parts[7].offset&= ~(erasesize-1);
403#endif             
404                    if (foundfis)
405                    {
406                    long highest=dir_parts[5].offset;
407                    if (dir_parts[6].offset<highest)
408                        highest=dir_parts[6].offset;
409#ifdef CONFIG_TONZE
410                    highest&= ~(erasesize-1);
411#endif
412                    dir_parts[2].size=(highest - (erasesize*2)) - dir_parts[2].offset;
413                    dir_parts[4].offset=highest - erasesize*2;
414                    dir_parts[4].size=erasesize;
415                    dir_parts[5].offset=highest - erasesize;
416                    dir_parts[5].size=erasesize;
417                    }
418                    foundconfig=1;
419                    }
420                if (!strncmp(fis->name,"linux",5) || !strncmp(fis->name,"vmlinux",7) || !strncmp(fis->name,"kernel",6))
421                    {
422                    printk(KERN_EMERG "found linux partition at [0x%08lX]\n",fis->flash_base);
423                    dir_parts[1].offset=fis->flash_base&(mtd->size-1);
424                    dir_parts[1].size=dir_parts[2].offset-dir_parts[1].offset+dir_parts[2].size;
425                    }
426                if (!strncmp(fis->name,"FIS directory",13))
427                    {
428                    printk(KERN_EMERG "found config partition at [0x%08lX]\n",fis->flash_base);
429                    dir_parts[6].offset=(fis->flash_base&(mtd->size-1));
430                    dir_parts[6].size=mtd->erasesize;
431#ifdef CONFIG_TONZE
432                    dir_parts[6].offset&= ~(erasesize-1);
433#endif             
434                    if (foundconfig)
435                    {
436                    long highest=dir_parts[6].offset;
437                    if (dir_parts[7].offset<highest)
438                        highest=dir_parts[7].offset;
439#ifdef CONFIG_TONZE
440                    highest&= ~(erasesize-1);
441#endif
442                    dir_parts[2].size=(highest - (erasesize*2)) - dir_parts[2].offset;
443                    dir_parts[4].offset=highest - erasesize*2;
444                    dir_parts[4].size=erasesize;
445                    dir_parts[5].offset=highest - erasesize;
446                    dir_parts[5].size=erasesize;
447                    }
448                    foundfis=1;
449                    }
450                p+=sizeof(struct fis_image_desc);
451                fis = (struct fis_image_desc*)p;
452                }
453                break;
454                }
455#ifdef CONFIG_TONZE
456            offset+=0x1000;
457            buf+=0x1000;
458#else
459            offset+=erasesize;
460            buf+=erasesize;
461#endif
462            }
463        def:;
464        info->partitions=dir_parts;
465        if (filesyssize)
466            {
467            dir_parts[2].size = filesyssize;   
468            }
469        dir_parts[3].offset = dir_parts[2].offset+dir_parts[2].size;
470        dir_parts[3].size = dir_parts[4].offset-dir_parts[3].offset;
471
472        dir_parts[8].offset = 0;
473        dir_parts[8].size = mtd->size;
474
475        err = add_mtd_partitions(mtd, dir_parts, 9);
476
477/*#ifndef CONFIG_NOP8670
478        err = parse_mtd_partitions(info->mtd, probes, &info->partitions, dev->resource->start);
479#else
480        info->partitions=ap71_parts;
481        err=AP71_MTDP_NUM;   
482#endif
483        if (err > 0) {
484                err = add_mtd_partitions(info->mtd, info->partitions, err);
485                if(err)
486                        printk(KERN_ERR "Could not parse partitions\n");
487        }
488*/
489        if (err)
490                goto Error;
491
492        return 0;
493
494Error:
495        ixp4xx_flash_remove(dev);
496        return err;
497}
498
499static struct platform_driver ixp4xx_flash_driver = {
500        .probe          = ixp4xx_flash_probe,
501        .remove         = ixp4xx_flash_remove,
502        .driver         = {
503                .name   = "IXP4XX-Flash",
504        },
505};
506
507module_platform_driver(ixp4xx_flash_driver);
508
509MODULE_LICENSE("GPL");
510MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems");
511MODULE_AUTHOR("Deepak Saxena");
Note: See TracBrowser for help on using the repository browser.