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