uboot/board/siemens/SMN42/flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2006 Embedded Artists AB <www.embeddedartists.com>
   3 *
   4 * (C) Copyright 2007 Gary Jennejohn garyj@denx.de
   5 * Modified to use the routines in arch/arm/cpu/arm720t/lpc2292/flash.c.
   6 * Heavily modified to support the SMN42 board from Siemens
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 */
  23
  24#include <common.h>
  25#include <asm/byteorder.h>
  26#include <asm/arch/hardware.h>
  27
  28static unsigned long flash_addr_table[CONFIG_SYS_MAX_FLASH_BANKS] = CONFIG_SYS_FLASH_BANKS_LIST;
  29flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
  30
  31extern int lpc2292_copy_buffer_to_flash(flash_info_t *, ulong);
  32extern int lpc2292_flash_erase(flash_info_t *, int, int);
  33extern int lpc2292_write_buff (flash_info_t *, uchar *, ulong, ulong);
  34static unsigned long ext_flash_init(void);
  35static int ext_flash_erase(flash_info_t *, int, int);
  36static int ext_write_buff(flash_info_t *, uchar *, ulong, ulong);
  37
  38/*-----------------------------------------------------------------------
  39 */
  40
  41ulong flash_init (void)
  42{
  43        int j, k;
  44        ulong size = 0;
  45        ulong flashbase = 0;
  46
  47        flash_info[0].flash_id = PHILIPS_LPC2292;
  48        flash_info[0].size = 0x003E000; /* 256 - 8 KB */
  49        flash_info[0].sector_count = 17;
  50        memset (flash_info[0].protect, 0, 17);
  51        flashbase = 0x00000000;
  52        for (j = 0, k = 0; j < 8; j++, k++) {
  53                flash_info[0].start[k] = flashbase;
  54                flashbase += 0x00002000;
  55        }
  56        for (j = 0; j < 2; j++, k++) {
  57                flash_info[0].start[k] = flashbase;
  58                flashbase += 0x00010000;
  59        }
  60        for (j = 0; j < 7; j++, k++) {
  61                flash_info[0].start[k] = flashbase;
  62                flashbase += 0x00002000;
  63        }
  64        size += flash_info[0].size;
  65
  66        /* Protect monitor and environment sectors */
  67        flash_protect (FLAG_PROTECT_SET,
  68                 0x0,
  69                 0x0 + monitor_flash_len - 1,
  70                 &flash_info[0]);
  71
  72        flash_protect (FLAG_PROTECT_SET,
  73                 CONFIG_ENV_ADDR,
  74                 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
  75                 &flash_info[0]);
  76
  77        size += ext_flash_init();
  78
  79        return size;
  80}
  81
  82/*-----------------------------------------------------------------------
  83 */
  84void flash_print_info (flash_info_t * info)
  85{
  86        int i;
  87        int erased = 0;
  88        unsigned long j;
  89        unsigned long count;
  90        unsigned char *p;
  91
  92        switch (info->flash_id & FLASH_VENDMASK) {
  93        case (PHILIPS_LPC2292 & FLASH_VENDMASK):
  94                printf("Philips: ");
  95                break;
  96        case FLASH_MAN_AMD:
  97                printf("AMD: ");
  98                break;
  99        default:
 100                printf ("Unknown Vendor ");
 101                break;
 102        }
 103
 104        switch (info->flash_id & FLASH_TYPEMASK) {
 105        case (PHILIPS_LPC2292 & FLASH_TYPEMASK):
 106                printf("LPC2292 internal flash\n");
 107                break;
 108        case FLASH_S29GL128N:
 109                printf ("S29GL128N (128 Mbit, uniform sector size)\n");
 110                break;
 111        default:
 112                printf("Unknown Chip Type\n");
 113                return;
 114        }
 115
 116        printf ("  Size: %ld KB in %d Sectors\n",
 117          info->size >> 10, info->sector_count);
 118
 119        printf ("  Sector Start Addresses:");
 120        for (i = 0; i < info->sector_count; i++) {
 121                if ((i % 5) == 0) {
 122                        printf ("\n   ");
 123                }
 124                if (i < (info->sector_count - 1)) {
 125                        count = info->start[i+1] - info->start[i];
 126                }
 127                else {
 128                        count = info->start[0] + info->size - info->start[i];
 129                }
 130                p = (unsigned char*)(info->start[i]);
 131                erased = 1;
 132                for (j = 0; j < count; j++) {
 133                        if (*p != 0xFF) {
 134                                erased = 0;
 135                                break;
 136                        }
 137                        p++;
 138                }
 139                printf (" %08lX%s%s", info->start[i], info->protect[i] ? " RO" : "   ",
 140                        erased ? " E" : "  ");
 141        }
 142        printf ("\n");
 143}
 144
 145int flash_erase (flash_info_t * info, int s_first, int s_last)
 146{
 147        switch (info->flash_id & FLASH_TYPEMASK) {
 148                case (PHILIPS_LPC2292 & FLASH_TYPEMASK):
 149                        return lpc2292_flash_erase(info, s_first, s_last);
 150                case FLASH_S29GL128N:
 151                        return ext_flash_erase(info, s_first, s_last);
 152                default:
 153                        return ERR_PROTECTED;
 154        }
 155        return ERR_PROTECTED;
 156}
 157
 158int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 159{
 160        switch (info->flash_id & FLASH_TYPEMASK) {
 161                case (PHILIPS_LPC2292 & FLASH_TYPEMASK):
 162                        return lpc2292_write_buff(info, src, addr, cnt);
 163                case FLASH_S29GL128N:
 164                        return ext_write_buff(info, src, addr, cnt);
 165                default:
 166                        return ERR_PROG_ERROR;
 167        }
 168        return ERR_PROG_ERROR;
 169}
 170
 171/*--------------------------------------------------------------------------
 172 * From here on is code for the external S29GL128N taken from cam5200_flash.c
 173 */
 174
 175#define CONFIG_SYS_FLASH_WORD_SIZE unsigned short
 176
 177static int wait_for_DQ7_32(flash_info_t * info, int sect)
 178{
 179        ulong start, now, last;
 180        volatile CONFIG_SYS_FLASH_WORD_SIZE *addr =
 181                (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[sect]);
 182
 183        start = get_timer(0);
 184        last = start;
 185        while ((addr[0] & (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080) !=
 186                        (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080) {
 187                if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 188                        printf("Timeout\n");
 189                        return -1;
 190                }
 191                /* show that we're waiting */
 192                if ((now - last) > 1000) {      /* every second */
 193                        putc('.');
 194                        last = now;
 195                }
 196        }
 197        return 0;
 198}
 199
 200int ext_flash_erase(flash_info_t * info, int s_first, int s_last)
 201{
 202        volatile CONFIG_SYS_FLASH_WORD_SIZE *addr = (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[0]);
 203        volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2;
 204        int flag, prot, sect, l_sect, ret;
 205
 206        ret = 0;
 207        if ((s_first < 0) || (s_first > s_last)) {
 208                if (info->flash_id == FLASH_UNKNOWN)
 209                        printf("- missing\n");
 210                else
 211                        printf("- no sectors to erase\n");
 212                return 1;
 213        }
 214
 215        if (info->flash_id == FLASH_UNKNOWN) {
 216                printf("Can't erase unknown flash type - aborted\n");
 217                return 1;
 218        }
 219
 220        prot = 0;
 221        for (sect = s_first; sect <= s_last; ++sect) {
 222                if (info->protect[sect])
 223                        prot++;
 224        }
 225
 226        if (prot)
 227                printf("- Warning: %d protected sectors will not be erased!", prot);
 228
 229        printf("\n");
 230
 231        l_sect = -1;
 232
 233        /* Disable interrupts which might cause a timeout here */
 234        flag = disable_interrupts();
 235
 236        /* Start erase on unprotected sectors */
 237        for (sect = s_first; sect <= s_last; sect++) {
 238                if (info->protect[sect] == 0) { /* not protected */
 239                        addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[sect]);
 240
 241                        addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
 242                        addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
 243                        addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080;
 244                        addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
 245                        addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
 246                        addr2[0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00300030;     /* sector erase */
 247
 248                        l_sect = sect;
 249                        /*
 250                         * Wait for each sector to complete, it's more
 251                         * reliable.  According to AMD Spec, you must
 252                         * issue all erase commands within a specified
 253                         * timeout.  This has been seen to fail, especially
 254                         * if printf()s are included (for debug)!!
 255                         */
 256                        ret = wait_for_DQ7_32(info, sect);
 257                        if (ret) {
 258                                ret = ERR_PROTECTED;
 259                                break;
 260                        }
 261                }
 262        }
 263
 264        /* re-enable interrupts if necessary */
 265        if (flag)
 266                enable_interrupts();
 267
 268        /* wait at least 80us - let's wait 1 ms */
 269        udelay(1000);
 270
 271        /* reset to read mode */
 272        addr = (CONFIG_SYS_FLASH_WORD_SIZE *) info->start[0];
 273        addr[0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00F000F0;      /* reset bank */
 274
 275        if (ret)
 276                printf(" error\n");
 277        else
 278                printf(" done\n");
 279        return ret;
 280}
 281
 282static ulong flash_get_size(vu_long * addr, flash_info_t * info)
 283{
 284        short i;
 285        CONFIG_SYS_FLASH_WORD_SIZE value;
 286        ulong base = (ulong) addr;
 287        volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *) addr;
 288
 289        /* Write auto select command: read Manufacturer ID */
 290        addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
 291        addr2[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
 292        addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00900090;
 293        udelay(1000);
 294
 295        value = addr2[0];
 296
 297        switch (value) {
 298                case (CONFIG_SYS_FLASH_WORD_SIZE) AMD_MANUFACT:
 299                        info->flash_id = FLASH_MAN_AMD;
 300                        break;
 301                default:
 302                        info->flash_id = FLASH_UNKNOWN;
 303                        info->sector_count = 0;
 304                        info->size = 0;
 305                        return (0);     /* no or unknown flash  */
 306        }
 307
 308        value = addr2[1];       /* device ID            */
 309
 310        switch (value) {
 311                case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_MIRROR:
 312                        value = addr2[14];
 313                        switch(value) {
 314                                case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_GL128N_2:
 315                                        value = addr2[15];
 316                                        if (value != (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_GL128N_3) {
 317                                                info->flash_id = FLASH_UNKNOWN;
 318                                        } else {
 319                                                info->flash_id += FLASH_S29GL128N;
 320                                                info->sector_count = 128;
 321                                                info->size = 0x01000000;
 322                                        }
 323                                        break;
 324                                default:
 325                                        info->flash_id = FLASH_UNKNOWN;
 326                                        return(0);
 327                        }
 328                        break;
 329
 330                default:
 331                        info->flash_id = FLASH_UNKNOWN;
 332                        return (0);     /* => no or unknown flash */
 333        }
 334
 335        /* set up sector start address table */
 336        for (i = 0; i < info->sector_count; i++)
 337                info->start[i] = base + (i * 0x00020000);
 338
 339        /* check for protected sectors */
 340        for (i = 0; i < info->sector_count; i++) {
 341                /* read sector protection at sector address, (A7 .. A0) = 0x02 */
 342                /* D0 = 1 if protected */
 343                addr2 = (volatile CONFIG_SYS_FLASH_WORD_SIZE *)(info->start[i]);
 344
 345                info->protect[i] = addr2[2] & 1;
 346        }
 347
 348        /* issue bank reset to return to read mode */
 349        addr2[0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00F000F0;
 350
 351        return (info->size);
 352}
 353
 354static unsigned long ext_flash_init(void)
 355{
 356        unsigned long total_b = 0;
 357        unsigned long size_b[CONFIG_SYS_MAX_FLASH_BANKS];
 358        int i;
 359
 360        /* Init: no FLASHes known */
 361        for (i = 1; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
 362                flash_info[i].flash_id = FLASH_UNKNOWN;
 363                flash_info[i].sector_count = -1;
 364                flash_info[i].size = 0;
 365
 366                /* call flash_get_size() to initialize sector address */
 367                size_b[i] = flash_get_size((vu_long *) flash_addr_table[i],
 368                                &flash_info[i]);
 369
 370                flash_info[i].size = size_b[i];
 371
 372                if (flash_info[i].flash_id == FLASH_UNKNOWN) {
 373                        printf("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
 374                                        i+1, size_b[i], size_b[i] << 20);
 375                        flash_info[i].sector_count = -1;
 376                        flash_info[i].size = 0;
 377                }
 378
 379                total_b += flash_info[i].size;
 380        }
 381
 382        return total_b;
 383}
 384
 385static int write_word(flash_info_t * info, ulong dest, ushort data)
 386{
 387        volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[0]);
 388        volatile CONFIG_SYS_FLASH_WORD_SIZE *dest2 = (CONFIG_SYS_FLASH_WORD_SIZE *) dest;
 389        volatile CONFIG_SYS_FLASH_WORD_SIZE *data2 = (CONFIG_SYS_FLASH_WORD_SIZE *) &data;
 390        ulong start;
 391        int flag;
 392
 393        /* Check if Flash is (sufficiently) erased */
 394        if ((*dest2 & *data2) != *data2) {
 395                return (2);
 396        }
 397
 398        /* Disable interrupts which might cause a timeout here */
 399        flag = disable_interrupts();
 400
 401        addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
 402        addr2[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
 403        addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00A000A0;
 404        *dest2 = *data2;
 405
 406        /* re-enable interrupts if necessary */
 407        if (flag)
 408                enable_interrupts();
 409
 410        /* data polling for D7 */
 411        start = get_timer(0);
 412        while ((*dest2 & (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080) !=
 413                        (*data2 & (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080)) {
 414
 415                if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 416                        printf("WRITE_TOUT\n");
 417                        return (1);
 418                }
 419        }
 420        return (0);
 421}
 422
 423/*-----------------------------------------------------------------------
 424 * This is taken from the original flash.c for the LPC2292 SODIMM board
 425 * and modified to suit.
 426 */
 427
 428int ext_write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 429{
 430        ushort tmp;
 431        ulong i;
 432        uchar* src_org;
 433        uchar* dst_org;
 434        ulong cnt_org = cnt;
 435        int ret = ERR_OK;
 436
 437        src_org = src;
 438        dst_org = (uchar*)addr;
 439
 440        if (addr & 1) {         /* if odd address */
 441                tmp = *((uchar*)(addr - 1)); /* little endian */
 442                tmp |= (*src << 8);
 443                if (write_word(info, addr - 1, tmp))
 444                        return ERR_PROG_ERROR;
 445                addr += 1;
 446                cnt -= 1;
 447                src++;
 448        }
 449        while (cnt > 1) {
 450                tmp = ((*(src+1)) << 8) + (*src); /* little endian */
 451                if (write_word(info, addr, tmp))
 452                        return ERR_PROG_ERROR;
 453                addr += 2;
 454                src += 2;
 455                cnt -= 2;
 456        }
 457        if (cnt > 0) {
 458                tmp = (*((uchar*)(addr + 1))) << 8;
 459                tmp |= *src;
 460                if (write_word(info, addr, tmp))
 461                        return ERR_PROG_ERROR;
 462        }
 463
 464        for (i = 0; i < cnt_org; i++) {
 465                if (*dst_org != *src_org) {
 466                        printf("Write failed. Byte %lX differs\n", i);
 467                        ret = ERR_PROG_ERROR;
 468                        break;
 469                }
 470                dst_org++;
 471                src_org++;
 472        }
 473
 474        return ret;
 475}
 476