Hi Tatha, sorry for answering so late I am currently very busy.
If I set CONFIG_BCMA_SFLASH=y and CONFIG_BCMA_NFLASH=y in the kernel config, which I want to do for the default image in OpenWrt the image will not work on by device with serial flash any more because bus->drv_cc.flash_type will contain BCMA_NFLASH and not BCMA_SFLASH. The patch in the mail I linked does not work as is with the current version of your patch but you should be able to modify it. ;-) The code in the linked mail should be able to detect nand flash at runtime. Without this modification it does not work on my device, which uses serial flash, but I do not know if it works on your device with nand flash. Hauke On 03/01/2012 06:06 AM, Tathagata Das wrote: > Hi Hauke, > Changes mentioned in > https://lists.openwrt.org/pipermail/openwrt-devel/2012-January/013481.html > will not work now as there is no such bcma_nflash_init() function anymore. > Now flash detection is done only once and that is in NAND flash section using > generic function nand_scan_ident. > > Regards, > Tatha > > -----Original Message----- > From: Hauke Mehrtens [mailto:[email protected]] > Sent: 01 March 2012 04:39 > To: Tathagata Das > Cc: 'OpenWrt Development List'; 'Florian Fainelli' > Subject: Re: [PATCH] Updated kernel patch in trunk to support brcm47xx BCMA > NAND flash > > On 02/27/2012 09:44 AM, Tathagata Das wrote: >> Hi Hauke, >> I have modified my patch according to your comments except in two cases. >> >> "We want to build one image supporting devices with serial and with nand >> flash. This makes it just possible to support one flash type at a time." >> Right now flash type can be either NAND or SERIAL. If we want to have two >> flash simultaneously then I think we need to have another parameter similar >> to "bcma_flash_type flash_type" What is your opinion ? > I want to build one image which can be flashed onto a device which uses > NAND flash or a device using serial flash. I have never seen any device > with two (different) flash chips, so this does not have to be supported. > In the last patch it is only possible to build an image which will use > NAND flash or an image which will support serial flash, they are > exclusive or. I want to have it like it is for parallel and serial flash > where you are able to build an image with support for both and it auto > detects it when booting and loads the correct driver. > > What about using this code, it work correctly on my device with serial > flash, but I do not know if it correctly detects nand flash? > https://lists.openwrt.org/pipermail/openwrt-devel/2012-January/013481.html > >> "cpu_relax(); >> Why is this needed?" >> Above change was done according to Florian's comment. > > using cpu_relax() is correct there, I just read some documentations > about it. > >> >> Florian, >> Can you clarify it ? >> >> Once these above cases resolve I will provide you the updated patch. >> >> Regards, >> Tatha >> >> -----Original Message----- >> From: Hauke Mehrtens [mailto:[email protected]] >> Sent: 25 February 2012 19:08 >> To: Tathagata Das >> Cc: 'OpenWrt Development List'; 'Florian Fainelli' >> Subject: Re: [PATCH] Updated kernel patch in trunk to support brcm47xx BCMA >> NAND flash >> >> Hi Tathagata Das, >> >> I had a look at bthe patch and added some comments, if bcma_nflash_init >> is not needed any more where is struct bcma_nflash initilized? >> >> Hauke >> >> On 02/23/2012 02:27 PM, Tathagata Das wrote: >>> Hi, >>> Attached is the updated kernel patch to support brcm47xx BCMA NAND flash. >>> I have used latest trunk source code to create this patch. >>> Thanks to Florian and Hauke for their comments. >>> >>> Regards, >>> Tathagata <[email protected]> >>> >>> diff -Naur a/arch/mips/bcm47xx/bus.c b/arch/mips/bcm47xx/bus.c >>> --- a/arch/mips/bcm47xx/bus.c 2012-02-17 16:34:21.000000000 +0530 >>> +++ b/arch/mips/bcm47xx/bus.c 2012-02-23 18:22:17.000000000 +0530 >>> @@ -2,6 +2,7 @@ >>> * BCM947xx nvram variable access >>> * >>> * Copyright (C) 2011 Hauke Mehrtens <[email protected]> >>> + * Copyright (C) 2011-2012 Tathagata Das <[email protected]> >>> * >>> * This program is free software; you can redistribute it and/or modify it >>> * under the terms of the GNU General Public License as published by the >>> @@ -92,3 +93,9 @@ >>> sflash->numblocks = scc->sflash.numblocks; >>> sflash->size = scc->sflash.size; >>> } >>> + >>> +void bcm47xx_nflash_struct_bcma_init(struct bcm47xx_nflash *nflash, struct >>> bcma_drv_cc *bcc) >>> +{ >>> + nflash->nflash_type = BCM47XX_BUS_TYPE_BCMA; >>> + nflash->bcc = bcc; >>> +} >>> diff -Naur a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c >>> --- a/arch/mips/bcm47xx/nvram.c 2012-02-17 16:34:22.000000000 +0530 >>> +++ b/arch/mips/bcm47xx/nvram.c 2012-02-23 18:20:57.000000000 +0530 >>> @@ -4,6 +4,7 @@ >>> * Copyright (C) 2005 Broadcom Corporation >>> * Copyright (C) 2006 Felix Fietkau <[email protected]> >>> * Copyright (C) 2010-2011 Hauke Mehrtens <[email protected]> >>> + * Copyright (C) 2011-2012 Tathagata Das <[email protected]> >>> * >>> * This program is free software; you can redistribute it and/or modify it >>> * under the terms of the GNU General Public License as published by the >>> @@ -21,6 +22,7 @@ >>> #include <asm/mach-bcm47xx/nvram.h> >>> #include <asm/mach-bcm47xx/bcm47xx.h> >>> #include <asm/mach-bcm47xx/bus.h> >>> +#include <linux/mtd/bcm47xx_nand.h> >>> >>> char nvram_buf[NVRAM_SPACE]; >>> EXPORT_SYMBOL(nvram_buf); >>> @@ -159,6 +161,53 @@ >>> return 0; >>> } >>> >>> +static int early_nvram_init_nflash(void) >>> +{ >>> + struct nvram_header *header; >>> + u32 off; >>> + int ret; >>> + int len; >>> + u32 flash_size = bcm47xx_nflash.size; >>> + u8 tmpbuf[NFL_SECTOR_SIZE]; >>> + int i; >>> + u32 *src, *dst; >>> + >>> + /* check if the struct is already initilized */ >>> + if (!flash_size) >>> + return -1; >>> + >>> + cfe_env = 0; >>> + >>> + off = FLASH_MIN; >>> + while (off <= flash_size) { >>> + ret = bcma_nflash_read(bcm47xx_nflash.bcc, off, >>> NFL_SECTOR_SIZE, tmpbuf); >>> + if (ret != NFL_SECTOR_SIZE) { >>> + goto done; >>> + } >>> + header = (struct nvram_header *)tmpbuf; >>> + if (header->magic == NVRAM_HEADER) { >>> + goto found; >>> + } >>> + off <<= 1; >>> + } >>> + >>> + ret = -1; >>> + goto done; >>> + >>> +found: >>> + len = header->len; >>> + header = (struct nvram_header *) KSEG1ADDR(NAND_FLASH1 + off); >>> + src = (u32 *) header; >>> + dst = (u32 *) nvram_buf; >>> + for (i = 0; i < sizeof(struct nvram_header); i += 4) >>> + *dst++ = *src++; >>> + for (; i < len && i < NVRAM_SPACE; i += 4) >>> + *dst++ = *src++; >>> + ret = 0; >>> +done: >>> + return ret; >>> +} >>> + >>> static void early_nvram_init(void) >>> { >>> int err = 0; >>> @@ -185,6 +234,10 @@ >>> err = early_nvram_init_sflash(); >>> if (err < 0) >>> printk(KERN_WARNING "can not read from flash: >>> %i\n", err); >>> + } else if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == >>> BCMA_NFLASH) { >>> + err = early_nvram_init_nflash(); >>> + if (err < 0) >>> + printk(KERN_WARNING "can not read from nflash: >>> %i\n", err); >>> } else { >>> printk(KERN_WARNING "unknow flash type\n"); >>> } >> I am not happy with the flash driver usage in arch/bcm47xx/ entirely and >> will change it some time so I am ok with this. >>> diff -Naur a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c >>> --- a/arch/mips/bcm47xx/setup.c 2012-02-17 16:34:22.000000000 +0530 >>> +++ b/arch/mips/bcm47xx/setup.c 2012-02-23 18:21:15.000000000 +0530 >>> @@ -4,6 +4,7 @@ >>> * Copyright (C) 2006 Michael Buesch <[email protected]> >>> * Copyright (C) 2010 Waldemar Brodkorb <[email protected]> >>> * Copyright (C) 2010-2011 Hauke Mehrtens <[email protected]> >>> + * Copyright (C) 2011-2012 Tathagata Das <[email protected]> >>> * >>> * This program is free software; you can redistribute it and/or modify >>> it >>> * under the terms of the GNU General Public License as published by >>> the >>> @@ -47,6 +48,7 @@ >>> EXPORT_SYMBOL(bcm47xx_bus_type); >>> >>> struct bcm47xx_sflash bcm47xx_sflash; >>> +struct bcm47xx_nflash bcm47xx_nflash; >>> >>> static void bcm47xx_machine_restart(char *command) >>> { >>> @@ -359,6 +361,9 @@ >>> >>> if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH) >>> bcm47xx_sflash_struct_bcma_init(&bcm47xx_sflash, >>> &bcm47xx_bus.bcma.bus.drv_cc); >>> + >>> + if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_NFLASH) >>> + bcm47xx_nflash_struct_bcma_init(&bcm47xx_nflash, >>> &bcm47xx_bus.bcma.bus.drv_cc); >>> } >>> #endif >>> >>> @@ -429,6 +434,19 @@ >>> .num_resources = 1, >>> }; >>> >>> +static struct resource bcm47xx_nflash_resource = { >>> + .name = "bcm47xx_nflash", >>> + .start = 0, >>> + .end = 0, >>> + .flags = 0, >>> +}; >>> + >>> +static struct platform_device bcm47xx_nflash_dev = { >>> + .name = "bcm47xx_nflash", >>> + .resource = &bcm47xx_nflash_resource, >>> + .num_resources = 1, >>> +}; >>> + >>> static int __init bcm47xx_register_flash(void) >>> { >>> #ifdef CONFIG_BCM47XX_SSB >>> @@ -463,6 +481,9 @@ >>> } else if (drv_cc->flash_type == BCMA_SFLASH) { >>> bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash; >>> return platform_device_register(&bcm47xx_sflash_dev); >>> + } else if (drv_cc->flash_type == BCMA_NFLASH) { >>> + bcm47xx_nflash_dev.dev.platform_data = &bcm47xx_nflash; >>> + return platform_device_register(&bcm47xx_nflash_dev); >>> } else { >>> printk(KERN_ERR "No flash device found\n"); >>> return -1; >>> diff -Naur a/arch/mips/include/asm/mach-bcm47xx/bus.h >>> b/arch/mips/include/asm/mach-bcm47xx/bus.h >>> --- a/arch/mips/include/asm/mach-bcm47xx/bus.h 2012-02-17 >>> 16:34:21.000000000 +0530 >>> +++ b/arch/mips/include/asm/mach-bcm47xx/bus.h 2012-02-23 >>> 18:25:36.000000000 +0530 >>> @@ -2,6 +2,7 @@ >>> * BCM947xx nvram variable access >>> * >>> * Copyright (C) 2011 Hauke Mehrtens <[email protected]> >>> + * Copyright (C) 2011-2012 Tathagata Das <[email protected]> >>> * >>> * This program is free software; you can redistribute it and/or modify it >>> * under the terms of the GNU General Public License as published by the >>> @@ -13,6 +14,7 @@ >>> #include <linux/bcma/bcma.h> >>> #include <linux/mtd/mtd.h> >>> #include <bcm47xx.h> >>> +#include <linux/mtd/nand.h> >>> >>> struct bcm47xx_sflash { >>> enum bcm47xx_bus_type sflash_type; >>> @@ -38,3 +40,18 @@ >>> void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct >>> ssb_chipcommon *scc); >>> >>> extern struct bcm47xx_sflash bcm47xx_sflash; >>> + >>> +struct bcm47xx_nflash { >>> + enum bcm47xx_bus_type nflash_type; >>> + struct bcma_drv_cc *bcc; >>> + >>> + u32 size; /* Total size in bytes */ >>> + u32 next_opcode; /* Next expected command from upper NAND layer */ >>> + >>> + struct mtd_info mtd; >>> + struct nand_chip nand; >> ^^^ use tabs >>> +}; >>> + >>> +void bcm47xx_nflash_struct_bcma_init(struct bcm47xx_nflash *nflash, struct >>> bcma_drv_cc *bcc); >>> + >>> +extern struct bcm47xx_nflash bcm47xx_nflash; >>> diff -Naur a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h >>> --- a/drivers/bcma/bcma_private.h 2012-02-17 16:34:21.000000000 +0530 >>> +++ b/drivers/bcma/bcma_private.h 2012-02-17 17:32:21.000000000 +0530 >>> @@ -46,6 +46,11 @@ >>> int bcma_sflash_init(struct bcma_drv_cc *cc); >>> #endif /* CONFIG_BCMA_SFLASH */ >>> >>> +#ifdef CONFIG_BCMA_NFLASH >>> +/* driver_chipcommon_nflash.c */ >>> +int bcma_nflash_init(struct bcma_drv_cc *cc); >>> +#endif /* CONFIG_BCMA_NFLASH */ >>> + >>> #ifdef CONFIG_BCMA_HOST_PCI >>> /* host_pci.c */ >>> extern int __init bcma_host_pci_init(void); >>> diff -Naur a/drivers/bcma/driver_chipcommon_nflash.c >>> b/drivers/bcma/driver_chipcommon_nflash.c >>> --- a/drivers/bcma/driver_chipcommon_nflash.c 1970-01-01 >>> 05:30:00.000000000 +0530 >>> +++ b/drivers/bcma/driver_chipcommon_nflash.c 2012-02-22 >>> 16:50:13.000000000 +0530 >>> @@ -0,0 +1,258 @@ >>> +/* >>> + * BCMA nand flash interface >>> + * >>> + * Copyright 2011, Tathagata Das <[email protected]> >>> + * Copyright 2010, Broadcom Corporation >>> + * >>> + * Licensed under the GNU/GPL. See COPYING for details. >>> + */ >>> + >>> +#include <linux/bcma/bcma.h> >>> +#include <linux/bcma/bcma_driver_chipcommon.h> >>> +#include <linux/delay.h> >>> +#include <linux/mtd/bcm47xx_nand.h> >>> +#include <linux/mtd/nand.h> >>> + >>> +#include "bcma_private.h" >>> + >>> +static int bcma_firsttime = 0; >> This is not very nice, is it possible to put this into the struct >> bcma_nflash, or is this needed to handle more than one nandflash chip? >>> + >>> +/* Issue a nand flash command */ >>> +static inline void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode) >>> +{ >>> + bcma_cc_write32(cc, NAND_CMD_START, opcode); >>> + bcma_cc_read32(cc, NAND_CMD_START); >>> +} >>> + >>> +/* Initialize serial flash access */ >>> +int bcma_nflash_init(struct bcma_drv_cc *cc) >> No references to this function, remove it. ?? >>> +{ >>> + u32 id, id2; >>> + char *name = ""; >>> + int i; >>> + u32 ncf, val; >>> + >>> + if (!bcma_firsttime && cc->nflash.size) >>> + return cc->nflash.size; >>> + >>> + memset(&cc->nflash, 0, sizeof(struct bcma_nflash)); >> This is not needed as cc->nflash was alloceted with kzalloc >>> + >>> + /* Read flash id */ >>> + bcma_nflash_cmd(cc, NCMD_ID_RD); >>> + if (bcma_nflash_poll(cc) < 0) >>> + return -ENODEV; >>> + id = bcma_cc_read32(cc, NAND_DEVID); >>> + id2 = bcma_cc_read32(cc, NAND_DEVID_X); >>> + for (i = 0; i < 5; i++) { >>> + if (i < 4) >>> + cc->nflash.id[i] = (id >> (8*i)) & 0xff; >>> + else >>> + cc->nflash.id[i] = id2 & 0xff; >>> + } >>> + cc->nflash.type = cc->nflash.id[0]; >>> + switch (cc->nflash.type) { >>> + case NAND_MFR_AMD: >>> + name = "AMD"; >>> + break; >>> + case NAND_MFR_STMICRO: >>> + name = "Numonyx"; >>> + break; >>> + case NAND_MFR_MICRON: >>> + name = "Micron"; >>> + break; >>> + case NAND_MFR_TOSHIBA: >>> + name = "Toshiba"; >>> + break; >>> + case NAND_MFR_HYNIX: >>> + name = "Hynix"; >>> + break; >>> + case NAND_MFR_SAMSUNG: >>> + name = "Samsung"; >>> + break; >>> + } >>> + ncf = bcma_cc_read32(cc, NAND_CONFIG); >>> + /* Page size (# of bytes) */ >>> + val = (ncf & NCF_PAGE_SIZE_MASK) >> NCF_PAGE_SIZE_SHIFT; >>> + switch (val) { >>> + case 0: >>> + cc->nflash.pagesize = 512; >>> + break; >>> + case 1: >>> + cc->nflash.pagesize = (1 << 10) * 2; >>> + break; >>> + case 2: >>> + cc->nflash.pagesize = (1 << 10) * 4; >>> + break; >>> + case 3: >>> + cc->nflash.pagesize = (1 << 10) * 8; >>> + break; >>> + } >>> + /* Block size (# of bytes) */ >>> + val = (ncf & NCF_BLOCK_SIZE_MASK) >> NCF_BLOCK_SIZE_SHIFT; >>> + switch (val) { >>> + case 0: >>> + cc->nflash.blocksize = (1 << 10) * 16; >>> + break; >>> + case 1: >>> + cc->nflash.blocksize = (1 << 10) * 128; >>> + break; >>> + case 2: >>> + cc->nflash.blocksize = (1 << 10) * 8; >>> + break; >>> + case 3: >>> + cc->nflash.blocksize = (1 << 10) * 512; >>> + break; >>> + case 4: >>> + cc->nflash.blocksize = (1 << 10) * 256; >>> + break; >>> + default: >>> + printk("Unknown block size\n"); >>> + return -ENODEV; >>> + } >>> + /* NAND flash size in MBytes */ >>> + val = (ncf & NCF_DEVICE_SIZE_MASK) >> NCF_DEVICE_SIZE_SHIFT; >>> + if (val == 0) { >>> + printk("Unknown flash size\n"); >>> + return -ENODEV; >>> + } >>> + cc->nflash.size = (1 << (val - 1)) * 8; >>> + cc->nflash.numblocks = (cc->nflash.size * (1 << 10)) / >>> (cc->nflash.blocksize >> 10); >>> + bcma_firsttime = 1; >>> + if (bcma_firsttime) >>> + printk("Found a %s NAND flash with %uB pages or %dKB blocks; >>> total size %dMB\n", >>> + name, cc->nflash.pagesize, (cc->nflash.blocksize >> 10), >>> cc->nflash.size); >>> + return cc->nflash.size ? 0 : -ENODEV; >>> +} >>> + >>> +/* Check offset and length */ >>> +static int bcma_nflash_offset_is_valid(struct bcma_drv_cc *cc, u32 offset, >>> u32 len, u32 mask) >>> +{ >>> + if ((offset & mask) != 0 || (len & mask) != 0) { >>> + printk("%s(): Address is not aligned. offset: %x, len: %x, >>> mask: %x\n", __func__, offset, len, mask); >> Please use pr_err() >>> + BUG_ON(1); >>> + return 1; >>> + } >>> + >>> + if ((((offset + len) >> 20) > cc->nflash.size) || >>> + ((((offset + len) >> 20) == cc->nflash.size) && >>> + (((offset + len) & ((1 << 20) - 1)) != 0))) { >>> + printk("%s(): Address is outside Flash memory region. offset: >>> %x, len: %x, mask: %x\n", __func__, offset, len, mask); >> Please use pr_err() >>> + return 1; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +/* Read len bytes starting at offset into buf. Returns number of bytes >>> read. */ >>> +int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf) >>> +{ >>> + u32 mask; >>> + int i; >>> + u32 *to, val, res; >>> + >>> + mask = NFL_SECTOR_SIZE - 1; >>> + if (bcma_nflash_offset_is_valid(cc, offset, len, mask)) >>> + return 0; >>> + >>> + to = (u32 *)buf; >>> + res = len; >>> + while (res > 0) { >>> + bcma_cc_write32(cc, NAND_CMD_ADDR, offset); >>> + bcma_nflash_cmd(cc, NCMD_PAGE_RD); >>> + if (bcma_nflash_poll(cc) < 0) >>> + break; >>> + val = bcma_cc_read32(cc, NAND_INTFC_STATUS); >>> + if ((val & NIST_CACHE_VALID) == 0) >>> + break; >>> + bcma_cc_write32(cc, NAND_CACHE_ADDR, 0); >>> + for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) { >>> + *to = bcma_cc_read32(cc, NAND_CACHE_DATA); >>> + } >>> + res -= NFL_SECTOR_SIZE; >>> + offset += NFL_SECTOR_SIZE; >>> + } >>> + return (len - res); >>> +} >>> + >>> +#define NF_RETRIES 1000000 >>> + >>> +/* Poll for command completion. Returns zero when complete. */ >>> +int bcma_nflash_poll(struct bcma_drv_cc *cc) >>> +{ >>> + u32 retries = NF_RETRIES; >>> + u32 pollmask = NIST_CTRL_READY|NIST_FLASH_READY; >>> + u32 mask; >>> + >>> + while (retries--) { >>> + mask = bcma_cc_read32(cc, NAND_INTFC_STATUS) & pollmask; >>> + if (mask == pollmask) >>> + break; >> Why not return 0 here? >>> + cpu_relax(); >> Why is this needed? >>> + } >>> + >>> + if (!retries) { >>> + printk("bcma_nflash_poll: not ready\n"); >> use pr_err() >>> + return -1; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +/* Write len bytes starting at offset into buf. Returns success (0) or >>> failure (!0). >>> + * Should poll for completion. >>> + */ >>> +int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, >>> + const u8 *buf) >>> +{ >>> + u32 mask; >>> + int i; >>> + u32 *from, res, reg; >>> + >>> + mask = cc->nflash.pagesize - 1; >>> + if (bcma_nflash_offset_is_valid(cc, offset, len, mask)) >>> + return 1; >>> + >>> + /* disable partial page enable */ >>> + reg = bcma_cc_read32(cc, NAND_ACC_CONTROL); >>> + reg &= ~NAC_PARTIAL_PAGE_EN; >>> + bcma_cc_write32(cc, NAND_ACC_CONTROL, reg); >>> + >>> + from = (u32 *)buf; >>> + res = len; >>> + while (res > 0) { >>> + bcma_cc_write32(cc, NAND_CACHE_ADDR, 0); >>> + for (i = 0; i < cc->nflash.pagesize; i += 4, from++) { >>> + if (i % 512 == 0) >>> + bcma_cc_write32(cc, NAND_CMD_ADDR, i); >>> + bcma_cc_write32(cc, NAND_CACHE_DATA, *from); >>> + } >>> + bcma_cc_write32(cc, NAND_CMD_ADDR, offset + cc->nflash.pagesize >>> - 512); >>> + bcma_nflash_cmd(cc, NCMD_PAGE_PROG); >>> + if (bcma_nflash_poll(cc) < 0) >>> + break; >> A more recent broacom driver does a check here why is that not in your >> patch? >>> + res -= cc->nflash.pagesize; >>> + offset += cc->nflash.pagesize; >>> + } >>> + >>> + if (res <= 0) >>> + return 0; >>> + else >>> + return (len - res); >>> +} >>> + >>> +/* Erase a region. Returns success (0) or failure (-1). >>> + * Caller should poll for completion. >>> + */ >>> +int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset) >>> +{ >>> + if ((offset >> 20) >= cc->nflash.size) >>> + return -1; >>> + if ((offset & (cc->nflash.blocksize - 1)) != 0) { >>> + return -1; >>> + } >>> + bcma_cc_write32(cc, NAND_CMD_ADDR, offset); >>> + bcma_nflash_cmd(cc, NCMD_BLOCK_ERASE); >>> + if (bcma_nflash_poll(cc) < 0) >>> + return -1; >>> + return 0; >>> +} >>> diff -Naur a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c >>> --- a/drivers/bcma/driver_mips.c 2012-02-17 16:34:21.000000000 +0530 >>> +++ b/drivers/bcma/driver_mips.c 2012-02-23 18:24:30.000000000 +0530 >>> @@ -6,6 +6,7 @@ >>> * Copyright 2006, 2007, Michael Buesch <[email protected]> >>> * Copyright 2010, Bernhard Loos <[email protected]> >>> * Copyright 2011, Hauke Mehrtens <[email protected]> >>> + * Copyright (C) 2011-2012 Tathagata Das <[email protected]> >>> * >>> * Licensed under the GNU/GPL. See COPYING for details. >>> */ >>> @@ -182,10 +183,14 @@ >>> { >>> struct bcma_bus *bus = mcore->core->bus; >>> >>> +printk("BUS Capability: %x\n", bus->drv_cc.capabilities); >>> switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { >>> case BCMA_CC_FLASHT_STSER: >>> case BCMA_CC_FLASHT_ATSER: >>> -#ifdef CONFIG_BCMA_SFLASH >>> +#ifdef CONFIG_BCMA_NFLASH >>> + printk("found nand flash.\n"); >>> + bus->drv_cc.flash_type = BCMA_NFLASH; >>> +#elif CONFIG_BCMA_SFLASH >> We want to build one image supporting devices with serial and with nand >> flash. This makes it just possible to support one flash type at a time. >>> pr_info("found serial flash.\n"); >>> bus->drv_cc.flash_type = BCMA_SFLASH; >>> bcma_sflash_init(&bus->drv_cc); >>> diff -Naur a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig >>> --- a/drivers/bcma/Kconfig 2012-02-17 16:34:21.000000000 +0530 >>> +++ b/drivers/bcma/Kconfig 2012-02-17 17:32:21.000000000 +0530 >>> @@ -44,6 +44,11 @@ >>> depends on BCMA_DRIVER_MIPS >>> default y >>> >>> +config BCMA_NFLASH >>> + bool >>> + depends on BCMA_DRIVER_MIPS >>> + default y >>> + >>> config BCMA_DRIVER_MIPS >>> bool "BCMA Broadcom MIPS core driver" >>> depends on BCMA && MIPS >>> diff -Naur a/drivers/bcma/Makefile b/drivers/bcma/Makefile >>> --- a/drivers/bcma/Makefile 2012-02-17 16:34:21.000000000 +0530 >>> +++ b/drivers/bcma/Makefile 2012-02-17 17:32:21.000000000 +0530 >>> @@ -1,6 +1,7 @@ >>> bcma-y += main.o scan.o core.o sprom.o >>> bcma-y += driver_chipcommon.o >>> driver_chipcommon_pmu.o >>> bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o >>> +bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o >>> bcma-y += driver_pci.o >>> bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o >>> bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o >>> diff -Naur a/drivers/mtd/nand/bcm47xx_nand.c >>> b/drivers/mtd/nand/bcm47xx_nand.c >>> --- a/drivers/mtd/nand/bcm47xx_nand.c 1970-01-01 05:30:00.000000000 >>> +0530 >>> +++ b/drivers/mtd/nand/bcm47xx_nand.c 2012-02-23 18:43:03.000000000 >>> +0530 >>> @@ -0,0 +1,484 @@ >>> +/* >>> + * BCMA nand flash interface >>> + * >>> + * Copyright (C) 2011-2012 Tathagata Das <[email protected]> >>> + * Copyright 2010, Broadcom Corporation >>> + * >>> + * 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$ >> remove this CVS thing >>> + */ >>> + >>> +#define pr_fmt(fmt) "bcm47xx_nflash: " fmt >>> +#include <linux/module.h> >>> +#include <linux/slab.h> >>> +#include <linux/ioport.h> >>> +#include <linux/sched.h> >>> +#include <linux/mtd/mtd.h> >>> +#include <linux/mtd/map.h> >>> +#include <linux/mtd/partitions.h> >>> +#include <linux/errno.h> >>> +#include <linux/delay.h> >>> +#include <linux/platform_device.h> >>> +#include <bcm47xx.h> >>> +#include <bus.h> >>> +#include <linux/cramfs_fs.h> >>> +#include <linux/romfs_fs.h> >>> +#include <linux/magic.h> >>> +#include <linux/byteorder/generic.h> >>> +#include <linux/mtd/bcm47xx_nand.h> >>> +#include <linux/mtd/nand.h> >>> + >>> +static int bcm47xx_block_bad(struct mtd_info *mtd, loff_t ofs, int >>> getchip); >>> + >>> +/* Private Global variable */ >>> +static u32 read_offset = 0; >>> +static u32 write_offset; >>> + >>> +static int >>> +nflash_mtd_poll(struct bcm47xx_nflash *nflash, unsigned int offset, int >>> timeout) >>> +{ >>> + unsigned long now = jiffies; >>> + int ret = 0; >>> + >>> + for (;;) { >>> + if (!bcma_nflash_poll(nflash->bcc)) { >>> + ret = 0; >>> + break; >>> + } >>> + if (time_after(jiffies, now + timeout)) { >>> + pr_err("timeout while polling\n"); >>> + ret = -ETIMEDOUT; >>> + break; >>> + } >>> + udelay(1); >>> + } >>> + >>> + return ret; >>> +} >>> + >>> +static int >>> +bcm47xx_read(struct mtd_info *mtd, loff_t from, size_t len, size_t >>> *retlen, u_char *buf) >>> +{ >>> + struct nand_chip *nchip = (struct nand_chip *)mtd->priv; >>> + struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; >>> + int bytes, ret = 0; >>> + u32 extra = 0; >>> + u8 *tmpbuf = NULL; >>> + int size; >>> + u32 offset, blocksize, mask, blk_offset, off; >>> + u32 skip_bytes = 0; >>> + int blk_idx; >>> + int need_copy = 0; >>> + u8 *ptr = NULL; >>> + >>> + /* Check address range */ >>> + if (!len) >>> + return 0; >>> + if ((from + len) > mtd->size) >>> + return -EINVAL; >>> + offset = from; >>> + if ((offset & (NFL_SECTOR_SIZE - 1)) != 0) { >>> + extra = offset & (NFL_SECTOR_SIZE - 1); >>> + offset -= extra; >>> + len += extra; >>> + need_copy = 1; >>> + } >>> + size = (len + (NFL_SECTOR_SIZE - 1)) & ~(NFL_SECTOR_SIZE - 1); >>> + if (size != len) { >>> + need_copy = 1; >>> + } >>> + if (!need_copy) { >>> + ptr = buf; >>> + } else { >>> + tmpbuf = (u8 *)kmalloc(size, GFP_KERNEL); >>> + ptr = tmpbuf; >>> + } >>> + >>> + blocksize = mtd->erasesize; >>> + mask = blocksize - 1; >>> + blk_offset = blocksize * blk_idx; >>> + *retlen = 0; >>> + while (len > 0) { >>> + off = offset + skip_bytes; >>> + if ((bytes = bcma_nflash_read(nflash->bcc, off, >>> NFL_SECTOR_SIZE, ptr)) < 0) { >>> + ret = bytes; >>> + goto done; >>> + } >>> + if (bytes > len) >>> + bytes = len; >>> + offset += bytes; >>> + len -= bytes; >>> + ptr += bytes; >>> + *retlen += bytes; >>> + } >>> + >>> +done: >>> + if (tmpbuf) { >>> + *retlen -= extra; >>> + memcpy(buf, tmpbuf+extra, *retlen); >>> + kfree(tmpbuf); >>> + } >>> + >>> + return ret; >>> +} >>> + >>> +static void bcm47xx_write(struct mtd_info *mtd, u32 to, const u_char *buf, >>> int len) >>> +{ >>> + struct nand_chip *nchip = (struct nand_chip *)mtd->priv; >>> + struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; >>> + u32 pagesize = 1 << nchip->page_shift; >>> + >>> + /* Check address range */ >>> + if (!len) { >>> + printk("Error: Attempted to write too small data\n"); >>> + return; >>> + } >>> + >>> + if (!to) >>> + return; >>> + >>> + if ((to + len) > mtd->size) { >>> + printk("Error: Attempted to write too large data\n"); >>> + return; >>> + } >>> + >>> + while (len > 0) { >>> + int ret; >>> + >>> + if (len > pagesize) >>> + ret = bcma_nflash_write(nflash->bcc, to, pagesize, buf); >>> + else >>> + ret = bcma_nflash_write(nflash->bcc, to, len, buf); >>> + if (ret) { >>> + printk("WRITE: nflash write error\n"); >>> + return; >>> + } >>> + >>> + ret = nflash_mtd_poll(nflash, (unsigned int) to, HZ / 10); >>> + if (ret) { >>> + printk("WRITE: nflash_mtd_poll error\n"); >>> + return; >>> + } >>> + >>> + to += pagesize; >>> + len -= pagesize; >>> + buf += pagesize; >>> + } >>> + >>> + return; >>> +} >>> + >>> +static void bcm47xx_erase(struct mtd_info *mtd, unsigned int addr, >>> unsigned int len) >>> +{ >>> + struct nand_chip *nchip = (struct nand_chip *)mtd->priv; >>> + struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; >>> + >>> + /* Check address range */ >>> + if (!len) >>> + return; >>> + if ((addr + len) > mtd->size) >>> + return; >>> + >>> + if (bcma_nflash_erase(nflash->bcc, addr)) { >>> + printk("ERASE: nflash erase error\n"); >>> + return; >>> + } >>> + >>> + if (nflash_mtd_poll(nflash, addr, 10 * HZ)) >>> + printk("ERASE: nflash_mtd_poll error\n"); >>> + >>> + return; >>> +} >>> + >>> +/* This functions is used by upper layer to checks if device is ready */ >>> +static int bcm47xx_dev_ready(struct mtd_info *mtd) >>> +{ >>> + return 1; >>> +} >>> + >>> +/* Issue a nand flash command */ >>> +static inline void bcm47xx_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode) >>> +{ >>> + bcma_cc_write32(cc, NAND_CMD_START, opcode); >>> + bcma_cc_read32(cc, NAND_CMD_START); >>> +} >>> + >>> +static void bcm47xx_command(struct mtd_info *mtd, unsigned command, >>> + int column, int page_addr) >>> +{ >>> + struct nand_chip *nchip = (struct nand_chip *)mtd->priv; >>> + struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; >>> + u32 pagesize = 1 << nchip->page_shift; >>> + >>> + /* Command pre-processing step */ >>> + switch (command) { >>> + case NAND_CMD_RESET: >>> + bcm47xx_nflash_cmd(nflash->bcc, NCMD_FLASH_RESET); >>> + break; >>> + >>> + case NAND_CMD_STATUS: >>> + nflash->next_opcode = NAND_CMD_STATUS; >>> + read_offset = 0; >>> + write_offset = 0; >>> + break; >>> + >>> + case NAND_CMD_READ0: >>> + read_offset = page_addr * pagesize; >>> + nflash->next_opcode = 0; >>> + break; >>> + >>> + case NAND_CMD_READOOB: >>> + read_offset = page_addr * pagesize; >>> + nflash->next_opcode = 0; >>> + break; >>> + >>> + case NAND_CMD_SEQIN: >>> + write_offset = page_addr * pagesize; >>> + nflash->next_opcode = 0; >>> + break; >>> + >>> + case NAND_CMD_PAGEPROG: >>> + nflash->next_opcode = 0; >>> + break; >>> + >>> + case NAND_CMD_READID: >>> + read_offset = column; >>> + bcm47xx_nflash_cmd(nflash->bcc, NCMD_ID_RD); >>> + nflash->next_opcode = NAND_DEVID; >>> + break; >>> + >>> + case NAND_CMD_ERASE1: >>> + nflash->next_opcode = 0; >>> + bcm47xx_erase(mtd, page_addr*pagesize, pagesize); >>> + break; >>> + >>> + case NAND_CMD_ERASE2: >>> + break; >>> + >>> + case NAND_CMD_RNDOUT: >>> + if (column > mtd->writesize) >>> + read_offset += (column - mtd->writesize); >>> + else >>> + read_offset += column; >>> + break; >>> + >>> + default: >>> + printk("COMMAND not supported %x\n", command); >>> + nflash->next_opcode = 0; >>> + break; >>> + } >>> +} >>> + >>> +/* This function is used by upper layer for select and >>> + * deselect of the NAND chip. >>> + * It is dummy function. */ >>> +static void bcm47xx_select_chip(struct mtd_info *mtd, int chip) >>> +{ >>> +} >>> + >>> +static u_char bcm47xx_read_byte(struct mtd_info *mtd) >>> +{ >>> + struct nand_chip *nchip = mtd->priv; >>> + struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; >>> + uint8_t ret = 0; >>> + static u32 id; >>> + >>> + if (nflash->next_opcode == 0) >>> + return ret; >>> + >>> + if (nflash->next_opcode == NAND_CMD_STATUS) >>> + return NAND_STATUS_WP; >>> + >>> + id = bcma_cc_read32(nflash->bcc, nflash->next_opcode); >>> + >>> + if (nflash->next_opcode == NAND_DEVID) { >>> + ret = (id >> (8*read_offset)) & 0xff; >>> + read_offset++; >>> + } >>> + >>> + return ret; >>> +} >>> + >>> +static uint16_t bcm47xx_read_word(struct mtd_info *mtd) >>> +{ >>> + loff_t from = read_offset; >>> + uint16_t buf = 0; >>> + int bytes; >>> + >>> + bcm47xx_read(mtd, from, sizeof(buf), &bytes, (u_char *)&buf); >>> + return buf; >>> +} >>> + >>> +/* Write data of length len to buffer buf. The data to be >>> + * written on NAND Flash is first copied to RAMbuffer. After the Data Input >>> + * Operation by the NFC, the data is written to NAND Flash */ >>> +static void bcm47xx_write_buf(struct mtd_info *mtd, >>> + const u_char *buf, int len) >>> +{ >>> + bcm47xx_write(mtd, write_offset, buf, len); >>> +} >>> + >>> +/* Read the data buffer from the NAND Flash. To read the data from NAND >>> + * Flash first the data output cycle is initiated by the NFC, which copies >>> + * the data to RAMbuffer. This data of length len is then copied to buffer >>> buf. >>> + */ >>> +static void bcm47xx_read_buf(struct mtd_info *mtd, u_char *buf, int len) >>> +{ >>> + loff_t from = read_offset; >>> + int bytes; >>> + >>> + bcm47xx_read(mtd, from, len, &bytes, buf); >>> +} >>> + >>> +/* Used by the upper layer to verify the data in NAND Flash >>> + * with the data in the buf. */ >>> +static int bcm47xx_verify_buf(struct mtd_info *mtd, >>> + const u_char *buf, int len) >>> +{ >>> + return -EFAULT; >>> +} >>> + >>> +static int bcm47xx_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) >>> +{ >>> + struct nand_chip *nchip = mtd->priv; >>> + struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; >>> + int i; >>> + uint off; >>> + u32 pagesize = 1 << nchip->page_shift; >>> + u32 blocksize = mtd->erasesize; >>> + >>> + if ((ofs >> 20) >= nflash->size) >>> + return -1; >>> + if ((ofs & (blocksize - 1)) != 0) { >>> + return -1; >>> + } >>> + for (i = 0; i < 2; i++) { >>> + off = ofs + pagesize; >>> + bcma_cc_write32(nflash->bcc, NAND_CMD_ADDR, off); >>> + bcm47xx_nflash_cmd(nflash->bcc, NCMD_SPARE_RD); >>> + if (bcma_nflash_poll(nflash->bcc) < 0) >>> + break; >>> + if ((bcma_cc_read32(nflash->bcc, NAND_INTFC_STATUS) & >>> NIST_SPARE_VALID) != NIST_SPARE_VALID) >>> + return -1; >>> + if ((bcma_cc_read32(nflash->bcc, NAND_SPARE_RD0) & 0xff) != 0xff) >>> + return -1; >>> + } >>> + return 0; >>> +} >>> + >>> +#ifdef CONFIG_MTD_CMDLINE_PARTS >>> +const char *part_probes[] = { "cmdlinepart", NULL }; >>> +#endif >>> +static int bcm47xx_probe(struct platform_device *pdev) >>> +{ >>> + struct nand_chip *nchip; >>> + struct mtd_info *mtd; >>> + struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev); >>> + int ret = 0, nr_part = 0; >>> + struct mtd_partition *parts = NULL; >>> + >>> + mtd = &nflash->mtd; >>> + nchip = &nflash->nand; >>> + >>> + /* Register with MTD */ >>> + mtd->priv = nchip; >>> + mtd->owner = THIS_MODULE; >>> + mtd->dev.parent = &pdev->dev; >>> + >>> + /* 50 us command delay time */ >>> + nchip->chip_delay = 50; >>> + >>> + nchip->priv = nflash; >>> + nchip->dev_ready = bcm47xx_dev_ready; >>> + nchip->cmdfunc = bcm47xx_command; >>> + nchip->select_chip = bcm47xx_select_chip; >>> + nchip->read_byte = bcm47xx_read_byte; >>> + nchip->read_word = bcm47xx_read_word; >>> + nchip->write_buf = bcm47xx_write_buf; >>> + nchip->read_buf = bcm47xx_read_buf; >>> + nchip->verify_buf = bcm47xx_verify_buf; >>> + nchip->block_bad = bcm47xx_block_bad; >>> + nchip->options = NAND_SKIP_BBTSCAN; >>> + >>> + /* Not known */ >>> + nchip->ecc.mode = NAND_ECC_NONE; >>> + >>> + /* first scan to find the device and get the page size */ >>> + if (nand_scan_ident(mtd, 1, NULL)) { >>> + printk("nand_scan_ident failed\n"); >>> + ret = -ENXIO; >>> + goto done; >>> + } >>> + nflash->bcc->nflash.size = mtd->size; >>> + bcm47xx_nflash.size = mtd->size; >>> + >>> + /* second phase scan */ >>> + if (nand_scan_tail(mtd)) { >>> + printk("nand_scan_tail failed\n"); >>> + ret = -ENXIO; >>> + goto done; >>> + } >>> + >>> +#ifdef CONFIG_MTD_CMDLINE_PARTS >>> + mtd->name = "bcm47xx-nflash"; >>> + nr_part = parse_mtd_partitions(mtd, part_probes, &parts, 0); >>> +#endif >>> + >>> + mtd->flags |= MTD_WRITEABLE; >>> + ret = mtd_device_register(mtd, parts, nr_part); >>> + >>> + if (ret) { >>> + printk("mtd_device_register failed\n"); >>> + return ret; >>> + } >>> + >>> + return 0; >>> + >>> +done: >>> + return ret; >>> +} >>> + >>> +static int __devexit bcm47xx_remove(struct platform_device *pdev) >>> +{ >>> + struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev); >>> + struct mtd_info *mtd = &nflash->mtd; >>> + >>> + if (nflash) { >>> + /* Release resources, unregister device */ >>> + nand_release(mtd); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static struct platform_driver bcm47xx_driver = { >>> + .remove = __devexit_p(bcm47xx_remove), >>> + .driver = { >>> + .name = "bcm47xx_nflash", >>> + .owner = THIS_MODULE, >>> + }, >>> +}; >>> + >>> +static int __init init_bcm47xx_nflash(void) >>> +{ >>> + int ret = platform_driver_probe(&bcm47xx_driver, bcm47xx_probe); >>> + >>> + if (ret) >>> + pr_err("error registering platform driver: %i\n", ret); >>> + return ret; >>> +} >>> + >>> +static void __exit exit_bcm47xx_nflash(void) >>> +{ >>> + platform_driver_unregister(&bcm47xx_driver); >>> +} >>> + >>> +module_init(init_bcm47xx_nflash); >>> +module_exit(exit_bcm47xx_nflash); >>> + >>> +MODULE_LICENSE("GPL"); >>> +MODULE_DESCRIPTION("BCM47XX NAND flash driver"); >>> diff -Naur a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig >>> --- a/drivers/mtd/nand/Kconfig 2012-01-26 06:56:46.000000000 +0530 >>> +++ b/drivers/mtd/nand/Kconfig 2012-02-17 17:32:21.000000000 +0530 >>> @@ -530,4 +530,14 @@ >>> Enables support for NAND Flash chips on the ST Microelectronics >>> Flexible Static Memory Controller (FSMC) >>> >>> +config MTD_NAND_BCM47XX >>> + tristate "bcm47xx nand flash support" >>> + default y >>> + depends on BCM47XX >>> + select MTD_PARTITIONS >>> + select MTD_BCM47XX_PARTS >>> + help >>> + Support for bcm47xx nand flash >>> + >>> + >>> endif # MTD_NAND >>> diff -Naur a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile >>> --- a/drivers/mtd/nand/Makefile 2012-01-26 06:56:46.000000000 +0530 >>> +++ b/drivers/mtd/nand/Makefile 2012-02-17 17:32:21.000000000 +0530 >>> @@ -49,5 +49,6 @@ >>> obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o >>> obj-$(CONFIG_MTD_NAND_RICOH) += r852.o >>> obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o >>> +obj-$(CONFIG_MTD_NAND_BCM47XX) += bcm47xx_nand.o >>> >>> nand-objs := nand_base.o nand_bbt.o >>> diff -Naur a/include/linux/bcma/bcma_driver_chipcommon.h >>> b/include/linux/bcma/bcma_driver_chipcommon.h >>> --- a/include/linux/bcma/bcma_driver_chipcommon.h 2012-02-17 >>> 16:34:21.000000000 +0530 >>> +++ b/include/linux/bcma/bcma_driver_chipcommon.h 2012-02-22 >>> 16:58:11.000000000 +0530 >>> @@ -376,6 +376,7 @@ >>> enum bcma_flash_type { >>> BCMA_PFLASH, >>> BCMA_SFLASH, >>> + BCMA_NFLASH, >>> }; >>> >>> struct bcma_pflash { >>> @@ -392,6 +393,17 @@ >>> }; >>> #endif /* CONFIG_BCMA_SFLASH */ >>> >>> +#ifdef CONFIG_BCMA_NFLASH >>> +struct bcma_nflash { >>> + u32 blocksize; /* Block size */ >>> + u32 pagesize; /* Page size */ >>> + u32 numblocks; /* Number of blocks */ >>> + u32 type; /* Type */ >>> + u32 size; /* Total size in bytes */ >>> + u8 id[5]; >>> +}; >>> +#endif >>> + >>> struct bcma_serial_port { >>> void *regs; >>> unsigned long clockspeed; >>> @@ -417,6 +429,9 @@ >>> #ifdef CONFIG_BCMA_SFLASH >>> struct bcma_sflash sflash; >>> #endif /* CONFIG_BCMA_SFLASH */ >>> +#ifdef CONFIG_BCMA_NFLASH >>> + struct bcma_nflash nflash; >>> +#endif >>> }; >>> >>> int nr_serial_ports; >>> @@ -483,4 +498,13 @@ >>> const u8 *buf); >>> #endif /* CONFIG_BCMA_SFLASH */ >>> >>> +#ifdef CONFIG_BCMA_NFLASH >>> +/* Chipcommon nflash support. */ >>> +int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf); >>> +int bcma_nflash_poll(struct bcma_drv_cc *cc); >>> +int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, const >>> u8 *buf); >>> +int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset); >>> +int bcma_nflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len, const >>> u8 *buf); >>> +#endif >>> + >>> #endif /* LINUX_BCMA_DRIVER_CC_H_ */ >>> diff -Naur a/include/linux/mtd/bcm47xx_nand.h >>> b/include/linux/mtd/bcm47xx_nand.h >>> --- a/include/linux/mtd/bcm47xx_nand.h 1970-01-01 05:30:00.000000000 >>> +0530 >>> +++ b/include/linux/mtd/bcm47xx_nand.h 2012-02-23 18:28:43.000000000 >>> +0530 >>> @@ -0,0 +1,134 @@ >>> +/* >>> + * Broadcom chipcommon NAND flash interface >>> + * >>> + * Copyright (C) 2011-2012 Tathagata Das <[email protected]> >>> + * Copyright (C) 2009, 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. >>> + * >>> + */ >>> + >>> +#ifndef _nflash_h_ >>> +#define _nflash_h_ >>> + >>> +#define NAND_FLASH1 0x1fc00000 /* MIPS Flash >>> Region 1 */ >>> + >>> +/* nand_cmd_start commands */ >>> +#define NCMD_NULL 0 >>> +#define NCMD_PAGE_RD 1 >>> +#define NCMD_SPARE_RD 2 >>> +#define NCMD_STATUS_RD 3 >>> +#define NCMD_PAGE_PROG 4 >>> +#define NCMD_SPARE_PROG 5 >>> +#define NCMD_COPY_BACK 6 >>> +#define NCMD_ID_RD 7 >>> +#define NCMD_BLOCK_ERASE 8 >>> +#define NCMD_FLASH_RESET 9 >>> +#define NCMD_LOCK 0xa >>> +#define NCMD_LOCK_DOWN 0xb >>> +#define NCMD_UNLOCK 0xc >>> +#define NCMD_LOCK_STATUS 0xd >>> + >>> +/* nand_acc_control */ >>> +#define NAC_RD_ECC_EN 0x80000000 >>> +#define NAC_WR_ECC_EN 0x40000000 >>> +#define NAC_RD_ECC_BLK0_EN 0x20000000 >>> +#define NAC_FAST_PGM_RDIN 0x10000000 >>> +#define NAC_RD_ERASED_ECC_EN 0x08000000 >>> +#define NAC_PARTIAL_PAGE_EN 0x04000000 >>> +#define NAC_PAGE_HIT_EN 0x01000000 >>> +#define NAC_ECC_LEVEL0 0x00f00000 >>> +#define NAC_ECC_LEVEL 0x000f0000 >>> +#define NAC_SPARE_SIZE0 0x00003f00 >>> +#define NAC_SPARE_SIZE 0x0000003f >>> + >>> +/* nand_config */ >>> +#define NCF_CONFIG_LOCK 0x80000000 >>> +#define NCF_BLOCK_SIZE_MASK 0x70000000 >>> +#define NCF_BLOCK_SIZE_SHIFT 28 >>> +#define NCF_DEVICE_SIZE_MASK 0x0f000000 >>> +#define NCF_DEVICE_SIZE_SHIFT 24 >>> +#define NCF_DEVICE_WIDTH 0x00800000 >>> +#define NCF_PAGE_SIZE_MASK 0x00300000 >>> +#define NCF_PAGE_SIZE_SHIFT 20 >>> +#define NCF_FULL_ADDR_BYTES_MASK 0x00070000 >>> +#define NCF_FULL_ADDR_BYTES_SHIFT 16 >>> +#define NCF_COL_ADDR_BYTES_MASK 0x00007000 >>> +#define NCF_COL_ADDR_BYTES_SHIFT 12 >>> +#define NCF_BLK_ADDR_BYTES_MASK 0x00000700 >>> +#define NCF_BLK_ADDR_BYTES_SHIFT 8 >>> + >>> +/* nand_intfc_status */ >>> +#define NIST_CTRL_READY 0x80000000 >>> +#define NIST_FLASH_READY 0x40000000 >>> +#define NIST_CACHE_VALID 0x20000000 >>> +#define NIST_SPARE_VALID 0x10000000 >>> +#define NIST_ERASED 0x08000000 >>> +#define NIST_STATUS 0x000000ff >>> + >>> +#define NFL_SECTOR_SIZE 512 >>> + >>> +#define NFL_TABLE_END 0xffffffff >>> +#define NFL_BOOT_SIZE 0x200000 >>> +#define NFL_BOOT_OS_SIZE 0x2000000 >>> + >>> +/* Nand flash MLC controller registers (corerev >= 38) */ >>> +#define NAND_REVISION 0xC00 >>> +#define NAND_CMD_START 0xC04 >>> +#define NAND_CMD_ADDR_X 0xC08 >>> +#define NAND_CMD_ADDR 0xC0C >>> +#define NAND_CMD_END_ADDR 0xC10 >>> +#define NAND_CS_NAND_SELECT 0xC14 >>> +#define NAND_CS_NAND_XOR 0xC18 >>> +#define NAND_SPARE_RD0 0xC20 >>> +#define NAND_SPARE_RD4 0xC24 >>> +#define NAND_SPARE_RD8 0xC28 >>> +#define NAND_SPARE_RD12 0xC2C >>> +#define NAND_SPARE_WR0 0xC30 >>> +#define NAND_SPARE_WR4 0xC34 >>> +#define NAND_SPARE_WR8 0xC38 >>> +#define NAND_SPARE_WR12 0xC3C >>> +#define NAND_ACC_CONTROL 0xC40 >>> +#define NAND_CONFIG 0xC48 >>> +#define NAND_TIMING_1 0xC50 >>> +#define NAND_TIMING_2 0xC54 >>> +#define NAND_SEMAPHORE 0xC58 >>> +#define NAND_DEVID 0xC60 >>> +#define NAND_DEVID_X 0xC64 >>> +#define NAND_BLOCK_LOCK_STATUS 0xC68 >>> +#define NAND_INTFC_STATUS 0xC6C >>> +#define NAND_ECC_CORR_ADDR_X 0xC70 >>> +#define NAND_ECC_CORR_ADDR 0xC74 >>> +#define NAND_ECC_UNC_ADDR_X 0xC78 >>> +#define NAND_ECC_UNC_ADDR 0xC7C >>> +#define NAND_READ_ERROR_COUNT 0xC80 >>> +#define NAND_CORR_STAT_THRESHOLD 0xC84 >>> +#define NAND_READ_ADDR_X 0xC90 >>> +#define NAND_READ_ADDR 0xC94 >>> +#define NAND_PAGE_PROGRAM_ADDR_X 0xC98 >>> +#define NAND_PAGE_PROGRAM_ADDR 0xC9C >>> +#define NAND_COPY_BACK_ADDR_X 0xCA0 >>> +#define NAND_COPY_BACK_ADDR 0xCA4 >>> +#define NAND_BLOCK_ERASE_ADDR_X 0xCA8 >>> +#define NAND_BLOCK_ERASE_ADDR 0xCAC >>> +#define NAND_INV_READ_ADDR_X 0xCB0 >>> +#define NAND_INV_READ_ADDR 0xCB4 >>> +#define NAND_BLK_WR_PROTECT 0xCC0 >>> +#define NAND_ACC_CONTROL_CS1 0xCD0 >>> +#define NAND_CONFIG_CS1 0xCD4 >>> +#define NAND_TIMING_1_CS1 0xCD8 >>> +#define NAND_TIMING_2_CS1 0xCDC >>> +#define NAND_SPARE_RD16 0xD30 >>> +#define NAND_SPARE_RD20 0xD34 >>> +#define NAND_SPARE_RD24 0xD38 >>> +#define NAND_SPARE_RD28 0xD3C >>> +#define NAND_CACHE_ADDR 0xD40 >>> +#define NAND_CACHE_DATA 0xD44 >>> +#define NAND_CTRL_CONFIG 0xD48 >>> +#define NAND_CTRL_STATUS 0xD4C >>> + >>> +#endif /* _nflash_h_ */ >> >> > > > _______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/mailman/listinfo/openwrt-devel
