[PATCH] MTD: NAND: pxa3xx_nand: add ability to keep controller settings defined by OBM/bootloader

Eric Miao eric.y.miao at gmail.com
Thu Jan 22 03:03:51 EST 2009


On Thu, Jan 22, 2009 at 3:06 PM, Mike Rapoport <mike at compulab.co.il> wrote:
> Eric,
> Any comments?

Yes, I'm OK with this.

Acked-by: Eric Miao <eric.miao at marvell.com>

>
> Mike Rapoport wrote:
>> Signed-off-by: Mike Rapoport <mike at compulab.co.il>
>> ---
>>  arch/arm/mach-pxa/include/mach/pxa3xx_nand.h |    3 +
>>  drivers/mtd/nand/pxa3xx_nand.c               |  103 +++++++++++++++++++++++++-
>>  2 files changed, 105 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h b/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h
>> index eb35fca..3478eae 100644
>> --- a/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h
>> +++ b/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h
>> @@ -49,6 +49,9 @@ struct pxa3xx_nand_platform_data {
>>        */
>>       int     enable_arbiter;
>>
>> +     /* allow platform code to keep OBM/bootloader defined NFC config */
>> +     int     keep_config;
>> +
>>       const struct mtd_partition              *parts;
>>       unsigned int                            nr_parts;
>>
>> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
>> index ead4a7a..2857a6a 100644
>> --- a/drivers/mtd/nand/pxa3xx_nand.c
>> +++ b/drivers/mtd/nand/pxa3xx_nand.c
>> @@ -171,7 +171,13 @@ static int use_dma = 1;
>>  module_param(use_dma, bool, 0444);
>>  MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");
>>
>> -#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN
>> +/*
>> + * Default NAND flash controller configuration setup by the
>> + * bootloader. This configuration is used only when pdata->keep_config is set
>> + */
>> +static struct pxa3xx_nand_timing default_timing;
>> +static struct pxa3xx_nand_flash default_flash;
>> +
>>  static struct pxa3xx_nand_cmdset smallpage_cmdset = {
>>       .read1          = 0x0000,
>>       .read2          = 0x0050,
>> @@ -198,6 +204,7 @@ static struct pxa3xx_nand_cmdset largepage_cmdset = {
>>       .lock_status    = 0x007A,
>>  };
>>
>> +#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN
>>  static struct pxa3xx_nand_timing samsung512MbX16_timing = {
>>       .tCH    = 10,
>>       .tCS    = 0,
>> @@ -297,9 +304,23 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = {
>>  #define NDTR1_tWHR(c)        (min((c), 15) << 4)
>>  #define NDTR1_tAR(c) (min((c), 15) << 0)
>>
>> +#define tCH_NDTR0(r) (((r) >> 19) & 0x7)
>> +#define tCS_NDTR0(r) (((r) >> 16) & 0x7)
>> +#define tWH_NDTR0(r) (((r) >> 11) & 0x7)
>> +#define tWP_NDTR0(r) (((r) >> 8) & 0x7)
>> +#define tRH_NDTR0(r) (((r) >> 3) & 0x7)
>> +#define tRP_NDTR0(r) (((r) >> 0) & 0x7)
>> +
>> +#define tR_NDTR1(r)  (((r) >> 16) & 0xffff)
>> +#define tWHR_NDTR1(r)        (((r) >> 4) & 0xf)
>> +#define tAR_NDTR1(r) (((r) >> 0) & 0xf)
>> +
>>  /* convert nano-seconds to nand flash controller clock cycles */
>>  #define ns2cycle(ns, clk)    (int)(((ns) * (clk / 1000000) / 1000) - 1)
>>
>> +/* convert nand flash controller clock cycles to nano-seconds */
>> +#define cycle2ns(c, clk)     ((((c) + 1) * 1000000 + clk / 500) / (clk / 1000))
>> +
>>  static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
>>                                  const struct pxa3xx_nand_timing *t)
>>  {
>> @@ -921,6 +942,82 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
>>       return 0;
>>  }
>>
>> +static void pxa3xx_nand_detect_timing(struct pxa3xx_nand_info *info,
>> +                                   struct pxa3xx_nand_timing *t)
>> +{
>> +     unsigned long nand_clk = clk_get_rate(info->clk);
>> +     uint32_t ndtr0 = nand_readl(info, NDTR0CS0);
>> +     uint32_t ndtr1 = nand_readl(info, NDTR1CS0);
>> +
>> +     t->tCH = cycle2ns(tCH_NDTR0(ndtr0), nand_clk);
>> +     t->tCS = cycle2ns(tCS_NDTR0(ndtr0), nand_clk);
>> +     t->tWH = cycle2ns(tWH_NDTR0(ndtr0), nand_clk);
>> +     t->tWP = cycle2ns(tWP_NDTR0(ndtr0), nand_clk);
>> +     t->tRH = cycle2ns(tRH_NDTR0(ndtr0), nand_clk);
>> +     t->tRP = cycle2ns(tRP_NDTR0(ndtr0), nand_clk);
>> +
>> +     t->tR = cycle2ns(tR_NDTR1(ndtr1), nand_clk);
>> +     t->tWHR = cycle2ns(tWHR_NDTR1(ndtr1), nand_clk);
>> +     t->tAR = cycle2ns(tAR_NDTR1(ndtr1), nand_clk);
>> +}
>> +
>> +static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
>> +{
>> +     uint32_t ndcr = nand_readl(info, NDCR);
>> +     struct nand_flash_dev *type = NULL;
>> +     uint32_t id = -1;
>> +     int i;
>> +
>> +     default_flash.page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32;
>> +     default_flash.page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
>> +     default_flash.flash_width = ndcr & NDCR_DWIDTH_M ? 16 : 8;
>> +     default_flash.dfc_width = ndcr & NDCR_DWIDTH_C ? 16 : 8;
>> +
>> +     if (default_flash.page_size == 2048)
>> +             default_flash.cmdset = &largepage_cmdset;
>> +     else
>> +             default_flash.cmdset = &smallpage_cmdset;
>> +
>> +     /* set info fields needed to __readid */
>> +     info->flash_info = &default_flash;
>> +     info->read_id_bytes = (default_flash.page_size == 2048) ? 4 : 2;
>> +     info->reg_ndcr = ndcr;
>> +
>> +     if (__readid(info, &id))
>> +             return -ENODEV;
>> +
>> +     /* Lookup the flash id */
>> +     id = (id >> 8) & 0xff;          /* device id is byte 2 */
>> +     for (i = 0; nand_flash_ids[i].name != NULL; i++) {
>> +             if (id == nand_flash_ids[i].id) {
>> +                     type =  &nand_flash_ids[i];
>> +                     break;
>> +             }
>> +     }
>> +
>> +     if (!type)
>> +             return -ENODEV;
>> +
>> +     /* fill the missing flash information */
>> +     i = __ffs(default_flash.page_per_block * default_flash.page_size);
>> +     default_flash.num_blocks = type->chipsize << (20 - i);
>> +
>> +     info->oob_size = (default_flash.page_size == 2048) ? 64 : 16;
>> +
>> +     /* calculate addressing information */
>> +     info->col_addr_cycles = (default_flash.page_size == 2048) ? 2 : 1;
>> +
>> +     if (default_flash.num_blocks * default_flash.page_per_block > 65536)
>> +             info->row_addr_cycles = 3;
>> +     else
>> +             info->row_addr_cycles = 2;
>> +
>> +     pxa3xx_nand_detect_timing(info, &default_timing);
>> +     default_flash.timing = &default_timing;
>> +
>> +     return 0;
>> +}
>> +
>>  static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info,
>>                                   const struct pxa3xx_nand_platform_data *pdata)
>>  {
>> @@ -928,6 +1025,10 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info,
>>       uint32_t id = -1;
>>       int i;
>>
>> +     if (pdata->keep_config)
>> +             if (pxa3xx_nand_detect_config(info) == 0)
>> +                     return 0;
>> +
>>       for (i = 0; i<pdata->num_flash; ++i) {
>>               f = pdata->flash + i;
>>
>
> --
> Sincerely yours,
> Mike.
>
>
> -------------------------------------------------------------------
> List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
> FAQ:        http://www.arm.linux.org.uk/mailinglists/faq.php
> Etiquette:  http://www.arm.linux.org.uk/mailinglists/etiquette.php
>



-- 
Cheers
- eric



More information about the linux-mtd mailing list