source: src/linux/universal/linux-4.9/drivers/mtd/maps/ixp4xx.c @ 31630

Last change on this file since 31630 was 31630, checked in by brainslayer, 4 months ago

new fs is compatible with standard squashfs, just smaller

File size: 13.5 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/err.h>
19#include <linux/module.h>
20#include <linux/types.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/magic.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_get_platdata(&dev->dev);
197        struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
198
199        if(!info)
200                return 0;
201
202        if (info->mtd) {
203                del_mtd_partitions(info->mtd);
204                map_destroy(info->mtd);
205        }
206        kfree(info->partitions);
207
208        if (plat->exit)
209                plat->exit();
210
211        return 0;
212}
213
214/*static struct mtd_partition ap71_parts[] = {
215        { name: "RedBoot", offset: 0, size: 0x80000, },//, mask_flags: MTD_WRITEABLE, },
216        { name: "linux", offset: 0x80000, size: 0xd20000, },
217        { name: "ramdisk", offset: 0x280000, size: 0xd00000,},
218        { name: "mampf", offset: 0xf80000, size: 0x20000, },
219        { name: "nvram", offset: 0xfa0000, size: 0x20000, },
220        { name: "RedBoot config", offset: 0xfc0000, size: 0x01000, },
221        { name: "FIS directory", offset: 0xfe0000, size: 0x20000, },
222        { name: NULL, },
223};*/
224
225#define AP71_MTDP_NUM 7
226
227
228static int ixp4xx_flash_probe(struct platform_device *dev)
229{
230        struct flash_platform_data *plat = dev_get_platdata(&dev->dev);
231        struct ixp4xx_flash_info *info;
232        int result = -1;
233        struct mtd_info *mtd;
234        int err = -1;
235        int offset=0;
236        char *buf;
237        unsigned char *p;
238        struct fis_image_desc *fis; 
239
240        if (!plat)
241                return -ENODEV;
242
243        if (plat->init) {
244                err = plat->init();
245                if (err)
246                        return err;
247        }
248
249        info = devm_kzalloc(&dev->dev, sizeof(struct ixp4xx_flash_info),
250                            GFP_KERNEL);
251        if(!info) {
252                err = -ENOMEM;
253                goto Error;
254        }
255        memset(info,0,sizeof(struct ixp4xx_flash_info));
256
257        platform_set_drvdata(dev, info);
258
259        /*
260         * Tell the MTD layer we're not 1:1 mapped so that it does
261         * not attempt to do a direct access on us.
262         */
263        info->map.phys = NO_XIP;
264        info->map.size = dev->resource->end - dev->resource->start + 1;
265
266        /*
267         * We only support 16-bit accesses for now. If and when
268         * any board use 8-bit access, we'll fixup the driver to
269         * handle that.
270         */
271        info->map.bankwidth = 2;
272        info->map.name = dev_name(&dev->dev);
273        info->map.read = ixp4xx_read16,
274        info->map.write = ixp4xx_probe_write16,
275        info->map.copy_from = ixp4xx_copy_from,
276        printk(KERN_ERR "try to reserve 0x%08X with size of 0x%08X\n",dev->resource->start,dev->resource->end - dev->resource->start + 1);
277        info->map.virt = devm_ioremap_resource(&dev->dev, dev->resource);
278        if (IS_ERR(info->map.virt)) {
279                err = PTR_ERR(info->map.virt);
280        }
281
282        info->mtd = do_map_probe(plat->map_name, &info->map);
283        if (!info->mtd) {
284                printk(KERN_ERR "IXP4XXFlash: map_probe failed\n");
285                err = -ENXIO;
286                goto Error;
287        }
288        info->mtd->dev.parent = &dev->dev;
289
290        /* Use the fast version */
291        info->map.write = ixp4xx_write16,
292
293        printk(KERN_EMERG "scanning for root partition\n");
294        mtd = info->mtd;
295        offset = 0;
296        buf = info->map.virt;
297        int foundconfig=0;
298        int foundfis=0;
299        int filesyssize=0;
300        int tmplen;
301        int erasesize = mtd->erasesize;
302        #ifdef CONFIG_TONZE
303        erasesize=0x20000;
304        #endif
305        #ifdef CONFIG_NOP8670
306        erasesize=0x20000;
307        #endif
308        while((offset+erasesize)<mtd->size)
309            {
310            printk(KERN_EMERG "[0x%08X]\r",offset);
311            if (*((__u32 *) buf) == SQUASHFS_MAGIC || *((__u16 *) buf) == 0x1985)
312                {
313                struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
314                if (*((__u16 *) buf) != 0x1985)
315                        {
316                        filesyssize = sb->bytes_used;
317                        tmplen = offset + filesyssize;
318                        tmplen +=  (erasesize - 1);
319                        tmplen &= ~(erasesize - 1);
320                        filesyssize = tmplen - offset;
321                        }
322
323
324                printk(KERN_EMERG "\nfound squashfs/jffs2 at %X\n",offset);
325                dir_parts[2].offset = offset;
326                //detect now compex board
327                //printk(KERN_EMERG "id = %s\n",(char*)(info->map.virt+0x23d6));
328                if (!strncmp((char*)(info->map.virt+0x23d6),"myloram.bin",11))
329                    {
330                    printk(KERN_EMERG "Compex WP188 detected!\n");
331                    dir_parts[0].size=0x40000;
332                    dir_parts[0].offset=0;
333                    dir_parts[7].size=0x1000;
334                    dir_parts[7].offset = mtd->size-0x1000;
335                    dir_parts[6].size=erasesize;
336                    dir_parts[6].offset = mtd->size-erasesize;
337
338                    long highest=dir_parts[6].offset;
339                    #ifdef CONFIG_TONZE
340                    highest&= ~(erasesize-1);
341                    #endif
342                    dir_parts[2].size=(highest - (erasesize*2)) - dir_parts[2].offset;
343                    dir_parts[4].offset=highest - erasesize*2;
344                    dir_parts[4].size=erasesize;
345                    dir_parts[5].offset=highest - erasesize;
346                    dir_parts[5].size=erasesize;
347                    dir_parts[1].offset=0x40000;
348                    dir_parts[1].size=dir_parts[2].offset-dir_parts[1].offset+dir_parts[2].size;
349                    goto def;
350                    }
351               
352               
353               
354                //now scan for linux offset
355#ifdef CONFIG_NOP8670
356                p=(unsigned char*)(info->map.virt+mtd->size-erasesize);
357#elif CONFIG_TONZE
358                p=(unsigned char*)(info->map.virt+mtd->size-0x8000);
359#else
360                p=(unsigned char*)(info->map.virt+mtd->size-erasesize);
361#endif
362                fis = (struct fis_image_desc*)p;
363                printk(KERN_EMERG "scan redboot from %p\n",fis);
364                while(1)
365                {
366                if (fis->name[0]==0xff)
367                    {
368                    goto def;
369                    }
370                if (!strncmp(fis->name,"RedBoot",7) && strncmp(fis->name,"RedBoot config",14))
371                    {
372                    printk(KERN_EMERG "found RedBoot partition at [0x%08lX]\n",fis->flash_base);
373                    dir_parts[0].size=fis->size;
374                    }
375                if (!strncmp(fis->name,"RedBoot config",14))
376                    {
377                    printk(KERN_EMERG "found RedBoot config partition at [0x%08lX]\n",fis->flash_base);
378                    dir_parts[7].size=mtd->erasesize;
379                    dir_parts[7].offset=fis->flash_base&(mtd->size-1);
380#ifdef CONFIG_TONZE
381                    dir_parts[7].offset&= ~(erasesize-1);
382#endif             
383                    if (foundfis)
384                    {
385                    long highest=dir_parts[5].offset;
386                    if (dir_parts[6].offset<highest)
387                        highest=dir_parts[6].offset;
388#ifdef CONFIG_TONZE
389                    highest&= ~(erasesize-1);
390#endif
391                    dir_parts[2].size=(highest - (erasesize*2)) - dir_parts[2].offset;
392                    dir_parts[4].offset=highest - erasesize*2;
393                    dir_parts[4].size=erasesize;
394                    dir_parts[5].offset=highest - erasesize;
395                    dir_parts[5].size=erasesize;
396                    }
397                    foundconfig=1;
398                    }
399                if (!strncmp(fis->name,"linux",5) || !strncmp(fis->name,"vmlinux",7) || !strncmp(fis->name,"kernel",6))
400                    {
401                    printk(KERN_EMERG "found linux partition at [0x%08lX]\n",fis->flash_base);
402                    dir_parts[1].offset=fis->flash_base&(mtd->size-1);
403                    dir_parts[1].size=dir_parts[2].offset-dir_parts[1].offset+dir_parts[2].size;
404                    }
405                if (!strncmp(fis->name,"FIS directory",13))
406                    {
407                    printk(KERN_EMERG "found config partition at [0x%08lX]\n",fis->flash_base);
408                    dir_parts[6].offset=(fis->flash_base&(mtd->size-1));
409                    dir_parts[6].size=mtd->erasesize;
410#ifdef CONFIG_TONZE
411                    dir_parts[6].offset&= ~(erasesize-1);
412#endif             
413                    if (foundconfig)
414                    {
415                    long highest=dir_parts[6].offset;
416                    if (dir_parts[7].offset<highest)
417                        highest=dir_parts[7].offset;
418#ifdef CONFIG_TONZE
419                    highest&= ~(erasesize-1);
420#endif
421                    dir_parts[2].size=(highest - (erasesize*2)) - dir_parts[2].offset;
422                    dir_parts[4].offset=highest - erasesize*2;
423                    dir_parts[4].size=erasesize;
424                    dir_parts[5].offset=highest - erasesize;
425                    dir_parts[5].size=erasesize;
426                    }
427                    foundfis=1;
428                    }
429                p+=sizeof(struct fis_image_desc);
430                fis = (struct fis_image_desc*)p;
431                }
432                break;
433                }
434#ifdef CONFIG_TONZE
435            offset+=0x1000;
436            buf+=0x1000;
437#else
438            offset+=erasesize;
439            buf+=erasesize;
440#endif
441            }
442        def:;
443        info->partitions=dir_parts;
444        if (filesyssize)
445            {
446            dir_parts[2].size = filesyssize;   
447            }
448        dir_parts[3].offset = dir_parts[2].offset+dir_parts[2].size;
449        dir_parts[3].size = dir_parts[4].offset-dir_parts[3].offset;
450
451        dir_parts[8].offset = 0;
452        dir_parts[8].size = mtd->size;
453
454        err = add_mtd_partitions(mtd, dir_parts, 9);
455
456/*#ifndef CONFIG_NOP8670
457        err = parse_mtd_partitions(info->mtd, probes, &info->partitions, dev->resource->start);
458#else
459        info->partitions=ap71_parts;
460        err=AP71_MTDP_NUM;   
461#endif
462        if (err > 0) {
463                err = add_mtd_partitions(info->mtd, info->partitions, err);
464                if(err)
465                        printk(KERN_ERR "Could not parse partitions\n");
466        }
467*/
468        if (err)
469                goto Error;
470
471        return 0;
472
473Error:
474        ixp4xx_flash_remove(dev);
475        return err;
476}
477
478static struct platform_driver ixp4xx_flash_driver = {
479        .probe          = ixp4xx_flash_probe,
480        .remove         = ixp4xx_flash_remove,
481        .driver         = {
482                .name   = "IXP4XX-Flash",
483        },
484};
485
486module_platform_driver(ixp4xx_flash_driver);
487
488MODULE_LICENSE("GPL");
489MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems");
490MODULE_AUTHOR("Deepak Saxena");
Note: See TracBrowser for help on using the repository browser.