uboot/drivers/mtd/pic32_flash.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2015
   4 * Cristian Birsan <cristian.birsan@microchip.com>
   5 * Purna Chandra Mandal <purna.mandal@microchip.com>
   6 */
   7
   8#include <common.h>
   9#include <cpu_func.h>
  10#include <dm.h>
  11#include <fdt_support.h>
  12#include <flash.h>
  13#include <init.h>
  14#include <irq_func.h>
  15#include <asm/global_data.h>
  16#include <linux/bitops.h>
  17#include <mach/pic32.h>
  18#include <wait_bit.h>
  19
  20DECLARE_GLOBAL_DATA_PTR;
  21
  22/* NVM Controller registers */
  23struct pic32_reg_nvm {
  24        struct pic32_reg_atomic ctrl;
  25        struct pic32_reg_atomic key;
  26        struct pic32_reg_atomic addr;
  27        struct pic32_reg_atomic data;
  28};
  29
  30/* NVM operations */
  31#define NVMOP_NOP               0
  32#define NVMOP_WORD_WRITE        1
  33#define NVMOP_PAGE_ERASE        4
  34
  35/* NVM control bits */
  36#define NVM_WR                  BIT(15)
  37#define NVM_WREN                BIT(14)
  38#define NVM_WRERR               BIT(13)
  39#define NVM_LVDERR              BIT(12)
  40
  41/* NVM programming unlock register */
  42#define LOCK_KEY                0x0
  43#define UNLOCK_KEY1             0xaa996655
  44#define UNLOCK_KEY2             0x556699aa
  45
  46/*
  47 * PIC32 flash banks consist of number of pages, each page
  48 * into number of rows and rows into number of words.
  49 * Here we will maintain page information instead of sector.
  50 */
  51flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
  52static struct pic32_reg_nvm *nvm_regs_p;
  53
  54static inline void flash_initiate_operation(u32 nvmop)
  55{
  56        /* set operation */
  57        writel(nvmop, &nvm_regs_p->ctrl.raw);
  58
  59        /* enable flash write */
  60        writel(NVM_WREN, &nvm_regs_p->ctrl.set);
  61
  62        /* unlock sequence */
  63        writel(LOCK_KEY, &nvm_regs_p->key.raw);
  64        writel(UNLOCK_KEY1, &nvm_regs_p->key.raw);
  65        writel(UNLOCK_KEY2, &nvm_regs_p->key.raw);
  66
  67        /* initiate operation */
  68        writel(NVM_WR, &nvm_regs_p->ctrl.set);
  69}
  70
  71static int flash_wait_till_busy(const char *func, ulong timeout)
  72{
  73        int ret = wait_for_bit_le32(&nvm_regs_p->ctrl.raw,
  74                                    NVM_WR, false, timeout, false);
  75
  76        return ret ? ERR_TIMEOUT : ERR_OK;
  77}
  78
  79static inline int flash_complete_operation(void)
  80{
  81        u32 tmp;
  82
  83        tmp = readl(&nvm_regs_p->ctrl.raw);
  84        if (tmp & NVM_WRERR) {
  85                printf("Error in Block Erase - Lock Bit may be set!\n");
  86                flash_initiate_operation(NVMOP_NOP);
  87                return ERR_PROTECTED;
  88        }
  89
  90        if (tmp & NVM_LVDERR) {
  91                printf("Error in Block Erase - low-vol detected!\n");
  92                flash_initiate_operation(NVMOP_NOP);
  93                return ERR_NOT_ERASED;
  94        }
  95
  96        /* disable flash write or erase operation */
  97        writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
  98
  99        return ERR_OK;
 100}
 101
 102/*
 103 * Erase flash sectors, returns:
 104 * ERR_OK - OK
 105 * ERR_INVAL - invalid sector arguments
 106 * ERR_TIMEOUT - write timeout
 107 * ERR_NOT_ERASED - Flash not erased
 108 * ERR_UNKNOWN_FLASH_VENDOR - incorrect flash
 109 */
 110int flash_erase(flash_info_t *info, int s_first, int s_last)
 111{
 112        ulong sect_start, sect_end, flags;
 113        int prot, sect;
 114        int rc;
 115
 116        if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
 117                printf("Can't erase unknown flash type %08lx - aborted\n",
 118                       info->flash_id);
 119                return ERR_UNKNOWN_FLASH_VENDOR;
 120        }
 121
 122        if ((s_first < 0) || (s_first > s_last)) {
 123                printf("- no sectors to erase\n");
 124                return ERR_INVAL;
 125        }
 126
 127        prot = 0;
 128        for (sect = s_first; sect <= s_last; ++sect) {
 129                if (info->protect[sect])
 130                        prot++;
 131        }
 132
 133        if (prot)
 134                printf("- Warning: %d protected sectors will not be erased!\n",
 135                       prot);
 136        else
 137                printf("\n");
 138
 139        /* erase on unprotected sectors */
 140        for (sect = s_first; sect <= s_last; sect++) {
 141                if (info->protect[sect])
 142                        continue;
 143
 144                /* disable interrupts */
 145                flags = disable_interrupts();
 146
 147                /* write destination page address (physical) */
 148                sect_start = CPHYSADDR(info->start[sect]);
 149                writel(sect_start, &nvm_regs_p->addr.raw);
 150
 151                /* page erase */
 152                flash_initiate_operation(NVMOP_PAGE_ERASE);
 153
 154                /* wait */
 155                rc = flash_wait_till_busy(__func__,
 156                                          CONFIG_SYS_FLASH_ERASE_TOUT);
 157
 158                /* re-enable interrupts if necessary */
 159                if (flags)
 160                        enable_interrupts();
 161
 162                if (rc != ERR_OK)
 163                        return rc;
 164
 165                rc = flash_complete_operation();
 166                if (rc != ERR_OK)
 167                        return rc;
 168
 169                /*
 170                 * flash content is updated but cache might contain stale
 171                 * data, so invalidate dcache.
 172                 */
 173                sect_end = info->start[sect] + info->size / info->sector_count;
 174                invalidate_dcache_range(info->start[sect], sect_end);
 175        }
 176
 177        printf(" done\n");
 178        return ERR_OK;
 179}
 180
 181int page_erase(flash_info_t *info, int sect)
 182{
 183        return 0;
 184}
 185
 186/* Write a word to flash */
 187static int write_word(flash_info_t *info, ulong dest, ulong word)
 188{
 189        ulong flags;
 190        int rc;
 191
 192        /* read flash to check if it is sufficiently erased */
 193        if ((readl((void __iomem *)dest) & word) != word) {
 194                printf("Error, Flash not erased!\n");
 195                return ERR_NOT_ERASED;
 196        }
 197
 198        /* disable interrupts */
 199        flags = disable_interrupts();
 200
 201        /* update destination page address (physical) */
 202        writel(CPHYSADDR(dest), &nvm_regs_p->addr.raw);
 203        writel(word, &nvm_regs_p->data.raw);
 204
 205        /* word write */
 206        flash_initiate_operation(NVMOP_WORD_WRITE);
 207
 208        /* wait for operation to complete */
 209        rc = flash_wait_till_busy(__func__, CONFIG_SYS_FLASH_WRITE_TOUT);
 210
 211        /* re-enable interrupts if necessary */
 212        if (flags)
 213                enable_interrupts();
 214
 215        if (rc != ERR_OK)
 216                return rc;
 217
 218        return flash_complete_operation();
 219}
 220
 221/*
 222 * Copy memory to flash, returns:
 223 * ERR_OK - OK
 224 * ERR_TIMEOUT - write timeout
 225 * ERR_NOT_ERASED - Flash not erased
 226 */
 227int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 228{
 229        ulong dst, tmp_le, len = cnt;
 230        int i, l, rc;
 231        uchar *cp;
 232
 233        /* get lower word aligned address */
 234        dst = (addr & ~3);
 235
 236        /* handle unaligned start bytes */
 237        l = addr - dst;
 238        if (l != 0) {
 239                tmp_le = 0;
 240                for (i = 0, cp = (uchar *)dst; i < l; ++i, ++cp)
 241                        tmp_le |= *cp << (i * 8);
 242
 243                for (; (i < 4) && (cnt > 0); ++i, ++src, --cnt, ++cp)
 244                        tmp_le |= *src << (i * 8);
 245
 246                for (; (cnt == 0) && (i < 4); ++i, ++cp)
 247                        tmp_le |= *cp << (i * 8);
 248
 249                rc = write_word(info, dst, tmp_le);
 250                if (rc)
 251                        goto out;
 252
 253                dst += 4;
 254        }
 255
 256        /* handle word aligned part */
 257        while (cnt >= 4) {
 258                tmp_le = src[0] | src[1] << 8 | src[2] << 16 | src[3] << 24;
 259                rc = write_word(info, dst, tmp_le);
 260                if (rc)
 261                        goto out;
 262                src += 4;
 263                dst += 4;
 264                cnt -= 4;
 265        }
 266
 267        if (cnt == 0) {
 268                rc = ERR_OK;
 269                goto out;
 270        }
 271
 272        /* handle unaligned tail bytes */
 273        tmp_le = 0;
 274        for (i = 0, cp = (uchar *)dst; (i < 4) && (cnt > 0); ++i, ++cp) {
 275                tmp_le |= *src++ << (i * 8);
 276                --cnt;
 277        }
 278
 279        for (; i < 4; ++i, ++cp)
 280                tmp_le |= *cp << (i * 8);
 281
 282        rc = write_word(info, dst, tmp_le);
 283out:
 284        /*
 285         * flash content updated by nvm controller but CPU cache might
 286         * have stale data, so invalidate dcache.
 287         */
 288        invalidate_dcache_range(addr, addr + len);
 289
 290        printf(" done\n");
 291        return rc;
 292}
 293
 294void flash_print_info(flash_info_t *info)
 295{
 296        int i;
 297
 298        if (info->flash_id == FLASH_UNKNOWN) {
 299                printf("missing or unknown FLASH type\n");
 300                return;
 301        }
 302
 303        switch (info->flash_id & FLASH_VENDMASK) {
 304        case FLASH_MAN_MCHP:
 305                printf("Microchip Technology ");
 306                break;
 307        default:
 308                printf("Unknown Vendor ");
 309                break;
 310        }
 311
 312        switch (info->flash_id & FLASH_TYPEMASK) {
 313        case FLASH_MCHP100T:
 314                printf("Internal (8 Mbit, 64 x 16k)\n");
 315                break;
 316        default:
 317                printf("Unknown Chip Type\n");
 318                break;
 319        }
 320
 321        printf("  Size: %ld MB in %d Sectors\n",
 322               info->size >> 20, info->sector_count);
 323
 324        printf("  Sector Start Addresses:");
 325        for (i = 0; i < info->sector_count; ++i) {
 326                if ((i % 5) == 0)
 327                        printf("\n   ");
 328
 329                printf(" %08lX%s", info->start[i],
 330                       info->protect[i] ? " (RO)" : "     ");
 331        }
 332        printf("\n");
 333}
 334
 335unsigned long flash_init(void)
 336{
 337        unsigned long size = 0;
 338        struct udevice *dev;
 339        int bank;
 340
 341        /* probe every MTD device */
 342        for (uclass_first_device(UCLASS_MTD, &dev); dev;
 343             uclass_next_device(&dev)) {
 344                /* nop */
 345        }
 346
 347        /* calc total flash size */
 348        for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank)
 349                size += flash_info[bank].size;
 350
 351        return size;
 352}
 353
 354static void pic32_flash_bank_init(flash_info_t *info,
 355                                  ulong base, ulong size)
 356{
 357        ulong sect_size;
 358        int sect;
 359
 360        /* device & manufacturer code */
 361        info->flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
 362        info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
 363        info->size = size;
 364
 365        /* update sector (i.e page) info */
 366        sect_size = info->size / info->sector_count;
 367        for (sect = 0; sect < info->sector_count; sect++) {
 368                info->start[sect] = base;
 369                /* protect each sector by default */
 370                info->protect[sect] = 1;
 371                base += sect_size;
 372        }
 373}
 374
 375static int pic32_flash_probe(struct udevice *dev)
 376{
 377        void *blob = (void *)gd->fdt_blob;
 378        int node = dev_of_offset(dev);
 379        const char *list, *end;
 380        const fdt32_t *cell;
 381        unsigned long addr, size;
 382        int parent, addrc, sizec;
 383        flash_info_t *info;
 384        int len, idx;
 385
 386        /*
 387         * decode regs. there are multiple reg tuples, and they need to
 388         * match with reg-names.
 389         */
 390        parent = fdt_parent_offset(blob, node);
 391        fdt_support_default_count_cells(blob, parent, &addrc, &sizec);
 392        list = fdt_getprop(blob, node, "reg-names", &len);
 393        if (!list)
 394                return -ENOENT;
 395
 396        end = list + len;
 397        cell = fdt_getprop(blob, node, "reg", &len);
 398        if (!cell)
 399                return -ENOENT;
 400
 401        for (idx = 0, info = &flash_info[0]; list < end;) {
 402                addr = fdt_translate_address((void *)blob, node, cell + idx);
 403                size = fdt_addr_to_cpu(cell[idx + addrc]);
 404                len = strlen(list);
 405                if (!strncmp(list, "nvm", len)) {
 406                        /* NVM controller */
 407                        nvm_regs_p = ioremap(addr, size);
 408                } else if (!strncmp(list, "bank", 4)) {
 409                        /* Flash bank: use kseg0 cached address */
 410                        pic32_flash_bank_init(info, CKSEG0ADDR(addr), size);
 411                        info++;
 412                }
 413                idx += addrc + sizec;
 414                list += len + 1;
 415        }
 416
 417        /* disable flash write/erase operations */
 418        writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
 419
 420#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
 421        /* monitor protection ON by default */
 422        flash_protect(FLAG_PROTECT_SET,
 423                      CONFIG_SYS_MONITOR_BASE,
 424                      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
 425                      &flash_info[0]);
 426#endif
 427
 428#ifdef CONFIG_ENV_IS_IN_FLASH
 429        /* ENV protection ON by default */
 430        flash_protect(FLAG_PROTECT_SET,
 431                      CONFIG_ENV_ADDR,
 432                      CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
 433                      &flash_info[0]);
 434#endif
 435        return 0;
 436}
 437
 438static const struct udevice_id pic32_flash_ids[] = {
 439        { .compatible = "microchip,pic32mzda-flash" },
 440        {}
 441};
 442
 443U_BOOT_DRIVER(pic32_flash) = {
 444        .name   = "pic32_flash",
 445        .id     = UCLASS_MTD,
 446        .of_match = pic32_flash_ids,
 447        .probe  = pic32_flash_probe,
 448};
 449