uboot/board/gw8260/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, 2001
   7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   8 *
   9 * (C) Copyright 2001
  10 * Advent Networks, Inc. <http://www.adventnetworks.com>
  11 * Oliver Brown <oliverb@alumni.utexas.net>
  12 *
  13 *--------------------------------------------------------------------
  14 * See file CREDITS for list of people who contributed to this
  15 * project.
  16 *
  17 * This program is free software; you can redistribute it and/or
  18 * modify it under the terms of the GNU General Public License as
  19 * published by the Free Software Foundation; either version 2 of
  20 * the License, or (at your option) any later version.
  21 *
  22 * This program is distributed in the hope that it will be useful,
  23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25 * GNU General Public License for more details.
  26 *
  27 * You should have received a copy of the GNU General Public License
  28 * along with this program; if not, write to the Free Software
  29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  30 * MA 02111-1307 USA
  31 */
  32
  33/*********************************************************************/
  34/* DESCRIPTION:
  35 *   This file contains the flash routines for the GW8260 board.
  36 *
  37 *
  38 *
  39 * MODULE DEPENDENCY:
  40 *   None
  41 *
  42 *
  43 * RESTRICTIONS/LIMITATIONS:
  44 *
  45 *   Only supports the following flash devices:
  46 *     AMD 29F080B
  47 *     AMD 29F016D
  48 *
  49 * Copyright (c) 2001, Advent Networks, Inc.
  50 *
  51 */
  52/*********************************************************************/
  53
  54#include <common.h>
  55#include <mpc8260.h>
  56
  57flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
  58
  59static ulong flash_get_size (vu_long *addr, flash_info_t *info);
  60static int write_word (flash_info_t *info, ulong dest, ulong data);
  61
  62/*********************************************************************/
  63/*                    functions                                      */
  64/*********************************************************************/
  65
  66/*********************************************************************/
  67/* NAME: flash_init() -  initializes flash banks                     */
  68/*                                                                   */
  69/* DESCRIPTION:                                                      */
  70/*   This function initializes the flash bank(s).                    */
  71/*                                                                   */
  72/* RETURNS:                                                          */
  73/*   The size in bytes of the flash                                  */
  74/*                                                                   */
  75/* RESTRICTIONS/LIMITATIONS:                                         */
  76/*                                                                   */
  77/*                                                                   */
  78/*********************************************************************/
  79unsigned long flash_init (void)
  80{
  81    unsigned long size;
  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    /* for now, only support the 4 MB Flash SIMM */
  90    size = flash_get_size((vu_long *)CONFIG_SYS_FLASH0_BASE, &flash_info[0]);
  91
  92    /*
  93     * protect monitor and environment sectors
  94     */
  95
  96#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH0_BASE
  97    flash_protect(FLAG_PROTECT_SET,
  98                  CONFIG_SYS_MONITOR_BASE,
  99                  CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
 100                  &flash_info[0]);
 101#endif
 102
 103#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR)
 104# ifndef  CONFIG_ENV_SIZE
 105#  define CONFIG_ENV_SIZE       CONFIG_ENV_SECT_SIZE
 106# endif
 107    flash_protect(FLAG_PROTECT_SET,
 108                  CONFIG_ENV_ADDR,
 109                  CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
 110                  &flash_info[0]);
 111#endif
 112
 113    return (CONFIG_SYS_FLASH0_SIZE * 1024 * 1024);  /*size*/
 114}
 115
 116/*********************************************************************/
 117/* NAME: flash_print_info() - prints flash imformation               */
 118/*                                                                   */
 119/* DESCRIPTION:                                                      */
 120/*   This function prints the flash information.                     */
 121/*                                                                   */
 122/* INPUTS:                                                           */
 123/*   flash_info_t *info - flash information structure                */
 124/*                                                                   */
 125/* OUTPUTS:                                                          */
 126/*   Displays flash information to console                           */
 127/*                                                                   */
 128/* RETURNS:                                                          */
 129/*   None                                                            */
 130/*                                                                   */
 131/* RESTRICTIONS/LIMITATIONS:                                         */
 132/*                                                                   */
 133/*                                                                   */
 134/*********************************************************************/
 135void flash_print_info  (flash_info_t *info)
 136{
 137    int i;
 138
 139    if (info->flash_id == FLASH_UNKNOWN) {
 140        printf ("missing or unknown FLASH type\n");
 141        return;
 142    }
 143
 144    switch ((info->flash_id >> 16) & 0xff) {
 145    case 0x1:
 146        printf ("AMD ");
 147        break;
 148    default:
 149        printf ("Unknown Vendor ");
 150        break;
 151    }
 152
 153    switch (info->flash_id & FLASH_TYPEMASK) {
 154    case AMD_ID_F040B:
 155        printf ("AM29F040B (4 Mbit)\n");
 156        break;
 157    case AMD_ID_F080B:
 158        printf ("AM29F080B (8 Mbit)\n");
 159        break;
 160    case AMD_ID_F016D:
 161        printf ("AM29F016D (16 Mbit)\n");
 162        break;
 163    default:
 164        printf ("Unknown Chip Type\n");
 165        break;
 166    }
 167
 168    printf ("  Size: %ld MB in %d Sectors\n",
 169            info->size >> 20, info->sector_count);
 170
 171    printf ("  Sector Start Addresses:");
 172    for (i=0; i<info->sector_count; ++i) {
 173        if ((i % 5) == 0)
 174            printf ("\n   ");
 175        printf (" %08lX%s",
 176                info->start[i],
 177                info->protect[i] ? " (RO)" : "     "
 178            );
 179    }
 180    printf ("\n");
 181    return;
 182}
 183
 184/*********************************************************************/
 185/*   The following code cannot be run from FLASH!                    */
 186/*********************************************************************/
 187
 188/*********************************************************************/
 189/* NAME: flash_get_size() - detects the flash size                   */
 190/*                                                                   */
 191/* DESCRIPTION:                                                      */
 192/*   1) Reads vendor ID and devices ID from the flash devices.       */
 193/*   2) Initializes flash info struct.                               */
 194/*   3) Return the flash size                                        */
 195/*                                                                   */
 196/* INPUTS:                                                           */
 197/*   vu_long *addr      - pointer to start of flash                  */
 198/*   flash_info_t *info - flash information structure                */
 199/*                                                                   */
 200/* OUTPUTS:                                                          */
 201/*   None                                                            */
 202/*                                                                   */
 203/* RETURNS:                                                          */
 204/*   Size of the flash in bytes, or 0 if device id is unknown.       */
 205/*                                                                   */
 206/* RESTRICTIONS/LIMITATIONS:                                         */
 207/*   Only supports the following devices:                            */
 208/*     AM29F080D                                                     */
 209/*     AM29F016D                                                     */
 210/*                                                                   */
 211/*********************************************************************/
 212static ulong flash_get_size (vu_long *addr, flash_info_t *info)
 213{
 214    short i;
 215    vu_long vendor, devid;
 216    ulong base = (ulong)addr;
 217
 218    /*printf("addr   = %08lx\n", (unsigned long)addr); */
 219
 220    /* Reset and Write auto select command: read Manufacturer ID */
 221    addr[0x0000] = 0xf0f0f0f0;
 222    addr[0x0555] = 0xAAAAAAAA;
 223    addr[0x02AA] = 0x55555555;
 224    addr[0x0555] = 0x90909090;
 225    udelay (1000);
 226
 227    vendor = addr[0];
 228    /*printf("vendor = %08lx\n", vendor); */
 229    if (vendor != 0x01010101) {
 230        info->size = 0;
 231        goto out;
 232    }
 233
 234    devid = addr[1];
 235    /*printf("devid  = %08lx\n", devid); */
 236
 237    if ((devid & 0xff) == AMD_ID_F080B) {
 238        info->flash_id     = (vendor & 0xff) << 16 | AMD_ID_F080B;
 239        /* we have 16 sectors with 64KB each x 4 */
 240        info->sector_count = 16;
 241        info->size         = 4 * info->sector_count * 64*1024;
 242    } else if ((devid & 0xff) == AMD_ID_F016D){
 243        info->flash_id     = (vendor & 0xff) << 16 | AMD_ID_F016D;
 244        /* we have 32 sectors with 64KB each x 4 */
 245        info->sector_count = 32;
 246        info->size         = 4 * info->sector_count * 64*1024;
 247    } else {
 248        info->size = 0;
 249        goto out;
 250    }
 251    /*printf("sector count = %08x\n", info->sector_count); */
 252    /* check for protected sectors */
 253    for (i = 0; i < info->sector_count; i++) {
 254        /* sector base address */
 255        info->start[i] = base + i * (info->size / info->sector_count);
 256        /* read sector protection at sector address, (A7 .. A0) = 0x02 */
 257        /* D0 = 1 if protected */
 258        addr = (volatile unsigned long *)(info->start[i]);
 259        info->protect[i] = addr[2] & 1;
 260    }
 261
 262    /* reset command */
 263    addr = (vu_long *)info->start[0];
 264
 265  out:
 266    addr[0] = 0xf0f0f0f0;
 267
 268    /*printf("size = %08x\n", info->size); */
 269    return info->size;
 270}
 271
 272/*********************************************************************/
 273/* NAME: flash_erase() - erases flash by sector                      */
 274/*                                                                   */
 275/* DESCRIPTION:                                                      */
 276/*   This function erases flash sectors starting for s_first to      */
 277/*   s_last.                                                         */
 278/*                                                                   */
 279/* INPUTS:                                                           */
 280/*   flash_info_t *info - flash information structure                */
 281/*   int s_first - first sector to erase                             */
 282/*   int s_last  - last sector to erase                              */
 283/*                                                                   */
 284/* OUTPUTS:                                                          */
 285/*   None                                                            */
 286/*                                                                   */
 287/* RETURNS:                                                          */
 288/*   Returns 0 for success, 1 for failure.                           */
 289/*                                                                   */
 290/* RESTRICTIONS/LIMITATIONS:                                         */
 291/*                                                                   */
 292/*********************************************************************/
 293int flash_erase (flash_info_t *info, int s_first, int s_last)
 294{
 295    vu_long *addr = (vu_long*)(info->start[0]);
 296    int flag, prot, sect, l_sect;
 297    ulong start, now, last;
 298
 299    if ((s_first < 0) || (s_first > s_last)) {
 300        if (info->flash_id == FLASH_UNKNOWN) {
 301            printf ("- missing\n");
 302        } else {
 303            printf ("- no sectors to erase\n");
 304        }
 305        return 1;
 306    }
 307
 308    prot = 0;
 309    for (sect = s_first; sect <= s_last; sect++) {
 310        if (info->protect[sect]) {
 311            prot++;
 312        }
 313    }
 314
 315    if (prot) {
 316        printf ("- Warning: %d protected sectors will not be erased!\n",
 317                prot);
 318    } else {
 319        printf ("\n");
 320    }
 321
 322    l_sect = -1;
 323
 324    /* Disable interrupts which might cause a timeout here */
 325    flag = disable_interrupts();
 326
 327    addr[0x0555] = 0xAAAAAAAA;
 328    addr[0x02AA] = 0x55555555;
 329    addr[0x0555] = 0x80808080;
 330    addr[0x0555] = 0xAAAAAAAA;
 331    addr[0x02AA] = 0x55555555;
 332    udelay (100);
 333
 334    /* Start erase on unprotected sectors */
 335    for (sect = s_first; sect <= s_last; sect++) {
 336        if (info->protect[sect] == 0) { /* not protected */
 337            addr = (vu_long*)(info->start[sect]);
 338            addr[0] = 0x30303030;
 339            l_sect = sect;
 340        }
 341    }
 342
 343    /* re-enable interrupts if necessary */
 344    if (flag)
 345        enable_interrupts();
 346
 347    /* wait at least 80us - let's wait 1 ms */
 348    udelay (1000);
 349
 350    /*
 351     * We wait for the last triggered sector
 352     */
 353    if (l_sect < 0)
 354        goto DONE;
 355
 356    start = get_timer (0);
 357    last  = start;
 358    addr = (vu_long*)(info->start[l_sect]);
 359    while ((addr[0] & 0x80808080) != 0x80808080) {
 360        if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 361            printf ("Timeout\n");
 362            return 1;
 363        }
 364        /* show that we're waiting */
 365        if ((now - last) > 1000) {  /* every second */
 366            serial_putc ('.');
 367            last = now;
 368        }
 369    }
 370
 371  DONE:
 372    /* reset to read mode */
 373    addr = (volatile unsigned long *)info->start[0];
 374    addr[0] = 0xF0F0F0F0;   /* reset bank */
 375
 376    printf (" done\n");
 377    return 0;
 378}
 379
 380/*********************************************************************/
 381/* NAME: write_buff() - writes a buffer to flash                     */
 382/*                                                                   */
 383/* DESCRIPTION:                                                      */
 384/*   This function copies a buffer, *src, to flash.                  */
 385/*                                                                   */
 386/* INPUTS:                                                           */
 387/*  flash_info_t *info - flash information structure                 */
 388/*  uchar *src - pointer to buffer to write to flash                 */
 389/*  ulong addr - address to start write at                           */
 390/*  ulong cnt - number of bytes to write to flash                    */
 391/*                                                                   */
 392/* OUTPUTS:                                                          */
 393/*   None                                                            */
 394/*                                                                   */
 395/* RETURNS:                                                          */
 396/*   0 - OK                                                          */
 397/*   1 - write timeout                                               */
 398/*   2 - Flash not erased                                            */
 399/*                                                                   */
 400/* RESTRICTIONS/LIMITATIONS:                                         */
 401/*                                                                   */
 402/*********************************************************************/
 403int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 404{
 405    ulong cp, wp, data;
 406    int i, l, rc;
 407
 408    wp = (addr & ~3);   /* get lower word aligned address */
 409
 410    /*
 411     * handle unaligned start bytes
 412     */
 413    if ((l = addr - wp) != 0) {
 414        data = 0;
 415        for (i = 0, cp = wp; i < l; ++i, ++cp) {
 416            data = (data << 8) | (*(uchar *)cp);
 417        }
 418        for (; (i < 4) && (cnt > 0); ++i) {
 419            data = (data << 8) | *src++;
 420            --cnt;
 421            ++cp;
 422        }
 423        for (; (cnt == 0) && (i < 4); ++i, ++cp) {
 424            data = (data << 8) | (*(uchar *)cp);
 425        }
 426
 427        if ((rc = write_word(info, wp, data)) != 0) {
 428            return (rc);
 429        }
 430        wp += 4;
 431    }
 432
 433    /*
 434     * handle word aligned part
 435     */
 436    while (cnt >= 4) {
 437        data = 0;
 438        for (i = 0; i < 4; ++i) {
 439            data = (data << 8) | *src++;
 440        }
 441        if ((rc = write_word(info, wp, data)) != 0) {
 442            return (rc);
 443        }
 444        wp  += 4;
 445        cnt -= 4;
 446    }
 447
 448    if (cnt == 0) {
 449        return (0);
 450    }
 451
 452    /*
 453     * handle unaligned tail bytes
 454     */
 455    data = 0;
 456    for (i = 0, cp = wp; (i < 4) && (cnt > 0); ++i, ++cp) {
 457        data = (data << 8) | *src++;
 458        --cnt;
 459    }
 460    for (; (i < 4); ++i, ++cp) {
 461        data = (data << 8) | (*(uchar *)cp);
 462    }
 463
 464    return (write_word(info, wp, data));
 465}
 466
 467/*********************************************************************/
 468/* NAME: write_word() - writes a word to flash                       */
 469/*                                                                   */
 470/* DESCRIPTION:                                                      */
 471/*   This writes a single word to flash.                             */
 472/*                                                                   */
 473/* INPUTS:                                                           */
 474/*  flash_info_t *info - flash information structure                 */
 475/*  ulong dest - address to write                                    */
 476/*  ulong data - data to write                                       */
 477/*                                                                   */
 478/* OUTPUTS:                                                          */
 479/*   None                                                            */
 480/*                                                                   */
 481/* RETURNS:                                                          */
 482/*   0 - OK                                                          */
 483/*   1 - write timeout                                               */
 484/*   2 - Flash not erased                                            */
 485/*                                                                   */
 486/* RESTRICTIONS/LIMITATIONS:                                         */
 487/*                                                                   */
 488/*********************************************************************/
 489static int write_word (flash_info_t *info, ulong dest, ulong data)
 490{
 491    vu_long *addr = (vu_long*)(info->start[0]);
 492    ulong start;
 493    int flag;
 494
 495    /* Check if Flash is (sufficiently) erased */
 496    if ((*((vu_long *)dest) & data) != data) {
 497        return (2);
 498    }
 499    /* Disable interrupts which might cause a timeout here */
 500    flag = disable_interrupts();
 501
 502    addr[0x0555] = 0xAAAAAAAA;
 503    addr[0x02AA] = 0x55555555;
 504    addr[0x0555] = 0xA0A0A0A0;
 505
 506    *((vu_long *)dest) = data;
 507
 508    /* re-enable interrupts if necessary */
 509    if (flag)
 510        enable_interrupts();
 511
 512    /* data polling for D7 */
 513    start = get_timer (0);
 514    while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
 515        if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 516            return (1);
 517        }
 518    }
 519    return (0);
 520}
 521/*********************************************************************/
 522/*                         End of flash.c                            */
 523/*********************************************************************/
 524