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