public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
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);

  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