[U-Boot] [PATCH v1 08/18] MIPS: pic32: Add driver for Microchip PIC32 flash controller.
Stefan Roese
sr at denx.de
Mon Dec 21 16:20:55 CET 2015
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 at microchip.com>
>>
>> Signed-off-by: Cristian Birsan <cristi.birsan at microchip.com>
>> Signed-off-by: Purna Chandra Mandal <purna.mandal at 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 at 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
More information about the U-Boot
mailing list