* (C) Copyright 2001
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
/* #define DEBUG */
#include <common.h>
#include <mpc8xx.h>
-#if defined(CFG_ENV_IS_IN_FLASH)
-# ifndef CFG_ENV_ADDR
-# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+#if defined(CONFIG_ENV_IS_IN_FLASH)
+# ifndef CONFIG_ENV_ADDR
+# define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
# endif
-# ifndef CFG_ENV_SIZE
-# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# ifndef CONFIG_ENV_SIZE
+# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
# endif
-# ifndef CFG_ENV_SECT_SIZE
-# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# ifndef CONFIG_ENV_SECT_SIZE
+# define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE
# endif
#endif
/*---------------------------------------------------------------------*/
-flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
/*-----------------------------------------------------------------------
* Functions
*/
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
static int write_data (flash_info_t *info, ulong dest, ulong data);
+#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+static int write_data_buf (flash_info_t * info, ulong dest, uchar * cp, int len);
+#endif
static void flash_get_offsets (ulong base, flash_info_t *info);
/*-----------------------------------------------------------------------
unsigned long flash_init (void)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
volatile memctl8xx_t *memctl = &immap->im_memctl;
unsigned long size_b0, size_b1;
int i;
/* Init: no FLASHes known */
- for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
}
memctl->memc_br1, memctl->memc_or1);
/* Remap FLASH according to real size */
- memctl->memc_or0 = (-size_b0 & 0xFFFF8000) | CFG_OR_TIMING_FLASH |
+ memctl->memc_or0 = (-size_b0 & 0xFFFF8000) | CONFIG_SYS_OR_TIMING_FLASH |
OR_CSNT_SAM | OR_ACS_DIV1;
- memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_PS_32 | BR_V;
+ memctl->memc_br0 = (CONFIG_SYS_FLASH_BASE & BR_BA_MSK) | BR_PS_32 | BR_V;
debug ("## BR0: 0x%08x OR0: 0x%08x\n",
memctl->memc_br0, memctl->memc_or0);
/* Re-do sizing to get full correct info */
- size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+ size_b0 = flash_get_size((vu_long *)CONFIG_SYS_FLASH_BASE, &flash_info[0]);
- flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+ flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
flash_info[0].size = size_b0;
-#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
/* monitor protection ON by default */
flash_protect(FLAG_PROTECT_SET,
- CFG_MONITOR_BASE,
- CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ CONFIG_SYS_MONITOR_BASE,
+ CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
&flash_info[0]);
#endif
-#ifdef CFG_ENV_IS_IN_FLASH
+#ifdef CONFIG_ENV_IS_IN_FLASH
/* ENV protection ON by default */
flash_protect(FLAG_PROTECT_SET,
- CFG_ENV_ADDR,
- CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ CONFIG_ENV_ADDR,
+ CONFIG_ENV_ADDR+CONFIG_ENV_SECT_SIZE-1,
&flash_info[0]);
#endif
if (size_b1) {
- memctl->memc_or1 = (-size_b1 & 0xFFFF8000) | CFG_OR_TIMING_FLASH |
+ memctl->memc_or1 = (-size_b1 & 0xFFFF8000) | CONFIG_SYS_OR_TIMING_FLASH |
OR_CSNT_SAM | OR_ACS_DIV1;
- memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ memctl->memc_br1 = ((CONFIG_SYS_FLASH_BASE + size_b0) & BR_BA_MSK) |
BR_PS_32 | BR_V;
debug ("## BR1: 0x%08x OR1: 0x%08x\n",
memctl->memc_br1, memctl->memc_or1);
/* Re-do sizing to get full correct info */
- size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+ size_b1 = flash_get_size((vu_long *)(CONFIG_SYS_FLASH_BASE + size_b0),
&flash_info[1]);
flash_info[1].size = size_b1;
- flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+ flash_get_offsets (CONFIG_SYS_FLASH_BASE + size_b0, &flash_info[1]);
-#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
/* monitor protection ON by default */
flash_protect(FLAG_PROTECT_SET,
- CFG_MONITOR_BASE,
- CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ CONFIG_SYS_MONITOR_BASE,
+ CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
&flash_info[1]);
#endif
-#ifdef CFG_ENV_IS_IN_FLASH
+#ifdef CONFIG_ENV_IS_IN_FLASH
/* ENV protection ON by default */
flash_protect(FLAG_PROTECT_SET,
- CFG_ENV_ADDR,
- CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ CONFIG_ENV_ADDR,
+ CONFIG_ENV_ADDR+CONFIG_ENV_SECT_SIZE-1,
&flash_info[1]);
#endif
} else {
}
- if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ if (info->sector_count > CONFIG_SYS_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;
+ info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
+ info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
}
addr[0] = 0x00FF00FF; /* restore read mode */
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
+ *addr = 0x00600060; /* clear lock bit setup */
+ *addr = 0x00D000D0; /* clear lock bit confirm */
+
+ udelay (1000);
+ /* This takes awfully long - up to 50 ms and more */
+ while (((status = *addr) & 0x00800080) != 0x00800080) {
+ if ((now=get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = 0x00FF00FF; /* reset to read mode */
+ return 1;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ udelay (1000); /* to trigger the watchdog */
+ }
+
*addr = 0x00500050; /* clear status register */
*addr = 0x00200020; /* erase setup */
*addr = 0x00D000D0; /* erase confirm */
udelay (1000);
while (((status = *addr) & 0x00800080) != 0x00800080) {
- if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ if ((now=get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
printf ("Timeout\n");
*addr = 0x00B000B0; /* suspend erase */
*addr = 0x00FF00FF; /* reset to read mode */
putc ('.');
last = now;
}
+ udelay (1000); /* to trigger the watchdog */
}
*addr = 0x00FF00FF; /* reset to read mode */
/*
* handle FLASH_WIDTH aligned part
*/
+#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+ while(cnt >= FLASH_WIDTH) {
+ i = CONFIG_SYS_FLASH_BUFFER_SIZE > cnt ?
+ (cnt & ~(FLASH_WIDTH - 1)) : CONFIG_SYS_FLASH_BUFFER_SIZE;
+ if((rc = write_data_buf(info, wp, src,i)) != 0)
+ return rc;
+ wp += i;
+ src += i;
+ cnt -=i;
+ }
+#else
while (cnt >= FLASH_WIDTH) {
data = 0;
for (i=0; i<FLASH_WIDTH; ++i) {
wp += FLASH_WIDTH;
cnt -= FLASH_WIDTH;
}
+#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
if (cnt == 0) {
return (0);
return (write_data(info, wp, data));
}
+/*-----------------------------------------------------------------------
+ * Check flash status, returns:
+ * 0 - OK
+ * 1 - timeout
+ */
+static int flash_status_check(vu_long *addr, ulong tout, char * prompt)
+{
+ ulong status;
+ ulong start;
+
+ /* Wait for command completion */
+ start = get_timer (0);
+ while(((status = *addr) & 0x00800080) != 0x00800080) {
+ if (get_timer(start) > tout) {
+ printf("Flash %s timeout at address %p\n", prompt, addr);
+ *addr = 0x00FF00FF; /* restore read mode */
+ return (1);
+ }
+ }
+ return 0;
+}
+
/*-----------------------------------------------------------------------
* Write a word to Flash, returns:
* 0 - OK
static int write_data (flash_info_t *info, ulong dest, ulong data)
{
vu_long *addr = (vu_long *)dest;
- ulong status;
- ulong start;
int flag;
/* Check if Flash is (sufficiently) erased */
if (flag)
enable_interrupts();
- start = get_timer (0);
-
- while (((status = *addr) & 0x00800080) != 0x00800080) {
- if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
- *addr = 0x00FF00FF; /* restore read mode */
- return (1);
- }
+ if (flash_status_check(addr, CONFIG_SYS_FLASH_WRITE_TOUT, "write") != 0) {
+ return (1);
}
*addr = 0x00FF00FF; /* restore read mode */
return (0);
}
+#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+/*-----------------------------------------------------------------------
+ * Write a buffer to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ */
+static int write_data_buf(flash_info_t * info, ulong dest, uchar * cp, int len)
+{
+ vu_long *addr = (vu_long *)dest;
+ int sector;
+ int cnt;
+ int retcode;
+ vu_long * src = (vu_long *)cp;
+ vu_long * dst = (vu_long *)dest;
+
+ /* find sector */
+ for(sector = info->sector_count - 1; sector >= 0; sector--) {
+ if(dest >= info->start[sector])
+ break;
+ }
+
+ *addr = 0x00500050; /* clear status */
+ *addr = 0x00e800e8; /* write buffer */
+
+ if((retcode = flash_status_check(addr, CONFIG_SYS_FLASH_BUFFER_WRITE_TOUT,
+ "write to buffer")) == 0) {
+ cnt = len / FLASH_WIDTH;
+ *addr = (cnt-1) | ((cnt-1) << 16);
+ while(cnt-- > 0) {
+ *dst++ = *src++;
+ }
+ *addr = 0x00d000d0; /* write buffer confirm */
+ retcode = flash_status_check(addr, CONFIG_SYS_FLASH_BUFFER_WRITE_TOUT,
+ "buffer write");
+ }
+ *addr = 0x00FF00FF; /* restore read mode */
+ *addr = 0x00500050; /* clear status */
+ return retcode;
+}
+#endif /* CONFIG_SYS_USE_FLASH_BUFFER_WRITE */
+
/*-----------------------------------------------------------------------
*/