hammerhead: Add missing printf parameter to CONFIG_AUTOBOOT_PROMPT
[platform/kernel/u-boot.git] / board / freescale / m54455evb / flash.c
index de2cca8..6b50e8d 100644 (file)
@@ -95,6 +95,11 @@ typedef volatile unsigned char FLASH_PORT_WIDTHV;
 #define FLASH_28F256P30T       0x00BD  /* Intel 28F256P30T  ( 256M = 16M x 16 )        */
 #define FLASH_28F256P30B       0x00BE  /* Intel 28F256P30B  ( 256M = 16M x 16 )        */
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+#define STM_ID_M25P16          0x20152015
+#define FLASH_M25P16           0x0055
+#endif
+
 #define SYNC                   __asm__("nop")
 
 /*-----------------------------------------------------------------------
@@ -111,6 +116,12 @@ void inline spin_wheel(void);
 void flash_sync_real_protect(flash_info_t * info);
 uchar intel_sector_protected(flash_info_t * info, ushort sector);
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+int write_ser_data(flash_info_t * info, ulong dest, uchar * data, ulong cnt);
+int serial_flash_read_status(int chipsel);
+static int ser_flash_cs = 0;
+#endif
+
 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
 
 ulong flash_init(void)
@@ -119,6 +130,10 @@ ulong flash_init(void)
        ulong size = 0;
        ulong fbase = 0;
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       dspi_init();
+#endif
+
        for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
                memset(&flash_info[i], 0, sizeof(flash_info_t));
 
@@ -129,6 +144,11 @@ ulong flash_init(void)
                case 1:
                        fbase = (ulong) CFG_FLASH1_BASE;
                        break;
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+               case 2:
+                       fbase = (ulong) CFG_FLASH2_BASE;
+                       break;
+#endif
                }
 
                flash_get_size((FPWV *) fbase, &flash_info[i]);
@@ -152,7 +172,6 @@ int flash_get_offsets(ulong base, flash_info_t * info)
 {
        int i, j, k;
        int sectors, bs, banks;
-       ulong start;
 
        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_ATM) {
                int sect[] = CFG_ATMEL_SECT;
@@ -196,6 +215,15 @@ int flash_get_offsets(ulong base, flash_info_t * info)
 
                *addr16 = (FPW) INTEL_RESET;    /* restore read mode */
        }
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM) {
+               info->start[0] = CFG_FLASH2_BASE;
+               for (k = 0, i = 0; i < CFG_STM_SECT; i++, k++) {
+                       info->start[k + 1] = info->start[k] + CFG_STM_SECTSZ;
+                       info->protect[k] = 0;
+               }
+       }
+#endif
 
        return ERR_OK;
 }
@@ -211,6 +239,11 @@ void flash_print_info(flash_info_t * info)
        case FLASH_MAN_ATM:
                printf("ATMEL ");
                break;
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       case FLASH_MAN_STM:
+               printf("ST ");
+               break;
+#endif
        default:
                printf("Unknown Vendor ");
                break;
@@ -221,8 +254,13 @@ void flash_print_info(flash_info_t * info)
                printf("AT49BV040A\n");
                break;
        case FLASH_28F128J3A:
-               printf("Intel 28F128J3A\n");
+               printf("28F128J3A\n");
+               break;
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       case FLASH_M25P16:
+               printf("M25P16\n");
                break;
+#endif
        default:
                printf("Unknown Chip Type\n");
                return;
@@ -267,6 +305,45 @@ ulong flash_get_size(FPWV * addr, flash_info_t * info)
        u16 value;
        int i;
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       if ((ulong) addr == CFG_FLASH2_BASE) {
+               int manufactId = 0;
+               int deviceId = 0;
+
+               ser_flash_cs = 1;
+
+               dspi_tx(ser_flash_cs, 0x80, SER_RDID);
+               dspi_tx(ser_flash_cs, 0x80, 0);
+               dspi_tx(ser_flash_cs, 0x80, 0);
+               dspi_tx(ser_flash_cs, 0x80, 0);
+
+               dspi_rx();
+               manufactId = dspi_rx();
+               deviceId = dspi_rx() << 8;
+               deviceId |= dspi_rx();
+
+               dspi_tx(ser_flash_cs, 0x00, 0);
+               dspi_rx();
+
+               switch (manufactId) {
+               case (u8) STM_MANUFACT:
+                       info->flash_id = FLASH_MAN_STM;
+                       break;
+               }
+
+               switch (deviceId) {
+               case (u16) STM_ID_M25P16:
+                       info->flash_id += FLASH_M25P16;
+                       break;
+               }
+
+               info->sector_count = CFG_STM_SECT;
+               info->size = CFG_STM_SECT * CFG_STM_SECTSZ;
+
+               return (info->size);
+       }
+#endif
+
        addr[FLASH_CYCLE1] = (FPWV) 0x00AA00AA; /* for Atmel, Intel ignores this */
        addr[FLASH_CYCLE2] = (FPWV) 0x00550055; /* for Atmel, Intel ignores this */
        addr[FLASH_CYCLE1] = (FPWV) 0x00900090; /* selects Intel or Atmel */
@@ -383,6 +460,21 @@ int flash_cmd_rd(volatile u16 * addr, int index)
        return (int)addr[index];
 }
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+int serial_flash_read_status(int chipsel)
+{
+       u16 status;
+
+       dspi_tx(chipsel, 0x80, SER_RDSR);
+       dspi_rx();
+
+       dspi_tx(chipsel, 0x00, 0);
+       status = dspi_rx();
+
+       return status;
+}
+#endif
+
 /*
  * This function gets the u-boot flash sector protection status
  * (flash_info_t.protect[]) in sync with the sector protection
@@ -462,8 +554,11 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
 {
        int flag, prot, sect;
        ulong type, start, last;
-       int rcode = 0, intel = 0;
-
+       int rcode = 0, flashtype = 0;
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       int count;
+       u16 status;
+#endif
        if ((s_first < 0) || (s_first > s_last)) {
                if (info->flash_id == FLASH_UNKNOWN)
                        printf("- missing\n");
@@ -474,19 +569,25 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
 
        type = (info->flash_id & FLASH_VENDMASK);
 
-       if (type != (FLASH_MAN_INTEL & FLASH_VENDMASK)) {
-               if (type != (FLASH_MAN_ATM & FLASH_VENDMASK)) {
-                       type = (info->flash_id & FLASH_VENDMASK);
-                       printf
-                           ("Can't erase unknown flash type %08lx - aborted\n",
-                            info->flash_id);
-                       return 1;
-               }
+       switch (type) {
+       case FLASH_MAN_ATM:
+               flashtype = 1;
+               break;
+       case FLASH_MAN_INTEL:
+               flashtype = 2;
+               break;
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       case FLASH_MAN_STM:
+               flashtype = 3;
+               break;
+#endif
+       default:
+               type = (info->flash_id & FLASH_VENDMASK);
+               printf("Can't erase unknown flash type %08lx - aborted\n",
+                      info->flash_id);
+               return 1;
        }
 
-       if (type == FLASH_MAN_INTEL)
-               intel = 1;
-
        prot = 0;
        for (sect = s_first; sect <= s_last; ++sect) {
                if (info->protect[sect]) {
@@ -503,6 +604,51 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
        start = get_timer(0);
        last = start;
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       /* Perform bulk erase */
+       if (flashtype == 3) {
+               if ((s_last - s_first) == (CFG_STM_SECT - 1)) {
+                       if (prot == 0) {
+                               dspi_tx(ser_flash_cs, 0x00, SER_WREN);
+                               dspi_rx();
+
+                               status = serial_flash_read_status(ser_flash_cs);
+                               if (((status & 0x9C) != 0)
+                                   && ((status & 0x02) != 0x02)) {
+                                       printf("Can't erase flash\n");
+                                       return 1;
+                               }
+
+                               dspi_tx(ser_flash_cs, 0x00, SER_BULK_ERASE);
+                               dspi_rx();
+
+                               count = 0;
+                               start = get_timer(0);
+                               do {
+                                       status =
+                                           serial_flash_read_status
+                                           (ser_flash_cs);
+
+                                       if (count++ > 0x10000) {
+                                               spin_wheel();
+                                               count = 0;
+                                       }
+
+                                       if (get_timer(start) >
+                                           CFG_FLASH_ERASE_TOUT) {
+                                               printf("Timeout\n");
+                                               return 1;
+                                       }
+                               } while (status & 0x01);
+
+                               printf("\b. done\n");
+                               return 0;
+                       } else if (prot == CFG_STM_SECT) {
+                               return 1;
+                       }
+               }
+       }
+#endif
        /* Start erase on unprotected sectors */
        for (sect = s_first; sect <= s_last; sect++) {
                if (info->protect[sect] == 0) { /* not protected */
@@ -515,65 +661,116 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
                        /* arm simple, non interrupt dependent timer */
                        start = get_timer(0);
 
-                       if (intel) {
-                               *addr = (FPW) INTEL_READID;
-                               min = addr[INTEL_CFI_TERB] & 0xff;
-                               min = 1 << min; /* ms */
-                               min = (min / info->sector_count) * 1000;
-
-                               /* start erase block */
-                               *addr = (FPW) INTEL_CLEAR;      /* clear status register */
-                               *addr = (FPW) INTEL_ERASE;      /* erase setup */
-                               *addr = (FPW) INTEL_CONFIRM;    /* erase confirm */
-
-                               while ((*addr & (FPW) INTEL_FINISHED) !=
-                                      (FPW) INTEL_FINISHED) {
-
-                                       if (get_timer(start) >
-                                           CFG_FLASH_ERASE_TOUT) {
-                                               printf("Timeout\n");
-                                               *addr = (FPW) INTEL_SUSERASE;   /* suspend erase     */
-                                               *addr = (FPW) INTEL_RESET;      /* reset to read mode */
-
-                                               rcode = 1;
-                                               break;
+                       switch (flashtype) {
+                       case 1:
+                               {
+                                       FPWV *base;     /* first address in bank */
+                                       FPWV *atmeladdr;
+
+                                       flag = disable_interrupts();
+
+                                       atmeladdr = (FPWV *) addr;      /* concatenate to 8 bit */
+                                       base = (FPWV *) (CFG_ATMEL_BASE);       /* First sector */
+
+                                       base[FLASH_CYCLE1] = (u8) 0x00AA00AA;   /* unlock */
+                                       base[FLASH_CYCLE2] = (u8) 0x00550055;   /* unlock */
+                                       base[FLASH_CYCLE1] = (u8) 0x00800080;   /* erase mode */
+                                       base[FLASH_CYCLE1] = (u8) 0x00AA00AA;   /* unlock */
+                                       base[FLASH_CYCLE2] = (u8) 0x00550055;   /* unlock */
+                                       *atmeladdr = (u8) 0x00300030;   /* erase sector */
+
+                                       if (flag)
+                                               enable_interrupts();
+
+                                       while ((*atmeladdr & (u8) 0x00800080) !=
+                                              (u8) 0x00800080) {
+                                               if (get_timer(start) >
+                                                   CFG_FLASH_ERASE_TOUT) {
+                                                       printf("Timeout\n");
+                                                       *atmeladdr = (u8) 0x00F000F0;   /* reset to read mode */
+
+                                                       rcode = 1;
+                                                       break;
+                                               }
                                        }
-                               }
-
-                               *addr = (FPW) INTEL_RESET;      /* resest to read mode          */
-                       } else {
-                               FPWV *base;     /* first address in bank */
-                               FPWV *atmeladdr;
-
-                               flag = disable_interrupts();
 
-                               atmeladdr = (FPWV *) addr;      /* concatenate to 8 bit */
-                               base = (FPWV *) (CFG_ATMEL_BASE);       /* First sector */
-
-                               base[FLASH_CYCLE1] = (u8) 0x00AA00AA;   /* unlock */
-                               base[FLASH_CYCLE2] = (u8) 0x00550055;   /* unlock */
-                               base[FLASH_CYCLE1] = (u8) 0x00800080;   /* erase mode */
-                               base[FLASH_CYCLE1] = (u8) 0x00AA00AA;   /* unlock */
-                               base[FLASH_CYCLE2] = (u8) 0x00550055;   /* unlock */
-                               *atmeladdr = (u8) 0x00300030;   /* erase sector */
+                                       *atmeladdr = (u8) 0x00F000F0;   /* reset to read mode */
+                                       break;
+                               }
 
-                               if (flag)
-                                       enable_interrupts();
+                       case 2:
+                               {
+                                       *addr = (FPW) INTEL_READID;
+                                       min = addr[INTEL_CFI_TERB] & 0xff;
+                                       min = 1 << min; /* ms */
+                                       min = (min / info->sector_count) * 1000;
+
+                                       /* start erase block */
+                                       *addr = (FPW) INTEL_CLEAR;      /* clear status register */
+                                       *addr = (FPW) INTEL_ERASE;      /* erase setup */
+                                       *addr = (FPW) INTEL_CONFIRM;    /* erase confirm */
+
+                                       while ((*addr & (FPW) INTEL_FINISHED) !=
+                                              (FPW) INTEL_FINISHED) {
+
+                                               if (get_timer(start) >
+                                                   CFG_FLASH_ERASE_TOUT) {
+                                                       printf("Timeout\n");
+                                                       *addr = (FPW) INTEL_SUSERASE;   /* suspend erase     */
+                                                       *addr = (FPW) INTEL_RESET;      /* reset to read mode */
+
+                                                       rcode = 1;
+                                                       break;
+                                               }
+                                       }
 
-                               while ((*atmeladdr & (u8) 0x00800080) !=
-                                      (u8) 0x00800080) {
-                                       if (get_timer(start) >
-                                           CFG_FLASH_ERASE_TOUT) {
-                                               printf("Timeout\n");
-                                               *atmeladdr = (u8) 0x00F000F0;   /* reset to read mode */
+                                       *addr = (FPW) INTEL_RESET;      /* resest to read mode          */
+                                       break;
+                               }
 
-                                               rcode = 1;
-                                               break;
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+                       case 3:
+                               {
+                                       u8 sec = ((ulong) addr >> 16) & 0xFF;
+
+                                       dspi_tx(ser_flash_cs, 0x00, SER_WREN);
+                                       dspi_rx();
+                                       status =
+                                           serial_flash_read_status
+                                           (ser_flash_cs);
+                                       if (((status & 0x9C) != 0)
+                                           && ((status & 0x02) != 0x02)) {
+                                               printf("Error Programming\n");
+                                               return 1;
                                        }
-                               }
 
-                               *atmeladdr = (u8) 0x00F000F0;   /* reset to read mode */
-                       }       /* Atmel or Intel */
+                                       dspi_tx(ser_flash_cs, 0x80,
+                                               SER_SECT_ERASE);
+                                       dspi_tx(ser_flash_cs, 0x80, sec);
+                                       dspi_tx(ser_flash_cs, 0x80, 0);
+                                       dspi_tx(ser_flash_cs, 0x00, 0);
+
+                                       dspi_rx();
+                                       dspi_rx();
+                                       dspi_rx();
+                                       dspi_rx();
+
+                                       do {
+                                               status =
+                                                   serial_flash_read_status
+                                                   (ser_flash_cs);
+
+                                               if (get_timer(start) >
+                                                   CFG_FLASH_ERASE_TOUT) {
+                                                       printf("Timeout\n");
+                                                       return 1;
+                                               }
+                                       } while (status & 0x01);
+
+                                       break;
+                               }
+#endif
+                       }       /* switch (flashtype) */
                }
        }
        printf(" done\n");
@@ -583,6 +780,8 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
 
 int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 {
+       int count;
+
        if (info->flash_id == FLASH_UNKNOWN)
                return 4;
 
@@ -623,7 +822,7 @@ int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
                {
                        ulong cp, wp;
                        u16 data;
-                       int count, i, l, rc, port_width;
+                       int i, l, rc, port_width;
 
                        /* get lower word aligned address */
                        wp = addr;
@@ -724,6 +923,51 @@ int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 
                }               /* case FLASH_MAN_INTEL */
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+       case FLASH_MAN_STM:
+               {
+                       ulong wp;
+                       u8 *data = (u8 *) src;
+                       int left;       /* number of bytes left to program */
+
+                       wp = addr;
+
+                       /* page align, each page is 256 bytes */
+                       if ((wp % 0x100) != 0) {
+                               left = (0x100 - (wp & 0xFF));
+                               write_ser_data(info, wp, data, left);
+                               cnt -= left;
+                               wp += left;
+                               data += left;
+                       }
+
+                       /* page program - 256 bytes at a time */
+                       if (cnt > 255) {
+                               count = 0;
+                               while (cnt >= 0x100) {
+                                       write_ser_data(info, wp, data, 0x100);
+                                       cnt -= 0x100;
+                                       wp += 0x100;
+                                       data += 0x100;
+
+                                       if (count++ > 0x400) {
+                                               spin_wheel();
+                                               count = 0;
+                                       }
+                               }
+                       }
+
+                       /* remainint bytes */
+                       if (cnt && (cnt < 256)) {
+                               write_ser_data(info, wp, data, cnt);
+                               wp += cnt;
+                               data += cnt;
+                               cnt -= cnt;
+                       }
+
+                       printf("\b.");
+               }
+#endif
        }                       /* switch */
 
        return ERR_OK;
@@ -844,6 +1088,75 @@ int write_data(flash_info_t * info, ulong dest, FPW data)
        return (0);
 }
 
+#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
+int write_ser_data(flash_info_t * info, ulong dest, uchar * data, ulong cnt)
+{
+       ulong start;
+       int status, i;
+       u8 flashdata;
+
+       /* Check if Flash is (sufficiently) erased */
+       dspi_tx(ser_flash_cs, 0x80, SER_READ);
+       dspi_tx(ser_flash_cs, 0x80, (dest >> 16) & 0xFF);
+       dspi_tx(ser_flash_cs, 0x80, (dest >> 8) & 0xFF);
+       dspi_tx(ser_flash_cs, 0x80, dest & 0xFF);
+       dspi_rx();
+       dspi_rx();
+       dspi_rx();
+       dspi_rx();
+       dspi_tx(ser_flash_cs, 0x80, 0);
+       flashdata = dspi_rx();
+       dspi_tx(ser_flash_cs, 0x00, 0);
+       dspi_rx();
+
+       if ((flashdata & *data) != *data) {
+               printf("not erased at %08lx (%lx)\n", (ulong) dest,
+                      (ulong) flashdata);
+               return (2);
+       }
+
+       dspi_tx(ser_flash_cs, 0x00, SER_WREN);
+       dspi_rx();
+
+       status = serial_flash_read_status(ser_flash_cs);
+       if (((status & 0x9C) != 0) && ((status & 0x02) != 0x02)) {
+               printf("Error Programming\n");
+               return 1;
+       }
+
+       start = get_timer(0);
+
+       dspi_tx(ser_flash_cs, 0x80, SER_PAGE_PROG);
+       dspi_tx(ser_flash_cs, 0x80, ((dest & 0xFF0000) >> 16));
+       dspi_tx(ser_flash_cs, 0x80, ((dest & 0xFF00) >> 8));
+       dspi_tx(ser_flash_cs, 0x80, (dest & 0xFF));
+       dspi_rx();
+       dspi_rx();
+       dspi_rx();
+       dspi_rx();
+
+       for (i = 0; i < (cnt - 1); i++) {
+               dspi_tx(ser_flash_cs, 0x80, *data);
+               dspi_rx();
+               data++;
+       }
+
+       dspi_tx(ser_flash_cs, 0x00, *data);
+       dspi_rx();
+
+       do {
+               status = serial_flash_read_status(ser_flash_cs);
+
+               if (get_timer(start) > CFG_FLASH_ERASE_TOUT) {
+                       printf("Timeout\n");
+                       return 1;
+               }
+       } while (status & 0x01);
+
+       return (0);
+}
+#endif
+
 /*-----------------------------------------------------------------------
  * Write a word to Flash for ATMEL FLASH
  * A word is 16 bits, whichever the bus width of the flash bank