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

Reply via email to