summaryrefslogtreecommitdiff
path: root/board/BuS/EB+MCF-EV123/flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/BuS/EB+MCF-EV123/flash.c')
-rw-r--r--board/BuS/EB+MCF-EV123/flash.c413
1 files changed, 413 insertions, 0 deletions
diff --git a/board/BuS/EB+MCF-EV123/flash.c b/board/BuS/EB+MCF-EV123/flash.c
new file mode 100644
index 0000000..ba76bef
--- /dev/null
+++ b/board/BuS/EB+MCF-EV123/flash.c
@@ -0,0 +1,413 @@
+/*
+ * (C) Copyright 2005
+ * BuS Elektronik GmbH & Co.KG <esw@bus-elektonik.de>
+ *
+ * Based On
+ * 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
+ */
+
+#include <common.h>
+#include "cfm_flash.h"
+
+#define PHYS_FLASH_1 CFG_FLASH_BASE
+#define FLASH_BANK_SIZE 0x200000
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+void flash_print_info (flash_info_t * info)
+{
+ int i;
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case (AMD_MANUFACT & FLASH_VENDMASK):
+ printf ("AMD: ");
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case (AMD_ID_LV160B & FLASH_TYPEMASK):
+ printf ("AM29LV160B (16Bit)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ break;
+ }
+ break;
+ case FREESCALE_MANUFACT & FLASH_VENDMASK:
+ cfm_flash_print_info (info);
+ break;
+ default:
+ printf ("Unknown Vendor ");
+ break;
+ }
+
+ puts (" Size: ");
+ if ((info->size >> 20) > 0)
+ {
+ printf ("%ld MiB",info->size >> 20);
+ }
+ else
+ {
+ printf ("%ld KiB",info->size >> 10);
+ }
+ printf (" in %d Sectors\n", info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i = 0; i < info->sector_count; i++) {
+ if ((i % 4) == 0) {
+ printf ("\n ");
+ }
+ printf ("%02d: %08lX%s ", i,info->start[i],
+ info->protect[i] ? " P" : " ");
+ }
+ printf ("\n\n");
+}
+
+unsigned long flash_init (void)
+{
+ int i, j;
+ ulong size = 0;
+
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+ ulong flashbase = 0;
+
+ switch (i)
+ {
+ case 1:
+ flash_info[i].flash_id =
+ (AMD_MANUFACT & FLASH_VENDMASK) |
+ (AMD_ID_LV160B & 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);
+ flashbase = PHYS_FLASH_1;
+ for (j = 0; j < flash_info[i].sector_count; j++) {
+ if (j == 0) {
+ /* 1st is 16 KiB */
+ flash_info[i].start[j] = flashbase;
+ }
+ if ((j >= 1) && (j <= 2)) {
+ /* 2nd and 3rd are 8 KiB */
+ flash_info[i].start[j] =
+ flashbase + 0x4000 + 0x2000 * (j - 1);
+ }
+ if (j == 3) {
+ /* 4th is 32 KiB */
+ flash_info[i].start[j] = flashbase + 0x8000;
+ }
+ if ((j >= 4) && (j <= 34)) {
+ /* rest is 256 KiB */
+ flash_info[i].start[j] =
+ flashbase + 0x10000 + 0x10000 * (j - 4);
+ }
+ }
+ break;
+ case 0:
+ cfm_flash_init (&flash_info[i]);
+ break;
+ default:
+ panic ("configured to many flash banks!\n");
+ }
+
+ size += flash_info[i].size;
+ }
+
+ flash_protect (FLAG_PROTECT_SET,
+ CFG_FLASH_BASE,
+ CFG_FLASH_BASE + 0xffff, &flash_info[0]);
+
+ return size;
+}
+
+#define CMD_READ_ARRAY 0x00F0
+#define CMD_UNLOCK1 0x00AA
+#define CMD_UNLOCK2 0x0055
+#define CMD_ERASE_SETUP 0x0080
+#define CMD_ERASE_CONFIRM 0x0030
+#define CMD_PROGRAM 0x00A0
+#define CMD_UNLOCK_BYPASS 0x0020
+
+#define MEM_FLASH_ADDR1 (*(volatile u16 *)(info->start[0] + (0x00000555<<1)))
+#define MEM_FLASH_ADDR2 (*(volatile u16 *)(info->start[0] + (0x000002AA<<1)))
+
+
+#define BIT_ERASE_DONE 0x0080
+#define BIT_RDY_MASK 0x0080
+#define BIT_PROGRAM_ERROR 0x0020
+#define BIT_TIMEOUT 0x80000000 /* our flag */
+
+#define ERR_READY -1
+
+int amd_flash_erase_sector(flash_info_t * info, int sector)
+{
+ int state;
+ ulong result;
+
+ volatile u16 *addr =
+ (volatile u16 *) (info->start[sector]);
+
+ MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+ MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+ MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
+
+ MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+ MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+ *addr = CMD_ERASE_CONFIRM;
+
+ /* wait until flash is ready */
+ state = 0;
+ set_timer (0);
+
+ do {
+ result = *addr;
+
+ /* check timeout */
+ if (get_timer (0) > CFG_FLASH_ERASE_TOUT) {
+ MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
+ state = ERR_TIMOUT;
+ }
+
+ if (!state && (result & 0xFFFF) & BIT_ERASE_DONE)
+ state = ERR_READY;
+ }
+ while (!state);
+ if (state == ERR_READY)
+ state = ERR_OK;
+
+ MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
+
+ return state;
+}
+
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+ int iflag, cflag;
+ int sector;
+ int rc;
+
+ rc = ERR_OK;
+
+ if (info->flash_id == FLASH_UNKNOWN)
+ {
+ rc = ERR_UNKNOWN_FLASH_TYPE;
+ } /* (info->flash_id == FLASH_UNKNOWN) */
+
+ if ((s_first < 0) || (s_first > s_last) || s_last >= info->sector_count)
+ {
+ rc = ERR_INVAL;
+ }
+
+ cflag = icache_status ();
+ icache_disable ();
+ iflag = disable_interrupts ();
+
+ for (sector = s_first; (sector <= s_last) && (rc == ERR_OK); sector++) {
+
+ if (info->protect[sector])
+ {
+ putc('P'); /* protected sector will not erase */
+ }
+ else
+ {
+ /* erase on unprotected sector */
+ puts("E\b");
+ switch (info->flash_id & FLASH_VENDMASK)
+ {
+ case (AMD_MANUFACT & FLASH_VENDMASK):
+ rc = amd_flash_erase_sector(info,sector);
+ break;
+ case (FREESCALE_MANUFACT & FLASH_VENDMASK):
+ rc = cfm_flash_erase_sector(info,sector);
+ break;
+ default:
+ return ERR_UNKNOWN_FLASH_VENDOR;
+ }
+ putc('.');
+ }
+ }
+ if (rc!=ERR_OK)
+ {
+ printf ("\n ");
+ flash_perror (rc);
+ }
+ else
+ {
+ printf (" done\n");
+ }
+
+ udelay (10000); /* allow flash to settle - wait 10 ms */
+
+ if (iflag)
+ enable_interrupts ();
+
+ if (cflag)
+ icache_enable ();
+
+ return rc;
+}
+
+volatile static int amd_write_word (flash_info_t * info, ulong dest, u16 data)
+{
+ volatile u16 *addr;
+ ulong result;
+ int cflag, iflag;
+ int state;
+
+ /*
+ * Check if Flash is (sufficiently) erased
+ */
+ addr = (volatile u16 *) dest;
+
+ result = *addr;
+ if ((result & data) != data)
+ return ERR_NOT_ERASED;
+
+ /*
+ * Disable interrupts which might cause a timeout
+ * here. Remember that our exception vectors are
+ * at address 0 in the flash, and we don't want a
+ * (ticker) exception to happen while the flash
+ * chip is in programming mode.
+ */
+
+ cflag = icache_status ();
+ icache_disable ();
+ iflag = disable_interrupts ();
+
+ MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+ MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+ MEM_FLASH_ADDR1 = CMD_PROGRAM;
+ *addr = data;
+
+ /* arm simple, non interrupt dependent timer */
+ set_timer (0);
+
+ /* wait until flash is ready */
+ state = 0;
+ do {
+ result = *addr;
+
+ /* check timeout */
+ if (get_timer (0) > CFG_FLASH_ERASE_TOUT) {
+ state = ERR_TIMOUT;
+ }
+ if (!state && ((result & BIT_RDY_MASK) == (data & BIT_RDY_MASK)))
+ state = ERR_READY;
+
+ } while (!state);
+
+ *addr = CMD_READ_ARRAY;
+
+ if (state == ERR_READY)
+ state = ERR_OK;
+ if ((*addr != data) && (state != ERR_TIMOUT))
+ state = ERR_PROG_ERROR;
+
+ if (iflag)
+ enable_interrupts ();
+
+ if (cflag)
+ icache_enable ();
+
+ return state;
+}
+
+int amd_flash_write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+ int rc;
+ ulong dest;
+ u16 data;
+
+ rc = ERR_OK;
+ if (addr & 1)
+ {
+ debug ("Byte alignment not supported\n");
+ rc = ERR_ALIGN;
+ }
+ if (cnt & 1)
+ {
+ debug ("Byte transfer not supported\n");
+ rc = ERR_ALIGN;
+ }
+
+ dest = addr;
+ while ((cnt>=2) && (rc == ERR_OK))
+ {
+ data =*((volatile u16 *) src);
+ rc=amd_write_word (info,dest,data);
+ src +=2;
+ dest +=2;
+ cnt -=2;
+ }
+ return rc;
+}
+
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+ int rc;
+
+ switch (info->flash_id & FLASH_VENDMASK)
+ {
+ case (AMD_MANUFACT & FLASH_VENDMASK):
+ rc = amd_flash_write_buff(info,src,addr,cnt);
+ break;
+ case (FREESCALE_MANUFACT & FLASH_VENDMASK):
+ rc = cfm_flash_write_buff(info,src,addr,cnt);
+ break;
+ default:
+ rc = ERR_UNKNOWN_FLASH_VENDOR;
+ }
+ return rc;
+
+}
+int amd_flash_protect(flash_info_t * info,long sector,int prot)
+{
+ int rc;
+ rc= ERR_OK;
+ if (prot)
+ {
+ info->protect[sector]=1;
+ }
+ else
+ {
+ info->protect[sector]=0;
+ }
+ return rc;
+}
+
+#ifdef CFG_FLASH_PROTECTION
+
+int flash_real_protect(flash_info_t * info,long sector,int prot)
+{
+ int rc;
+
+ switch (info->flash_id & FLASH_VENDMASK)
+ {
+ case (AMD_MANUFACT & FLASH_VENDMASK):
+ rc = amd_flash_protect(info,sector,prot);
+ break;
+ case (FREESCALE_MANUFACT & FLASH_VENDMASK):
+ rc = cfm_flash_protect(info,sector,prot);
+ break;
+ default:
+ rc = ERR_UNKNOWN_FLASH_VENDOR;
+ }
+ return rc;
+}
+
+#endif