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

Reply via email to