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 <tathag...@alumnux.com> > > 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 <ha...@hauke-m.de> > + * Copyright (C) 2011-2012 Tathagata Das <tathag...@alumnux.com> > * > * 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 <n...@openwrt.org> > * Copyright (C) 2010-2011 Hauke Mehrtens <ha...@hauke-m.de> > + * Copyright (C) 2011-2012 Tathagata Das <tathag...@alumnux.com> > * > * 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 <m...@bu3sch.de> > * Copyright (C) 2010 Waldemar Brodkorb <w...@openadk.org> > * Copyright (C) 2010-2011 Hauke Mehrtens <ha...@hauke-m.de> > + * Copyright (C) 2011-2012 Tathagata Das <tathag...@alumnux.com> > * > * 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 <ha...@hauke-m.de> > + * Copyright (C) 2011-2012 Tathagata Das <tathag...@alumnux.com> > * > * 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 <tathag...@alumnux.com> > + * 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 <m...@bu3sch.de> > * Copyright 2010, Bernhard Loos <bernhardl...@googlemail.com> > * Copyright 2011, Hauke Mehrtens <ha...@hauke-m.de> > + * Copyright (C) 2011-2012 Tathagata Das <tathag...@alumnux.com> > * > * 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 <tathag...@alumnux.com> > + * 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 <tathag...@alumnux.com> > + * 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 openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel