From: "Flávio Silveira" <fggs@terra.com.br>
To: <linux-mtd@lists.infradead.org>
Subject: Re: [Help] SST39VF6401B Support
Date: Thu, 8 Dec 2011 19:21:57 -0200 [thread overview]
Message-ID: <40BE7F31D03F42C2BE4F0E68243C6A8C@THOR> (raw)
In-Reply-To: <91E44F522C8645C9B6F1B4063D33779C@THOR>
[-- Attachment #1: Type: text/plain, Size: 10026 bytes --]
Hi,
I've backported every single patch for this chip, I don't know what else I
can do, where to look at.
The error I'm getting is: pflash: cfi_probe failed
Attached is the map file which I found this message error.
Here's some parts of the code, perhaps I need to modify something on this
file...
static struct mtd_info *bcm947xx_mtd;
......................................
struct map_info bcm947xx_map = {
name: "Physically mapped flash",
size: WINDOW_SIZE,
bankwidth: BUSWIDTH,
phys: WINDOW_ADDR,
};
....................
if ((bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map)) == NULL) {
printk(KERN_ERR "pflash: cfi_probe failed\n");
ret = -ENXIO;
goto fail;
}
I would really appreciate any help, I mean really!
Thanks in advance!
----- Original Message -----
From: "Flávio Silveira" <fggs@terra.com.br>
To: "yidong zhang" <zhangyd6@gmail.com>
Cc: <linux-mtd@lists.infradead.org>
Sent: Monday, June 20, 2011 9:55 PM
Subject: Re: [Help] SST39VF6401B Support
Hi,
Thanks for your help, I'll see if I can compile it with more debug and see
what I'm doing wrong.
Biggest problem is this kernel that is old and I can't update, but let's
hope I can make it work!
----- Original Message -----
From: "yidong zhang" <zhangyd6@gmail.com>
To: "Flávio Silveira" <fggs@terra.com.br>
Cc: <linux-mtd@lists.infradead.org>
Sent: Monday, June 20, 2011 12:36 AM
Subject: Re: [Help] SST39VF6401B Support
Hi
Please see the datasheet for the erase command. Some uses 0x50
rather than 0x30, and the erase size are different. I think you may
need porting the code listed bellow to your driver. It has been a
long time since i used this flash, so i don't remember it very well.
Using the log may help you a lot.
static void fixup_sst39vf_rev_b(struct mtd_info *mtd)
286 {
287 struct map_info *map = mtd->priv;
288 struct cfi_private *cfi = map->fldrv_priv;
289
290 fixup_old_sst_eraseregion(mtd);
291
292 cfi->addr_unlock1 = 0x555;
293 cfi->addr_unlock2 = 0x2AA;
294
295 cfi->sector_erase_cmd = CMD(0x50);
296 }
297
298 static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd)
299 {
300 struct map_info *map = mtd->priv;
301 struct cfi_private *cfi = map->fldrv_priv;
302
303 fixup_sst39vf_rev_b(mtd);
304
305 /*
306 * CFI reports 1024 sectors (0x03ff+1) of 64KBytes
(0x0100*256) where
307 * it should report a size of 8KBytes (0x0020*256).
308 */
309 cfi->cfiq->EraseRegionInfo[0] = 0x002003ff;
310 pr_warning("%s: Bad 38VF640x CFI data; adjusting sector
size from 64 to 8KiB\n", mtd->name);
311 }
312
2011/6/20 Flávio Silveira <fggs@terra.com.br>:
> Hi,
>
> I'm attaching some other files to see if it helps finding what's wrong.
>
> Thanks in advance!
>
> ----- Original Message ----- From: "Flávio Silveira" <fggs@terra.com.br>
> To: "Fabio Giovagnini" <fabio.giovagnini@aurion-tech.com>;
> <linux-mtd@lists.infradead.org>
> Cc: "yidong zhang" <zhangyd6@gmail.com>; <David.Woodhouse@intel.com>;
> "Wolfram Sang" <w.sang@pengutronix.de>; <yegorslists@googlemail.com>;
> "Guillaume LECERF" <glecerf@gmail.com>; <taliaferro62@gmail.com>
> Sent: Wednesday, June 15, 2011 9:55 PM
> Subject: Re: [Help] SST39VF6401B Support
>
>
> Hi guys,
>
> I've tested this patch on kernel 2.6.23 (actually it's called 2.6.24.111)
> and didn't work.
>
> Below are my diffs and I can post original files as well, please help me
> make it work!
>
> Thanks in advance!
>
> cfi_util.c
>
> 29a30,107
>>
>> int __xipram cfi_qry_present(struct map_info *map, __u32 base,
>> struct cfi_private *cfi)
>> {
>> int osf = cfi->interleave * cfi->device_type; /* scale factor */
>> map_word val[3];
>> map_word qry[3];
>>
>> qry[0] = cfi_build_cmd('Q', map, cfi);
>> qry[1] = cfi_build_cmd('R', map, cfi);
>> qry[2] = cfi_build_cmd('Y', map, cfi);
>>
>> val[0] = map_read(map, base + osf*0x10);
>> val[1] = map_read(map, base + osf*0x11);
>> val[2] = map_read(map, base + osf*0x12);
>>
>> if (!map_word_equal(map, qry[0], val[0]))
>> return 0;
>>
>> if (!map_word_equal(map, qry[1], val[1]))
>> return 0;
>>
>> if (!map_word_equal(map, qry[2], val[2]))
>> return 0;
>>
>> return 1; /* "QRY" found */
>> }
>> EXPORT_SYMBOL_GPL(cfi_qry_present);
>>
>> int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
>> struct cfi_private *cfi)
>> {
>> cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
>> if (cfi_qry_present(map, base, cfi))
>> return 1;
>> /* QRY not found probably we deal with some odd CFI chips */
>> /* Some revisions of some old Intel chips? */
>> cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
>> if (cfi_qry_present(map, base, cfi))
>> return 1;
>> /* ST M29DW chips */
>> cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
>> if (cfi_qry_present(map, base, cfi))
>> return 1;
>> /* some old SST chips, e.g. 39VF160x/39VF320x */
>> cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
>> if (cfi_qry_present(map, base, cfi))
>> return 1;
>> /* SST 39VF640xB */
>> cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
>> if (cfi_qry_present(map, base, cfi))
>> return 1;
>> /* QRY not found */
>> return 0;
>> }
>> EXPORT_SYMBOL_GPL(cfi_qry_mode_on);
>>
>> void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map,
>> struct cfi_private *cfi)
>> {
>> cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
>> cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
>> /* M29W128G flashes require an additional reset command
>> when exit qry mode */
>> if ((cfi->mfr == CFI_MFR_ST) && (cfi->id == 0x227E || cfi->id == 0x7E))
>> cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
>> }
>> EXPORT_SYMBOL_GPL(cfi_qry_mode_off);
>>
>
> cfi_cmdset_0002.c
>
> 219a220,253
>>
>> static void fixup_old_sst_eraseregion(struct mtd_info *mtd)
>> {
>> struct map_info *map = mtd->priv;
>> struct cfi_private *cfi = map->fldrv_priv;
>>
>> /*
>> * These flashes report two seperate eraseblock regions based on the
>> * sector_erase-size and block_erase-size, although they both operate on
>> the
>> * same memory. This is not allowed according to CFI, so we just pick
>> the
>> * sector_erase-size.
>> */
>> cfi->cfiq->NumEraseRegions = 1;
>> }
>>
>> static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param)
>> {
>> struct map_info *map = mtd->priv;
>> struct cfi_private *cfi = map->fldrv_priv;
>>
>> fixup_old_sst_eraseregion(mtd);
>>
>> cfi->addr_unlock1 = 0x555;
>> cfi->addr_unlock2 = 0x2AA;
>> }
>>
>> /* Used to fix CFI-Tables of chips without Extended Query Tables */
>> static struct cfi_fixup cfi_nopri_fixup_table[] = {
>> { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, // SST39VF3202B
>> { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, // SST39VF3201B
>> { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, // SST39VF6402B
>> { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, // SST39VF6401B
>> { 0, 0, NULL, NULL }
>> };
>>
>
>
> ----- Original Message ----- From: "Fabio Giovagnini"
> <fabio.giovagnini@aurion-tech.com>
> To: <linux-mtd@lists.infradead.org>
> Cc: "yidong zhang" <zhangyd6@gmail.com>; <David.Woodhouse@intel.com>;
> "Wolfram Sang" <w.sang@pengutronix.de>; <yegorslists@googlemail.com>;
> "Guillaume LECERF" <glecerf@gmail.com>; <taliaferro62@gmail.com>
> Sent: Friday, October 22, 2010 2:50 PM
> Subject: Re: [Help] SST39VF6401B Support
>
>
> Hi Guys,
> As Gullelm remeber for sure, I used the jedec probe for such a flash in a
> very
> old 2.6 kernel.
>
> Now I'm migrating to the newets one kernel.
> Do you tell me how the kernel will be updated with the last mtd stuff
> developed; or in place of it how to patch a standard kernel?
>
> Thanks a lot and sorry for my question if it is improper
>
>
> In data venerdì 22 ottobre 2010 17:42:39, yidong zhang ha scritto:
> : > On Fri, Oct 22, 2010 at 11:36 PM, Guillaume LECERF <glecerf@gmail.com>
> wrote:
>>
>> > 2010/10/22 yidong zhang <zhangyd6@gmail.com>:
>> >>> Could you try setting cif->cfiq->EraseRegionInfo[0] to 0x02003FF in
>> >>> fixup_sst39vf_rev_b() ?
>> >>
>> >> Hi
>> >> how about this attached patch.
>> >
>> > If it works for you, I'll send a patch series for SST 39VF640xB and
>> > 38VF640x, because both chips needs 0x50 as erase command.
>>
>> Sorry, i cannot test it right now. I will sent the result as soon as i
>> can.
>>
>> > --
>> > Guillaume LECERF
>> > GeeXboX developer - www.geexbox.org
>>
>> ______________________________________________________
>> Linux MTD discussion mailing list
>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
> --
> Ing. Fabio Giovagnini
>
> Aurion s.r.l.
> P.I e C.F.
> 00885711200
> skype: aurion.giovagnini
> Tel. +39.051.594.78.24
> Cell. +39.335.83.50.919
> www.aurion-tech.com
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
[-- Attachment #2: bcm947xx-flash.c --]
[-- Type: application/octet-stream, Size: 19567 bytes --]
/*
* Flash mapping for BCM947XX boards
*
* Copyright (C) 2008, Broadcom Corporation
* All Rights Reserved.
*
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
*
* $Id: bcm947xx-flash.c,v 1.5 2008/03/25 01:27:49 Exp $
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
#include <linux/squashfs_fs.h>
#include <linux/jffs2.h>
#include <linux/crc32.h>
#include <linux/vmalloc.h>
#include <typedefs.h>
#include <bcmnvram.h>
#include <bcmutils.h>
#include <hndsoc.h>
#include <sbchipc.h>
#include <siutils.h>
#include <trxhdr.h>
/* Global SB handle */
extern void *bcm947xx_sih;
extern spinlock_t bcm947xx_sih_lock;
/* Convenience */
#define sih bcm947xx_sih
#define sih_lock bcm947xx_sih_lock
#define WINDOW_ADDR 0x1fc00000
#define WINDOW_SIZE 0x400000
#define BUSWIDTH 2
/* e.g., flash=2M or flash=4M */
static int flash = 0;
module_param(flash, int, 0);
static int __init
bcm947xx_setup(char *str)
{
flash = memparse(str, &str);
return 1;
}
__setup("flash=", bcm947xx_setup);
static struct mtd_info *bcm947xx_mtd;
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define init_bcm947xx_map init_module
#define cleanup_bcm947xx_map cleanup_module
#endif
#define ROUTER_NETGEAR_WGR614L 1
#define ROUTER_NETGEAR_WNR834B 2
#define ROUTER_NETGEAR_WNDR3300 3
#define ROUTER_NETGEAR_WNR3500L 4
#define ROUTER_NETGEAR_WNR2000V2 5
#define ROUTER_NETGEAR_WNDR3400 6
#define ROUTER_NETGEAR_WNDR4000 7
#define ROUTER_BELKIN_F5D8235V3 8
#define ROUTER_BELKIN_F7D3301_3302_4302 9
/* Belkin series */
#define TRX_MAGIC_F7D3301 0x20100322 /* Belkin Share Max; router's birthday ? */
#define TRX_MAGIC_F7D3302 0x20090928 /* Belkin Share; router's birthday ? */
#define TRX_MAGIC_F7D4302 0x20091006 /* Belkin Play; router's birthday ? */
#define TRX_MAGIC_F5D8235V3 0x00017116 /* Belkin F5D8235-4v3 */
#define TRX_MAGIC_QA 0x12345678 /* cfe: It's QA firmware */
/* Netgear wgr614 */
#define WGR614_CHECKSUM_BLOCK_START 0x003A0000
#define WGR614_CHECKSUM_OFF 0x003AFFF8
#define WGR614_FAKE_LEN 0x00000004 //we fake checksum only over 4 bytes (HDR0)
#define WGR614_FAKE_CHK 0x02C0010E
static int get_router (void)
{
uint boardnum = bcm_strtoul( nvram_safe_get( "boardnum" ), NULL, 0 );
if ( (boardnum == 8 || boardnum == 01)
&& nvram_match ("boardtype", "0x0472")
&& nvram_match ("cardbus", "1") ) {
return ROUTER_NETGEAR_WNR834B; //Netgear WNR834B, Netgear WNR834Bv2
}
if ( boardnum == 01
&& nvram_match ("boardtype", "0x0472")
&& nvram_match ("boardrev", "0x23") ) {
return ROUTER_NETGEAR_WNDR3300; //Netgear WNDR-3300
}
if ( (boardnum == 83258 || boardnum == 01) //or 001 or 0x01
&& (nvram_match ("boardtype", "0x048e") || nvram_match ("boardtype", "0x48E"))
&& (nvram_match ("boardrev", "0x11") || nvram_match ("boardrev", "0x10"))
&& (nvram_match ("boardflags", "0x750") || nvram_match ("boardflags", "0x0750"))
&& nvram_match ("sdram_init", "0x000A") ) {
return ROUTER_NETGEAR_WGR614L; //Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5
}
if ( (boardnum == 1 || boardnum == 3500)
&& nvram_match ("boardtype", "0x04CF")
&& (nvram_match ("boardrev", "0x1213") || nvram_match ("boardrev", "02")) ) {
return ROUTER_NETGEAR_WNR3500L; //Netgear WNR3500v2/U/L
}
if ( boardnum == 1
&& nvram_match ("boardtype", "0xE4CD")
&& nvram_match ("boardrev", "0x1700") ) {
return ROUTER_NETGEAR_WNR2000V2; //Netgear WNR2000v2
}
if ( boardnum == 01
&& nvram_match("boardtype", "0xb4cf")
&& nvram_match("boardrev", "0x1100")) {
return ROUTER_NETGEAR_WNDR3400; //Netgear WNDR3400
}
if ( boardnum == 01
&& nvram_match("boardtype", "0xF52C")
&& nvram_match("boardrev", "0x1101")) {
return ROUTER_NETGEAR_WNDR4000; //Netgear WNDR4000
}
if (nvram_match("boardtype", "0xa4cf")
&& nvram_match("boardrev", "0x1100")) {
return ROUTER_BELKIN_F5D8235V3; //F5D8235v3
}
if (nvram_match("boardtype", "0xa4cf")
&& nvram_match("boardrev", "0x1102")) {
return ROUTER_BELKIN_F7D3301_3302_4302; //Belkin F7D3301v1 /F7D3302v1 / F7D4302v1
}
return 0;
}
static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
if (len==1) {
memcpy_fromio(to, map->virt + from, len);
} else {
int i;
u16 *dest = (u16 *) to;
u16 *src = (u16 *) (map->virt + from);
for (i = 0; i < (len / 2); i++) {
dest[i] = src[i];
}
if (len & 1)
*((u8 *)dest+len-1) = src[i] & 0xff;
}
}
struct map_info bcm947xx_map = {
name: "Physically mapped flash",
size: WINDOW_SIZE,
bankwidth: BUSWIDTH,
phys: WINDOW_ADDR,
};
#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition bcm947xx_parts[] = {
{ name: "cfe", offset: 0, size: 0, },
{ name: "linux", offset: 0, size: 0, },
{ name: "rootfs", offset: 0, size: 0, },
{ name: "nvram", offset: 0, size: 0, },
{ name: "ddwrt", offset: 0, size: 0, },
{ name: NULL, },
};
static int __init
find_cfe_size(struct mtd_info *mtd, size_t size)
{
struct trx_header *trx;
unsigned char buf[512];
int off;
size_t len;
int blocksize;
trx = (struct trx_header *) buf;
blocksize = mtd->erasesize;
if (blocksize < 0x10000)
blocksize = 0x10000;
// printk(KERN_EMERG "blocksize is %d\n",blocksize);
for (off = 0; off < size; off += 64*1024) {
memset(buf, 0xe5, sizeof(buf));
// printk(KERN_EMERG "scan at 0x%08x\n",off);
/*
* Read into buffer
*/
if (mtd->read(mtd, off, sizeof(buf), &len, buf) ||
len != sizeof(buf))
continue;
switch (le32_to_cpu(trx->magic)) {
/* found a TRX header */
case TRX_MAGIC:
goto found;
break;
/* found a Belkin TRX header */
case TRX_MAGIC_F7D3301:
case TRX_MAGIC_F7D3302:
case TRX_MAGIC_F7D4302:
case TRX_MAGIC_F5D8235V3:
case TRX_MAGIC_QA:
if (get_router() == ROUTER_BELKIN_F7D3301_3302_4302
|| get_router() == ROUTER_BELKIN_F5D8235V3) {
printk(KERN_EMERG "Found Belkin TRX magic\n");
goto found;
}
break;
}
}
printk(KERN_EMERG
"%s: Couldn't find bootloader size\n",
mtd->name);
return -1;
found:
printk(KERN_EMERG "bootloader size: %d\n", off);
printk(KERN_EMERG "nvram size: %d\n", NVRAM_SPACE);
return off;
}
/*
* Copied from mtdblock.c
*
* Cache stuff...
*
* Since typical flash erasable sectors are much larger than what Linux's
* buffer cache can handle, we must implement read-modify-write on flash
* sectors for each block write requests. To avoid over-erasing flash sectors
* and to speed things up, we locally cache a whole flash sector while it is
* being written to until a different sector is required.
*/
static void erase_callback(struct erase_info *done)
{
wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
wake_up(wait_q);
}
static int erase_write (struct mtd_info *mtd, unsigned long pos,
int len, const char *buf)
{
struct erase_info erase;
DECLARE_WAITQUEUE(wait, current);
wait_queue_head_t wait_q;
size_t retlen;
int ret;
/*
* First, let's erase the flash block.
*/
init_waitqueue_head(&wait_q);
erase.mtd = mtd;
erase.callback = erase_callback;
erase.addr = pos;
erase.len = len;
erase.priv = (u_long)&wait_q;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
ret = mtd->erase(mtd, &erase);
if (ret) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&wait_q, &wait);
printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
"on \"%s\" failed\n",
pos, len, mtd->name);
return ret;
}
schedule(); /* Wait for erase to finish. */
remove_wait_queue(&wait_q, &wait);
/*
* Next, writhe data to flash.
*/
ret = mtd->write (mtd, pos, len, &retlen, buf);
if (ret)
return ret;
if (retlen != len)
return -EIO;
return 0;
}
static int __init
find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
{
struct trx_header trx, *trx2;
unsigned char buf[512], *block;
int off, blocksize;
u32 i, crc = ~0;
size_t len;
struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
blocksize = mtd->erasesize;
if (blocksize < 0x10000)
blocksize = 0x10000;
for (off = 0; off < size; off += 64*1024) {
memset(&trx, 0xe5, sizeof(trx));
// printk(KERN_EMERG "scan root at 0x%08x\n",off);
/*
* Read into buffer
*/
if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
len != sizeof(trx))
continue;
switch (le32_to_cpu(trx.magic)) {
/* found a TRX header */
case TRX_MAGIC:
goto found;
break;
/* found a Belkin TRX header */
case TRX_MAGIC_F7D3301:
case TRX_MAGIC_F7D3302:
case TRX_MAGIC_F7D4302:
case TRX_MAGIC_F5D8235V3:
case TRX_MAGIC_QA:
if (get_router() == ROUTER_BELKIN_F7D3301_3302_4302
|| get_router() == ROUTER_BELKIN_F5D8235V3) {
printk(KERN_EMERG "Found Belkin TRX magic\n");
goto found;
}
break;
}
}
printk(KERN_EMERG
"%s: Couldn't find root filesystem\n",
mtd->name);
return -1;
found:
part->offset = le32_to_cpu(trx.offsets[2]) ? :
le32_to_cpu(trx.offsets[1]);
part->size = le32_to_cpu(trx.len);
part->size -= part->offset;
part->offset += off;
if (part->size == 0)
return 0;
if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
return 0;
if (*((__u32 *) buf) == SQUASHFS_MAGIC) {
printk(KERN_EMERG "%s: Filesystem type: squashfs, size=0x%x\n", mtd->name, (u32) sb->bytes_used);
/* Update the squashfs partition size based on the superblock info */
part->size = sb->bytes_used;
//part->size = part->size + 1024; /* uncomment for belkin v2000 ! */
len = part->offset + part->size;
len += (mtd->erasesize - 1);
len &= ~(mtd->erasesize - 1);
part->size = len - part->offset;
printk(KERN_EMERG "partition size = %d\n",part->size);
} else if (*((__u16 *) buf) == JFFS2_MAGIC_BITMASK) {
printk(KERN_EMERG "%s: Filesystem type: jffs2\n", mtd->name);
/* Move the squashfs outside of the trx */
part->size = 0;
} else {
printk(KERN_EMERG "%s: Filesystem type: unknown\n", mtd->name);
return 0;
}
if (trx.len != part->offset + part->size - off) {
/* Update the trx offsets and length */
trx.len = part->offset + part->size - off;
// printk(KERN_EMERG "update crc32\n");
/* Update the trx crc32 */
for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
// printk(KERN_EMERG "read from %d\n",off + i);
if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
return 0;
crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
}
trx.crc32 = crc;
// printk(KERN_EMERG "malloc\n",off + i);
/* read first eraseblock from the trx */
trx2 = block = vmalloc(mtd->erasesize);
if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) {
printk(KERN_EMERG "Error accessing the first trx eraseblock\n");
vfree(block);
return 0;
}
printk(KERN_EMERG "Updating TRX offsets and length:\n");
printk(KERN_EMERG "old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
printk(KERN_EMERG "new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32);
/* Write updated trx header to the flash */
memcpy(block, &trx, sizeof(trx));
if (mtd->unlock)
mtd->unlock(mtd, off, mtd->erasesize);
erase_write(mtd, off, mtd->erasesize, block);
if (mtd->sync)
mtd->sync(mtd);
vfree(block);
printk(KERN_EMERG "Done\n");
/* Write fake Netgear checksum to the flash */
if (get_router() == ROUTER_NETGEAR_WGR614L) {
/*
* Read into buffer
*/
block = vmalloc(mtd->erasesize);
if (mtd->read(mtd, WGR614_CHECKSUM_BLOCK_START, mtd->erasesize, &len, block) ||
len != mtd->erasesize) {
printk(KERN_EMERG "Error accessing the WGR614 checksum eraseblock\n");
vfree(block);
}
else {
char imageInfo[8];
u32 fake_len = le32_to_cpu(WGR614_FAKE_LEN);
u32 fake_chk = le32_to_cpu(WGR614_FAKE_CHK);
memcpy(&imageInfo[0], (char *)&fake_len, 4);
memcpy(&imageInfo[4], (char *)&fake_chk, 4);
char *tmp;
tmp = block + ((WGR614_CHECKSUM_OFF - WGR614_CHECKSUM_BLOCK_START) % mtd->erasesize);
memcpy( tmp, imageInfo, sizeof( imageInfo ) );
if (mtd->unlock)
mtd->unlock(mtd, WGR614_CHECKSUM_BLOCK_START, mtd->erasesize);
erase_write(mtd, WGR614_CHECKSUM_BLOCK_START, mtd->erasesize, block);
if (mtd->sync)
mtd->sync(mtd);
vfree(block);
printk(KERN_EMERG "Done fixing WGR614 checksum\n");
}
}
}
return part->size;
}
struct mtd_partition * __init
init_mtd_partitions(struct mtd_info *mtd, size_t size)
{
int cfe_size;
int board_data_size = 0; // e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this part from our mapping
int jffs_exclude_size = 0; // to prevent overwriting len/checksum on e.g. Netgear WGR614v8/L/WW
switch (get_router()) {
case ROUTER_NETGEAR_WGR614L:
case ROUTER_NETGEAR_WNR834B:
case ROUTER_NETGEAR_WNDR3300:
case ROUTER_NETGEAR_WNR3500L:
board_data_size = 4 * 0x10000; //Netgear: checksum is @ 0x003AFFF8 for 4M flash
jffs_exclude_size = 0x10000; //or checksum is @ 0x007AFFF8 for 8M flash
break;
case ROUTER_NETGEAR_WNR2000V2:
board_data_size = 0x10000;
break;
case ROUTER_NETGEAR_WNDR3400: //Netgear: checksum is @ 0x0070FFF8 @ 8M flash, but can be overwritten
case ROUTER_NETGEAR_WNDR4000: //Netgear: checksum is @ 0x0073FFF8 @ 8M flash, but can be overwritten
board_data_size = 0x10000;
break;
}
if ((cfe_size = find_cfe_size(mtd,size)) < 0)
return NULL;
/* boot loader */
bcm947xx_parts[0].offset = 0;
bcm947xx_parts[0].size = cfe_size;
/* nvram */
if (cfe_size != 384 * 1024) {
bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
} else {
/* nvram (old 128kb config partition on netgear wgt634u) */
bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
}
/* linux (kernel and rootfs) */
if (cfe_size != 384 * 1024) {
bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
bcm947xx_parts[1].size = (bcm947xx_parts[3].offset - bcm947xx_parts[1].offset) - board_data_size;
} else {
/* do not count the elf loader, which is on one block */
bcm947xx_parts[1].offset = bcm947xx_parts[0].size +
bcm947xx_parts[3].size + mtd->erasesize;
bcm947xx_parts[1].size = (((size - bcm947xx_parts[0].size) - (2*bcm947xx_parts[3].size)) - mtd->erasesize) - board_data_size;
}
/* find and size rootfs */
if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
/* entirely jffs2 */
bcm947xx_parts[4].name = NULL;
bcm947xx_parts[2].size = (size - bcm947xx_parts[2].offset) - bcm947xx_parts[3].size;
} else {
/* legacy setup */
/* calculate leftover flash, and assign it to the jffs2 partition */
if (cfe_size != 384 * 1024) {
bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
bcm947xx_parts[2].size;
if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
bcm947xx_parts[4].offset += mtd->erasesize -
(bcm947xx_parts[4].offset % mtd->erasesize);
}
bcm947xx_parts[4].size = ((bcm947xx_parts[3].offset - bcm947xx_parts[4].offset) - board_data_size) - jffs_exclude_size;
} else {
bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
bcm947xx_parts[2].size;
if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
bcm947xx_parts[4].offset += mtd->erasesize -
(bcm947xx_parts[4].offset % mtd->erasesize);
}
bcm947xx_parts[4].size = (((size - bcm947xx_parts[3].size) - bcm947xx_parts[4].offset) - board_data_size) - jffs_exclude_size;
}
/* do not make zero size jffs2 partition */
if (bcm947xx_parts[4].size < mtd->erasesize) {
bcm947xx_parts[4].name = NULL;
}
}
return bcm947xx_parts;
}
#endif
static int __init
init_bcm947xx_map(void)
{
ulong flags;
uint coreidx;
chipcregs_t *cc;
uint32 fltype;
uint window_addr = 0, window_size = 0;
size_t size;
int ret = 0;
#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *parts;
int i;
#endif
spin_lock_irqsave(&sih_lock, flags);
coreidx = si_coreidx(sih);
/* Check strapping option if chipcommon exists */
if ((cc = si_setcore(sih, CC_CORE_ID, 0))) {
fltype = readl(&cc->capabilities) & CC_CAP_FLASH_MASK;
if (fltype == PFLASH) {
bcm947xx_map.map_priv_2 = 1;
window_addr = 0x1c000000;
bcm947xx_map.size = window_size = 32 * 1024 * 1024;
if ((readl(&cc->flash_config) & CC_CFG_DS) == 0)
bcm947xx_map.bankwidth = 1;
}
} else {
fltype = PFLASH;
bcm947xx_map.map_priv_2 = 0;
window_addr = WINDOW_ADDR;
bcm947xx_map.size = window_size = WINDOW_SIZE;
}
si_setcoreidx(sih, coreidx);
spin_unlock_irqrestore(&sih_lock, flags);
if (fltype != PFLASH) {
printk(KERN_ERR "pflash: found no supported devices\n");
ret = -ENODEV;
goto fail;
}
bcm947xx_map.virt = ioremap(window_addr, window_size);
if (bcm947xx_map.virt == NULL) {
printk(KERN_ERR "pflash: ioremap failed\n");
ret = -EIO;
goto fail;
}
if ((bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map)) == NULL) {
printk(KERN_ERR "pflash: cfi_probe failed\n");
ret = -ENXIO;
goto fail;
}
bcm947xx_mtd->owner = THIS_MODULE;
/* override copy_from routine */
// bcm947xx_map.copy_from = bcm47xx_map_copy_from;
/* Allow size override for testing */
size = flash ? : bcm947xx_mtd->size;
printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr);
#ifdef CONFIG_MTD_PARTITIONS
parts = init_mtd_partitions(bcm947xx_mtd, size);
for (i = 0; parts[i].name; i++);
ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
if (ret) {
printk(KERN_ERR "pflash: add_mtd_partitions failed\n");
goto fail;
}
#endif
return 0;
fail:
if (bcm947xx_mtd)
map_destroy(bcm947xx_mtd);
if (bcm947xx_map.map_priv_1)
iounmap((void *) bcm947xx_map.map_priv_1);
bcm947xx_map.map_priv_1 = 0;
return ret;
}
static void __exit
cleanup_bcm947xx_map(void)
{
#ifdef CONFIG_MTD_PARTITIONS
del_mtd_partitions(bcm947xx_mtd);
#endif
map_destroy(bcm947xx_mtd);
iounmap((void *) bcm947xx_map.map_priv_1);
bcm947xx_map.map_priv_1 = 0;
}
module_init(init_bcm947xx_map);
module_exit(cleanup_bcm947xx_map);
next prev parent reply other threads:[~2011-12-08 21:22 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-16 7:08 Re :Re: [Help] SST39VF6401B Support yidong zhang
2010-10-16 10:07 ` Wolfram Sang
2010-10-16 12:25 ` yidong zhang
2010-10-16 13:17 ` Wolfram Sang
2010-10-16 14:20 ` yidong zhang
2010-10-18 4:00 ` yidong zhang
2010-10-18 11:41 ` Wolfram Sang
2010-10-18 13:05 ` yidong zhang
2010-10-18 13:41 ` Guillaume LECERF
2010-10-21 10:33 ` Guillaume LECERF
[not found] ` <AANLkTinLTW25faUTBfKBVcpFXFrtv1UhWWDN9Dgm1jOH@mail.gmail.com>
[not found] ` <AANLkTiknoWR_v-TfV5M5ZwsV3Lsk=EDDD185kXp4B96V@mail.gmail.com>
[not found] ` <AANLkTin-4fGYzD8a9rDp9M7YEk1y7JbXmZVLjA=3iU3Q@mail.gmail.com>
2010-10-21 15:24 ` Guillaume LECERF
2010-10-22 0:17 ` yidong zhang
2010-10-22 7:52 ` Guillaume LECERF
2010-10-22 8:46 ` yidong zhang
2010-10-22 10:41 ` Guillaume LECERF
2010-10-22 15:07 ` yidong zhang
2010-10-22 15:36 ` Guillaume LECERF
2010-10-22 15:42 ` yidong zhang
2010-10-22 17:50 ` Fabio Giovagnini
2011-06-16 0:55 ` Flávio Silveira
2011-06-20 3:12 ` Flávio Silveira
2011-06-20 3:36 ` yidong zhang
2011-06-20 23:55 ` Flávio Silveira
2011-12-08 21:21 ` Flávio Silveira [this message]
2011-12-09 23:15 ` Flávio Silveira
2011-12-10 0:54 ` Guillaume LECERF
2011-12-10 1:56 ` Flávio Silveira
-- strict thread matches above, loose matches on Subject: below --
2010-09-23 3:43 Flávio Silveira
2010-09-23 7:28 ` Yegor Yefremov
2010-09-23 11:01 ` Flávio Silveira
2010-09-23 12:05 ` Wolfram Sang
2010-09-23 12:15 ` Flávio Silveira
2010-09-23 12:37 ` Wolfram Sang
2010-09-23 12:23 ` Guillaume LECERF
2010-09-23 12:34 ` Flávio Silveira
2010-09-23 15:21 ` Fabio Giovagnini
2010-09-23 12:18 ` Yegor Yefremov
2010-09-23 12:30 ` Flávio Silveira
2010-09-23 12:33 ` Yegor Yefremov
2010-09-23 12:40 ` Flávio Silveira
2010-09-23 13:45 ` Yegor Yefremov
2010-09-23 13:56 ` Flávio Silveira
2010-09-23 14:56 ` Flávio Silveira
2010-09-23 15:14 ` Yegor Yefremov
2010-09-23 15:33 ` Guillaume LECERF
2010-09-24 10:56 ` Flávio Silveira
2010-10-05 9:38 ` Guillaume LECERF
2010-10-05 10:07 ` Flávio Silveira
2010-10-05 10:12 ` Guillaume LECERF
2010-10-12 10:48 ` Guillaume LECERF
2010-10-17 20:22 ` Flávio Silveira
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=40BE7F31D03F42C2BE4F0E68243C6A8C@THOR \
--to=fggs@terra.com.br \
--cc=linux-mtd@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox