uboot/board/r360mpi/flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2001
   3 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
   4 *
   5 * (C) Copyright 2001
   6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   7 *
   8 * SPDX-License-Identifier:     GPL-2.0+
   9 */
  10
  11/* #define DEBUG */
  12
  13#include <common.h>
  14#include <mpc8xx.h>
  15
  16flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];    /* info for FLASH chips    */
  17
  18#if defined(CONFIG_ENV_IS_IN_FLASH)
  19# ifndef  CONFIG_ENV_ADDR
  20#  define CONFIG_ENV_ADDR       (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
  21# endif
  22# ifndef  CONFIG_ENV_SIZE
  23#  define CONFIG_ENV_SIZE       CONFIG_ENV_SECT_SIZE
  24# endif
  25# ifndef  CONFIG_ENV_SECT_SIZE
  26#  define CONFIG_ENV_SECT_SIZE  CONFIG_ENV_SIZE
  27# endif
  28#endif
  29
  30/*-----------------------------------------------------------------------
  31 * Protection Flags:
  32 */
  33#define FLAG_PROTECT_SET        0x01
  34#define FLAG_PROTECT_CLEAR      0x02
  35
  36/* Board support for 1 or 2 flash devices */
  37#undef FLASH_PORT_WIDTH32
  38#define FLASH_PORT_WIDTH16
  39
  40#ifdef FLASH_PORT_WIDTH16
  41#define FLASH_PORT_WIDTH        ushort
  42#define FLASH_PORT_WIDTHV       vu_short
  43#else
  44#define FLASH_PORT_WIDTH        ulong
  45#define FLASH_PORT_WIDTHV       vu_long
  46#endif
  47
  48#define FPW                     FLASH_PORT_WIDTH
  49#define FPWV                    FLASH_PORT_WIDTHV
  50
  51/*-----------------------------------------------------------------------
  52 * Functions
  53 */
  54static ulong flash_get_size (FPW * addr, flash_info_t * info);
  55static int write_data (flash_info_t * info, ulong dest, FPW data);
  56static void flash_get_offsets (ulong base, flash_info_t * info);
  57
  58/*-----------------------------------------------------------------------
  59 */
  60
  61unsigned long flash_init (void)
  62{
  63        volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
  64        volatile memctl8xx_t *memctl = &immap->im_memctl;
  65        unsigned long size_b0;
  66        int i;
  67
  68        /* Init: no FLASHes known */
  69        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
  70                flash_info[i].flash_id = FLASH_UNKNOWN;
  71        }
  72
  73        /* Static FLASH Bank configuration here - FIXME XXX */
  74        size_b0 = flash_get_size ((FPW *) FLASH_BASE0_PRELIM, &flash_info[0]);
  75
  76        if (flash_info[0].flash_id == FLASH_UNKNOWN) {
  77                printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
  78                        size_b0, size_b0 << 20);
  79        }
  80
  81        /* Remap FLASH according to real size */
  82        memctl->memc_or0 = CONFIG_SYS_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
  83        memctl->memc_br0 = (CONFIG_SYS_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
  84
  85        /* Re-do sizing to get full correct info */
  86        size_b0 = flash_get_size ((FPW *) CONFIG_SYS_FLASH_BASE, &flash_info[0]);
  87
  88        flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
  89
  90#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
  91        /* monitor protection ON by default */
  92        (void) flash_protect (FLAG_PROTECT_SET,
  93                                CONFIG_SYS_FLASH_BASE,
  94                                CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
  95                                &flash_info[0]);
  96#endif
  97
  98#ifdef  CONFIG_ENV_IS_IN_FLASH
  99        /* ENV protection ON by default */
 100        flash_protect (FLAG_PROTECT_SET,
 101                        CONFIG_ENV_ADDR,
 102                        CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
 103                        &flash_info[0]);
 104#endif
 105
 106        flash_info[0].size = size_b0;
 107
 108        return (size_b0);
 109}
 110
 111/*-----------------------------------------------------------------------
 112 */
 113static void flash_get_offsets (ulong base, flash_info_t * info)
 114{
 115        int i;
 116
 117        if (info->flash_id == FLASH_UNKNOWN) {
 118                return;
 119        }
 120
 121        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
 122                for (i = 0; i < info->sector_count; i++) {
 123                        info->start[i] = base + (i * 0x00020000);
 124                }
 125        }
 126}
 127
 128/*-----------------------------------------------------------------------
 129 */
 130void flash_print_info (flash_info_t * info)
 131{
 132        int i;
 133
 134        if (info->flash_id == FLASH_UNKNOWN) {
 135                printf ("missing or unknown FLASH type\n");
 136                return;
 137        }
 138
 139        switch (info->flash_id & FLASH_VENDMASK) {
 140        case FLASH_MAN_INTEL:
 141                printf ("INTEL ");
 142                break;
 143        default:
 144                printf ("Unknown Vendor ");
 145                break;
 146        }
 147
 148        switch (info->flash_id & FLASH_TYPEMASK) {
 149        case FLASH_28F320J3A:
 150                printf ("28F320J3A\n");
 151                break;
 152        case FLASH_28F640J3A:
 153                printf ("28F640J3A\n");
 154                break;
 155        case FLASH_28F128J3A:
 156                printf ("28F128J3A\n");
 157                break;
 158        default:
 159                printf ("Unknown Chip Type\n");
 160                break;
 161        }
 162
 163        printf ("  Size: %ld MB in %d Sectors\n",
 164                        info->size >> 20, info->sector_count);
 165
 166        printf ("  Sector Start Addresses:");
 167        for (i = 0; i < info->sector_count; ++i) {
 168                if ((i % 5) == 0)
 169                        printf ("\n   ");
 170                printf (" %08lX%s",
 171                        info->start[i],
 172                        info->protect[i] ? " (RO)" : "     ");
 173        }
 174        printf ("\n");
 175        return;
 176}
 177
 178/*-----------------------------------------------------------------------
 179 */
 180
 181
 182/*-----------------------------------------------------------------------
 183 */
 184
 185/*
 186 * The following code cannot be run from FLASH!
 187 */
 188
 189static ulong flash_get_size (FPW * addr, flash_info_t * info)
 190{
 191        FPW value;
 192
 193        /* Make sure Block Lock Bits get cleared */
 194        addr[0] = (FPW) 0x00FF00FF;
 195        addr[0] = (FPW) 0x00600060;
 196        addr[0] = (FPW) 0x00D000D0;
 197        addr[0] = (FPW) 0x00FF00FF;
 198
 199        /* Write auto select command: read Manufacturer ID */
 200        addr[0x5555] = (FPW) 0x00AA00AA;
 201        addr[0x2AAA] = (FPW) 0x00550055;
 202        addr[0x5555] = (FPW) 0x00900090;
 203
 204        value = addr[0];
 205
 206        debug("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
 207
 208        switch (value) {
 209        case (FPW) INTEL_MANUFACT:
 210                info->flash_id = FLASH_MAN_INTEL;
 211                break;
 212        default:
 213                info->flash_id = FLASH_UNKNOWN;
 214                info->sector_count = 0;
 215                info->size = 0;
 216                addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
 217                return (0);                     /* no or unknown flash  */
 218        }
 219
 220        value = addr[1];                        /* device ID        */
 221
 222        debug("Device ID @ 0x%08lx: 0x%08x\n", (ulong)(&addr[1]), value);
 223
 224        switch (value) {
 225        case (FPW) INTEL_ID_28F320J3A:
 226                info->flash_id += FLASH_28F320J3A;
 227                info->sector_count = 32;
 228                info->size = 0x00400000;
 229                break;                          /* => 4 MB     */
 230
 231        case (FPW) INTEL_ID_28F640J3A:
 232                info->flash_id += FLASH_28F640J3A;
 233                info->sector_count = 64;
 234                info->size = 0x00800000;
 235                break;                          /* => 8 MB     */
 236
 237        case (FPW) INTEL_ID_28F128J3A:
 238                info->flash_id += FLASH_28F128J3A;
 239                info->sector_count = 128;
 240                info->size = 0x01000000;
 241                break;                          /* => 16 MB     */
 242
 243        default:
 244                info->flash_id = FLASH_UNKNOWN;
 245                break;
 246        }
 247
 248        if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
 249                printf ("** ERROR: sector count %d > max (%d) **\n",
 250                                info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
 251                info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
 252        }
 253
 254        addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
 255
 256        return (info->size);
 257}
 258
 259
 260/*-----------------------------------------------------------------------
 261 */
 262
 263int flash_erase (flash_info_t * info, int s_first, int s_last)
 264{
 265        int flag, prot, sect;
 266        ulong type, start, now, last;
 267        int rcode = 0;
 268
 269        if ((s_first < 0) || (s_first > s_last)) {
 270                if (info->flash_id == FLASH_UNKNOWN) {
 271                        printf ("- missing\n");
 272                } else {
 273                        printf ("- no sectors to erase\n");
 274                }
 275                return 1;
 276        }
 277
 278        type = (info->flash_id & FLASH_VENDMASK);
 279        if ((type != FLASH_MAN_INTEL)) {
 280                printf ("Can't erase unknown flash type %08lx - aborted\n",
 281                        info->flash_id);
 282                return 1;
 283        }
 284
 285        prot = 0;
 286        for (sect = s_first; sect <= s_last; ++sect) {
 287                if (info->protect[sect]) {
 288                        prot++;
 289                }
 290        }
 291
 292        if (prot) {
 293                printf ("- Warning: %d protected sectors will not be erased!\n",
 294                        prot);
 295        } else {
 296                printf ("\n");
 297        }
 298
 299        start = get_timer (0);
 300        last = start;
 301        /* Start erase on unprotected sectors */
 302        for (sect = s_first; sect <= s_last; sect++) {
 303                if (info->protect[sect] == 0) { /* not protected */
 304                        FPWV *addr = (FPWV *) (info->start[sect]);
 305                        FPW status;
 306
 307                        /* Disable interrupts which might cause a timeout here */
 308                        flag = disable_interrupts ();
 309
 310                        *addr = (FPW) 0x00500050;       /* clear status register */
 311                        *addr = (FPW) 0x00200020;       /* erase setup */
 312                        *addr = (FPW) 0x00D000D0;       /* erase confirm */
 313
 314                        /* re-enable interrupts if necessary */
 315                        if (flag)
 316                                enable_interrupts ();
 317
 318                        /* wait at least 80us - let's wait 1 ms */
 319                        udelay (1000);
 320
 321                        while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
 322                            if ((now = get_timer (start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 323                                printf ("Timeout\n");
 324                                *addr = (FPW) 0x00B000B0;       /* suspend erase     */
 325                                *addr = (FPW) 0x00FF00FF;       /* reset to read mode */
 326                                rcode = 1;
 327                                break;
 328                            }
 329
 330                            /* show that we're waiting */
 331                            if ((now - last) > 1000) {  /* every second */
 332                                putc ('.');
 333                                last = now;
 334                            }
 335                        }
 336
 337                        *addr = (FPW) 0x00FF00FF;       /* reset to read mode */
 338                }
 339        }
 340        printf (" done\n");
 341        return rcode;
 342}
 343
 344/*-----------------------------------------------------------------------
 345 * Copy memory to flash, returns:
 346 * 0 - OK
 347 * 1 - write timeout
 348 * 2 - Flash not erased
 349 * 4 - Flash not identified
 350 */
 351
 352int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 353{
 354        ulong cp, wp;
 355        FPW data;
 356
 357        int i, l, rc, port_width;
 358
 359        if (info->flash_id == FLASH_UNKNOWN) {
 360                return 4;
 361        }
 362/* get lower word aligned address */
 363#ifdef FLASH_PORT_WIDTH16
 364        wp = (addr & ~1);
 365        port_width = 2;
 366#else
 367        wp = (addr & ~3);
 368        port_width = 4;
 369#endif
 370
 371        /*
 372         * handle unaligned start bytes
 373         */
 374        if ((l = addr - wp) != 0) {
 375                data = 0;
 376                for (i = 0, cp = wp; i < l; ++i, ++cp) {
 377                        data = (data << 8) | (*(uchar *) cp);
 378                }
 379                for (; i < port_width && cnt > 0; ++i) {
 380                        data = (data << 8) | *src++;
 381                        --cnt;
 382                        ++cp;
 383                }
 384                for (; cnt == 0 && i < port_width; ++i, ++cp) {
 385                        data = (data << 8) | (*(uchar *) cp);
 386                }
 387
 388                if ((rc = write_data (info, wp, data)) != 0) {
 389                        return (rc);
 390                }
 391                wp += port_width;
 392        }
 393
 394        /*
 395         * handle word aligned part
 396         */
 397        while (cnt >= port_width) {
 398                data = 0;
 399                for (i = 0; i < port_width; ++i) {
 400                        data = (data << 8) | *src++;
 401                }
 402                if ((rc = write_data (info, wp, data)) != 0) {
 403                        return (rc);
 404                }
 405                wp += port_width;
 406                cnt -= port_width;
 407        }
 408
 409        if (cnt == 0) {
 410                return (0);
 411        }
 412
 413        /*
 414         * handle unaligned tail bytes
 415         */
 416        data = 0;
 417        for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) {
 418                data = (data << 8) | *src++;
 419                --cnt;
 420        }
 421        for (; i < port_width; ++i, ++cp) {
 422                data = (data << 8) | (*(uchar *) cp);
 423        }
 424
 425        return (write_data (info, wp, data));
 426}
 427
 428/*-----------------------------------------------------------------------
 429 * Write a word or halfword to Flash, returns:
 430 * 0 - OK
 431 * 1 - write timeout
 432 * 2 - Flash not erased
 433 */
 434static int write_data (flash_info_t * info, ulong dest, FPW data)
 435{
 436        FPWV *addr = (FPWV *) dest;
 437        ulong status;
 438        ulong start;
 439        int flag;
 440
 441        /* Check if Flash is (sufficiently) erased */
 442        if ((*addr & data) != data) {
 443                printf ("not erased at %08lx (%x)\n", (ulong) addr, *addr);
 444                return (2);
 445        }
 446        /* Disable interrupts which might cause a timeout here */
 447        flag = disable_interrupts ();
 448
 449        *addr = (FPW) 0x00400040;       /* write setup */
 450        *addr = data;
 451
 452        /* re-enable interrupts if necessary */
 453        if (flag)
 454                enable_interrupts ();
 455
 456        start = get_timer (0);
 457
 458        while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
 459                if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 460                        *addr = (FPW) 0x00FF00FF;       /* restore read mode */
 461                        return (1);
 462                }
 463        }
 464
 465        *addr = (FPW) 0x00FF00FF;       /* restore read mode */
 466
 467        return (0);
 468}
 469