uboot/board/gcplus/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 * 2003 (c) MontaVista Software, Inc.
   9 *
  10 * See file CREDITS for list of people who contributed to this
  11 * project.
  12 *
  13 * This program is free software; you can redistribute it and/or
  14 * modify it under the terms of the GNU General Public License as
  15 * published by the Free Software Foundation; either version 2 of
  16 * the License, or (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  26 * MA 02111-1307 USA
  27 */
  28
  29#include <common.h>
  30#include <linux/byteorder/swab.h>
  31
  32flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];    /* info for FLASH chips */
  33
  34/* Board support for 1 or 2 flash devices */
  35#define FLASH_PORT_WIDTH32
  36#undef FLASH_PORT_WIDTH16
  37
  38#ifdef FLASH_PORT_WIDTH16
  39#define FLASH_PORT_WIDTH                ushort
  40#define FLASH_PORT_WIDTHV               vu_short
  41#define SWAP(x)                         __swab16(x)
  42#else
  43#define FLASH_PORT_WIDTH                ulong
  44#define FLASH_PORT_WIDTHV               vu_long
  45#define SWAP(x)                         __swab32(x)
  46#endif
  47
  48#define FPW                             FLASH_PORT_WIDTH
  49#define FPWV                            FLASH_PORT_WIDTHV
  50
  51#define mb() __asm__ __volatile__ ("" : : : "memory")
  52
  53/*-----------------------------------------------------------------------
  54 * Functions
  55 */
  56static ulong flash_get_size(FPW * addr, flash_info_t * info);
  57static int write_data(flash_info_t * info, ulong dest, FPW data);
  58static void flash_get_offsets(ulong base, flash_info_t * info);
  59void inline spin_wheel(void);
  60
  61/*-----------------------------------------------------------------------
  62 */
  63
  64unsigned long
  65flash_init(void)
  66{
  67        int i;
  68        ulong size = 0;
  69
  70        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
  71                switch (i) {
  72                case 0:
  73                        flash_get_size((FPW *) PHYS_FLASH_1, &flash_info[i]);
  74                        flash_get_offsets(PHYS_FLASH_1, &flash_info[i]);
  75                        break;
  76                default:
  77                        panic("configured too many flash banks!\n");
  78                        break;
  79                }
  80                size += flash_info[i].size;
  81        }
  82
  83        /* Protect monitor and environment sectors
  84         */
  85        flash_protect(FLAG_PROTECT_SET,
  86                      CONFIG_SYS_FLASH_BASE,
  87                      CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1, &flash_info[0]);
  88
  89        flash_protect(FLAG_PROTECT_SET,
  90                      CONFIG_ENV_ADDR,
  91                      CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
  92
  93        return size;
  94}
  95
  96/*-----------------------------------------------------------------------
  97 */
  98static void
  99flash_get_offsets(ulong base, flash_info_t * info)
 100{
 101        int i;
 102
 103        if (info->flash_id == FLASH_UNKNOWN) {
 104                return;
 105        }
 106
 107        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
 108                for (i = 0; i < info->sector_count; i++) {
 109                        info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE);
 110                        info->protect[i] = 0;
 111                }
 112        }
 113}
 114
 115/*-----------------------------------------------------------------------
 116 */
 117void
 118flash_print_info(flash_info_t * info)
 119{
 120        int i;
 121
 122        if (info->flash_id == FLASH_UNKNOWN) {
 123                printf("missing or unknown FLASH type\n");
 124                return;
 125        }
 126
 127        switch (info->flash_id & FLASH_VENDMASK) {
 128        case FLASH_MAN_INTEL:
 129                printf("INTEL ");
 130                break;
 131        default:
 132                printf("Unknown Vendor ");
 133                break;
 134        }
 135
 136        switch (info->flash_id & FLASH_TYPEMASK) {
 137        case FLASH_28F128J3A:
 138                printf("28F128J3A\n");
 139                break;
 140        case FLASH_28F640J5:
 141                printf("28F640J5\n");
 142                break;
 143        default:
 144                printf("Unknown Chip Type\n");
 145                break;
 146        }
 147
 148        printf("  Size: %ld MB in %d Sectors\n",
 149               info->size >> 20, info->sector_count);
 150
 151        printf("  Sector Start Addresses:");
 152        for (i = 0; i < info->sector_count; ++i) {
 153                if ((i % 5) == 0)
 154                        printf("\n   ");
 155                printf(" %08lX%s",
 156                       info->start[i], info->protect[i] ? " (RO)" : "     ");
 157        }
 158        printf("\n");
 159        return;
 160}
 161
 162/*
 163 * The following code cannot be run from FLASH!
 164 */
 165static ulong
 166flash_get_size(FPW * addr, flash_info_t * info)
 167{
 168        volatile FPW value;
 169        /* Write auto select command: read Manufacturer ID */
 170        addr[0x5555] = (FPW) 0x00AA00AA;
 171        addr[0x2AAA] = (FPW) 0x00550055;
 172        addr[0x5555] = (FPW) 0x00900090;
 173
 174        mb();
 175        value = addr[0];
 176
 177        switch (value) {
 178
 179        case (FPW) INTEL_MANUFACT:
 180                info->flash_id = FLASH_MAN_INTEL;
 181                break;
 182
 183        default:
 184                info->flash_id = FLASH_UNKNOWN;
 185                info->sector_count = 0;
 186                info->size = 0;
 187                addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
 188                return (0);     /* no or unknown flash  */
 189        }
 190
 191        mb();
 192        value = addr[1];        /* device ID            */
 193        switch (value) {
 194        case (FPW) INTEL_ID_28F128J3A:
 195                info->flash_id += FLASH_28F128J3A;
 196                info->sector_count = 128;
 197                info->size = 0x02000000;
 198                break;          /* => 16 MB     */
 199        case (FPW) INTEL_ID_28F640J5:
 200                info->flash_id += FLASH_28F640J5;
 201                info->sector_count = 64;
 202                info->size = 0x01000000;
 203                break;          /* => 16 MB     */
 204
 205        default:
 206                info->flash_id = FLASH_UNKNOWN;
 207                break;
 208        }
 209
 210        if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
 211                printf("** ERROR: sector count %d > max (%d) **\n",
 212                       info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
 213                info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
 214        }
 215
 216        addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
 217
 218        return (info->size);
 219}
 220
 221/*-----------------------------------------------------------------------
 222 */
 223
 224int
 225flash_erase(flash_info_t * info, int s_first, int s_last)
 226{
 227        int flag, prot, sect;
 228        ulong type, start, last;
 229        int rcode = 0;
 230
 231        if ((s_first < 0) || (s_first > s_last)) {
 232                if (info->flash_id == FLASH_UNKNOWN) {
 233                        printf("- missing\n");
 234                } else {
 235                        printf("- no sectors to erase\n");
 236                }
 237                return 1;
 238        }
 239
 240        type = (info->flash_id & FLASH_VENDMASK);
 241        if ((type != FLASH_MAN_INTEL)) {
 242                printf("Can't erase unknown flash type %08lx - aborted\n",
 243                       info->flash_id);
 244                return 1;
 245        }
 246
 247        prot = 0;
 248        for (sect = s_first; sect <= s_last; ++sect) {
 249                if (info->protect[sect]) {
 250                        prot++;
 251                }
 252        }
 253
 254        if (prot) {
 255                printf("- Warning: %d protected sectors will not be erased!\n",
 256                       prot);
 257        } else {
 258                printf("\n");
 259        }
 260
 261        start = get_timer(0);
 262        last = start;
 263
 264        /* Disable interrupts which might cause a timeout here */
 265        flag = disable_interrupts();
 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                        FPWV *addr = (FPWV *) (info->start[sect]);
 271                        FPW status;
 272
 273                        printf("Erasing sector %2d ... ", sect);
 274
 275                        /* arm simple, non interrupt dependent timer */
 276                        reset_timer_masked();
 277
 278                        *addr = (FPW) 0x00500050;       /* clear status register */
 279                        *addr = (FPW) 0x00200020;       /* erase setup */
 280                        *addr = (FPW) 0x00D000D0;       /* erase confirm */
 281
 282                        while (((status =
 283                                 *addr) & (FPW) 0x00800080) !=
 284                               (FPW) 0x00800080) {
 285                                if (get_timer_masked() > CONFIG_SYS_FLASH_ERASE_TOUT) {
 286                                        printf("Timeout\n");
 287                                        *addr = (FPW) 0x00B000B0;       /* suspend erase         */
 288                                        *addr = (FPW) 0x00FF00FF;       /* reset to read mode */
 289                                        rcode = 1;
 290                                        break;
 291                                }
 292                        }
 293
 294                        *addr = (FPW) 0x00500050;       /* clear status register cmd.   */
 295                        *addr = (FPW) 0x00FF00FF;       /* resest to read mode          */
 296
 297                        printf(" done\n");
 298                }
 299        }
 300        return rcode;
 301}
 302
 303/*-----------------------------------------------------------------------
 304 * Copy memory to flash, returns:
 305 * 0 - OK
 306 * 1 - write timeout
 307 * 2 - Flash not erased
 308 * 4 - Flash not identified
 309 */
 310
 311int
 312write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 313{
 314        ulong cp, wp;
 315        FPW data;
 316        int count, i, l, rc, port_width;
 317
 318        if (info->flash_id == FLASH_UNKNOWN) {
 319                return 4;
 320        }
 321/* get lower word aligned address */
 322#ifdef FLASH_PORT_WIDTH16
 323        wp = (addr & ~1);
 324        port_width = 2;
 325#else
 326        wp = (addr & ~3);
 327        port_width = 4;
 328#endif
 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 < port_width && cnt > 0; ++i) {
 339                        data = (data << 8) | *src++;
 340                        --cnt;
 341                        ++cp;
 342                }
 343                for (; cnt == 0 && i < port_width; ++i, ++cp) {
 344                        data = (data << 8) | (*(uchar *) cp);
 345                }
 346
 347                if ((rc = write_data(info, wp, SWAP(data))) != 0) {
 348                        return (rc);
 349                }
 350                wp += port_width;
 351        }
 352
 353        /*
 354         * handle word aligned part
 355         */
 356        count = 0;
 357        while (cnt >= port_width) {
 358                data = 0;
 359                for (i = 0; i < port_width; ++i) {
 360                        data = (data << 8) | *src++;
 361                }
 362                if ((rc = write_data(info, wp, SWAP(data))) != 0) {
 363                        return (rc);
 364                }
 365                wp += port_width;
 366                cnt -= port_width;
 367                if (count++ > 0x800) {
 368                        spin_wheel();
 369                        count = 0;
 370                }
 371        }
 372
 373        if (cnt == 0) {
 374                return (0);
 375        }
 376
 377        /*
 378         * handle unaligned tail bytes
 379         */
 380        data = 0;
 381        for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) {
 382                data = (data << 8) | *src++;
 383                --cnt;
 384        }
 385        for (; i < port_width; ++i, ++cp) {
 386                data = (data << 8) | (*(uchar *) cp);
 387        }
 388
 389        return (write_data(info, wp, SWAP(data)));
 390}
 391
 392/*-----------------------------------------------------------------------
 393 * Write a word or halfword to Flash, returns:
 394 * 0 - OK
 395 * 1 - write timeout
 396 * 2 - Flash not erased
 397 */
 398static int
 399write_data(flash_info_t * info, ulong dest, FPW data)
 400{
 401        FPWV *addr = (FPWV *) dest;
 402        ulong status;
 403        int flag;
 404
 405        /* Check if Flash is (sufficiently) erased */
 406        if ((*addr & data) != data) {
 407                printf("not erased at %08lX (%lX)\n", (ulong) addr, *addr);
 408                return (2);
 409        }
 410        /* Disable interrupts which might cause a timeout here */
 411        flag = disable_interrupts();
 412
 413        *addr = (FPW) 0x00400040;       /* write setup */
 414        *addr = data;
 415
 416        /* arm simple, non interrupt dependent timer */
 417        reset_timer_masked();
 418
 419        /* wait while polling the status register */
 420        while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
 421                if (get_timer_masked() > CONFIG_SYS_FLASH_WRITE_TOUT) {
 422                        *addr = (FPW) 0x00FF00FF;       /* restore read mode */
 423                        return (1);
 424                }
 425        }
 426
 427        *addr = (FPW) 0x00FF00FF;       /* restore read mode */
 428
 429        return (0);
 430}
 431
 432void inline
 433spin_wheel(void)
 434{
 435        static int p = 0;
 436        static char w[] = "\\/-";
 437
 438        printf("\010%c", w[p]);
 439        (++p == 3) ? (p = 0) : 0;
 440}
 441