]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - board/trab/flash.c
Fix flash driver for TRAB board (must use Unlock Bypass Reset command
[karo-tx-uboot.git] / board / trab / flash.c
index 2443777ae18fb0529cf91588324915c9bd25cfb8..764c57b482fc7e06ffe4d26974f8c12c625f85b8 100644 (file)
 #include <common.h>
 #include <environment.h>
 
-ulong myflush (void);
-
-
-#define FLASH_BANK_SIZE        0x800000        /* 8 MB */
-/* this varies depending on the sector */
-#define MAIN_SECT_SIZE  0x20000                /* 2 x 64 kB */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
 
 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
 
@@ -43,7 +38,11 @@ flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
 #define CMD_ERASE_CONFIRM      0x00300030
 #define CMD_PROGRAM            0x00A000A0
 #define CMD_UNLOCK_BYPASS      0x00200020
+#define CMD_READ_MANF_ID       0x00900090
+#define CMD_UNLOCK_BYPASS_RES1 0x00900090
+#define CMD_UNLOCK_BYPASS_RES2 0x00000000
 
+#define MEM_FLASH_ADDR         (*(volatile u32 *)CFG_FLASH_BASE)
 #define MEM_FLASH_ADDR1                (*(volatile u32 *)(CFG_FLASH_BASE + (0x00000555 << 2)))
 #define MEM_FLASH_ADDR2                (*(volatile u32 *)(CFG_FLASH_BASE + (0x000002AA << 2)))
 
@@ -64,27 +63,38 @@ ulong flash_init (void)
        int i, j;
        ulong size = 0;
 
-       for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
                ulong flashbase = 0;
+               flash_info_t *info = &flash_info[i];
+
+               /* Init: no FLASHes known */
+               info->flash_id = FLASH_UNKNOWN;
+
+               size += flash_get_size (CFG_FLASH_BASE, info);
 
-               flash_info[i].flash_id =
-                       (AMD_MANUFACT  & FLASH_VENDMASK) |
-                       (AMD_ID_LV320B & FLASH_TYPEMASK);
-               flash_info[i].size = FLASH_BANK_SIZE;
-               flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
-               memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
                if (i == 0)
-                       flashbase = PHYS_FLASH_1;
+                       flashbase = CFG_FLASH_BASE;
                else
                        panic ("configured too many flash banks!\n");
-               for (j = 0; j < flash_info[i].sector_count; j++) {
-
-                       flash_info[i].start[j] = flashbase;
-
-                       /* the first 8 sectors are 8 kB */
-                       flashbase += (j < 8) ? 0x4000 : MAIN_SECT_SIZE;
+               for (j = 0; j < info->sector_count; j++) {
+
+                       info->protect[j] = 0;
+                       info->start[j] = flashbase;
+
+                       switch (info->flash_id & FLASH_TYPEMASK) {
+                       case (FLASH_AM320B & FLASH_TYPEMASK):
+                               /* Boot sector type: 8 x 8 + N x 128 kB */
+                               flashbase += (j < 8) ? 0x4000 : 0x20000;
+                               break;
+                       case (FLASH_AM640U & FLASH_TYPEMASK):
+                               /* Uniform sector type: 128 kB */
+                               flashbase += 0x20000;
+                               break;
+                       default:
+                               printf ("## Bad flash chip type 0x%04lX\n",
+                                       info->flash_id & FLASH_TYPEMASK);
+                       }
                }
-               size += flash_info[i].size;
        }
 
        /*
@@ -92,7 +102,7 @@ ulong flash_init (void)
         */
        flash_protect ( FLAG_PROTECT_SET,
                        CFG_FLASH_BASE,
-                       CFG_FLASH_BASE + _armboot_end_data - _armboot_start,
+                       CFG_FLASH_BASE + monitor_flash_len - 1,
                        &flash_info[0]);
 
        flash_protect ( FLAG_PROTECT_SET,
@@ -116,18 +126,20 @@ void flash_print_info (flash_info_t * info)
        int i;
 
        switch (info->flash_id & FLASH_VENDMASK) {
-       case (AMD_MANUFACT & FLASH_VENDMASK):
-               printf ("AMD: ");
-               break;
-       default:
-               printf ("Unknown Vendor ");
-               break;
+       case (FLASH_MAN_AMD & FLASH_VENDMASK):
+                       printf ("AMD ");                break;
+       case (FLASH_MAN_FUJ & FLASH_VENDMASK):
+                       printf ("FUJITSU ");            break;
+       default:        printf ("Unknown Vendor ");     break;
        }
 
        switch (info->flash_id & FLASH_TYPEMASK) {
-       case (AMD_ID_LV320B & FLASH_TYPEMASK):
+       case (FLASH_AM320B & FLASH_TYPEMASK):
                printf ("2x Am29LV320DB (32Mbit)\n");
                break;
+       case (FLASH_AM640U & FLASH_TYPEMASK):
+               printf ("2x Am29LV640D (64Mbit)\n");
+               break;
        default:
                printf ("Unknown Chip Type\n");
                goto Done;
@@ -176,9 +188,12 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
                return ERR_INVAL;
        }
 
-       if ((info->flash_id & FLASH_VENDMASK) !=
-               (AMD_MANUFACT & FLASH_VENDMASK)) {
-               return ERR_UNKNOWN_FLASH_VENDOR;
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case (FLASH_MAN_AMD & FLASH_VENDMASK):  break;  /* OK */
+       case (FLASH_MAN_FUJ & FLASH_VENDMASK):  break;  /* OK */
+       default:
+               debug ("## flash_erase: unknown manufacturer\n");
+               return (ERR_UNKNOWN_FLASH_VENDOR);
        }
 
        prot = 0;
@@ -265,13 +280,6 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
                                rc = ERR_TIMOUT;
                                goto outahere;
                        }
-
-#if 0
-                       printf ("ok.\n");
-               } else {                /* it was protected */
-
-                       printf ("protected!\n");
-#endif
                }
        }
 
@@ -326,9 +334,6 @@ volatile static int write_word (flash_info_t * info, ulong dest,
 #endif
        iflag = disable_interrupts ();
 
-       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-       MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
        *addr = CMD_PROGRAM;
        *addr = data;
 
@@ -397,6 +402,10 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
        int l;
        int i, rc;
 
+       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+       MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
+
        wp = (addr & ~3);       /* get lower word aligned address */
 
        /*
@@ -417,7 +426,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
                }
 
                if ((rc = write_word (info, wp, data)) != 0) {
-                       return (rc);
+                       goto Done;
                }
                wp += 4;
        }
@@ -426,9 +435,17 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
         * handle word aligned part
         */
        while (cnt >= 4) {
-               data = *((vu_long *) src);
+               if (((ulong)src) & 0x3) {
+                       for (i = 0; i < 4; i++) {
+                               ((char *)&data)[i] = ((vu_char *)src)[i];
+                       }
+               }
+               else {
+                       data = *((vu_long *) src);
+               }
+
                if ((rc = write_word (info, wp, data)) != 0) {
-                       return (rc);
+                       goto Done;
                }
                src += 4;
                wp += 4;
@@ -436,7 +453,8 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
        }
 
        if (cnt == 0) {
-               return ERR_OK;
+               rc = ERR_OK;
+               goto Done;
        }
 
        /*
@@ -451,5 +469,82 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
                data = (data >> 8) | (*(uchar *) cp << 24);
        }
 
-       return write_word (info, wp, data);
+       rc = write_word (info, wp, data);
+
+       Done:
+
+       MEM_FLASH_ADDR = CMD_UNLOCK_BYPASS_RES1;
+       MEM_FLASH_ADDR = CMD_UNLOCK_BYPASS_RES2;
+
+       return (rc);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       ulong value;
+
+       /* Write auto select command sequence and read Manufacturer ID */
+       addr[0x0555] = CMD_UNLOCK1;
+       addr[0x02AA] = CMD_UNLOCK2;
+       addr[0x0555] = CMD_READ_MANF_ID;
+
+       value = addr[0];
+
+       debug ("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value);
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               addr[0] = 0x00FF00FF;           /* restore read mode */
+               debug ("## flash_init: unknown manufacturer\n");
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       debug ("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value);
+
+       switch (value) {
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 71;
+               info->size = 0x00800000;
+
+               addr[0] = 0x00FF00FF;           /* restore read mode */
+               break;                          /* =>  8 MB             */
+
+       case AMD_ID_LV640U:
+               info->flash_id += FLASH_AM640U;
+               info->sector_count = 128;
+               info->size = 0x01000000;
+
+               addr[0] = 0x00F000F0;           /* restore read mode */
+               break;                          /* => 16 MB             */
+
+       default:
+               debug ("## flash_init: unknown flash chip\n");
+               info->flash_id = FLASH_UNKNOWN;
+               addr[0] = 0x00FF00FF;           /* restore read mode */
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       return (info->size);
 }