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