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