uboot/board/rpxsuper/flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000
   3 * Marius Groeger <mgroeger@sysgo.de>
   4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   5 *
   6 * (C) Copyright 2000
   7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   8 *
   9 * Flash Routines for AMD 29F080B devices
  10 * Added support for 64bit and AMD 29DL323B
  11 *
  12 *--------------------------------------------------------------------
  13 * See file CREDITS for list of people who contributed to this
  14 * project.
  15 *
  16 * This program is free software; you can redistribute it and/or
  17 * modify it under the terms of the GNU General Public License as
  18 * published by the Free Software Foundation; either version 2 of
  19 * the License, or (at your option) any later version.
  20 *
  21 * This program is distributed in the hope that it will be useful,
  22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24 * GNU General Public License for more details.
  25 *
  26 * You should have received a copy of the GNU General Public License
  27 * along with this program; if not, write to the Free Software
  28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  29 * MA 02111-1307 USA
  30 */
  31
  32#include <common.h>
  33#include <mpc8xx.h>
  34#include <asm/io.h>
  35
  36flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
  37
  38#define RD_SWP32(x) in_le32((volatile u32*)x)
  39
  40/*-----------------------------------------------------------------------
  41 * Functions
  42 */
  43
  44static ulong flash_get_size (vu_long *addr, flash_info_t *info);
  45static int write_word (flash_info_t *info, ulong dest, ulong data);
  46
  47/*-----------------------------------------------------------------------
  48 */
  49
  50unsigned long flash_init (void)
  51{
  52    unsigned long size;
  53    int i;
  54
  55    /* Init: no FLASHes known */
  56    for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
  57        flash_info[i].flash_id = FLASH_UNKNOWN;
  58    }
  59
  60    /* for now, only support the 4 MB Flash SIMM */
  61    size = flash_get_size((vu_long *)CONFIG_SYS_FLASH0_BASE, &flash_info[0]);
  62
  63    /*
  64     * protect monitor and environment sectors
  65     */
  66
  67#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH0_BASE
  68    flash_protect(FLAG_PROTECT_SET,
  69                  CONFIG_SYS_MONITOR_BASE,
  70                  CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
  71                  &flash_info[0]);
  72#endif
  73
  74#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR)
  75# ifndef  CONFIG_ENV_SIZE
  76#  define CONFIG_ENV_SIZE       CONFIG_ENV_SECT_SIZE
  77# endif
  78    flash_protect(FLAG_PROTECT_SET,
  79                  CONFIG_ENV_ADDR,
  80                  CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
  81                  &flash_info[0]);
  82#endif
  83
  84    return /*size*/ (CONFIG_SYS_FLASH0_SIZE * 1024 * 1024);
  85}
  86
  87/*-----------------------------------------------------------------------
  88 */
  89void flash_print_info  (flash_info_t *info)
  90{
  91    int i;
  92
  93    if (info->flash_id == FLASH_UNKNOWN) {
  94        printf ("missing or unknown FLASH type\n");
  95        return;
  96    }
  97
  98    switch (info->flash_id & FLASH_VENDMASK) {
  99    case (AMD_MANUFACT & FLASH_VENDMASK):
 100        printf ("AMD ");
 101        break;
 102    case (FUJ_MANUFACT & FLASH_VENDMASK):
 103        printf ("FUJITSU ");
 104        break;
 105    case (SST_MANUFACT & FLASH_VENDMASK):
 106        printf ("SST ");
 107        break;
 108    default:
 109        printf ("Unknown Vendor ");
 110        break;
 111    }
 112
 113    switch (info->flash_id & FLASH_TYPEMASK) {
 114    case (AMD_ID_DL323B & FLASH_TYPEMASK):
 115        printf("AM29DL323B (32 MBit)\n");
 116        break;
 117    default:
 118        printf ("Unknown Chip Type\n");
 119        break;
 120    }
 121
 122    printf ("  Size: %ld MB in %d Sectors\n",
 123            info->size >> 20, info->sector_count);
 124
 125    printf ("  Sector Start Addresses:");
 126    for (i = 0; i < info->sector_count; ++i) {
 127        if ((i % 5) == 0) printf ("\n   ");
 128        printf (" %08lX%s",
 129                info->start[i],
 130                info->protect[i] ? " (RO)" : "     "
 131                );
 132    }
 133    printf ("\n");
 134    return;
 135}
 136
 137/*
 138 * The following code cannot be run from FLASH!
 139 */
 140
 141static ulong flash_get_size (vu_long *addr, flash_info_t *info)
 142{
 143    short i;
 144    vu_long vendor[2], devid[2];
 145    ulong base = (ulong)addr;
 146
 147    /* Reset and Write auto select command: read Manufacturer ID */
 148    addr[0] = 0xf0f0f0f0;
 149    addr[2 * 0x0555] = 0xAAAAAAAA;
 150    addr[2 * 0x02AA] = 0x55555555;
 151    addr[2 * 0x0555] = 0x90909090;
 152    addr[1] = 0xf0f0f0f0;
 153    addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
 154    addr[2 * 0x02AA + 1] = 0x55555555;
 155    addr[2 * 0x0555 + 1] = 0x90909090;
 156    udelay (1000);
 157
 158    vendor[0] = RD_SWP32(&addr[0]);
 159    vendor[1] = RD_SWP32(&addr[1]);
 160    if (vendor[0] != vendor[1] || vendor[0] != AMD_MANUFACT) {
 161        info->size = 0;
 162        goto out;
 163    }
 164
 165    devid[0] = RD_SWP32(&addr[2]);
 166    devid[1] = RD_SWP32(&addr[3]);
 167
 168    if (devid[0] == AMD_ID_DL323B) {
 169        /*
 170        * we have 2 Banks
 171        * Bank 1 (23 Sectors): 0-7=8kbyte, 8-22=64kbyte
 172        * Bank 2 (48 Sectors): 23-70=64kbyte
 173        */
 174        info->flash_id     = (AMD_MANUFACT & FLASH_VENDMASK) |
 175                             (AMD_ID_DL323B & FLASH_TYPEMASK);
 176        info->sector_count = 71;
 177        info->size         = 4 * (8 * 8 + 63 * 64) * 1024;
 178    }
 179    else {
 180        info->size = 0;
 181        goto out;
 182    }
 183
 184    /* set up sector start address table */
 185    for (i = 0; i < 8; i++) {
 186        info->start[i] = base + (i * 0x8000);
 187    }
 188    for (i = 8; i < info->sector_count; i++) {
 189        info->start[i] = base + (i * 0x40000) + 8 * 0x8000 - 8 * 0x40000;
 190    }
 191
 192    /* check for protected sectors */
 193    for (i = 0; i < info->sector_count; i++) {
 194        /* read sector protection at sector address */
 195        addr = (volatile unsigned long *)(info->start[i]);
 196        addr[2 * 0x0555] = 0xAAAAAAAA;
 197        addr[2 * 0x02AA] = 0x55555555;
 198        addr[2 * 0x0555] = 0x90909090;
 199        addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
 200        addr[2 * 0x02AA + 1] = 0x55555555;
 201        addr[2 * 0x0555 + 1] = 0x90909090;
 202        udelay (1000);
 203        base = RD_SWP32(&addr[4]);
 204        base |= RD_SWP32(&addr[5]);
 205        info->protect[i] = base & 0x00010001 ? 1 : 0;
 206    }
 207    addr = (vu_long*)info->start[0];
 208
 209out:
 210    /* reset command */
 211    addr[0] = 0xf0f0f0f0;
 212    addr[1] = 0xf0f0f0f0;
 213
 214    return info->size;
 215}
 216
 217
 218/*-----------------------------------------------------------------------
 219 */
 220
 221int flash_erase (flash_info_t *info, int s_first, int s_last)
 222{
 223    vu_long *addr = (vu_long*)(info->start[0]);
 224    int flag, prot, sect, l_sect;
 225    ulong start, now, last;
 226
 227    if ((s_first < 0) || (s_first > s_last)) {
 228        if (info->flash_id == FLASH_UNKNOWN) {
 229            printf ("- missing\n");
 230        } else {
 231            printf ("- no sectors to erase\n");
 232        }
 233        return 1;
 234    }
 235
 236    prot = 0;
 237    for (sect = s_first; sect <= s_last; sect++) {
 238        if (info->protect[sect]) {
 239            prot++;
 240        }
 241    }
 242
 243    if (prot) {
 244        printf ("- Warning: %d protected sectors will not be erased!\n",
 245                prot);
 246    } else {
 247        printf ("\n");
 248    }
 249
 250    l_sect = -1;
 251
 252    /* Disable interrupts which might cause a timeout here */
 253    flag = disable_interrupts();
 254
 255    addr[2 * 0x0555] = 0xAAAAAAAA;
 256    addr[2 * 0x02AA] = 0x55555555;
 257    addr[2 * 0x0555] = 0x80808080;
 258    addr[2 * 0x0555] = 0xAAAAAAAA;
 259    addr[2 * 0x02AA] = 0x55555555;
 260    addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
 261    addr[2 * 0x02AA + 1] = 0x55555555;
 262    addr[2 * 0x0555 + 1] = 0x80808080;
 263    addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
 264    addr[2 * 0x02AA + 1] = 0x55555555;
 265    udelay (100);
 266
 267    /* Start erase on unprotected sectors */
 268    for (sect = s_first; sect<=s_last; sect++) {
 269        if (info->protect[sect] == 0) { /* not protected */
 270            addr = (vu_long*)(info->start[sect]);
 271            addr[0] = 0x30303030;
 272            addr[1] = 0x30303030;
 273            l_sect = sect;
 274        }
 275    }
 276
 277    /* re-enable interrupts if necessary */
 278    if (flag)
 279      enable_interrupts();
 280
 281    /* wait at least 80us - let's wait 1 ms */
 282    udelay (1000);
 283
 284    /*
 285     * We wait for the last triggered sector
 286     */
 287    if (l_sect < 0)
 288      goto DONE;
 289
 290    start = get_timer (0);
 291    last  = start;
 292    addr = (vu_long*)(info->start[l_sect]);
 293    while (     (addr[0] & 0x80808080) != 0x80808080 ||
 294                (addr[1] & 0x80808080) != 0x80808080) {
 295        if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 296            printf ("Timeout\n");
 297            return 1;
 298        }
 299        /* show that we're waiting */
 300        if ((now - last) > 1000) {      /* every second */
 301            serial_putc ('.');
 302            last = now;
 303        }
 304    }
 305
 306    DONE:
 307    /* reset to read mode */
 308    addr = (volatile unsigned long *)info->start[0];
 309    addr[0] = 0xF0F0F0F0;       /* reset bank */
 310    addr[1] = 0xF0F0F0F0;       /* reset bank */
 311
 312    printf (" done\n");
 313    return 0;
 314}
 315
 316/*-----------------------------------------------------------------------
 317 * Copy memory to flash, returns:
 318 * 0 - OK
 319 * 1 - write timeout
 320 * 2 - Flash not erased
 321 */
 322
 323int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 324{
 325    ulong cp, wp, data;
 326    int i, l, rc;
 327
 328    wp = (addr & ~3);   /* get lower word aligned address */
 329
 330    /*
 331     * handle unaligned start bytes
 332     */
 333    if ((l = addr - wp) != 0) {
 334        data = 0;
 335        for (i=0, cp=wp; i<l; ++i, ++cp) {
 336            data = (data << 8) | (*(uchar *)cp);
 337        }
 338        for (; i<4 && cnt>0; ++i) {
 339            data = (data << 8) | *src++;
 340            --cnt;
 341            ++cp;
 342        }
 343        for (; cnt==0 && i<4; ++i, ++cp) {
 344            data = (data << 8) | (*(uchar *)cp);
 345        }
 346
 347        if ((rc = write_word(info, wp, data)) != 0) {
 348            return (rc);
 349        }
 350        wp += 4;
 351    }
 352
 353    /*
 354     * handle word aligned part
 355     */
 356    while (cnt >= 4) {
 357        data = 0;
 358        for (i=0; i<4; ++i) {
 359            data = (data << 8) | *src++;
 360        }
 361        if ((rc = write_word(info, wp, data)) != 0) {
 362            return (rc);
 363        }
 364        wp  += 4;
 365        cnt -= 4;
 366    }
 367
 368    if (cnt == 0) {
 369        return (0);
 370    }
 371
 372    /*
 373     * handle unaligned tail bytes
 374     */
 375    data = 0;
 376    for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
 377        data = (data << 8) | *src++;
 378        --cnt;
 379    }
 380    for (; i<4; ++i, ++cp) {
 381        data = (data << 8) | (*(uchar *)cp);
 382    }
 383
 384    return (write_word(info, wp, data));
 385}
 386
 387/*-----------------------------------------------------------------------
 388 * Write a word to Flash, returns:
 389 * 0 - OK
 390 * 1 - write timeout
 391 * 2 - Flash not erased
 392 */
 393static int write_word (flash_info_t *info, ulong dest, ulong data)
 394{
 395    vu_long *addr = (vu_long*)(info->start[0]);
 396    ulong start;
 397    int flag;
 398
 399    /* Check if Flash is (sufficiently) erased */
 400    if ((*((vu_long *)dest) & data) != data) {
 401        return (2);
 402    }
 403    /* Disable interrupts which might cause a timeout here */
 404    flag = disable_interrupts();
 405
 406    if ((dest & 0x00000004) == 0) {
 407        addr[2 * 0x0555] = 0xAAAAAAAA;
 408        addr[2 * 0x02AA] = 0x55555555;
 409        addr[2 * 0x0555] = 0xA0A0A0A0;
 410    }
 411    else {
 412        addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
 413        addr[2 * 0x02AA + 1] = 0x55555555;
 414        addr[2 * 0x0555 + 1] = 0xA0A0A0A0;
 415    }
 416
 417    *((vu_long *)dest) = data;
 418
 419    /* re-enable interrupts if necessary */
 420    if (flag)
 421      enable_interrupts();
 422
 423    /* data polling for D7 */
 424    start = get_timer (0);
 425    while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
 426        if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 427            return (1);
 428        }
 429    }
 430    return (0);
 431}
 432
 433/*-----------------------------------------------------------------------
 434 */
 435