diff mbox

[U-Boot,v1,08/18] MIPS: pic32: Add driver for Microchip PIC32 flash controller.

Message ID 5672F14B.8070006@microchip.com
State Superseded
Delegated to: Daniel Schwierzeck
Headers show

Commit Message

Purna Chandra Mandal Dec. 17, 2015, 5:30 p.m. UTC
From: Cristian Birsan <cristi.birsan@microchip.com>

Signed-off-by: Cristian Birsan <cristi.birsan@microchip.com>
Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com>
---

 arch/mips/mach-pic32/Makefile |   5 +-
 arch/mips/mach-pic32/flash.c  | 471 ++++++++++++++++++++++++++++++++++++++++++
 include/flash.h               |   5 +-
 3 files changed, 479 insertions(+), 2 deletions(-)
 create mode 100644 arch/mips/mach-pic32/flash.c

Comments

Daniel Schwierzeck Dec. 21, 2015, 2:58 p.m. UTC | #1
Am 17.12.2015 um 18:30 schrieb Purna Chandra Mandal:
> From: Cristian Birsan <cristi.birsan@microchip.com>
> 
> Signed-off-by: Cristian Birsan <cristi.birsan@microchip.com>
> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com>
> ---
> 
>  arch/mips/mach-pic32/Makefile |   5 +-
>  arch/mips/mach-pic32/flash.c  | 471 ++++++++++++++++++++++++++++++++++++++++++
>  include/flash.h               |   5 +-
>  3 files changed, 479 insertions(+), 2 deletions(-)
>  create mode 100644 arch/mips/mach-pic32/flash.c
> 

+cc Stefan Roese

have you tried to use drivers/mtd/cfi_flash.c? You are duplicating some
common code. If you need additional logic for your flash controller,
then you can try to overwrite the weak flash_readX/flash_writeX
accessors. You have to enable CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS to be
able to do this.

> diff --git a/arch/mips/mach-pic32/Makefile b/arch/mips/mach-pic32/Makefile
> index 03d5f27..3a621c3 100644
> --- a/arch/mips/mach-pic32/Makefile
> +++ b/arch/mips/mach-pic32/Makefile
> @@ -4,4 +4,7 @@
>  # SPDX-License-Identifier:      GPL-2.0+
>  #
>  
> -obj-y = cpu.o reset.o lowlevel_init.o
> \ No newline at end of file
> +obj-y = cpu.o reset.o lowlevel_init.o
> +ifndef CONFIG_SYS_NO_FLASH
> +obj-y += flash.o
> +endif
> \ No newline at end of file
> diff --git a/arch/mips/mach-pic32/flash.c b/arch/mips/mach-pic32/flash.c
> new file mode 100644
> index 0000000..b3c1e0a
> --- /dev/null
> +++ b/arch/mips/mach-pic32/flash.c
> @@ -0,0 +1,471 @@
> +/*
> + * Copyright (C) 2015
> + * Cristian Birsan <cristian.birsan@microchip.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + *
> + */
> +
> +#include <common.h>
> +#include <flash.h>
> +#include <asm/io.h>
> +#include <linux/byteorder/swab.h>
> +#include <asm/arch-pic32/pic32.h>
> +
> +#if defined(CONFIG_ENV_IS_IN_FLASH)
> +#ifndef CONFIG_ENV_ADDR
> +#define CONFIG_ENV_ADDR    (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
> +#endif
> +
> +#ifndef CONFIG_ENV_SIZE
> +#define CONFIG_ENV_SIZE    CONFIG_ENV_SECT_SIZE
> +#endif
> +
> +#ifndef CONFIG_ENV_SECT_SIZE
> +#define CONFIG_ENV_SECT_SIZE  CONFIG_ENV_SIZE
> +#endif
> +#endif
> +
> +/* NVM Controller registers */
> +#define NVMCON        (PIC32_NVM_BASE + 0x00)
> +#define NVMCONCLR    (NVMCON + _CLR_OFFSET)
> +#define NVMCONSET    (NVMCON + _SET_OFFSET)
> +#define NVMKEY        (PIC32_NVM_BASE + 0x10)
> +#define NVMADDR        (PIC32_NVM_BASE + 0x20)
> +#define NVMDATA0    (PIC32_NVM_BASE + 0x30)
> +
> +/* NVM Operations */
> +#define NVMOP_NOP        0x00000000
> +#define NVMOP_WORD_WRITE    0x00000001
> +#define NVMOP_PAGE_ERASE    0x00000004
> +
> +/* NVM Programming Control Register*/
> +#define NVMCON_WREN        0x00004000
> +#define NVMCON_WR        0x00008000
> +#define NVMCON_WRERR        0x00002000
> +#define NVMCON_LVDERR        0x00001000
> +
> +/*-----------------------------------------------------------------------
> + */
> +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
> +
> +/*
> + * The following code cannot be run from FLASH!
> + */
> +static ulong flash_get_size(vu_long *addr, flash_info_t *info)
> +{
> +    short i;
> +    ulong base = (ulong)addr;
> +    ulong sector_offset;
> +
> +    /* On chip flash ID */
> +    switch (info->flash_id & FLASH_VENDMASK) {
> +    case FLASH_MAN_MCHP:
> +        break;
> +    default:
> +        /* no or unknown flash    */
> +        printf("unknown manufacturer: 0x%lx\n",
> +               info->flash_id & FLASH_VENDMASK);
> +        info->flash_id = FLASH_UNKNOWN;
> +        info->sector_count = 0;
> +        info->size = 0;
> +        return 0;
> +    }
> +
> +    switch (info->flash_id & FLASH_TYPEMASK) {
> +    case FLASH_MCHP100T:
> +        info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
> +        info->size = CONFIG_SYS_FLASH_SIZE;
> +        sector_offset = info->size / info->sector_count;
> +        break;
> +    default:
> +        info->flash_id = FLASH_UNKNOWN;
> +        return 0;            /* => no or unknown flash */
> +    }
> +
> +    /* set up sector start address table */
> +    for (i = 0; i < info->sector_count; i++) {
> +        info->start[i] = base;
> +        base += sector_offset;
> +        /* protect each sector by default */
> +        info->protect[i] = 1;
> +    }
> +
> +    /* Disable Flash Write/Erase operations */
> +    writel(NVMCON_WREN, NVMCONCLR);
> +
> +    if (info->flash_id != FLASH_UNKNOWN)
> +        addr = (vu_long *)info->start[0];
> +
> +    return info->size;
> +}
> +
> +/*-----------------------------------------------------------------------
> + */
> +void flash_print_info(flash_info_t *info)
> +{
> +    int i;
> +
> +    if (info->flash_id == FLASH_UNKNOWN) {
> +        printf("missing or unknown FLASH type\n");
> +        return;
> +    }
> +
> +    switch (info->flash_id & FLASH_VENDMASK) {
> +    case FLASH_MAN_MCHP:
> +        printf("Microchip ");
> +        break;
> +    default:
> +        printf("Unknown Vendor ");
> +        break;
> +    }
> +
> +    switch (info->flash_id & FLASH_TYPEMASK) {
> +    case FLASH_MCHP100T:
> +        printf("Internal (8 Mbit, 64 x 16k)\n");
> +        break;
> +    default:
> +        printf("Unknown Chip Type\n");
> +        break;
> +    }
> +
> +    printf("  Size: %ld MB in %d Sectors\n",
> +           info->size >> 20, info->sector_count);
> +
> +    printf("  Sector Start Addresses:");
> +    for (i = 0; i < info->sector_count; ++i) {
> +        if ((i % 5) == 0)
> +            printf("\n   ");
> +
> +        printf(" %08lX%s", info->start[i],
> +               info->protect[i] ? " (RO)" : "     ");
> +    }
> +    printf("\n");
> +}
> +
> +static inline void flash_initiate_operation(void)
> +{
> +    /* Unlock sequence */
> +    writel(0x00000000, NVMKEY);
> +    writel(0xAA996655, NVMKEY);
> +    writel(0x556699AA, NVMKEY);
> +
> +    writel(NVMCON_WR, NVMCON);
> +}
> +
> +static inline void flash_nop_operation(void)
> +{
> +    /* reset error bits using a flash NOP command */
> +
> +    writel(NVMOP_NOP, NVMCON); /* NVMOP for page erase*/
> +    writel(NVMCON_WREN, NVMCONSET); /* Enable Flash Write*/
> +    flash_initiate_operation();
> +}
> +
> +int flash_erase(flash_info_t *info, int s_first, int s_last)
> +{
> +    int flag, prot, sect;
> +    ulong base, elapsed, last = 0, tmp, addr;
> +
> +    if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
> +        printf("Can't erase unknown flash type %08lx - aborted\n",
> +               info->flash_id);
> +        return ERR_UNKNOWN_FLASH_VENDOR;
> +    }
> +
> +    if ((s_first < 0) || (s_first > s_last)) {
> +        printf("- no sectors to erase\n");
> +        return ERR_INVAL;
> +    }
> +
> +    prot = 0;
> +    for (sect = s_first; sect <= s_last; ++sect) {
> +        if (info->protect[sect])
> +            prot++;
> +    }
> +
> +    if (prot)
> +        printf("- Warning: %d protected sectors will not be erased!\n",
> +               prot);
> +    else
> +        printf("\n");
> +
> +    base = get_timer(0);
> +
> +    /* Start erase on unprotected sectors */
> +    for (sect = s_first; sect <= s_last; sect++) {
> +        if (info->protect[sect]) /* skip protected sector */
> +            continue;
> +
> +        /* Disable interrupts which might cause timeout */
> +        flag = disable_interrupts();
> +
> +        /* destination page physical address */
> +        addr = virt_to_phys((void *)info->start[sect]);
> +        writel(addr, NVMADDR);
> +
> +        /* NVMOP for page erase*/
> +        writel(NVMOP_PAGE_ERASE, NVMCON);
> +        /* Enable Flash Write*/
> +        writel(NVMCON_WREN, NVMCONSET);
> +
> +        /* Initiate operation */
> +        flash_initiate_operation();
> +
> +        /* Wait for WR bit to clear */
> +        while (readl(NVMCON) & NVMCON_WR) {
> +            elapsed = get_timer(base);
> +            if (elapsed > CONFIG_SYS_FLASH_ERASE_TOUT) {
> +                printf("Timeout\n");
> +                /* reset bank */
> +                return ERR_TIMOUT;
> +            }
> +
> +            /* show that we're waiting */
> +            if ((elapsed - last) > 100) { /* every 100msec */
> +                putc('.');
> +                last = elapsed;
> +            }
> +        }
> +
> +        tmp = readl(NVMCON);
> +        if (tmp & NVMCON_WRERR) {
> +            printf("Error in Block Erase - Lock Bit may be set!\n");
> +            flash_nop_operation();
> +            return ERR_PROTECTED;
> +        }
> +
> +        if (tmp & NVMCON_LVDERR) {
> +            printf("Error in Block Erase - low-vol detected!\n");
> +            flash_nop_operation();
> +            return ERR_NOT_ERASED;
> +        }
> +
> +        /* Disable future Flash Write/Erase operations */
> +        writel(NVMCON_WREN, NVMCONCLR);
> +
> +        /* re-enable interrupts if necessary */
> +        if (flag)
> +            enable_interrupts();
> +    }
> +
> +    for (sect = s_first; sect <= s_last; sect++) {
> +        addr = info->start[sect];
> +        tmp = addr + (info->size / info->sector_count);
> +        invalidate_dcache_range(addr, tmp);
> +    }
> +
> +    printf(" done\n");
> +    return ERR_OK;
> +}
> +
> +int page_erase(flash_info_t *info, int sect)
> +{
> +    return 0;
> +}
> +
> +/*-----------------------------------------------------------------------
> + * Write a word to Flash, returns:
> + * 0 - OK
> + * 1 - write timeout
> + * 2 - Flash not erased
> + */
> +static int write_word(flash_info_t *info, ulong dest, ulong data)
> +{
> +    vu_long *addr = (vu_long *)dest;
> +    ulong base, elapsed, last = 0, tmp;
> +    int rc;
> +
> +    /* Check if Flash is (sufficiently) erased */
> +    if ((*addr & data) != data) {
> +        printf("Error, Flash not erased!\n");
> +        return ERR_NOT_ERASED;
> +    }
> +
> +    base = get_timer(0);
> +
> +    /* Disable interrupts which might cause a timeout here */
> +    rc = disable_interrupts();
> +
> +    /* destination page physical address*/
> +    writel(virt_to_phys(addr), NVMADDR);
> +    writel(data, NVMDATA0);
> +
> +    /* NVMOP for word write*/
> +    writel(NVMOP_WORD_WRITE, NVMCON);
> +
> +    /* Enable Flash Write*/
> +    writel(NVMCON_WREN, NVMCONSET);
> +
> +    /* Initiate operation */
> +    flash_initiate_operation();
> +
> +    /* re-enable interrupts if necessary */
> +    if (rc)
> +        enable_interrupts();
> +
> +    /* Wait for WR bit to clear */
> +    while (readl(NVMCON) & NVMCON_WR) {
> +        elapsed = get_timer(base);
> +        if (elapsed > CONFIG_SYS_FLASH_WRITE_TOUT) {
> +            printf("Timeout\n");
> +            /* reset bank */
> +            return ERR_TIMOUT;
> +        }
> +
> +        /* show that we're waiting */
> +        if ((elapsed - last) > 10) {    /* every 10msec */
> +            putc('.');
> +            last = elapsed;
> +        }
> +    }
> +
> +    rc = 0;
> +    tmp = readl(NVMCON);
> +    if (tmp & NVMCON_WRERR) {
> +        printf("Error in Block Write - Flash may be locked !\n");
> +        flash_nop_operation();
> +        rc |= ERR_PROG_ERROR;
> +    }
> +
> +    if (tmp & NVMCON_LVDERR) {
> +        printf("Error in Block Write - Brown out Reset detected!\n");
> +        flash_nop_operation();
> +        rc |= ERR_ABORTED;
> +    }
> +
> +    /* Disable future Flash Write/Erase operations */
> +    writel(NVMCON_WREN, NVMCONCLR);
> +
> +    return rc;
> +}
> +
> +/*-----------------------------------------------------------------------
> + * Copy memory to flash, returns:
> + * 0 - OK
> + * 1 - write timeout
> + * 2 - Flash not erased
> + */
> +
> +int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
> +{
> +    ulong cp, wp, data, n = cnt;
> +    int i, l, rc;
> +
> +    wp = (addr & ~3);    /* get lower word aligned address */
> +
> +    /*
> +     * handle unaligned start bytes
> +     */
> +    l = addr - wp;
> +    if (l != 0) {
> +        data = 0;
> +        for (i = 0, cp = wp; i < l; ++i, ++cp)
> +            data = (data << 8) | (*(uchar *)cp);
> +
> +        for (; (i < 4) && (cnt > 0); ++i) {
> +            data = (data << 8) | *src++;
> +            --cnt;
> +            ++cp;
> +        }
> +
> +        for (; (cnt == 0) && (i < 4); ++i, ++cp)
> +            data = (data << 8) | (*(uchar *)cp);
> +
> +        rc = write_word(info, wp, __swab32(data));
> +        if (rc)
> +            goto out;
> +
> +        wp += 4;
> +    }
> +
> +    /*
> +     * handle word aligned part
> +     */
> +    while (cnt >= 4) {
> +        data = 0;
> +        for (i = 0; i < 4; ++i)
> +            data = (data << 8) | *src++;
> +
> +        rc = write_word(info, wp, __swab32(data));
> +        if (rc)
> +            goto out;
> +
> +        wp  += 4;
> +        cnt -= 4;
> +    }
> +
> +    if (cnt == 0) {
> +        rc = ERR_OK;
> +        goto out;
> +    }
> +
> +    /*
> +     * handle unaligned tail bytes
> +     */
> +    data = 0;
> +    for (i = 0, cp = wp; (i < 4) && (cnt > 0); ++i, ++cp) {
> +        data = (data << 8) | *src++;
> +        --cnt;
> +    }
> +
> +    for (; i < 4; ++i, ++cp)
> +        data = (data << 8) | (*(uchar *)cp);
> +
> +    rc = write_word(info, wp,  __swab32(data));
> +
> +out:
> +    invalidate_dcache_range(addr, addr + n);
> +    return rc;
> +}
> +
> +unsigned long flash_init(void)
> +{
> +    unsigned long size;
> +    vu_long *addr;
> +    int i;
> +
> +    /* Init: enable write,
> +     * or we cannot even write flash commands
> +     */
> +
> +    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i)
> +        flash_info[i].flash_id = FLASH_UNKNOWN;
> +
> +    /* flash info: combined device & manufacturer code  */
> +    flash_info[0].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
> +    flash_info[1].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
> +
> +    /* Static FLASH Bank configuration here */
> +    addr = (vu_long *)phys_to_virt(PHYS_FLASH_1);
> +    flash_info[0].size = flash_get_size(addr, &flash_info[0]);
> +    size = flash_info[0].size;
> +
> +    addr = (vu_long *)phys_to_virt(PHYS_FLASH_2);
> +    flash_info[1].size = flash_get_size(addr, &flash_info[1]);
> +    size += flash_info[1].size;
> +
> +    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
> +        if (flash_info[i].flash_id == FLASH_UNKNOWN) {
> +            printf("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",
> +                   size);
> +        }
> +    }
> +
> +#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
> +    /* monitor protection ON by default */
> +    flash_protect(FLAG_PROTECT_SET,
> +              CONFIG_SYS_MONITOR_BASE,
> +              CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
> +              &flash_info[0]);
> +#endif
> +
> +#ifdef CONFIG_ENV_IS_IN_FLASH
> +    /* ENV protection ON by default */
> +    flash_protect(FLAG_PROTECT_SET,
> +              CONFIG_ENV_ADDR,
> +              CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
> +              &flash_info[0]);
> +#endif
> +    return size;
> +}
> diff --git a/include/flash.h b/include/flash.h
> index f53ace7..c9aacd5 100644
> --- a/include/flash.h
> +++ b/include/flash.h
> @@ -400,6 +400,9 @@ extern flash_info_t *flash_get_info(ulong base);
>  #define FLASH_STM800DT    0x00D7        /* STM M29W800DT (1M = 64K x 16, top)    */
>  #define FLASH_STM800DB    0x005B        /* STM M29W800DB (1M = 64K x 16, bottom)*/
>  
> +#define FLASH_MCHP100T    0x0060        /* MCHP internal (1M = 64K x 16) */
> +#define FLASH_MCHP100B    0x0061        /* MCHP internal (1M = 64K x 16) */
> +
>  #define FLASH_28F400_T    0x0062        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
>  #define FLASH_28F400_B    0x0063        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
>  
> @@ -486,7 +489,7 @@ extern flash_info_t *flash_get_info(ulong base);
>  #define FLASH_MAN_SHARP 0x00500000
>  #define FLASH_MAN_ATM    0x00600000
>  #define FLASH_MAN_CFI    0x01000000
> -
> +#define FLASH_MAN_MCHP    0x02000000    /* Microchip Technology        */
>  
>  #define FLASH_TYPEMASK    0x0000FFFF    /* extract FLASH type    information    */
>  #define FLASH_VENDMASK    0xFFFF0000    /* extract FLASH vendor information    */
>
Stefan Roese Dec. 21, 2015, 3:20 p.m. UTC | #2
On 21.12.2015 15:58, Daniel Schwierzeck wrote:
>
>
> Am 17.12.2015 um 18:30 schrieb Purna Chandra Mandal:
>> From: Cristian Birsan <cristi.birsan@microchip.com>
>>
>> Signed-off-by: Cristian Birsan <cristi.birsan@microchip.com>
>> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com>
>> ---
>>
>>   arch/mips/mach-pic32/Makefile |   5 +-
>>   arch/mips/mach-pic32/flash.c  | 471 ++++++++++++++++++++++++++++++++++++++++++
>>   include/flash.h               |   5 +-
>>   3 files changed, 479 insertions(+), 2 deletions(-)
>>   create mode 100644 arch/mips/mach-pic32/flash.c
>>
>
> +cc Stefan Roese
>
> have you tried to use drivers/mtd/cfi_flash.c? You are duplicating some
> common code. If you need additional logic for your flash controller,
> then you can try to overwrite the weak flash_readX/flash_writeX
> accessors. You have to enable CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS to be
> able to do this.

Yes, this really looks like it could use the common CFI flash driver.
You might need to add support for the new flash devices with the
commands, if its not already supported. But this should be better
than duplicating some of the code already available.

So please take a deeper look at cfi_flash.c and try to integrate
your flash support there.

Thanks,
Stefan

>> diff --git a/arch/mips/mach-pic32/Makefile b/arch/mips/mach-pic32/Makefile
>> index 03d5f27..3a621c3 100644
>> --- a/arch/mips/mach-pic32/Makefile
>> +++ b/arch/mips/mach-pic32/Makefile
>> @@ -4,4 +4,7 @@
>>   # SPDX-License-Identifier:      GPL-2.0+
>>   #
>>
>> -obj-y = cpu.o reset.o lowlevel_init.o
>> \ No newline at end of file
>> +obj-y = cpu.o reset.o lowlevel_init.o
>> +ifndef CONFIG_SYS_NO_FLASH
>> +obj-y += flash.o
>> +endif
>> \ No newline at end of file
>> diff --git a/arch/mips/mach-pic32/flash.c b/arch/mips/mach-pic32/flash.c
>> new file mode 100644
>> index 0000000..b3c1e0a
>> --- /dev/null
>> +++ b/arch/mips/mach-pic32/flash.c
>> @@ -0,0 +1,471 @@
>> +/*
>> + * Copyright (C) 2015
>> + * Cristian Birsan <cristian.birsan@microchip.com>
>> + *
>> + * SPDX-License-Identifier:    GPL-2.0+
>> + *
>> + */
>> +
>> +#include <common.h>
>> +#include <flash.h>
>> +#include <asm/io.h>
>> +#include <linux/byteorder/swab.h>
>> +#include <asm/arch-pic32/pic32.h>
>> +
>> +#if defined(CONFIG_ENV_IS_IN_FLASH)
>> +#ifndef CONFIG_ENV_ADDR
>> +#define CONFIG_ENV_ADDR    (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
>> +#endif
>> +
>> +#ifndef CONFIG_ENV_SIZE
>> +#define CONFIG_ENV_SIZE    CONFIG_ENV_SECT_SIZE
>> +#endif
>> +
>> +#ifndef CONFIG_ENV_SECT_SIZE
>> +#define CONFIG_ENV_SECT_SIZE  CONFIG_ENV_SIZE
>> +#endif
>> +#endif
>> +
>> +/* NVM Controller registers */
>> +#define NVMCON        (PIC32_NVM_BASE + 0x00)
>> +#define NVMCONCLR    (NVMCON + _CLR_OFFSET)
>> +#define NVMCONSET    (NVMCON + _SET_OFFSET)
>> +#define NVMKEY        (PIC32_NVM_BASE + 0x10)
>> +#define NVMADDR        (PIC32_NVM_BASE + 0x20)
>> +#define NVMDATA0    (PIC32_NVM_BASE + 0x30)
>> +
>> +/* NVM Operations */
>> +#define NVMOP_NOP        0x00000000
>> +#define NVMOP_WORD_WRITE    0x00000001
>> +#define NVMOP_PAGE_ERASE    0x00000004
>> +
>> +/* NVM Programming Control Register*/
>> +#define NVMCON_WREN        0x00004000
>> +#define NVMCON_WR        0x00008000
>> +#define NVMCON_WRERR        0x00002000
>> +#define NVMCON_LVDERR        0x00001000
>> +
>> +/*-----------------------------------------------------------------------
>> + */
>> +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
>> +
>> +/*
>> + * The following code cannot be run from FLASH!
>> + */
>> +static ulong flash_get_size(vu_long *addr, flash_info_t *info)
>> +{
>> +    short i;
>> +    ulong base = (ulong)addr;
>> +    ulong sector_offset;
>> +
>> +    /* On chip flash ID */
>> +    switch (info->flash_id & FLASH_VENDMASK) {
>> +    case FLASH_MAN_MCHP:
>> +        break;
>> +    default:
>> +        /* no or unknown flash    */
>> +        printf("unknown manufacturer: 0x%lx\n",
>> +               info->flash_id & FLASH_VENDMASK);
>> +        info->flash_id = FLASH_UNKNOWN;
>> +        info->sector_count = 0;
>> +        info->size = 0;
>> +        return 0;
>> +    }
>> +
>> +    switch (info->flash_id & FLASH_TYPEMASK) {
>> +    case FLASH_MCHP100T:
>> +        info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
>> +        info->size = CONFIG_SYS_FLASH_SIZE;
>> +        sector_offset = info->size / info->sector_count;
>> +        break;
>> +    default:
>> +        info->flash_id = FLASH_UNKNOWN;
>> +        return 0;            /* => no or unknown flash */
>> +    }
>> +
>> +    /* set up sector start address table */
>> +    for (i = 0; i < info->sector_count; i++) {
>> +        info->start[i] = base;
>> +        base += sector_offset;
>> +        /* protect each sector by default */
>> +        info->protect[i] = 1;
>> +    }
>> +
>> +    /* Disable Flash Write/Erase operations */
>> +    writel(NVMCON_WREN, NVMCONCLR);
>> +
>> +    if (info->flash_id != FLASH_UNKNOWN)
>> +        addr = (vu_long *)info->start[0];
>> +
>> +    return info->size;
>> +}
>> +
>> +/*-----------------------------------------------------------------------
>> + */
>> +void flash_print_info(flash_info_t *info)
>> +{
>> +    int i;
>> +
>> +    if (info->flash_id == FLASH_UNKNOWN) {
>> +        printf("missing or unknown FLASH type\n");
>> +        return;
>> +    }
>> +
>> +    switch (info->flash_id & FLASH_VENDMASK) {
>> +    case FLASH_MAN_MCHP:
>> +        printf("Microchip ");
>> +        break;
>> +    default:
>> +        printf("Unknown Vendor ");
>> +        break;
>> +    }
>> +
>> +    switch (info->flash_id & FLASH_TYPEMASK) {
>> +    case FLASH_MCHP100T:
>> +        printf("Internal (8 Mbit, 64 x 16k)\n");
>> +        break;
>> +    default:
>> +        printf("Unknown Chip Type\n");
>> +        break;
>> +    }
>> +
>> +    printf("  Size: %ld MB in %d Sectors\n",
>> +           info->size >> 20, info->sector_count);
>> +
>> +    printf("  Sector Start Addresses:");
>> +    for (i = 0; i < info->sector_count; ++i) {
>> +        if ((i % 5) == 0)
>> +            printf("\n   ");
>> +
>> +        printf(" %08lX%s", info->start[i],
>> +               info->protect[i] ? " (RO)" : "     ");
>> +    }
>> +    printf("\n");
>> +}
>> +
>> +static inline void flash_initiate_operation(void)
>> +{
>> +    /* Unlock sequence */
>> +    writel(0x00000000, NVMKEY);
>> +    writel(0xAA996655, NVMKEY);
>> +    writel(0x556699AA, NVMKEY);
>> +
>> +    writel(NVMCON_WR, NVMCON);
>> +}
>> +
>> +static inline void flash_nop_operation(void)
>> +{
>> +    /* reset error bits using a flash NOP command */
>> +
>> +    writel(NVMOP_NOP, NVMCON); /* NVMOP for page erase*/
>> +    writel(NVMCON_WREN, NVMCONSET); /* Enable Flash Write*/
>> +    flash_initiate_operation();
>> +}
>> +
>> +int flash_erase(flash_info_t *info, int s_first, int s_last)
>> +{
>> +    int flag, prot, sect;
>> +    ulong base, elapsed, last = 0, tmp, addr;
>> +
>> +    if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
>> +        printf("Can't erase unknown flash type %08lx - aborted\n",
>> +               info->flash_id);
>> +        return ERR_UNKNOWN_FLASH_VENDOR;
>> +    }
>> +
>> +    if ((s_first < 0) || (s_first > s_last)) {
>> +        printf("- no sectors to erase\n");
>> +        return ERR_INVAL;
>> +    }
>> +
>> +    prot = 0;
>> +    for (sect = s_first; sect <= s_last; ++sect) {
>> +        if (info->protect[sect])
>> +            prot++;
>> +    }
>> +
>> +    if (prot)
>> +        printf("- Warning: %d protected sectors will not be erased!\n",
>> +               prot);
>> +    else
>> +        printf("\n");
>> +
>> +    base = get_timer(0);
>> +
>> +    /* Start erase on unprotected sectors */
>> +    for (sect = s_first; sect <= s_last; sect++) {
>> +        if (info->protect[sect]) /* skip protected sector */
>> +            continue;
>> +
>> +        /* Disable interrupts which might cause timeout */
>> +        flag = disable_interrupts();
>> +
>> +        /* destination page physical address */
>> +        addr = virt_to_phys((void *)info->start[sect]);
>> +        writel(addr, NVMADDR);
>> +
>> +        /* NVMOP for page erase*/
>> +        writel(NVMOP_PAGE_ERASE, NVMCON);
>> +        /* Enable Flash Write*/
>> +        writel(NVMCON_WREN, NVMCONSET);
>> +
>> +        /* Initiate operation */
>> +        flash_initiate_operation();
>> +
>> +        /* Wait for WR bit to clear */
>> +        while (readl(NVMCON) & NVMCON_WR) {
>> +            elapsed = get_timer(base);
>> +            if (elapsed > CONFIG_SYS_FLASH_ERASE_TOUT) {
>> +                printf("Timeout\n");
>> +                /* reset bank */
>> +                return ERR_TIMOUT;
>> +            }
>> +
>> +            /* show that we're waiting */
>> +            if ((elapsed - last) > 100) { /* every 100msec */
>> +                putc('.');
>> +                last = elapsed;
>> +            }
>> +        }
>> +
>> +        tmp = readl(NVMCON);
>> +        if (tmp & NVMCON_WRERR) {
>> +            printf("Error in Block Erase - Lock Bit may be set!\n");
>> +            flash_nop_operation();
>> +            return ERR_PROTECTED;
>> +        }
>> +
>> +        if (tmp & NVMCON_LVDERR) {
>> +            printf("Error in Block Erase - low-vol detected!\n");
>> +            flash_nop_operation();
>> +            return ERR_NOT_ERASED;
>> +        }
>> +
>> +        /* Disable future Flash Write/Erase operations */
>> +        writel(NVMCON_WREN, NVMCONCLR);
>> +
>> +        /* re-enable interrupts if necessary */
>> +        if (flag)
>> +            enable_interrupts();
>> +    }
>> +
>> +    for (sect = s_first; sect <= s_last; sect++) {
>> +        addr = info->start[sect];
>> +        tmp = addr + (info->size / info->sector_count);
>> +        invalidate_dcache_range(addr, tmp);
>> +    }
>> +
>> +    printf(" done\n");
>> +    return ERR_OK;
>> +}
>> +
>> +int page_erase(flash_info_t *info, int sect)
>> +{
>> +    return 0;
>> +}
>> +
>> +/*-----------------------------------------------------------------------
>> + * Write a word to Flash, returns:
>> + * 0 - OK
>> + * 1 - write timeout
>> + * 2 - Flash not erased
>> + */
>> +static int write_word(flash_info_t *info, ulong dest, ulong data)
>> +{
>> +    vu_long *addr = (vu_long *)dest;
>> +    ulong base, elapsed, last = 0, tmp;
>> +    int rc;
>> +
>> +    /* Check if Flash is (sufficiently) erased */
>> +    if ((*addr & data) != data) {
>> +        printf("Error, Flash not erased!\n");
>> +        return ERR_NOT_ERASED;
>> +    }
>> +
>> +    base = get_timer(0);
>> +
>> +    /* Disable interrupts which might cause a timeout here */
>> +    rc = disable_interrupts();
>> +
>> +    /* destination page physical address*/
>> +    writel(virt_to_phys(addr), NVMADDR);
>> +    writel(data, NVMDATA0);
>> +
>> +    /* NVMOP for word write*/
>> +    writel(NVMOP_WORD_WRITE, NVMCON);
>> +
>> +    /* Enable Flash Write*/
>> +    writel(NVMCON_WREN, NVMCONSET);
>> +
>> +    /* Initiate operation */
>> +    flash_initiate_operation();
>> +
>> +    /* re-enable interrupts if necessary */
>> +    if (rc)
>> +        enable_interrupts();
>> +
>> +    /* Wait for WR bit to clear */
>> +    while (readl(NVMCON) & NVMCON_WR) {
>> +        elapsed = get_timer(base);
>> +        if (elapsed > CONFIG_SYS_FLASH_WRITE_TOUT) {
>> +            printf("Timeout\n");
>> +            /* reset bank */
>> +            return ERR_TIMOUT;
>> +        }
>> +
>> +        /* show that we're waiting */
>> +        if ((elapsed - last) > 10) {    /* every 10msec */
>> +            putc('.');
>> +            last = elapsed;
>> +        }
>> +    }
>> +
>> +    rc = 0;
>> +    tmp = readl(NVMCON);
>> +    if (tmp & NVMCON_WRERR) {
>> +        printf("Error in Block Write - Flash may be locked !\n");
>> +        flash_nop_operation();
>> +        rc |= ERR_PROG_ERROR;
>> +    }
>> +
>> +    if (tmp & NVMCON_LVDERR) {
>> +        printf("Error in Block Write - Brown out Reset detected!\n");
>> +        flash_nop_operation();
>> +        rc |= ERR_ABORTED;
>> +    }
>> +
>> +    /* Disable future Flash Write/Erase operations */
>> +    writel(NVMCON_WREN, NVMCONCLR);
>> +
>> +    return rc;
>> +}
>> +
>> +/*-----------------------------------------------------------------------
>> + * Copy memory to flash, returns:
>> + * 0 - OK
>> + * 1 - write timeout
>> + * 2 - Flash not erased
>> + */
>> +
>> +int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
>> +{
>> +    ulong cp, wp, data, n = cnt;
>> +    int i, l, rc;
>> +
>> +    wp = (addr & ~3);    /* get lower word aligned address */
>> +
>> +    /*
>> +     * handle unaligned start bytes
>> +     */
>> +    l = addr - wp;
>> +    if (l != 0) {
>> +        data = 0;
>> +        for (i = 0, cp = wp; i < l; ++i, ++cp)
>> +            data = (data << 8) | (*(uchar *)cp);
>> +
>> +        for (; (i < 4) && (cnt > 0); ++i) {
>> +            data = (data << 8) | *src++;
>> +            --cnt;
>> +            ++cp;
>> +        }
>> +
>> +        for (; (cnt == 0) && (i < 4); ++i, ++cp)
>> +            data = (data << 8) | (*(uchar *)cp);
>> +
>> +        rc = write_word(info, wp, __swab32(data));
>> +        if (rc)
>> +            goto out;
>> +
>> +        wp += 4;
>> +    }
>> +
>> +    /*
>> +     * handle word aligned part
>> +     */
>> +    while (cnt >= 4) {
>> +        data = 0;
>> +        for (i = 0; i < 4; ++i)
>> +            data = (data << 8) | *src++;
>> +
>> +        rc = write_word(info, wp, __swab32(data));
>> +        if (rc)
>> +            goto out;
>> +
>> +        wp  += 4;
>> +        cnt -= 4;
>> +    }
>> +
>> +    if (cnt == 0) {
>> +        rc = ERR_OK;
>> +        goto out;
>> +    }
>> +
>> +    /*
>> +     * handle unaligned tail bytes
>> +     */
>> +    data = 0;
>> +    for (i = 0, cp = wp; (i < 4) && (cnt > 0); ++i, ++cp) {
>> +        data = (data << 8) | *src++;
>> +        --cnt;
>> +    }
>> +
>> +    for (; i < 4; ++i, ++cp)
>> +        data = (data << 8) | (*(uchar *)cp);
>> +
>> +    rc = write_word(info, wp,  __swab32(data));
>> +
>> +out:
>> +    invalidate_dcache_range(addr, addr + n);
>> +    return rc;
>> +}
>> +
>> +unsigned long flash_init(void)
>> +{
>> +    unsigned long size;
>> +    vu_long *addr;
>> +    int i;
>> +
>> +    /* Init: enable write,
>> +     * or we cannot even write flash commands
>> +     */
>> +
>> +    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i)
>> +        flash_info[i].flash_id = FLASH_UNKNOWN;
>> +
>> +    /* flash info: combined device & manufacturer code  */
>> +    flash_info[0].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
>> +    flash_info[1].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
>> +
>> +    /* Static FLASH Bank configuration here */
>> +    addr = (vu_long *)phys_to_virt(PHYS_FLASH_1);
>> +    flash_info[0].size = flash_get_size(addr, &flash_info[0]);
>> +    size = flash_info[0].size;
>> +
>> +    addr = (vu_long *)phys_to_virt(PHYS_FLASH_2);
>> +    flash_info[1].size = flash_get_size(addr, &flash_info[1]);
>> +    size += flash_info[1].size;
>> +
>> +    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
>> +        if (flash_info[i].flash_id == FLASH_UNKNOWN) {
>> +            printf("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",
>> +                   size);
>> +        }
>> +    }
>> +
>> +#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
>> +    /* monitor protection ON by default */
>> +    flash_protect(FLAG_PROTECT_SET,
>> +              CONFIG_SYS_MONITOR_BASE,
>> +              CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
>> +              &flash_info[0]);
>> +#endif
>> +
>> +#ifdef CONFIG_ENV_IS_IN_FLASH
>> +    /* ENV protection ON by default */
>> +    flash_protect(FLAG_PROTECT_SET,
>> +              CONFIG_ENV_ADDR,
>> +              CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
>> +              &flash_info[0]);
>> +#endif
>> +    return size;
>> +}
>> diff --git a/include/flash.h b/include/flash.h
>> index f53ace7..c9aacd5 100644
>> --- a/include/flash.h
>> +++ b/include/flash.h
>> @@ -400,6 +400,9 @@ extern flash_info_t *flash_get_info(ulong base);
>>   #define FLASH_STM800DT    0x00D7        /* STM M29W800DT (1M = 64K x 16, top)    */
>>   #define FLASH_STM800DB    0x005B        /* STM M29W800DB (1M = 64K x 16, bottom)*/
>>
>> +#define FLASH_MCHP100T    0x0060        /* MCHP internal (1M = 64K x 16) */
>> +#define FLASH_MCHP100B    0x0061        /* MCHP internal (1M = 64K x 16) */
>> +
>>   #define FLASH_28F400_T    0x0062        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
>>   #define FLASH_28F400_B    0x0063        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
>>
>> @@ -486,7 +489,7 @@ extern flash_info_t *flash_get_info(ulong base);
>>   #define FLASH_MAN_SHARP 0x00500000
>>   #define FLASH_MAN_ATM    0x00600000
>>   #define FLASH_MAN_CFI    0x01000000
>> -
>> +#define FLASH_MAN_MCHP    0x02000000    /* Microchip Technology        */
>>
>>   #define FLASH_TYPEMASK    0x0000FFFF    /* extract FLASH type    information    */
>>   #define FLASH_VENDMASK    0xFFFF0000    /* extract FLASH vendor information    */
>>
>
Purna Chandra Mandal Jan. 8, 2016, 1:53 p.m. UTC | #3
On 12/21/2015 08:50 PM, Stefan Roese wrote:
> On 21.12.2015 15:58, Daniel Schwierzeck wrote:
>>
>>
>> Am 17.12.2015 um 18:30 schrieb Purna Chandra Mandal:
>>> From: Cristian Birsan <cristi.birsan@microchip.com>
>>>
>>> Signed-off-by: Cristian Birsan <cristi.birsan@microchip.com>
>>> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com>
>>> ---
>>>
>>>   arch/mips/mach-pic32/Makefile |   5 +-
>>>   arch/mips/mach-pic32/flash.c  | 471 ++++++++++++++++++++++++++++++++++++++++++
>>>   include/flash.h               |   5 +-
>>>   3 files changed, 479 insertions(+), 2 deletions(-)
>>>   create mode 100644 arch/mips/mach-pic32/flash.c
>>>
>>
>> +cc Stefan Roese
>>
>> have you tried to use drivers/mtd/cfi_flash.c? You are duplicating some
>> common code. If you need additional logic for your flash controller,
>> then you can try to overwrite the weak flash_readX/flash_writeX
>> accessors. You have to enable CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS to be
>> able to do this.
>
> Yes, this really looks like it could use the common CFI flash driver.
> You might need to add support for the new flash devices with the
> commands, if its not already supported. But this should be better
> than duplicating some of the code already available.
>
Thanks Stefan.

Tried to understand and map PIC32 flash driver on cfi_flash.c. It is not straight
forward and resultant code becomes clumsy, full of if-else.

Please note PIC32 flash is not CFI complaint. Specific operations
(like erase, and program) on the flash panel are handled by PIC32 nvm controller.
NVM controller documentation: http://ww1.microchip.com/downloads/en/DeviceDoc/60001193B.pdf

Instead I'll propose to improve current pic32_flash driver and move it to drivers/mtd/
(like st_smi.c).

NVM controller: 

Thanks,
Purna

> So please take a deeper look at cfi_flash.c and try to integrate
> your flash support there.
>
> Thanks,
> Stefan
>
>>> diff --git a/arch/mips/mach-pic32/Makefile b/arch/mips/mach-pic32/Makefile
>>> index 03d5f27..3a621c3 100644
>>> --- a/arch/mips/mach-pic32/Makefile
>>> +++ b/arch/mips/mach-pic32/Makefile
>>> @@ -4,4 +4,7 @@
>>>   # SPDX-License-Identifier:      GPL-2.0+
>>>   #
>>>
>>> -obj-y = cpu.o reset.o lowlevel_init.o
>>> \ No newline at end of file
>>> +obj-y = cpu.o reset.o lowlevel_init.o
>>> +ifndef CONFIG_SYS_NO_FLASH
>>> +obj-y += flash.o
>>> +endif
>>> \ No newline at end of file
>>> diff --git a/arch/mips/mach-pic32/flash.c b/arch/mips/mach-pic32/flash.c
>>> new file mode 100644
>>> index 0000000..b3c1e0a
>>> --- /dev/null
>>> +++ b/arch/mips/mach-pic32/flash.c
>>> @@ -0,0 +1,471 @@
>>> +/*
>>> + * Copyright (C) 2015
>>> + * Cristian Birsan <cristian.birsan@microchip.com>
>>> + *
>>> + * SPDX-License-Identifier:    GPL-2.0+
>>> + *
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <flash.h>
>>> +#include <asm/io.h>
>>> +#include <linux/byteorder/swab.h>
>>> +#include <asm/arch-pic32/pic32.h>
>>> +
>>> +#if defined(CONFIG_ENV_IS_IN_FLASH)
>>> +#ifndef CONFIG_ENV_ADDR
>>> +#define CONFIG_ENV_ADDR    (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
>>> +#endif
>>> +
>>> +#ifndef CONFIG_ENV_SIZE
>>> +#define CONFIG_ENV_SIZE    CONFIG_ENV_SECT_SIZE
>>> +#endif
>>> +
>>> +#ifndef CONFIG_ENV_SECT_SIZE
>>> +#define CONFIG_ENV_SECT_SIZE  CONFIG_ENV_SIZE
>>> +#endif
>>> +#endif
>>> +
>>> +/* NVM Controller registers */
>>> +#define NVMCON        (PIC32_NVM_BASE + 0x00)
>>> +#define NVMCONCLR    (NVMCON + _CLR_OFFSET)
>>> +#define NVMCONSET    (NVMCON + _SET_OFFSET)
>>> +#define NVMKEY        (PIC32_NVM_BASE + 0x10)
>>> +#define NVMADDR        (PIC32_NVM_BASE + 0x20)
>>> +#define NVMDATA0    (PIC32_NVM_BASE + 0x30)
>>> +
>>> +/* NVM Operations */
>>> +#define NVMOP_NOP        0x00000000
>>> +#define NVMOP_WORD_WRITE    0x00000001
>>> +#define NVMOP_PAGE_ERASE    0x00000004
>>> +
>>> +/* NVM Programming Control Register*/
>>> +#define NVMCON_WREN        0x00004000
>>> +#define NVMCON_WR        0x00008000
>>> +#define NVMCON_WRERR        0x00002000
>>> +#define NVMCON_LVDERR        0x00001000
>>> +
>>> +/*-----------------------------------------------------------------------
>>> + */
>>> +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
>>> +
>>> +/*
>>> + * The following code cannot be run from FLASH!
>>> + */
>>> +static ulong flash_get_size(vu_long *addr, flash_info_t *info)
>>> +{
>>> +    short i;
>>> +    ulong base = (ulong)addr;
>>> +    ulong sector_offset;
>>> +
>>> +    /* On chip flash ID */
>>> +    switch (info->flash_id & FLASH_VENDMASK) {
>>> +    case FLASH_MAN_MCHP:
>>> +        break;
>>> +    default:
>>> +        /* no or unknown flash    */
>>> +        printf("unknown manufacturer: 0x%lx\n",
>>> +               info->flash_id & FLASH_VENDMASK);
>>> +        info->flash_id = FLASH_UNKNOWN;
>>> +        info->sector_count = 0;
>>> +        info->size = 0;
>>> +        return 0;
>>> +    }
>>> +
>>> +    switch (info->flash_id & FLASH_TYPEMASK) {
>>> +    case FLASH_MCHP100T:
>>> +        info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
>>> +        info->size = CONFIG_SYS_FLASH_SIZE;
>>> +        sector_offset = info->size / info->sector_count;
>>> +        break;
>>> +    default:
>>> +        info->flash_id = FLASH_UNKNOWN;
>>> +        return 0;            /* => no or unknown flash */
>>> +    }
>>> +
>>> +    /* set up sector start address table */
>>> +    for (i = 0; i < info->sector_count; i++) {
>>> +        info->start[i] = base;
>>> +        base += sector_offset;
>>> +        /* protect each sector by default */
>>> +        info->protect[i] = 1;
>>> +    }
>>> +
>>> +    /* Disable Flash Write/Erase operations */
>>> +    writel(NVMCON_WREN, NVMCONCLR);
>>> +
>>> +    if (info->flash_id != FLASH_UNKNOWN)
>>> +        addr = (vu_long *)info->start[0];
>>> +
>>> +    return info->size;
>>> +}
>>> +
>>> +/*-----------------------------------------------------------------------
>>> + */
>>> +void flash_print_info(flash_info_t *info)
>>> +{
>>> +    int i;
>>> +
>>> +    if (info->flash_id == FLASH_UNKNOWN) {
>>> +        printf("missing or unknown FLASH type\n");
>>> +        return;
>>> +    }
>>> +
>>> +    switch (info->flash_id & FLASH_VENDMASK) {
>>> +    case FLASH_MAN_MCHP:
>>> +        printf("Microchip ");
>>> +        break;
>>> +    default:
>>> +        printf("Unknown Vendor ");
>>> +        break;
>>> +    }
>>> +
>>> +    switch (info->flash_id & FLASH_TYPEMASK) {
>>> +    case FLASH_MCHP100T:
>>> +        printf("Internal (8 Mbit, 64 x 16k)\n");
>>> +        break;
>>> +    default:
>>> +        printf("Unknown Chip Type\n");
>>> +        break;
>>> +    }
>>> +
>>> +    printf("  Size: %ld MB in %d Sectors\n",
>>> +           info->size >> 20, info->sector_count);
>>> +
>>> +    printf("  Sector Start Addresses:");
>>> +    for (i = 0; i < info->sector_count; ++i) {
>>> +        if ((i % 5) == 0)
>>> +            printf("\n   ");
>>> +
>>> +        printf(" %08lX%s", info->start[i],
>>> +               info->protect[i] ? " (RO)" : "     ");
>>> +    }
>>> +    printf("\n");
>>> +}
>>> +
>>> +static inline void flash_initiate_operation(void)
>>> +{
>>> +    /* Unlock sequence */
>>> +    writel(0x00000000, NVMKEY);
>>> +    writel(0xAA996655, NVMKEY);
>>> +    writel(0x556699AA, NVMKEY);
>>> +
>>> +    writel(NVMCON_WR, NVMCON);
>>> +}
>>> +
>>> +static inline void flash_nop_operation(void)
>>> +{
>>> +    /* reset error bits using a flash NOP command */
>>> +
>>> +    writel(NVMOP_NOP, NVMCON); /* NVMOP for page erase*/
>>> +    writel(NVMCON_WREN, NVMCONSET); /* Enable Flash Write*/
>>> +    flash_initiate_operation();
>>> +}
>>> +
>>> +int flash_erase(flash_info_t *info, int s_first, int s_last)
>>> +{
>>> +    int flag, prot, sect;
>>> +    ulong base, elapsed, last = 0, tmp, addr;
>>> +
>>> +    if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
>>> +        printf("Can't erase unknown flash type %08lx - aborted\n",
>>> +               info->flash_id);
>>> +        return ERR_UNKNOWN_FLASH_VENDOR;
>>> +    }
>>> +
>>> +    if ((s_first < 0) || (s_first > s_last)) {
>>> +        printf("- no sectors to erase\n");
>>> +        return ERR_INVAL;
>>> +    }
>>> +
>>> +    prot = 0;
>>> +    for (sect = s_first; sect <= s_last; ++sect) {
>>> +        if (info->protect[sect])
>>> +            prot++;
>>> +    }
>>> +
>>> +    if (prot)
>>> +        printf("- Warning: %d protected sectors will not be erased!\n",
>>> +               prot);
>>> +    else
>>> +        printf("\n");
>>> +
>>> +    base = get_timer(0);
>>> +
>>> +    /* Start erase on unprotected sectors */
>>> +    for (sect = s_first; sect <= s_last; sect++) {
>>> +        if (info->protect[sect]) /* skip protected sector */
>>> +            continue;
>>> +
>>> +        /* Disable interrupts which might cause timeout */
>>> +        flag = disable_interrupts();
>>> +
>>> +        /* destination page physical address */
>>> +        addr = virt_to_phys((void *)info->start[sect]);
>>> +        writel(addr, NVMADDR);
>>> +
>>> +        /* NVMOP for page erase*/
>>> +        writel(NVMOP_PAGE_ERASE, NVMCON);
>>> +        /* Enable Flash Write*/
>>> +        writel(NVMCON_WREN, NVMCONSET);
>>> +
>>> +        /* Initiate operation */
>>> +        flash_initiate_operation();
>>> +
>>> +        /* Wait for WR bit to clear */
>>> +        while (readl(NVMCON) & NVMCON_WR) {
>>> +            elapsed = get_timer(base);
>>> +            if (elapsed > CONFIG_SYS_FLASH_ERASE_TOUT) {
>>> +                printf("Timeout\n");
>>> +                /* reset bank */
>>> +                return ERR_TIMOUT;
>>> +            }
>>> +
>>> +            /* show that we're waiting */
>>> +            if ((elapsed - last) > 100) { /* every 100msec */
>>> +                putc('.');
>>> +                last = elapsed;
>>> +            }
>>> +        }
>>> +
>>> +        tmp = readl(NVMCON);
>>> +        if (tmp & NVMCON_WRERR) {
>>> +            printf("Error in Block Erase - Lock Bit may be set!\n");
>>> +            flash_nop_operation();
>>> +            return ERR_PROTECTED;
>>> +        }
>>> +
>>> +        if (tmp & NVMCON_LVDERR) {
>>> +            printf("Error in Block Erase - low-vol detected!\n");
>>> +            flash_nop_operation();
>>> +            return ERR_NOT_ERASED;
>>> +        }
>>> +
>>> +        /* Disable future Flash Write/Erase operations */
>>> +        writel(NVMCON_WREN, NVMCONCLR);
>>> +
>>> +        /* re-enable interrupts if necessary */
>>> +        if (flag)
>>> +            enable_interrupts();
>>> +    }
>>> +
>>> +    for (sect = s_first; sect <= s_last; sect++) {
>>> +        addr = info->start[sect];
>>> +        tmp = addr + (info->size / info->sector_count);
>>> +        invalidate_dcache_range(addr, tmp);
>>> +    }
>>> +
>>> +    printf(" done\n");
>>> +    return ERR_OK;
>>> +}
>>> +
>>> +int page_erase(flash_info_t *info, int sect)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +/*-----------------------------------------------------------------------
>>> + * Write a word to Flash, returns:
>>> + * 0 - OK
>>> + * 1 - write timeout
>>> + * 2 - Flash not erased
>>> + */
>>> +static int write_word(flash_info_t *info, ulong dest, ulong data)
>>> +{
>>> +    vu_long *addr = (vu_long *)dest;
>>> +    ulong base, elapsed, last = 0, tmp;
>>> +    int rc;
>>> +
>>> +    /* Check if Flash is (sufficiently) erased */
>>> +    if ((*addr & data) != data) {
>>> +        printf("Error, Flash not erased!\n");
>>> +        return ERR_NOT_ERASED;
>>> +    }
>>> +
>>> +    base = get_timer(0);
>>> +
>>> +    /* Disable interrupts which might cause a timeout here */
>>> +    rc = disable_interrupts();
>>> +
>>> +    /* destination page physical address*/
>>> +    writel(virt_to_phys(addr), NVMADDR);
>>> +    writel(data, NVMDATA0);
>>> +
>>> +    /* NVMOP for word write*/
>>> +    writel(NVMOP_WORD_WRITE, NVMCON);
>>> +
>>> +    /* Enable Flash Write*/
>>> +    writel(NVMCON_WREN, NVMCONSET);
>>> +
>>> +    /* Initiate operation */
>>> +    flash_initiate_operation();
>>> +
>>> +    /* re-enable interrupts if necessary */
>>> +    if (rc)
>>> +        enable_interrupts();
>>> +
>>> +    /* Wait for WR bit to clear */
>>> +    while (readl(NVMCON) & NVMCON_WR) {
>>> +        elapsed = get_timer(base);
>>> +        if (elapsed > CONFIG_SYS_FLASH_WRITE_TOUT) {
>>> +            printf("Timeout\n");
>>> +            /* reset bank */
>>> +            return ERR_TIMOUT;
>>> +        }
>>> +
>>> +        /* show that we're waiting */
>>> +        if ((elapsed - last) > 10) {    /* every 10msec */
>>> +            putc('.');
>>> +            last = elapsed;
>>> +        }
>>> +    }
>>> +
>>> +    rc = 0;
>>> +    tmp = readl(NVMCON);
>>> +    if (tmp & NVMCON_WRERR) {
>>> +        printf("Error in Block Write - Flash may be locked !\n");
>>> +        flash_nop_operation();
>>> +        rc |= ERR_PROG_ERROR;
>>> +    }
>>> +
>>> +    if (tmp & NVMCON_LVDERR) {
>>> +        printf("Error in Block Write - Brown out Reset detected!\n");
>>> +        flash_nop_operation();
>>> +        rc |= ERR_ABORTED;
>>> +    }
>>> +
>>> +    /* Disable future Flash Write/Erase operations */
>>> +    writel(NVMCON_WREN, NVMCONCLR);
>>> +
>>> +    return rc;
>>> +}
>>> +
>>> +/*-----------------------------------------------------------------------
>>> + * Copy memory to flash, returns:
>>> + * 0 - OK
>>> + * 1 - write timeout
>>> + * 2 - Flash not erased
>>> + */
>>> +
>>> +int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
>>> +{
>>> +    ulong cp, wp, data, n = cnt;
>>> +    int i, l, rc;
>>> +
>>> +    wp = (addr & ~3);    /* get lower word aligned address */
>>> +
>>> +    /*
>>> +     * handle unaligned start bytes
>>> +     */
>>> +    l = addr - wp;
>>> +    if (l != 0) {
>>> +        data = 0;
>>> +        for (i = 0, cp = wp; i < l; ++i, ++cp)
>>> +            data = (data << 8) | (*(uchar *)cp);
>>> +
>>> +        for (; (i < 4) && (cnt > 0); ++i) {
>>> +            data = (data << 8) | *src++;
>>> +            --cnt;
>>> +            ++cp;
>>> +        }
>>> +
>>> +        for (; (cnt == 0) && (i < 4); ++i, ++cp)
>>> +            data = (data << 8) | (*(uchar *)cp);
>>> +
>>> +        rc = write_word(info, wp, __swab32(data));
>>> +        if (rc)
>>> +            goto out;
>>> +
>>> +        wp += 4;
>>> +    }
>>> +
>>> +    /*
>>> +     * handle word aligned part
>>> +     */
>>> +    while (cnt >= 4) {
>>> +        data = 0;
>>> +        for (i = 0; i < 4; ++i)
>>> +            data = (data << 8) | *src++;
>>> +
>>> +        rc = write_word(info, wp, __swab32(data));
>>> +        if (rc)
>>> +            goto out;
>>> +
>>> +        wp  += 4;
>>> +        cnt -= 4;
>>> +    }
>>> +
>>> +    if (cnt == 0) {
>>> +        rc = ERR_OK;
>>> +        goto out;
>>> +    }
>>> +
>>> +    /*
>>> +     * handle unaligned tail bytes
>>> +     */
>>> +    data = 0;
>>> +    for (i = 0, cp = wp; (i < 4) && (cnt > 0); ++i, ++cp) {
>>> +        data = (data << 8) | *src++;
>>> +        --cnt;
>>> +    }
>>> +
>>> +    for (; i < 4; ++i, ++cp)
>>> +        data = (data << 8) | (*(uchar *)cp);
>>> +
>>> +    rc = write_word(info, wp,  __swab32(data));
>>> +
>>> +out:
>>> +    invalidate_dcache_range(addr, addr + n);
>>> +    return rc;
>>> +}
>>> +
>>> +unsigned long flash_init(void)
>>> +{
>>> +    unsigned long size;
>>> +    vu_long *addr;
>>> +    int i;
>>> +
>>> +    /* Init: enable write,
>>> +     * or we cannot even write flash commands
>>> +     */
>>> +
>>> +    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i)
>>> +        flash_info[i].flash_id = FLASH_UNKNOWN;
>>> +
>>> +    /* flash info: combined device & manufacturer code  */
>>> +    flash_info[0].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
>>> +    flash_info[1].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
>>> +
>>> +    /* Static FLASH Bank configuration here */
>>> +    addr = (vu_long *)phys_to_virt(PHYS_FLASH_1);
>>> +    flash_info[0].size = flash_get_size(addr, &flash_info[0]);
>>> +    size = flash_info[0].size;
>>> +
>>> +    addr = (vu_long *)phys_to_virt(PHYS_FLASH_2);
>>> +    flash_info[1].size = flash_get_size(addr, &flash_info[1]);
>>> +    size += flash_info[1].size;
>>> +
>>> +    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
>>> +        if (flash_info[i].flash_id == FLASH_UNKNOWN) {
>>> +            printf("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",
>>> +                   size);
>>> +        }
>>> +    }
>>> +
>>> +#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
>>> +    /* monitor protection ON by default */
>>> +    flash_protect(FLAG_PROTECT_SET,
>>> +              CONFIG_SYS_MONITOR_BASE,
>>> +              CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
>>> +              &flash_info[0]);
>>> +#endif
>>> +
>>> +#ifdef CONFIG_ENV_IS_IN_FLASH
>>> +    /* ENV protection ON by default */
>>> +    flash_protect(FLAG_PROTECT_SET,
>>> +              CONFIG_ENV_ADDR,
>>> +              CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
>>> +              &flash_info[0]);
>>> +#endif
>>> +    return size;
>>> +}
>>> diff --git a/include/flash.h b/include/flash.h
>>> index f53ace7..c9aacd5 100644
>>> --- a/include/flash.h
>>> +++ b/include/flash.h
>>> @@ -400,6 +400,9 @@ extern flash_info_t *flash_get_info(ulong base);
>>>   #define FLASH_STM800DT    0x00D7        /* STM M29W800DT (1M = 64K x 16, top)    */
>>>   #define FLASH_STM800DB    0x005B        /* STM M29W800DB (1M = 64K x 16, bottom)*/
>>>
>>> +#define FLASH_MCHP100T    0x0060        /* MCHP internal (1M = 64K x 16) */
>>> +#define FLASH_MCHP100B    0x0061        /* MCHP internal (1M = 64K x 16) */
>>> +
>>>   #define FLASH_28F400_T    0x0062        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
>>>   #define FLASH_28F400_B    0x0063        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
>>>
>>> @@ -486,7 +489,7 @@ extern flash_info_t *flash_get_info(ulong base);
>>>   #define FLASH_MAN_SHARP 0x00500000
>>>   #define FLASH_MAN_ATM    0x00600000
>>>   #define FLASH_MAN_CFI    0x01000000
>>> -
>>> +#define FLASH_MAN_MCHP    0x02000000    /* Microchip Technology        */
>>>
>>>   #define FLASH_TYPEMASK    0x0000FFFF    /* extract FLASH type    information    */
>>>   #define FLASH_VENDMASK    0xFFFF0000    /* extract FLASH vendor information    */
>>>
>>
>
>
Stefan Roese Jan. 8, 2016, 2:11 p.m. UTC | #4
On 08.01.2016 14:53, Purna Chandra Mandal wrote:
> On 12/21/2015 08:50 PM, Stefan Roese wrote:
>> On 21.12.2015 15:58, Daniel Schwierzeck wrote:
>>>
>>>
>>> Am 17.12.2015 um 18:30 schrieb Purna Chandra Mandal:
>>>> From: Cristian Birsan <cristi.birsan@microchip.com>
>>>>
>>>> Signed-off-by: Cristian Birsan <cristi.birsan@microchip.com>
>>>> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com>
>>>> ---
>>>>
>>>>    arch/mips/mach-pic32/Makefile |   5 +-
>>>>    arch/mips/mach-pic32/flash.c  | 471 ++++++++++++++++++++++++++++++++++++++++++
>>>>    include/flash.h               |   5 +-
>>>>    3 files changed, 479 insertions(+), 2 deletions(-)
>>>>    create mode 100644 arch/mips/mach-pic32/flash.c
>>>>
>>>
>>> +cc Stefan Roese
>>>
>>> have you tried to use drivers/mtd/cfi_flash.c? You are duplicating some
>>> common code. If you need additional logic for your flash controller,
>>> then you can try to overwrite the weak flash_readX/flash_writeX
>>> accessors. You have to enable CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS to be
>>> able to do this.
>>
>> Yes, this really looks like it could use the common CFI flash driver.
>> You might need to add support for the new flash devices with the
>> commands, if its not already supported. But this should be better
>> than duplicating some of the code already available.
>>
> Thanks Stefan.
>
> Tried to understand and map PIC32 flash driver on cfi_flash.c. It is not straight
> forward and resultant code becomes clumsy, full of if-else.

Ughh. Thats definitely not something that we strive for.

> Please note PIC32 flash is not CFI complaint. Specific operations
> (like erase, and program) on the flash panel are handled by PIC32 nvm controller.
> NVM controller documentation: http://ww1.microchip.com/downloads/en/DeviceDoc/60001193B.pdf
>
> Instead I'll propose to improve current pic32_flash driver and move it to drivers/mtd/
> (like st_smi.c).

Okay. Then please continue with this approach and lets see,
how the resulting code will be structured.

Thanks,
Stefan
diff mbox

Patch

diff --git a/arch/mips/mach-pic32/Makefile b/arch/mips/mach-pic32/Makefile
index 03d5f27..3a621c3 100644
--- a/arch/mips/mach-pic32/Makefile
+++ b/arch/mips/mach-pic32/Makefile
@@ -4,4 +4,7 @@ 
 # SPDX-License-Identifier:      GPL-2.0+
 #
 
-obj-y = cpu.o reset.o lowlevel_init.o
\ No newline at end of file
+obj-y = cpu.o reset.o lowlevel_init.o
+ifndef CONFIG_SYS_NO_FLASH
+obj-y += flash.o
+endif
\ No newline at end of file
diff --git a/arch/mips/mach-pic32/flash.c b/arch/mips/mach-pic32/flash.c
new file mode 100644
index 0000000..b3c1e0a
--- /dev/null
+++ b/arch/mips/mach-pic32/flash.c
@@ -0,0 +1,471 @@ 
+/*
+ * Copyright (C) 2015
+ * Cristian Birsan <cristian.birsan@microchip.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ */
+
+#include <common.h>
+#include <flash.h>
+#include <asm/io.h>
+#include <linux/byteorder/swab.h>
+#include <asm/arch-pic32/pic32.h>
+
+#if defined(CONFIG_ENV_IS_IN_FLASH)
+#ifndef CONFIG_ENV_ADDR
+#define CONFIG_ENV_ADDR    (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
+#endif
+
+#ifndef CONFIG_ENV_SIZE
+#define CONFIG_ENV_SIZE    CONFIG_ENV_SECT_SIZE
+#endif
+
+#ifndef CONFIG_ENV_SECT_SIZE
+#define CONFIG_ENV_SECT_SIZE  CONFIG_ENV_SIZE
+#endif
+#endif
+
+/* NVM Controller registers */
+#define NVMCON        (PIC32_NVM_BASE + 0x00)
+#define NVMCONCLR    (NVMCON + _CLR_OFFSET)
+#define NVMCONSET    (NVMCON + _SET_OFFSET)
+#define NVMKEY        (PIC32_NVM_BASE + 0x10)
+#define NVMADDR        (PIC32_NVM_BASE + 0x20)
+#define NVMDATA0    (PIC32_NVM_BASE + 0x30)
+
+/* NVM Operations */
+#define NVMOP_NOP        0x00000000
+#define NVMOP_WORD_WRITE    0x00000001
+#define NVMOP_PAGE_ERASE    0x00000004
+
+/* NVM Programming Control Register*/
+#define NVMCON_WREN        0x00004000
+#define NVMCON_WR        0x00008000
+#define NVMCON_WRERR        0x00002000
+#define NVMCON_LVDERR        0x00001000
+
+/*-----------------------------------------------------------------------
+ */
+flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size(vu_long *addr, flash_info_t *info)
+{
+    short i;
+    ulong base = (ulong)addr;
+    ulong sector_offset;
+
+    /* On chip flash ID */
+    switch (info->flash_id & FLASH_VENDMASK) {
+    case FLASH_MAN_MCHP:
+        break;
+    default:
+        /* no or unknown flash    */
+        printf("unknown manufacturer: 0x%lx\n",
+               info->flash_id & FLASH_VENDMASK);
+        info->flash_id = FLASH_UNKNOWN;
+        info->sector_count = 0;
+        info->size = 0;
+        return 0;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case FLASH_MCHP100T:
+        info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
+        info->size = CONFIG_SYS_FLASH_SIZE;
+        sector_offset = info->size / info->sector_count;
+        break;
+    default:
+        info->flash_id = FLASH_UNKNOWN;
+        return 0;            /* => no or unknown flash */
+    }
+
+    /* set up sector start address table */
+    for (i = 0; i < info->sector_count; i++) {
+        info->start[i] = base;
+        base += sector_offset;
+        /* protect each sector by default */
+        info->protect[i] = 1;
+    }
+
+    /* Disable Flash Write/Erase operations */
+    writel(NVMCON_WREN, NVMCONCLR);
+
+    if (info->flash_id != FLASH_UNKNOWN)
+        addr = (vu_long *)info->start[0];
+
+    return info->size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info(flash_info_t *info)
+{
+    int i;
+
+    if (info->flash_id == FLASH_UNKNOWN) {
+        printf("missing or unknown FLASH type\n");
+        return;
+    }
+
+    switch (info->flash_id & FLASH_VENDMASK) {
+    case FLASH_MAN_MCHP:
+        printf("Microchip ");
+        break;
+    default:
+        printf("Unknown Vendor ");
+        break;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case FLASH_MCHP100T:
+        printf("Internal (8 Mbit, 64 x 16k)\n");
+        break;
+    default:
+        printf("Unknown Chip Type\n");
+        break;
+    }
+
+    printf("  Size: %ld MB in %d Sectors\n",
+           info->size >> 20, info->sector_count);
+
+    printf("  Sector Start Addresses:");
+    for (i = 0; i < info->sector_count; ++i) {
+        if ((i % 5) == 0)
+            printf("\n   ");
+
+        printf(" %08lX%s", info->start[i],
+               info->protect[i] ? " (RO)" : "     ");
+    }
+    printf("\n");
+}
+
+static inline void flash_initiate_operation(void)
+{
+    /* Unlock sequence */
+    writel(0x00000000, NVMKEY);
+    writel(0xAA996655, NVMKEY);
+    writel(0x556699AA, NVMKEY);
+
+    writel(NVMCON_WR, NVMCON);
+}
+
+static inline void flash_nop_operation(void)
+{
+    /* reset error bits using a flash NOP command */
+
+    writel(NVMOP_NOP, NVMCON); /* NVMOP for page erase*/
+    writel(NVMCON_WREN, NVMCONSET); /* Enable Flash Write*/
+    flash_initiate_operation();
+}
+
+int flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+    int flag, prot, sect;
+    ulong base, elapsed, last = 0, tmp, addr;
+
+    if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
+        printf("Can't erase unknown flash type %08lx - aborted\n",
+               info->flash_id);
+        return ERR_UNKNOWN_FLASH_VENDOR;
+    }
+
+    if ((s_first < 0) || (s_first > s_last)) {
+        printf("- no sectors to erase\n");
+        return ERR_INVAL;
+    }
+
+    prot = 0;
+    for (sect = s_first; sect <= s_last; ++sect) {
+        if (info->protect[sect])
+            prot++;
+    }
+
+    if (prot)
+        printf("- Warning: %d protected sectors will not be erased!\n",
+               prot);
+    else
+        printf("\n");
+
+    base = get_timer(0);
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect <= s_last; sect++) {
+        if (info->protect[sect]) /* skip protected sector */
+            continue;
+
+        /* Disable interrupts which might cause timeout */
+        flag = disable_interrupts();
+
+        /* destination page physical address */
+        addr = virt_to_phys((void *)info->start[sect]);
+        writel(addr, NVMADDR);
+
+        /* NVMOP for page erase*/
+        writel(NVMOP_PAGE_ERASE, NVMCON);
+        /* Enable Flash Write*/
+        writel(NVMCON_WREN, NVMCONSET);
+
+        /* Initiate operation */
+        flash_initiate_operation();
+
+        /* Wait for WR bit to clear */
+        while (readl(NVMCON) & NVMCON_WR) {
+            elapsed = get_timer(base);
+            if (elapsed > CONFIG_SYS_FLASH_ERASE_TOUT) {
+                printf("Timeout\n");
+                /* reset bank */
+                return ERR_TIMOUT;
+            }
+
+            /* show that we're waiting */
+            if ((elapsed - last) > 100) { /* every 100msec */
+                putc('.');
+                last = elapsed;
+            }
+        }
+
+        tmp = readl(NVMCON);
+        if (tmp & NVMCON_WRERR) {
+            printf("Error in Block Erase - Lock Bit may be set!\n");
+            flash_nop_operation();
+            return ERR_PROTECTED;
+        }
+
+        if (tmp & NVMCON_LVDERR) {
+            printf("Error in Block Erase - low-vol detected!\n");
+            flash_nop_operation();
+            return ERR_NOT_ERASED;
+        }
+
+        /* Disable future Flash Write/Erase operations */
+        writel(NVMCON_WREN, NVMCONCLR);
+
+        /* re-enable interrupts if necessary */
+        if (flag)
+            enable_interrupts();
+    }
+
+    for (sect = s_first; sect <= s_last; sect++) {
+        addr = info->start[sect];
+        tmp = addr + (info->size / info->sector_count);
+        invalidate_dcache_range(addr, tmp);
+    }
+
+    printf(" done\n");
+    return ERR_OK;
+}
+
+int page_erase(flash_info_t *info, int sect)
+{
+    return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word(flash_info_t *info, ulong dest, ulong data)
+{
+    vu_long *addr = (vu_long *)dest;
+    ulong base, elapsed, last = 0, tmp;
+    int rc;
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*addr & data) != data) {
+        printf("Error, Flash not erased!\n");
+        return ERR_NOT_ERASED;
+    }
+
+    base = get_timer(0);
+
+    /* Disable interrupts which might cause a timeout here */
+    rc = disable_interrupts();
+
+    /* destination page physical address*/
+    writel(virt_to_phys(addr), NVMADDR);
+    writel(data, NVMDATA0);
+
+    /* NVMOP for word write*/
+    writel(NVMOP_WORD_WRITE, NVMCON);
+
+    /* Enable Flash Write*/
+    writel(NVMCON_WREN, NVMCONSET);
+
+    /* Initiate operation */
+    flash_initiate_operation();
+
+    /* re-enable interrupts if necessary */
+    if (rc)
+        enable_interrupts();
+
+    /* Wait for WR bit to clear */
+    while (readl(NVMCON) & NVMCON_WR) {
+        elapsed = get_timer(base);
+        if (elapsed > CONFIG_SYS_FLASH_WRITE_TOUT) {
+            printf("Timeout\n");
+            /* reset bank */
+            return ERR_TIMOUT;
+        }
+
+        /* show that we're waiting */
+        if ((elapsed - last) > 10) {    /* every 10msec */
+            putc('.');
+            last = elapsed;
+        }
+    }
+
+    rc = 0;
+    tmp = readl(NVMCON);
+    if (tmp & NVMCON_WRERR) {
+        printf("Error in Block Write - Flash may be locked !\n");
+        flash_nop_operation();
+        rc |= ERR_PROG_ERROR;
+    }
+
+    if (tmp & NVMCON_LVDERR) {
+        printf("Error in Block Write - Brown out Reset detected!\n");
+        flash_nop_operation();
+        rc |= ERR_ABORTED;
+    }
+
+    /* Disable future Flash Write/Erase operations */
+    writel(NVMCON_WREN, NVMCONCLR);
+
+    return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong cp, wp, data, n = cnt;
+    int i, l, rc;
+
+    wp = (addr & ~3);    /* get lower word aligned address */
+
+    /*
+     * handle unaligned start bytes
+     */
+    l = addr - wp;
+    if (l != 0) {
+        data = 0;
+        for (i = 0, cp = wp; i < l; ++i, ++cp)
+            data = (data << 8) | (*(uchar *)cp);
+
+        for (; (i < 4) && (cnt > 0); ++i) {
+            data = (data << 8) | *src++;
+            --cnt;
+            ++cp;
+        }
+
+        for (; (cnt == 0) && (i < 4); ++i, ++cp)
+            data = (data << 8) | (*(uchar *)cp);
+
+        rc = write_word(info, wp, __swab32(data));
+        if (rc)
+            goto out;
+
+        wp += 4;
+    }
+
+    /*
+     * handle word aligned part
+     */
+    while (cnt >= 4) {
+        data = 0;
+        for (i = 0; i < 4; ++i)
+            data = (data << 8) | *src++;
+
+        rc = write_word(info, wp, __swab32(data));
+        if (rc)
+            goto out;
+
+        wp  += 4;
+        cnt -= 4;
+    }
+
+    if (cnt == 0) {
+        rc = ERR_OK;
+        goto out;
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    data = 0;
+    for (i = 0, cp = wp; (i < 4) && (cnt > 0); ++i, ++cp) {
+        data = (data << 8) | *src++;
+        --cnt;
+    }
+
+    for (; i < 4; ++i, ++cp)
+        data = (data << 8) | (*(uchar *)cp);
+
+    rc = write_word(info, wp,  __swab32(data));
+
+out:
+    invalidate_dcache_range(addr, addr + n);
+    return rc;
+}
+
+unsigned long flash_init(void)
+{
+    unsigned long size;
+    vu_long *addr;
+    int i;
+
+    /* Init: enable write,
+     * or we cannot even write flash commands
+     */
+
+    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i)
+        flash_info[i].flash_id = FLASH_UNKNOWN;
+
+    /* flash info: combined device & manufacturer code  */
+    flash_info[0].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
+    flash_info[1].flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
+
+    /* Static FLASH Bank configuration here */
+    addr = (vu_long *)phys_to_virt(PHYS_FLASH_1);
+    flash_info[0].size = flash_get_size(addr, &flash_info[0]);
+    size = flash_info[0].size;
+
+    addr = (vu_long *)phys_to_virt(PHYS_FLASH_2);
+    flash_info[1].size = flash_get_size(addr, &flash_info[1]);
+    size += flash_info[1].size;
+
+    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
+        if (flash_info[i].flash_id == FLASH_UNKNOWN) {
+            printf("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",
+                   size);
+        }
+    }
+
+#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
+    /* monitor protection ON by default */
+    flash_protect(FLAG_PROTECT_SET,
+              CONFIG_SYS_MONITOR_BASE,
+              CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
+              &flash_info[0]);
+#endif
+
+#ifdef CONFIG_ENV_IS_IN_FLASH
+    /* ENV protection ON by default */
+    flash_protect(FLAG_PROTECT_SET,
+              CONFIG_ENV_ADDR,
+              CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
+              &flash_info[0]);
+#endif
+    return size;
+}
diff --git a/include/flash.h b/include/flash.h
index f53ace7..c9aacd5 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -400,6 +400,9 @@  extern flash_info_t *flash_get_info(ulong base);
 #define FLASH_STM800DT    0x00D7        /* STM M29W800DT (1M = 64K x 16, top)    */
 #define FLASH_STM800DB    0x005B        /* STM M29W800DB (1M = 64K x 16, bottom)*/
 
+#define FLASH_MCHP100T    0x0060        /* MCHP internal (1M = 64K x 16) */
+#define FLASH_MCHP100B    0x0061        /* MCHP internal (1M = 64K x 16) */
+
 #define FLASH_28F400_T    0x0062        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
 #define FLASH_28F400_B    0x0063        /* MT  28F400B3 ID (  4M = 256K x 16 )    */
 
@@ -486,7 +489,7 @@  extern flash_info_t *flash_get_info(ulong base);
 #define FLASH_MAN_SHARP 0x00500000
 #define FLASH_MAN_ATM    0x00600000
 #define FLASH_MAN_CFI    0x01000000
-
+#define FLASH_MAN_MCHP    0x02000000    /* Microchip Technology        */
 
 #define FLASH_TYPEMASK    0x0000FFFF    /* extract FLASH type    information    */
 #define FLASH_VENDMASK    0xFFFF0000    /* extract FLASH vendor information    */