public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Stefan Roese <sr@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v1 08/18] MIPS: pic32: Add driver for Microchip PIC32 flash controller.
Date: Mon, 21 Dec 2015 16:20:55 +0100	[thread overview]
Message-ID: <567818D7.6090602@denx.de> (raw)
In-Reply-To: <567813A8.3050706@gmail.com>

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    */
>>
>


-- 
Viele Gr??e,
Stefan

--
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de

  reply	other threads:[~2015-12-21 15:20 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-17 17:30 [U-Boot] [PATCH v1 08/18] MIPS: pic32: Add driver for Microchip PIC32 flash controller Purna Chandra Mandal
2015-12-21 14:58 ` Daniel Schwierzeck
2015-12-21 15:20   ` Stefan Roese [this message]
2016-01-08 13:53     ` Purna Chandra Mandal
2016-01-08 14:11       ` Stefan Roese

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=567818D7.6090602@denx.de \
    --to=sr@denx.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox