Initial revision

This commit is contained in:
wdenk
2002-11-02 22:58:18 +00:00
parent 1a4d6164af
commit cc1c8a136f
17 changed files with 6163 additions and 0 deletions

615
board/cpu86/flash.c Normal file
View File

@@ -0,0 +1,615 @@
/*
* (C) Copyright 2001, 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* Flash Routines for Intel devices
*
*--------------------------------------------------------------------
* 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 <mpc8xx.h>
#include "cpu86.h"
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
/*-----------------------------------------------------------------------
*/
ulong flash_int_get_size (volatile unsigned long *baseaddr,
flash_info_t * info)
{
short i;
unsigned long flashtest_h, flashtest_l;
info->sector_count = info->size = 0;
info->flash_id = FLASH_UNKNOWN;
/* Write query command sequence and test FLASH answer
*/
baseaddr[0] = 0x00980098;
baseaddr[1] = 0x00980098;
flashtest_h = baseaddr[0]; /* manufacturer ID */
flashtest_l = baseaddr[1];
if (flashtest_h != INTEL_MANUFACT || flashtest_l != INTEL_MANUFACT)
return (0); /* no or unknown flash */
flashtest_h = baseaddr[2]; /* device ID */
flashtest_l = baseaddr[3];
if (flashtest_h != flashtest_l)
return (0);
switch (flashtest_h) {
case INTEL_ID_28F160C3B:
info->flash_id = FLASH_28F160C3B;
info->sector_count = 39;
info->size = 0x00800000; /* 4 * 2 MB = 8 MB */
break;
case INTEL_ID_28F160F3B:
info->flash_id = FLASH_28F160F3B;
info->sector_count = 39;
info->size = 0x00800000; /* 4 * 2 MB = 8 MB */
break;
default:
return (0); /* no or unknown flash */
}
info->flash_id |= INTEL_MANUFACT << 16; /* set manufacturer offset */
if (info->flash_id & FLASH_BTYPE) {
volatile unsigned long *tmp = baseaddr;
/* set up sector start adress table (bottom sector type)
* AND unlock the sectors (if our chip is 160C3)
*/
for (i = 0; i < info->sector_count; i++) {
if ((info->flash_id & FLASH_TYPEMASK) == FLASH_28F160C3B) {
tmp[0] = 0x00600060;
tmp[1] = 0x00600060;
tmp[0] = 0x00D000D0;
tmp[1] = 0x00D000D0;
}
info->start[i] = (uint) tmp;
tmp += i < 8 ? 0x2000 : 0x10000; /* pointer arith */
}
}
memset (info->protect, 0, info->sector_count);
baseaddr[0] = 0x00FF00FF;
baseaddr[1] = 0x00FF00FF;
return (info->size);
}
static ulong flash_amd_get_size (vu_char *addr, flash_info_t *info)
{
short i;
uchar vendor, devid;
ulong base = (ulong)addr;
/* Write auto select command: read Manufacturer ID */
addr[0x0555] = 0xAA;
addr[0x02AA] = 0x55;
addr[0x0555] = 0x90;
udelay(1000);
vendor = addr[0];
devid = addr[1] & 0xff;
/* only support AMD */
if (vendor != 0x01) {
return 0;
}
vendor &= 0xf;
devid &= 0xff;
if (devid == AMD_ID_F040B) {
info->flash_id = vendor << 16 | devid;
info->sector_count = 8;
info->size = info->sector_count * 0x10000;
}
else if (devid == AMD_ID_F080B) {
info->flash_id = vendor << 16 | devid;
info->sector_count = 16;
info->size = 4 * info->sector_count * 0x10000;
}
else if (devid == AMD_ID_F016D) {
info->flash_id = vendor << 16 | devid;
info->sector_count = 32;
info->size = 4 * info->sector_count * 0x10000;
}
else {
printf ("## Unknown Flash Type: %02x\n", devid);
return 0;
}
/* check for protected sectors */
for (i = 0; i < info->sector_count; i++) {
/* sector base address */
info->start[i] = base + i * (info->size / info->sector_count);
/* read sector protection at sector address, (A7 .. A0) = 0x02 */
/* D0 = 1 if protected */
addr = (volatile unsigned char *)(info->start[i]);
info->protect[i] = addr[2] & 1;
}
/*
* Prevent writes to uninitialized FLASH.
*/
if (info->flash_id != FLASH_UNKNOWN) {
addr = (vu_char *)info->start[0];
addr[0] = 0xF0; /* reset bank */
}
return (info->size);
}
/*-----------------------------------------------------------------------
*/
unsigned long flash_init (void)
{
unsigned long size_b0 = 0;
unsigned long size_b1 = 0;
int i;
/* Init: no FLASHes known
*/
for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
}
/* Disable flash protection */
CPU86_BCR |= (CPU86_BCR_FWPT | CPU86_BCR_FWRE);
/* Static FLASH Bank configuration here (only one bank) */
size_b0 = flash_int_get_size ((ulong *) CFG_FLASH_BASE, &flash_info[0]);
size_b1 = flash_amd_get_size ((uchar *) CFG_BOOTROM_BASE, &flash_info[1]);
if (size_b0 > 0 || size_b1 > 0) {
printf("(");
if (size_b0 > 0) {
puts ("Bank#1 - ");
print_size (size_b0, (size_b1 > 0) ? ", " : ") ");
}
if (size_b1 > 0) {
puts ("Bank#2 - ");
print_size (size_b1, ") ");
}
}
else {
printf ("## No FLASH found.\n");
return 0;
}
/* protect monitor and environment sectors
*/
#if CFG_MONITOR_BASE >= CFG_BOOTROM_BASE
if (size_b1) {
/* If U-Boot is booted from ROM the CFG_MONITOR_BASE > CFG_FLASH_BASE
* but we shouldn't protect it.
*/
flash_protect (FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[1]
);
}
#else
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
flash_protect (FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]
);
#endif
#endif
#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
# ifndef CFG_ENV_SIZE
# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
# endif
# if CFG_ENV_ADDR >= CFG_BOOTROM_BASE
if (size_b1) {
flash_protect (FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[1]);
}
# else
flash_protect (FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
# endif
#endif
return (size_b0 + size_b1);
}
/*-----------------------------------------------------------------------
*/
void flash_print_info (flash_info_t * info)
{
int i;
if (info->flash_id == FLASH_UNKNOWN) {
printf ("missing or unknown FLASH type\n");
return;
}
switch ((info->flash_id >> 16) & 0xff) {
case 0x89:
printf ("INTEL ");
break;
case 0x1:
printf ("AMD ");
break;
default:
printf ("Unknown Vendor ");
break;
}
switch (info->flash_id & FLASH_TYPEMASK) {
case FLASH_28F160C3B:
printf ("28F160C3B (16 Mbit, bottom sector)\n");
break;
case FLASH_28F160F3B:
printf ("28F160F3B (16 Mbit, bottom sector)\n");
break;
case AMD_ID_F040B:
printf ("AM29F040B (4 Mbit)\n");
break;
default:
printf ("Unknown Chip Type\n");
break;
}
if (info->size < 0x100000)
printf (" Size: %ld KB in %d Sectors\n",
info->size >> 10, info->sector_count);
else
printf (" Size: %ld MB in %d Sectors\n",
info->size >> 20, info->sector_count);
printf (" Sector Start Addresses:");
for (i = 0; i < info->sector_count; ++i) {
if ((i % 5) == 0)
printf ("\n ");
printf (" %08lX%s",
info->start[i],
info->protect[i] ? " (RO)" : " "
);
}
printf ("\n");
}
/*-----------------------------------------------------------------------
*/
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
vu_char *addr = (vu_char *)(info->start[0]);
int flag, prot, sect, l_sect;
ulong start, now, last;
if ((s_first < 0) || (s_first > s_last)) {
if (info->flash_id == FLASH_UNKNOWN) {
printf ("- missing\n");
} else {
printf ("- no sectors to erase\n");
}
return 1;
}
prot = 0;
for (sect = s_first; sect <= s_last; sect++) {
if (info->protect[sect])
prot++;
}
if (prot) {
printf ("- Warning: %d protected sectors will not be erased!\n",
prot);
} else {
printf ("\n");
}
/* Check the type of erased flash
*/
if (info->flash_id >> 16 == 0x1) {
/* Erase AMD flash
*/
l_sect = -1;
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
addr[0x0555] = 0xAA;
addr[0x02AA] = 0x55;
addr[0x0555] = 0x80;
addr[0x0555] = 0xAA;
addr[0x02AA] = 0x55;
/* wait at least 80us - let's wait 1 ms */
udelay (1000);
/* Start erase on unprotected sectors */
for (sect = s_first; sect<=s_last; sect++) {
if (info->protect[sect] == 0) { /* not protected */
addr = (vu_char *)(info->start[sect]);
addr[0] = 0x30;
l_sect = sect;
}
}
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
/* wait at least 80us - let's wait 1 ms */
udelay (1000);
/*
* We wait for the last triggered sector
*/
if (l_sect < 0)
goto AMD_DONE;
start = get_timer (0);
last = start;
addr = (vu_char *)(info->start[l_sect]);
while ((addr[0] & 0x80) != 0x80) {
if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
printf ("Timeout\n");
return 1;
}
/* show that we're waiting */
if ((now - last) > 1000) { /* every second */
serial_putc ('.');
last = now;
}
}
AMD_DONE:
/* reset to read mode */
addr = (volatile unsigned char *)info->start[0];
addr[0] = 0xF0; /* reset bank */
} else {
/* Erase Intel flash
*/
/* Start erase on unprotected sectors
*/
for (sect = s_first; sect <= s_last; sect++) {
volatile ulong *addr =
(volatile unsigned long *) info->start[sect];
start = get_timer (0);
last = start;
if (info->protect[sect] == 0) {
/* Disable interrupts which might cause a timeout here
*/
flag = disable_interrupts ();
/* Erase the block
*/
addr[0] = 0x00200020;
addr[1] = 0x00200020;
addr[0] = 0x00D000D0;
addr[1] = 0x00D000D0;
/* re-enable interrupts if necessary
*/
if (flag)
enable_interrupts ();
/* wait at least 80us - let's wait 1 ms
*/
udelay (1000);
last = start;
while ((addr[0] & 0x00800080) != 0x00800080 ||
(addr[1] & 0x00800080) != 0x00800080) {
if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
printf ("Timeout (erase suspended!)\n");
/* Suspend erase
*/
addr[0] = 0x00B000B0;
addr[1] = 0x00B000B0;
goto DONE;
}
/* show that we're waiting
*/
if ((now - last) > 1000) { /* every second */
serial_putc ('.');
last = now;
}
}
if (addr[0] & 0x00220022 || addr[1] & 0x00220022) {
printf ("*** ERROR: erase failed!\n");
goto DONE;
}
}
/* Clear status register and reset to read mode
*/
addr[0] = 0x00500050;
addr[1] = 0x00500050;
addr[0] = 0x00FF00FF;
addr[1] = 0x00FF00FF;
}
}
printf (" done\n");
DONE:
return 0;
}
static int write_word (flash_info_t *, volatile unsigned long *, ulong);
static int write_byte (flash_info_t *info, ulong dest, uchar data);
/*-----------------------------------------------------------------------
* Copy memory to flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
{
ulong v;
int i, l, rc, cc = cnt, res = 0;
if (info->flash_id >> 16 == 0x1) {
/* Write to AMD 8-bit flash
*/
while (cnt > 0) {
if ((rc = write_byte(info, addr, *src)) != 0) {
return (rc);
}
addr++;
src++;
cnt--;
}
return (0);
} else {
/* Write to Intel 64-bit flash
*/
for (v=0; cc > 0; addr += 4, cc -= 4 - l) {
l = (addr & 3);
addr &= ~3;
for (i = 0; i < 4; i++) {
v = (v << 8) + (i < l || i - l >= cc ?
*((unsigned char *) addr + i) : *src++);
}
if ((res = write_word (info, (volatile unsigned long *) addr, v)) != 0)
break;
}
}
return (res);
}
/*-----------------------------------------------------------------------
* Write a word to Flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
static int write_word (flash_info_t * info, volatile unsigned long *addr,
ulong data)
{
int flag, res = 0;
ulong start;
/* Check if Flash is (sufficiently) erased
*/
if ((*addr & data) != data)
return (2);
/* Disable interrupts which might cause a timeout here
*/
flag = disable_interrupts ();
*addr = 0x00400040;
*addr = data;
/* re-enable interrupts if necessary
*/
if (flag)
enable_interrupts ();
start = get_timer (0);
while ((*addr & 0x00800080) != 0x00800080) {
if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
/* Suspend program
*/
*addr = 0x00B000B0;
res = 1;
goto OUT;
}
}
if (*addr & 0x00220022) {
printf ("*** ERROR: program failed!\n");
res = 1;
}
OUT:
/* Clear status register and reset to read mode
*/
*addr = 0x00500050;
*addr = 0x00FF00FF;
return (res);
}
/*-----------------------------------------------------------------------
* Write a byte to Flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
static int write_byte (flash_info_t *info, ulong dest, uchar data)
{
vu_char *addr = (vu_char *)(info->start[0]);
ulong start;
int flag;
/* Check if Flash is (sufficiently) erased */
if ((*((vu_char *)dest) & data) != data) {
return (2);
}
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
addr[0x0555] = 0xAA;
addr[0x02AA] = 0x55;
addr[0x0555] = 0xA0;
*((vu_char *)dest) = data;
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
/* data polling for D7 */
start = get_timer (0);
while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
return (1);
}
}
return (0);
}
/*-----------------------------------------------------------------------
*/

127
board/lwmon/README.keybd Normal file
View File

@@ -0,0 +1,127 @@
Tastaturabfrage:
Die Implementierung / Decodierung beruht auf den Angaben aus dem Do-
kument "PIC LWE-Tastatur" in der Fassung vom 9. 3. 2001, insbesonde-
re Tabelle 3 im Kapitel 4.3 Tastencodes. In U-Boot werden die vom
Keyboard-Controller gelesenen Daten hexadezimal codiert in der auto-
matisch angelegten Environment-Variablen "keybd" <20>bergeben. Ist kei-
ne Taste gedr<64>ckt worden, steht dort:
keybd=000000000000000000
Der decodierte Tastencode ("keybd") kann mit den "bootargs" an den
Linux-Kernel <20>bergeben und dort z. B. in einem Device-Treiber oder
einer Applikation ausgewertet werden.
Sonderfunktionen beim Booten:
Es lassen sich eine oder mehrere (beliebig viele) Tasten oder Tasten-
kombinationen definieren, die Sonderfunktionen ausl<73>sen, wenn diese
Tasten beim Booten (Reset) gedr<64>ckt sind.
Wird eine eingestellte Taste bzw. Tastenkombination erkannt, so wird
in U-Boot noch vor dem Start des "Countdown" und somit vor jedem an-
deren Kommando der Inhalt einer dieser Taste bzw. Tastenkombination
zugeordneten Environment-Variablen ausf<73>hren.
Die Environment-Variable "magic_keys" wird als Liste von Zeichen ver-
standen, die als Suffix an den Namen "key_magic" angef<65>gt werden und
so die Namen der Environment-Variablen definieren, mit denen die
Tasten (-kombinationen) festgelegt werden:
Ist "magic_keys" NICHT definiert, so wird nur die in der Environment-
Variablen "key_magic" codierte Tasten (-kombination) gepr<70>ft, und
ggf. der Inhalt der Environment-Variablen "key_cmd" ausgef<65>hrt (ge-
nauer: der Inhalt von "key_cmd" wird der Variablen "preboot" zugewie-
sen, die ausgef<65>hrt wird, unmittelbar bevor die interaktive Kommando-
interpretation beginnt).
Enth<EFBFBD>lt "magic_keys" z. B. die Zeichenkette "0123CB*", so werden
nacheinander folgende Aktionen ausgef<65>hrt:
pr<70>fe Tastencode ggf. f<>hre aus Kommando
in Variable in Variable
-----------------------------------
key_magic0 ==> key_cmd0
key_magic1 ==> key_cmd1
key_magic2 ==> key_cmd2
key_magic3 ==> key_cmd3
key_magicC ==> key_cmdC
key_magicB ==> key_cmdB
key_magicA ==> key_cmdA
key_magic* ==> key_cmd*
Hinweis: sobald ein aktivierter Tastencode erkannt wurde, wird die
Bearbeitung abgebrochen; es wird daher h<>chstens eines der definier-
ten Kommandos ausgef<65>hrt, wobei die Priorit<69>t durch die Suchreihen-
folge festgelegt wird, also durch die Reihenfolge der Zeichen in der
Varuiablen "magic_keys".
Die Codierung der Tasten, die beim Booten gedr<64>ckt werden m<>ssen, um
eine Funktion auszul<75>sen, erfolgt nach der Tastaturtabelle.
Die Definitionen
=> setenv key_magic0 3a+3b
=> setenv key_cmd0 setenv bootdelay 30
bedeuten dementsprechend, da<64> die Tasten mit den Codes 0x3A (Taste
"F1") und 0x3B (Taste "F2") gleichzeitig gedr<64>ckt werden m<>ssen. Sie
k<EFBFBD>nnen dort eine beliebige Tastenkombination eintragen (jeweils 2
Zeichen f<>r die Hex-Codes der Tasten, und '+' als Trennzeichen).
Wird die eingestellte Tastenkombination erkannt, so wird in U-Boot
noch vor dem Start des "Countdown" und somit vor jedem anderen Kom-
mando das angebene Kommando ausgef<65>hrt und somit ein langes Boot-
Delay eingetragen.
Praktisch k<>nnten Sie also in U-Boot "bootdelay" auf 0 setzen und
somit stets ohne jede User-Interaktion automatisch booten, au<61>er,
wenn die beiden Tasten "F1" und "F2" beim Booten gedr<64>ckt werden:
dann w<>rde ein Boot-Delay von 30 Sekunden eingef<65>gt.
Hinweis: dem Zeichen '#' kommt innerhalb von "magic_keys" eine beson-
dere Bedeutung zu: die dadurch definierte Key-Sequenz schaltet den
Monitor in den "Debug-Modus" - das bedeutet zun<75>chst, da<64> alle weite-
ren Meldungen von U-Boot <20>ber das LCD-Display ausgegeben werden;
au<EFBFBD>erdem kann man durch das mit dieser Tastenkombination verkn<6B>pfte
Kommando z. B. die Linux-Bootmeldungen ebenfalls auf das LCD-Display
legen, so da<64> der Boot-Vorgang direkt und ohne weitere Hilfsmittel
analysiert werden kann.
Beispiel:
In U-Boot werden folgende Environment-Variablen gesetzt und abgespei-
chert:
(1) => setenv magic_keys 01234#X
(2) => setenv key_cmd# setenv addfb setenv bootargs \\$(bootargs) console=tty0 console=ttyS1,\\$(baudrate)
(3) => setenv nfsargs setenv bootargs root=/dev/nfs rw nfsroot=\$(serverip):\$(rootpath)
(4) => setenv addip setenv bootargs \$(bootargs) ip=\$(ipaddr):\$(serverip):\$(gatewayip):\$(netmask):\$(hostname)::off panic=1
(5) => setenv addfb setenv bootargs \$(bootargs) console=ttyS1,\$(baudrate)
(6) => setenv bootcmd bootp\;run nfsargs\;run addip\;run addfb\;bootm
Hierbei wird die Linux Commandline (in der Variablen "bootargs") im
Boot-Kommando "bootcmd" (6) schrittweise zusammengesetzt: zun<75>chst
werden die f<>r Root-Filesystem <20>ber NFS erforderlichen Optionen ge-
setzt ("run nfsargs", vgl. (3)), dann die Netzwerkkonfiguration an-
gef<EFBFBD>gt ("run addip", vgl. (4)), und schlie<69>lich die Systemconsole
definiert ("run addfb").
Dabei wird im Normalfall die Definition (5) verwendt; wurde aller-
dings beim Reset die entsprechende Taste gedr<64>ckt gehalten, so wird
diese Definition bei der Ausf<73>hrung des in (2) definierten Kommandos
<EFBFBD>berschrieben, so da<64> Linux die Bootmeldungen auch <20>ber das Frame-
buffer-Device (=LCD-Display) ausgibt.
Beachten Sie die Verdoppelung der '\'-Escapes in der Definition von
"key_cmd#" - diese ist erforderlich, weil der String _zweimal_ inter-
pretiert wird: das erste Mal bei der Eingabe von "key_cmd#", das
zweite Mal, wenn der String (als Inhalt von "preboot") ausgef<65>hrt
wird.

944
board/mousse/flash.c Normal file
View File

@@ -0,0 +1,944 @@
/*
* MOUSSE/MPC8240 Board definitions.
* Flash Routines for MOUSSE onboard AMD29LV106DB devices
*
* (C) Copyright 2000
* Marius Groeger <mgroeger@sysgo.de>
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 1999, by Curt McDowell, 08-06-99, Broadcom Corp.
* (C) Copyright 2001, James Dougherty, 07/18/01, Broadcom Corp.
*
* 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 <mpc8xx.h>
#include <malloc.h>
#include "mousse.h"
#include "flash.h"
int flashLibDebug = 0;
int flashLibInited = 0;
#define OK 0
#define ERROR -1
#define STATUS int
#define PRINTF if (flashLibDebug) printf
#if 0
#define PRIVATE static
#else
#define PRIVATE
#endif
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
#define SLEEP_DELAY 166
#define FLASH_SECTOR_SIZE (64*1024)
/***********************************************************************
*
* Virtual Flash Devices on Mousse board
*
* These must be kept in sync with the definitions in flashLib.h.
*
***********************************************************************/
PRIVATE flash_dev_t flashDev[] = {
/* Bank 0 sector SA0 (16 kB) */
{ "SA0",FLASH0_BANK, FLASH0_SEG0_START, 1, 14,
FLASH0_VENDOR_ID, FLASH0_DEVICE_ID
},
/* Bank 0 sector SA1 (8 kB) */
{ "SA1", FLASH0_BANK, FLASH0_SEG0_START + 0x4000, 1, 13,
FLASH0_VENDOR_ID, FLASH0_DEVICE_ID
},
/* Bank 0 sector SA2 (8 kB) */
{ "SA2", FLASH0_BANK, FLASH0_SEG0_START + 0x6000, 1, 13,
FLASH0_VENDOR_ID, FLASH0_DEVICE_ID
},
/* Bank 0 sector SA3 is occluded by Mousse I/O devices */
/* Bank 0 sectors SA4-SA18, after Mousse devices up to PLCC (960 kB) */
{ "KERNEL", FLASH0_BANK, FLASH0_SEG1_START, 15, 16,
FLASH0_VENDOR_ID, FLASH0_DEVICE_ID
},
/* Bank 0 sectors SA19-SA26, jumper can occlude this by PLCC (512 kB) */
/* This is where the Kahlua boot vector and boot ROM code resides. */
{ "BOOT",FLASH0_BANK, FLASH0_SEG2_START, 8, 16,
FLASH0_VENDOR_ID, FLASH0_DEVICE_ID
},
/* Bank 0 sectors SA27-SA34 (512 kB) */
{ "RAMDISK",FLASH0_BANK, FLASH0_SEG3_START, 8, 16,
FLASH0_VENDOR_ID, FLASH0_DEVICE_ID
},
};
int flashDevCount = (sizeof (flashDev) / sizeof (flashDev[0]));
#define DEV(no) (&flashDev[no])
#define DEV_NO(dev) ((dev) - flashDev)
/***********************************************************************
*
* Private Flash Routines
*
***********************************************************************/
/*
* The convention is:
*
* "addr" is always the PROM raw address, which is the address of an
* 8-bit quantity for flash 0 and 16-bit quantity for flash 1.
*
* "pos" is always a logical byte position from the PROM beginning.
*/
#define FLASH0_ADDR(dev, addr) \
((unsigned char *) ((dev)->base + (addr)))
#define FLASH0_WRITE(dev, addr, value) \
(*FLASH0_ADDR(dev, addr) = (value))
#define FLASH0_READ(dev, addr) \
(*FLASH0_ADDR(dev, addr))
PRIVATE int flashCheck(flash_dev_t *dev)
{
if (! flashLibInited) {
printf("flashCheck: flashLib not initialized\n");
return ERROR;
}
if (dev < &flashDev[0] || dev >= &flashDev[flashDevCount]) {
printf("flashCheck: Bad dev parameter\n");
return ERROR;
}
if (! dev->found) {
printf("flashCheck: Device %d not available\n", DEV_NO(dev));
return ERROR;
}
return OK;
}
PRIVATE void flashReset(flash_dev_t *dev)
{
PRINTF("flashReset: dev=%d\n", DEV_NO(dev));
if (dev->bank == FLASH0_BANK) {
FLASH0_WRITE(dev, 0x555, 0xaa);
FLASH0_WRITE(dev, 0xaaa, 0x55);
FLASH0_WRITE(dev, 0x555, 0xf0);
}
udelay(SLEEP_DELAY);
PRINTF("flashReset: done\n");
}
PRIVATE int flashProbe(flash_dev_t *dev)
{
int rv, deviceID, vendorID;
PRINTF("flashProbe: dev=%d\n", DEV_NO(dev));
if (dev->bank != FLASH0_BANK) {
rv = ERROR;
goto DONE;
}
FLASH0_WRITE(dev, 0xaaa, 0xaa);
FLASH0_WRITE(dev, 0x555, 0x55);
FLASH0_WRITE(dev, 0xaaa, 0x90);
udelay(SLEEP_DELAY);
vendorID = FLASH0_READ(dev, 0);
deviceID = FLASH0_READ(dev, 2);
FLASH0_WRITE(dev, 0, 0xf0);
PRINTF("flashProbe: vendor=0x%x device=0x%x\n", vendorID, deviceID);
if (vendorID == dev->vendorID && deviceID == dev->deviceID)
rv = OK;
else
rv = ERROR;
DONE:
PRINTF("flashProbe: rv=%d\n", rv);
return rv;
}
PRIVATE int flashWait(flash_dev_t *dev, int addr, int expect, int erase)
{
int rv = ERROR;
int i, data;
int polls;
#if 0
PRINTF("flashWait: dev=%d addr=0x%x expect=0x%x erase=%d\n",
DEV_NO(dev), addr, expect, erase);
#endif
if (dev->bank != FLASH0_BANK) {
rv = ERROR;
goto done;
}
if (erase)
polls = FLASH_ERASE_SECTOR_TIMEOUT; /* Ticks */
else
polls = FLASH_PROGRAM_POLLS; /* Loops */
for (i = 0; i < polls; i++) {
if (erase)
udelay(SLEEP_DELAY);
data = FLASH0_READ(dev, addr);
if (((data ^ expect) & 0x80) == 0) {
rv = OK;
goto done;
}
if (data & 0x20) {
/*
* If the 0x20 bit has come on, it could actually be because
* the operation succeeded, so check the done bit again.
*/
data = FLASH0_READ(dev, addr);
if (((data ^ expect) & 0x80) == 0) {
rv = OK;
goto done;
}
printf("flashWait: Program error (dev: %d, addr: 0x%x)\n",
DEV_NO(dev), addr);
flashReset(dev);
rv = ERROR;
goto done;
}
}
printf("flashWait: Timeout %s (dev: %d, addr: 0x%x)\n",
erase ? "erasing sector" : "programming byte",
DEV_NO(dev), addr);
done:
#if 0
PRINTF("flashWait: rv=%d\n", rv);
#endif
return rv;
}
/***********************************************************************
*
* Public Flash Routines
*
***********************************************************************/
STATUS flashLibInit(void)
{
int i;
PRINTF("flashLibInit: devices=%d\n", flashDevCount);
for (i = 0; i < flashDevCount; i++) {
flash_dev_t *dev = &flashDev[i];
/*
* For bank 1, probe both without and with byte swappage,
* so that this module works on both old and new Mousse boards.
*/
flashReset(dev);
if (flashProbe(dev) != ERROR)
dev->found = 1;
flashReset(dev);
if (flashProbe(dev) != ERROR)
dev->found = 1;
dev->swap = 0;
if(dev->found){
PRINTF("\n FLASH %s[%d]: iobase=0x%x - %d sectors %d KB",
flashDev[i].name,i,flashDev[i].base, flashDev[i].sectors,
(flashDev[i].sectors * FLASH_SECTOR_SIZE)/1024);
}
}
flashLibInited = 1;
PRINTF("flashLibInit: done\n");
return OK;
}
STATUS flashEraseSector(flash_dev_t *dev, int sector)
{
int pos, addr;
PRINTF("flashErasesector: dev=%d sector=%d\n", DEV_NO(dev), sector);
if (flashCheck(dev) == ERROR)
return ERROR;
if (sector < 0 || sector >= dev->sectors) {
printf("flashEraseSector: Sector out of range (dev: %d, sector: %d)\n",
DEV_NO(dev), sector);
return ERROR;
}
pos = FLASH_SECTOR_POS(dev, sector);
if (dev->bank != FLASH0_BANK) {
return ERROR;
}
addr = pos;
FLASH0_WRITE(dev, 0xaaa, 0xaa);
FLASH0_WRITE(dev, 0x555, 0x55);
FLASH0_WRITE(dev, 0xaaa, 0x80);
FLASH0_WRITE(dev, 0xaaa, 0xaa);
FLASH0_WRITE(dev, 0x555, 0x55);
FLASH0_WRITE(dev, addr, 0x30);
return flashWait(dev, addr, 0xff, 1);
}
/*
* Note: it takes about as long to flash all sectors together with Chip
* Erase as it does to flash them one at a time (about 30 seconds for 2
* MB). Also since we want to be able to treat subsets of sectors as if
* they were complete devices, we don't use Chip Erase.
*/
STATUS flashErase(flash_dev_t *dev)
{
int sector;
PRINTF("flashErase: dev=%d sectors=%d\n", DEV_NO(dev), dev->sectors);
if (flashCheck(dev) == ERROR)
return ERROR;
for (sector = 0; sector < dev->sectors; sector++) {
if (flashEraseSector(dev, sector) == ERROR)
return ERROR;
}
return OK;
}
/*
* Read and write bytes
*/
STATUS flashRead(flash_dev_t *dev, int pos, char *buf, int len)
{
int addr, words;
PRINTF("flashRead: dev=%d pos=0x%x buf=0x%x len=0x%x\n",
DEV_NO(dev), pos, (int) buf, len);
if (flashCheck(dev) == ERROR)
return ERROR;
if (pos < 0 || len < 0 || pos + len > FLASH_MAX_POS(dev)) {
printf("flashRead: Position out of range "
"(dev: %d, pos: 0x%x, len: 0x%x)\n",
DEV_NO(dev), pos, len);
return ERROR;
}
if (len == 0)
return OK;
if (dev->bank == FLASH0_BANK) {
addr = pos;
words = len;
PRINTF("flashRead: memcpy(0x%x, 0x%x, 0x%x)\n",
(int) buf, (int) FLASH0_ADDR(dev, pos), len);
memcpy(buf, FLASH0_ADDR(dev, addr), words);
}
PRINTF("flashRead: rv=OK\n");
return OK;
}
STATUS flashWrite(flash_dev_t *dev, int pos, char *buf, int len)
{
int addr, words;
PRINTF("flashWrite: dev=%d pos=0x%x buf=0x%x len=0x%x\n",
DEV_NO(dev), pos, (int) buf, len);
if (flashCheck(dev) == ERROR)
return ERROR;
if (pos < 0 || len < 0 || pos + len > FLASH_MAX_POS(dev)) {
printf("flashWrite: Position out of range "
"(dev: %d, pos: 0x%x, len: 0x%x)\n",
DEV_NO(dev), pos, len);
return ERROR;
}
if (len == 0)
return OK;
if (dev->bank == FLASH0_BANK) {
unsigned char tmp;
addr = pos;
words = len;
while (words--) {
tmp = *buf;
if (~FLASH0_READ(dev, addr) & tmp) {
printf("flashWrite: Attempt to program 0 to 1 "
"(dev: %d, addr: 0x%x, data: 0x%x)\n",
DEV_NO(dev), addr, tmp);
return ERROR;
}
FLASH0_WRITE(dev, 0xaaa, 0xaa);
FLASH0_WRITE(dev, 0x555, 0x55);
FLASH0_WRITE(dev, 0xaaa, 0xa0);
FLASH0_WRITE(dev, addr, tmp);
if (flashWait(dev, addr, tmp, 0) < 0)
return ERROR;
buf++;
addr++;
}
}
PRINTF("flashWrite: rv=OK\n");
return OK;
}
/*
* flashWritable returns TRUE if a range contains all F's.
*/
STATUS flashWritable(flash_dev_t *dev, int pos, int len)
{
int addr, words;
int rv = ERROR;
PRINTF("flashWritable: dev=%d pos=0x%x len=0x%x\n",
DEV_NO(dev), pos, len);
if (flashCheck(dev) == ERROR)
goto done;
if (pos < 0 || len < 0 || pos + len > FLASH_MAX_POS(dev)) {
printf("flashWritable: Position out of range "
"(dev: %d, pos: 0x%x, len: 0x%x)\n",
DEV_NO(dev), pos, len);
goto done;
}
if (len == 0) {
rv = 1;
goto done;
}
if (dev->bank == FLASH0_BANK) {
addr = pos;
words = len;
while (words--) {
if (FLASH0_READ(dev, addr) != 0xff) {
rv = 0;
goto done;
}
addr++;
}
}
rv = 1;
done:
PRINTF("flashWrite: rv=%d\n", rv);
return rv;
}
/*
* NOTE: the below code cannot run from FLASH!!!
*/
/***********************************************************************
*
* Flash Diagnostics
*
***********************************************************************/
STATUS flashDiag(flash_dev_t *dev)
{
unsigned int *buf = 0;
int i, len, sector;
int rv = ERROR;
if (flashCheck(dev) == ERROR)
return ERROR;
printf("flashDiag: Testing device %d, "
"base: 0x%x, %d sectors @ %d kB = %d kB\n",
DEV_NO(dev), dev->base,
dev->sectors,
1 << (dev->lgSectorSize - 10),
dev->sectors << (dev->lgSectorSize - 10));
len = 1 << dev->lgSectorSize;
printf("flashDiag: Erasing\n");
if (flashErase(dev) == ERROR) {
printf("flashDiag: Erase failed\n");
goto done;
}
printf("%d bytes requested ...\n", len);
buf = malloc(len);
printf("allocated %d bytes ...\n", len);
if (buf == 0) {
printf("flashDiag: Out of memory\n");
goto done;
}
/*
* Write unique counting pattern to each sector
*/
for (sector = 0; sector < dev->sectors; sector++) {
printf("flashDiag: Write sector %d\n", sector);
for (i = 0; i < len / 4; i++)
buf[i] = sector << 24 | i;
if (flashWrite(dev,
sector << dev->lgSectorSize,
(char *) buf,
len) == ERROR) {
printf("flashDiag: Write failed (dev: %d, sector: %d)\n",
DEV_NO(dev), sector);
goto done;
}
}
/*
* Verify
*/
for (sector = 0; sector < dev->sectors; sector++) {
printf("flashDiag: Verify sector %d\n", sector);
if (flashRead(dev,
sector << dev->lgSectorSize,
(char *) buf,
len) == ERROR) {
printf("flashDiag: Read failed (dev: %d, sector: %d)\n",
DEV_NO(dev), sector);
goto done;
}
for (i = 0; i < len / 4; i++) {
if (buf[i] != (sector << 24 | i)) {
printf("flashDiag: Verify error "
"(dev: %d, sector: %d, offset: 0x%x)\n",
DEV_NO(dev), sector, i);
printf("flashDiag: Expected 0x%08x, got 0x%08x\n",
sector << 24 | i, buf[i]);
goto done;
}
}
}
printf("flashDiag: Erasing\n");
if (flashErase(dev) == ERROR) {
printf("flashDiag: Final erase failed\n");
goto done;
}
rv = OK;
done:
if (buf)
free(buf);
if (rv == OK)
printf("flashDiag: Device %d passed\n", DEV_NO(dev));
else
printf("flashDiag: Device %d failed\n", DEV_NO(dev));
return rv;
}
STATUS flashDiagAll(void)
{
int i;
int rv = OK;
PRINTF("flashDiagAll: devices=%d\n", flashDevCount);
for (i = 0; i < flashDevCount; i++) {
flash_dev_t *dev = &flashDev[i];
if (dev->found && flashDiag(dev) == ERROR)
rv = ERROR;
}
if (rv == OK)
printf("flashDiagAll: Passed\n");
else
printf("flashDiagAll: Failed because of earlier errors\n");
return OK;
}
/*-----------------------------------------------------------------------
*/
unsigned long flash_init (void)
{
unsigned long size = 0;
flash_dev_t *dev = NULL;
flashLibInit();
/*
* Provide info for FLASH (up to 960K) of Kernel Image data.
*/
dev = FLASH_DEV_BANK0_LOW;
flash_info[FLASH_BANK_KERNEL].flash_id =
(dev->vendorID << 16) | dev->deviceID;
flash_info[FLASH_BANK_KERNEL].sector_count = dev->sectors;
flash_info[FLASH_BANK_KERNEL].size =
flash_info[FLASH_BANK_KERNEL].sector_count * FLASH_SECTOR_SIZE;
flash_info[FLASH_BANK_KERNEL].start[FIRST_SECTOR] = dev->base;
size += flash_info[FLASH_BANK_KERNEL].size;
/*
* Provide info for 512K PLCC FLASH ROM (U-Boot)
*/
dev = FLASH_DEV_BANK0_BOOT;
flash_info[FLASH_BANK_BOOT].flash_id =
(dev->vendorID << 16) | dev->deviceID;
flash_info[FLASH_BANK_BOOT].sector_count = dev->sectors;
flash_info[FLASH_BANK_BOOT].size =
flash_info[FLASH_BANK_BOOT].sector_count * FLASH_SECTOR_SIZE;
flash_info[FLASH_BANK_BOOT].start[FIRST_SECTOR] = dev->base;
size += flash_info[FLASH_BANK_BOOT].size;
/*
* Provide info for 512K FLASH0 segment (U-Boot)
*/
dev = FLASH_DEV_BANK0_HIGH;
flash_info[FLASH_BANK_AUX].flash_id =
(dev->vendorID << 16) | dev->deviceID;
flash_info[FLASH_BANK_AUX].sector_count = dev->sectors;
flash_info[FLASH_BANK_AUX].size =
flash_info[FLASH_BANK_AUX].sector_count * FLASH_SECTOR_SIZE;
flash_info[FLASH_BANK_AUX].start[FIRST_SECTOR] = dev->base;
size += flash_info[FLASH_BANK_AUX].size;
return size;
}
/*
* Get flash device from U-Boot flash info.
*/
flash_dev_t*
getFlashDevFromInfo(flash_info_t* info)
{
int i;
if(!info)
return NULL;
for (i = 0; i < flashDevCount; i++) {
flash_dev_t *dev = &flashDev[i];
if(dev->found && (dev->base == info->start[0]))
return dev;
}
printf("ERROR: notice, no FLASH mapped at address 0x%x\n",
(unsigned int)info->start[0]);
return NULL;
}
ulong
flash_get_size (vu_long *addr, flash_info_t *info)
{
int i;
for(i = 0; i < flashDevCount; i++) {
flash_dev_t *dev = &flashDev[i];
if(dev->found){
if(dev->base == (unsigned int)addr){
info->flash_id = (dev->vendorID << 16) | dev->deviceID;
info->sector_count = dev->sectors;
info->size = info->sector_count * FLASH_SECTOR_SIZE;
return dev->sectors * FLASH_SECTOR_SIZE;
}
}
}
return 0;
}
void
flash_print_info (flash_info_t *info)
{
int i;
unsigned int chip;
if (info->flash_id == FLASH_UNKNOWN) {
printf ("missing or unknown FLASH type\n");
return;
}
switch ((info->flash_id >> 16) & 0xff) {
case 0x1:
printf ("AMD ");
break;
default:
printf ("Unknown Vendor ");
break;
}
chip = (unsigned int) info->flash_id & 0x000000ff;
switch (chip) {
case AMD_ID_F040B:
printf ("AM29F040B (4 Mbit)\n");
break;
case AMD_ID_LV160B:
case FLASH_AM160LV:
case 0x49:
printf ("AM29LV160B (16 Mbit / 2M x 8bit)\n");
break;
default:
printf ("Unknown Chip Type:0x%x\n", chip);
break;
}
printf (" Size: %ld bytes in %d Sectors\n",
info->size, info->sector_count);
printf (" Sector Start Addresses:");
for (i=0; i<info->sector_count; ++i) {
if ((i % 5) == 0)
printf ("\n ");
printf (" %08lX%s",
info->start[FIRST_SECTOR] + i*FLASH_SECTOR_SIZE,
info->protect[i] ? " (RO)" : " "
);
}
printf ("\n");
}
/*
* Erase a range of flash sectors.
*/
int flash_erase (flash_info_t *info, int s_first, int s_last)
{
vu_long *addr = (vu_long*)(info->start[0]);
int prot, sect, l_sect;
flash_dev_t* dev = NULL;
if ((s_first < 0) || (s_first > s_last)) {
if (info->flash_id == FLASH_UNKNOWN) {
printf ("- missing\n");
} else {
printf ("- no sectors to erase\n");
}
return 1;
}
prot = 0;
for (sect = s_first; sect <= s_last; sect++) {
if (info->protect[sect]) {
prot++;
}
}
if (prot) {
printf ("- Warning: %d protected sectors will not be erased!\n",
prot);
} else {
printf ("\n");
}
l_sect = -1;
/* Start erase on unprotected sectors */
dev = getFlashDevFromInfo(info);
if(dev){
printf("Erase FLASH[%s] -%d sectors:", dev->name, dev->sectors);
for (sect = s_first; sect<=s_last; sect++) {
if (info->protect[sect] == 0) { /* not protected */
addr = (vu_long*)(dev->base);
/* printf("erase_sector: sector=%d, addr=0x%x\n",
sect, addr); */
printf(".");
if(ERROR == flashEraseSector(dev, sect)){
printf("ERROR: could not erase sector %d on FLASH[%s]\n",
sect, dev->name);
return 1;
}
}
}
}
printf (" done\n");
return 0;
}
/*-----------------------------------------------------------------------
* Write a word to Flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
static int
write_word (flash_info_t *info, ulong dest, ulong data)
{
flash_dev_t* dev = getFlashDevFromInfo(info);
int addr = dest - info->start[0];
if (! dev)
return 1;
if(OK != flashWrite(dev, addr, (char*)&data, sizeof(ulong))){
printf("ERROR: could not write to addr=0x%x, data=0x%x\n",
(unsigned int)addr, (unsigned)data);
return 1;
}
if((addr % FLASH_SECTOR_SIZE) == 0)
printf(".");
PRINTF("write_word:0x%x, base=0x%x, addr=0x%x, data=0x%x\n",
(unsigned)info->start[0],
(unsigned)dest,
(unsigned)(dest - info->start[0]),
(unsigned)data);
return (0);
}
/*-----------------------------------------------------------------------
* Copy memory to flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
{
ulong cp, wp, data;
int i, l, rc;
flash_dev_t* dev = getFlashDevFromInfo(info);
if( dev ) {
printf("FLASH[%s]:", dev->name);
wp = (addr & ~3); /* get lower word aligned address */
/*
* handle unaligned start bytes
*/
if ((l = addr - wp) != 0) {
data = 0;
for (i=0, cp=wp; i<l; ++i, ++cp) {
data = (data << 8) | (*(uchar *)cp);
}
for (; i<4 && cnt>0; ++i) {
data = (data << 8) | *src++;
--cnt;
++cp;
}
for (; cnt==0 && i<4; ++i, ++cp) {
data = (data << 8) | (*(uchar *)cp);
}
if ((rc = write_word(info, wp, data)) != 0) {
return (rc);
}
wp += 4;
}
/*
* handle word aligned part
*/
while (cnt >= 4) {
data = 0;
for (i=0; i<4; ++i) {
data = (data << 8) | *src++;
}
if ((rc = write_word(info, wp, data)) != 0) {
return (rc);
}
wp += 4;
cnt -= 4;
}
if (cnt == 0) {
return (0);
}
/*
* handle unaligned tail bytes
*/
data = 0;
for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
data = (data << 8) | *src++;
--cnt;
}
for (; i<4; ++i, ++cp) {
data = (data << 8) | (*(uchar *)cp);
}
return (write_word(info, wp, data));
}
return 1;
}
/*-----------------------------------------------------------------------
*/

323
board/mousse/m48t59y.c Normal file
View File

@@ -0,0 +1,323 @@
/*
* SGS M48-T59Y TOD/NVRAM Driver
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 1999, by Curt McDowell, 08-06-99, Broadcom Corp.
*
* (C) Copyright 2001, James Dougherty, 07/18/01, Broadcom Corp.
*
* 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
*/
/*
* SGS M48-T59Y TOD/NVRAM Driver
*
* The SGS M48 an 8K NVRAM starting at offset M48_BASE_ADDR and
* continuing for 8176 bytes. After that starts the Time-Of-Day (TOD)
* registers which are used to set/get the internal date/time functions.
*
* This module implements Y2K compliance by taking full year numbers
* and translating back and forth from the TOD 2-digit year.
*
* NOTE: for proper interaction with an operating system, the TOD should
* be used to store Universal Coordinated Time (GMT) and timezone
* conversions should be used.
*
* Here is a diagram of the memory layout:
*
* +---------------------------------------------+ 0xffe0a000
* | Non-volatile memory | .
* | | .
* | (8176 bytes of Non-volatile memory) | .
* | | .
* +---------------------------------------------+ 0xffe0bff0
* | Flags |
* +---------------------------------------------+ 0xffe0bff1
* | Unused |
* +---------------------------------------------+ 0xffe0bff2
* | Alarm Seconds |
* +---------------------------------------------+ 0xffe0bff3
* | Alarm Minutes |
* +---------------------------------------------+ 0xffe0bff4
* | Alarm Date |
* +---------------------------------------------+ 0xffe0bff5
* | Interrupts |
* +---------------------------------------------+ 0xffe0bff6
* | WatchDog |
* +---------------------------------------------+ 0xffe0bff7
* | Calibration |
* +---------------------------------------------+ 0xffe0bff8
* | Seconds |
* +---------------------------------------------+ 0xffe0bff9
* | Minutes |
* +---------------------------------------------+ 0xffe0bffa
* | Hours |
* +---------------------------------------------+ 0xffe0bffb
* | Day |
* +---------------------------------------------+ 0xffe0bffc
* | Date |
* +---------------------------------------------+ 0xffe0bffd
* | Month |
* +---------------------------------------------+ 0xffe0bffe
* | Year (2 digits only) |
* +---------------------------------------------+ 0xffe0bfff
*/
#include <common.h>
#include <rtc.h>
#include "mousse.h"
/*
* Imported from mousse.h:
*
* TOD_REG_BASE Base of m48t59y TOD registers
* SYS_TOD_UNPROTECT() Disable NVRAM write protect
* SYS_TOD_PROTECT() Re-enable NVRAM write protect
*/
#define YEAR 0xf
#define MONTH 0xe
#define DAY 0xd
#define DAY_OF_WEEK 0xc
#define HOUR 0xb
#define MINUTE 0xa
#define SECOND 0x9
#define CONTROL 0x8
#define WATCH 0x7
#define INTCTL 0x6
#define WD_DATE 0x5
#define WD_HOUR 0x4
#define WD_MIN 0x3
#define WD_SEC 0x2
#define _UNUSED 0x1
#define FLAGS 0x0
#define M48_ADDR ((volatile unsigned char *) TOD_REG_BASE)
int m48_tod_init(void)
{
SYS_TOD_UNPROTECT();
M48_ADDR[CONTROL] = 0;
M48_ADDR[WATCH] = 0;
M48_ADDR[INTCTL] = 0;
/*
* If the oscillator is currently stopped (as on a new part shipped
* from the factory), start it running.
*
* Here is an example of the TOD bytes on a brand new M48T59Y part:
* 00 00 00 00 00 00 00 00 00 88 8c c3 bf c8 f5 01
*/
if (M48_ADDR[SECOND] & 0x80)
M48_ADDR[SECOND] = 0;
/* Is battery low */
if ( M48_ADDR[FLAGS] & 0x10) {
printf("NOTICE: Battery low on Real-Time Clock (replace SNAPHAT).\n");
}
SYS_TOD_PROTECT();
return 0;
}
/*
* m48_tod_set
*/
static int to_bcd(int value)
{
return value / 10 * 16 + value % 10;
}
static int from_bcd(int value)
{
return value / 16 * 10 + value % 16;
}
static int day_of_week(int y, int m, int d) /* 0-6 ==> Sun-Sat */
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
/*
* Note: the TOD should store the current GMT
*/
int m48_tod_set(int year, /* 1980-2079 */
int month, /* 01-12 */
int day, /* 01-31 */
int hour, /* 00-23 */
int minute, /* 00-59 */
int second) /* 00-59 */
{
SYS_TOD_UNPROTECT();
M48_ADDR[CONTROL] |= 0x80; /* Set WRITE bit */
M48_ADDR[YEAR] = to_bcd(year % 100);
M48_ADDR[MONTH] = to_bcd(month);
M48_ADDR[DAY] = to_bcd(day);
M48_ADDR[DAY_OF_WEEK] = day_of_week(year, month, day) + 1;
M48_ADDR[HOUR] = to_bcd(hour);
M48_ADDR[MINUTE] = to_bcd(minute);
M48_ADDR[SECOND] = to_bcd(second);
M48_ADDR[CONTROL] &= ~0x80; /* Clear WRITE bit */
SYS_TOD_PROTECT();
return 0;
}
/*
* Note: the TOD should store the current GMT
*/
int m48_tod_get(int *year, /* 1980-2079 */
int *month, /* 01-12 */
int *day, /* 01-31 */
int *hour, /* 00-23 */
int *minute, /* 00-59 */
int *second) /* 00-59 */
{
int y;
SYS_TOD_UNPROTECT();
M48_ADDR[CONTROL] |= 0x40; /* Set READ bit */
y = from_bcd(M48_ADDR[YEAR]);
*year = y < 80 ? 2000 + y : 1900 + y;
*month = from_bcd(M48_ADDR[MONTH]);
*day = from_bcd(M48_ADDR[DAY]);
/* day_of_week = M48_ADDR[DAY_OF_WEEK] & 0xf; */
*hour = from_bcd(M48_ADDR[HOUR]);
*minute = from_bcd(M48_ADDR[MINUTE]);
*second = from_bcd(M48_ADDR[SECOND] & 0x7f);
M48_ADDR[CONTROL] &= ~0x40; /* Clear READ bit */
SYS_TOD_PROTECT();
return 0;
}
int m48_tod_get_second(void)
{
return from_bcd(M48_ADDR[SECOND] & 0x7f);
}
/*
* Watchdog function
*
* If usec is 0, the watchdog timer is disarmed.
*
* If usec is non-zero, the watchdog timer is armed (or re-armed) for
* approximately usec microseconds (if the exact requested usec is
* not supported by the chip, the next higher available value is used).
*
* Minimum watchdog timeout = 62500 usec
* Maximum watchdog timeout = 124 sec (124000000 usec)
*/
void m48_watchdog_arm(int usec)
{
int mpy, res;
SYS_TOD_UNPROTECT();
if (usec == 0) {
res = 0;
mpy = 0;
} else if (usec < 2000000) { /* Resolution: 1/16s if below 2s */
res = 0;
mpy = (usec + 62499) / 62500;
} else if (usec < 8000000) { /* Resolution: 1/4s if below 8s */
res = 1;
mpy = (usec + 249999) / 250000;
} else if (usec < 32000000) { /* Resolution: 1s if below 32s */
res = 2;
mpy = (usec + 999999) / 1000000;
} else { /* Resolution: 4s up to 124s */
res = 3;
mpy = (usec + 3999999) / 4000000;
if (mpy > 31)
mpy = 31;
}
M48_ADDR[WATCH] = (0x80 | /* Steer to RST signal (IRQ = N/C) */
mpy << 2 |
res);
SYS_TOD_PROTECT();
}
/*
* U-Boot RTC support.
*/
void
rtc_get( struct rtc_time *tmp )
{
m48_tod_get(&tmp->tm_year,
&tmp->tm_mon,
&tmp->tm_mday,
&tmp->tm_hour,
&tmp->tm_min,
&tmp->tm_sec);
tmp->tm_yday = 0;
tmp->tm_isdst= 0;
#ifdef RTC_DEBUG
printf( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
#endif
}
void
rtc_set( struct rtc_time *tmp )
{
m48_tod_set(tmp->tm_year, /* 1980-2079 */
tmp->tm_mon, /* 01-12 */
tmp->tm_mday, /* 01-31 */
tmp->tm_hour, /* 00-23 */
tmp->tm_min, /* 00-59 */
tmp->tm_sec); /* 00-59 */
#ifdef RTC_DEBUG
printf( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
#endif
}
void
rtc_reset (void)
{
m48_tod_init();
}

377
board/pm826/flash.c Normal file
View File

@@ -0,0 +1,377 @@
/*
* (C) Copyright 2001, 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* Flash Routines for Intel devices
*
*--------------------------------------------------------------------
* 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 <mpc8xx.h>
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
/*-----------------------------------------------------------------------
*/
ulong flash_get_size (volatile unsigned long *baseaddr,
flash_info_t * info)
{
short i;
unsigned long flashtest_h, flashtest_l;
info->sector_count = info->size = 0;
info->flash_id = FLASH_UNKNOWN;
/* Write query command sequence and test FLASH answer
*/
baseaddr[0] = 0x00980098;
baseaddr[1] = 0x00980098;
flashtest_h = baseaddr[0]; /* manufacturer ID */
flashtest_l = baseaddr[1];
if (flashtest_h != INTEL_MANUFACT || flashtest_l != INTEL_MANUFACT)
return (0); /* no or unknown flash */
flashtest_h = baseaddr[2]; /* device ID */
flashtest_l = baseaddr[3];
if (flashtest_h != flashtest_l)
return (0);
switch (flashtest_h) {
case INTEL_ID_28F160C3B:
info->flash_id = FLASH_28F160C3B;
info->sector_count = 39;
info->size = 0x00800000; /* 4 * 2 MB = 8 MB */
break;
case INTEL_ID_28F160F3B:
info->flash_id = FLASH_28F160F3B;
info->sector_count = 39;
info->size = 0x00800000; /* 4 * 2 MB = 8 MB */
break;
default:
return (0); /* no or unknown flash */
}
info->flash_id |= INTEL_MANUFACT << 16; /* set manufacturer offset */
if (info->flash_id & FLASH_BTYPE) {
volatile unsigned long *tmp = baseaddr;
/* set up sector start adress table (bottom sector type)
* AND unlock the sectors (if our chip is 160C3)
*/
for (i = 0; i < info->sector_count; i++) {
if ((info->flash_id & FLASH_TYPEMASK) == FLASH_28F160C3B) {
tmp[0] = 0x00600060;
tmp[1] = 0x00600060;
tmp[0] = 0x00D000D0;
tmp[1] = 0x00D000D0;
}
info->start[i] = (uint) tmp;
tmp += i < 8 ? 0x2000 : 0x10000; /* pointer arith */
}
}
memset (info->protect, 0, info->sector_count);
baseaddr[0] = 0x00FF00FF;
baseaddr[1] = 0x00FF00FF;
return (info->size);
}
/*-----------------------------------------------------------------------
*/
unsigned long flash_init (void)
{
unsigned long size_b0 = 0;
int i;
/* Init: no FLASHes known
*/
for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
}
/* Static FLASH Bank configuration here (only one bank) */
size_b0 = flash_get_size ((ulong *) CFG_FLASH0_BASE, &flash_info[0]);
if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
size_b0, size_b0 >> 20);
}
/* protect monitor and environment sectors
*/
#ifndef CONFIG_BOOT_ROM
/* If U-Boot is booted from ROM the CFG_MONITOR_BASE > CFG_FLASH0_BASE
* but we shouldn't protect it.
*/
# if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
flash_protect (FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]
);
# endif
#endif /* CONFIG_BOOT_ROM */
#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
# ifndef CFG_ENV_SIZE
# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
# endif
flash_protect (FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
#endif
return (size_b0);
}
/*-----------------------------------------------------------------------
*/
void flash_print_info (flash_info_t * info)
{
int i;
if (info->flash_id == FLASH_UNKNOWN) {
printf ("missing or unknown FLASH type\n");
return;
}
switch ((info->flash_id >> 16) & 0xff) {
case 0x89:
printf ("INTEL ");
break;
default:
printf ("Unknown Vendor ");
break;
}
switch (info->flash_id & FLASH_TYPEMASK) {
case FLASH_28F160C3B:
printf ("28F160C3B (16 M, bottom sector)\n");
break;
case FLASH_28F160F3B:
printf ("28F160F3B (16 M, bottom sector)\n");
break;
default:
printf ("Unknown Chip Type\n");
break;
}
printf (" Size: %ld MB in %d Sectors\n",
info->size >> 20, info->sector_count);
printf (" Sector Start Addresses:");
for (i = 0; i < info->sector_count; ++i) {
if ((i % 5) == 0)
printf ("\n ");
printf (" %08lX%s",
info->start[i],
info->protect[i] ? " (RO)" : " "
);
}
printf ("\n");
}
/*-----------------------------------------------------------------------
*/
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
int flag, prot, sect;
ulong start, now, last;
if ((s_first < 0) || (s_first > s_last)) {
if (info->flash_id == FLASH_UNKNOWN) {
printf ("- missing\n");
} else {
printf ("- no sectors to erase\n");
}
return 1;
}
prot = 0;
for (sect = s_first; sect <= s_last; sect++) {
if (info->protect[sect])
prot++;
}
if (prot) {
printf ("- Warning: %d protected sectors will not be erased!\n",
prot);
} else {
printf ("\n");
}
/* Start erase on unprotected sectors
*/
for (sect = s_first; sect <= s_last; sect++) {
volatile ulong *addr =
(volatile unsigned long *) info->start[sect];
start = get_timer (0);
last = start;
if (info->protect[sect] == 0) {
/* Disable interrupts which might cause a timeout here
*/
flag = disable_interrupts ();
/* Erase the block
*/
addr[0] = 0x00200020;
addr[1] = 0x00200020;
addr[0] = 0x00D000D0;
addr[1] = 0x00D000D0;
/* re-enable interrupts if necessary
*/
if (flag)
enable_interrupts ();
/* wait at least 80us - let's wait 1 ms
*/
udelay (1000);
last = start;
while ((addr[0] & 0x00800080) != 0x00800080 ||
(addr[1] & 0x00800080) != 0x00800080) {
if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
printf ("Timeout (erase suspended!)\n");
/* Suspend erase
*/
addr[0] = 0x00B000B0;
addr[1] = 0x00B000B0;
goto DONE;
}
/* show that we're waiting
*/
if ((now - last) > 1000) { /* every second */
serial_putc ('.');
last = now;
}
}
if (addr[0] & 0x00220022 || addr[1] & 0x00220022) {
printf ("*** ERROR: erase failed!\n");
goto DONE;
}
}
/* Clear status register and reset to read mode
*/
addr[0] = 0x00500050;
addr[1] = 0x00500050;
addr[0] = 0x00FF00FF;
addr[1] = 0x00FF00FF;
}
printf (" done\n");
DONE:
return 0;
}
static int write_word (flash_info_t *, volatile unsigned long *, ulong);
/*-----------------------------------------------------------------------
* Copy memory to flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
{
ulong v;
int i, l, cc = cnt, res = 0;
for (v=0; cc > 0; addr += 4, cc -= 4 - l) {
l = (addr & 3);
addr &= ~3;
for (i = 0; i < 4; i++) {
v = (v << 8) + (i < l || i - l >= cc ?
*((unsigned char *) addr + i) : *src++);
}
if ((res = write_word (info, (volatile unsigned long *) addr, v)) != 0)
break;
}
return (res);
}
/*-----------------------------------------------------------------------
* Write a word to Flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
static int write_word (flash_info_t * info, volatile unsigned long *addr,
ulong data)
{
int flag, res = 0;
ulong start;
/* Check if Flash is (sufficiently) erased
*/
if ((*addr & data) != data)
return (2);
/* Disable interrupts which might cause a timeout here
*/
flag = disable_interrupts ();
*addr = 0x00400040;
*addr = data;
/* re-enable interrupts if necessary
*/
if (flag)
enable_interrupts ();
start = get_timer (0);
while ((*addr & 0x00800080) != 0x00800080) {
if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
/* Suspend program
*/
*addr = 0x00B000B0;
res = 1;
goto OUT;
}
}
if (*addr & 0x00220022) {
printf ("*** ERROR: program failed!\n");
res = 1;
}
OUT:
/* Clear status register and reset to read mode
*/
*addr = 0x00500050;
*addr = 0x00FF00FF;
return (res);
}

523
board/sacsng/flash.c Normal file
View File

@@ -0,0 +1,523 @@
/*
* (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
*/
#include <common.h>
#include <configs/sacsng.h>
#undef DEBUG
#ifndef CFG_ENV_ADDR
#define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
#endif
#ifndef CFG_ENV_SIZE
#define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
#endif
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
/*-----------------------------------------------------------------------
* Functions
*/
static ulong flash_get_size (vu_short *addr, flash_info_t *info);
static int write_word (flash_info_t *info, ulong dest, ulong data);
/*-----------------------------------------------------------------------
*/
unsigned long flash_init (void)
{
unsigned long size_b0, size_b1;
int i;
/* Init: no FLASHes known */
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
}
size_b0 = flash_get_size((vu_short *)CFG_FLASH0_BASE, &flash_info[0]);
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
size_b0, size_b0<<20);
}
size_b1 = flash_get_size((vu_short *)CFG_FLASH1_BASE, &flash_info[1]);
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
/* monitor protection ON by default */
flash_protect(FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
&flash_info[0]);
#endif
#ifdef CFG_ENV_IS_IN_FLASH
/* ENV protection ON by default */
flash_protect(FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR+CFG_ENV_SIZE-1,
&flash_info[0]);
#endif
if (size_b1) {
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
/* monitor protection ON by default */
flash_protect(FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
&flash_info[1]);
#endif
#ifdef CFG_ENV_IS_IN_FLASH
/* ENV protection ON by default */
flash_protect(FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR+CFG_ENV_SIZE-1,
&flash_info[1]);
#endif
} else {
flash_info[1].flash_id = FLASH_UNKNOWN;
flash_info[1].sector_count = -1;
}
flash_info[0].size = size_b0;
flash_info[1].size = size_b1;
/*
* We only report the primary flash for U-Boot's use.
*/
return (size_b0);
}
/*-----------------------------------------------------------------------
*/
void flash_print_info (flash_info_t *info)
{
int i;
if (info->flash_id == FLASH_UNKNOWN) {
printf ("missing or unknown FLASH type\n");
return;
}
switch (info->flash_id & FLASH_VENDMASK) {
case FLASH_MAN_AMD: printf ("AMD "); break;
case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
default: printf ("Unknown Vendor "); break;
}
switch (info->flash_id & FLASH_TYPEMASK) {
case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
break;
case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
break;
case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
break;
case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
break;
case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
break;
case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
break;
case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
break;
case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
break;
default: printf ("Unknown Chip Type\n");
break;
}
printf (" Size: %ld MB in %d Sectors\n",
info->size >> 20, info->sector_count);
printf (" Sector Start Addresses:");
for (i=0; i<info->sector_count; ++i) {
if ((i % 5) == 0)
printf ("\n ");
printf (" %08lX%s",
info->start[i],
info->protect[i] ? " (RO)" : " "
);
}
printf ("\n");
return;
}
/*-----------------------------------------------------------------------
*/
/*-----------------------------------------------------------------------
*/
/*
* The following code cannot be run from FLASH!
*/
static ulong flash_get_size (vu_short *addr, flash_info_t *info)
{
short i;
ushort value;
ulong base = (ulong)addr;
/* Write auto select command: read Manufacturer ID */
addr[0x0555] = 0xAAAA;
addr[0x02AA] = 0x5555;
addr[0x0555] = 0x9090;
__asm__ __volatile__(" sync\n ");
value = addr[0];
#ifdef DEBUG
printf("Flash manufacturer 0x%04X\n", value);
#endif
if(value == (ushort)AMD_MANUFACT) {
info->flash_id = FLASH_MAN_AMD;
} else if (value == (ushort)FUJ_MANUFACT) {
info->flash_id = FLASH_MAN_FUJ;
} else {
#ifdef DEBUG
printf("Unknown flash manufacturer 0x%04X\n", value);
#endif
info->flash_id = FLASH_UNKNOWN;
info->sector_count = 0;
info->size = 0;
return (0); /* no or unknown flash */
}
value = addr[1]; /* device ID */
#ifdef DEBUG
printf("Flash type 0x%04X\n", value);
#endif
if(value == (ushort)AMD_ID_LV400T) {
info->flash_id += FLASH_AM400T;
info->sector_count = 11;
info->size = 0x00080000; /* => 0.5 MB */
} else if(value == (ushort)AMD_ID_LV400B) {
info->flash_id += FLASH_AM400B;
info->sector_count = 11;
info->size = 0x00080000; /* => 0.5 MB */
} else if(value == (ushort)AMD_ID_LV800T) {
info->flash_id += FLASH_AM800T;
info->sector_count = 19;
info->size = 0x00100000; /* => 1 MB */
} else if(value == (ushort)AMD_ID_LV800B) {
info->flash_id += FLASH_AM800B;
info->sector_count = 19;
info->size = 0x00100000; /* => 1 MB */
} else if(value == (ushort)AMD_ID_LV160T) {
info->flash_id += FLASH_AM160T;
info->sector_count = 35;
info->size = 0x00200000; /* => 2 MB */
} else if(value == (ushort)AMD_ID_LV160B) {
info->flash_id += FLASH_AM160B;
info->sector_count = 35;
info->size = 0x00200000; /* => 2 MB */
} else if(value == (ushort)AMD_ID_LV320T) {
info->flash_id += FLASH_AM320T;
info->sector_count = 67;
info->size = 0x00400000; /* => 4 MB */
} else if(value == (ushort)AMD_ID_LV320B) {
info->flash_id += FLASH_AM320B;
info->sector_count = 67;
info->size = 0x00400000; /* => 4 MB */
} else {
#ifdef DEBUG
printf("Unknown flash type 0x%04X\n", value);
info->size = CFG_FLASH_SIZE;
#else
info->flash_id = FLASH_UNKNOWN;
return (0); /* => no or unknown flash */
#endif
}
/* set up sector start address table */
if (info->flash_id & FLASH_BTYPE) {
/* set sector offsets for bottom boot block type */
info->start[0] = base + 0x00000000;
info->start[1] = base + 0x00004000;
info->start[2] = base + 0x00006000;
info->start[3] = base + 0x00008000;
for (i = 4; i < info->sector_count; i++) {
info->start[i] = base + ((i - 3) * 0x00010000);
}
} else {
/* set sector offsets for top boot block type */
i = info->sector_count - 1;
info->start[i--] = base + info->size - 0x00004000;
info->start[i--] = base + info->size - 0x00006000;
info->start[i--] = base + info->size - 0x00008000;
for (; i >= 0; i--) {
info->start[i] = base + (i * 0x00010000);
}
}
/* check for protected sectors */
for (i = 0; i < info->sector_count; i++) {
/* read sector protection at sector address, (A7 .. A0) = 0x02 */
/* D0 = 1 if protected */
addr = (volatile unsigned short *)(info->start[i]);
info->protect[i] = addr[2] & 1;
}
/*
* Prevent writes to uninitialized FLASH.
*/
if (info->flash_id != FLASH_UNKNOWN) {
addr = (volatile unsigned short *)info->start[0];
}
addr[0] = 0xF0F0; /* reset bank */
__asm__ __volatile__(" sync\n ");
return (info->size);
}
/*-----------------------------------------------------------------------
*/
int flash_erase (flash_info_t *info, int s_first, int s_last)
{
vu_short *addr = (vu_short*)(info->start[0]);
int flag, prot, sect, l_sect;
ulong start, now, last;
if ((s_first < 0) || (s_first > s_last)) {
if (info->flash_id == FLASH_UNKNOWN) {
printf ("- missing\n");
} else {
printf ("- no sectors to erase\n");
}
return 1;
}
if ((info->flash_id == FLASH_UNKNOWN) ||
(info->flash_id > FLASH_AMD_COMP)) {
printf ("Can't erase unknown flash type %08lx - aborted\n",
info->flash_id);
return 1;
}
prot = 0;
for (sect=s_first; sect<=s_last; ++sect) {
if (info->protect[sect]) {
prot++;
}
}
if (prot) {
printf ("- Warning: %d protected sectors will not be erased!\n",
prot);
} else {
printf ("\n");
}
l_sect = -1;
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
addr[0x0555] = 0xAAAA;
addr[0x02AA] = 0x5555;
addr[0x0555] = 0x8080;
addr[0x0555] = 0xAAAA;
addr[0x02AA] = 0x5555;
__asm__ __volatile__(" sync\n ");
/* Start erase on unprotected sectors */
for (sect = s_first; sect<=s_last; sect++) {
if (info->protect[sect] == 0) { /* not protected */
addr = (vu_short*)(info->start[sect]);
addr[0] = 0x3030;
l_sect = sect;
}
}
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
/* wait at least 80us - let's wait 1 ms */
udelay (1000);
/*
* We wait for the last triggered sector
*/
if (l_sect < 0)
goto DONE;
start = get_timer (0);
last = start;
addr = (vu_short*)(info->start[l_sect]);
while ((addr[0] & 0x0080) != 0x0080) {
if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
printf ("Timeout\n");
addr[0] = 0xF0F0; /* reset bank */
__asm__ __volatile__(" sync\n ");
return 1;
}
/* show that we're waiting */
if ((now - last) > 1000) { /* every second */
putc ('.');
last = now;
}
}
DONE:
/* reset to read mode */
addr = (vu_short*)info->start[0];
addr[0] = 0xF0F0; /* reset bank */
__asm__ __volatile__(" sync\n ");
printf (" done\n");
return 0;
}
/*-----------------------------------------------------------------------
* Copy memory to flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
{
ulong cp, wp, data;
int i, l, rc;
wp = (addr & ~3); /* get lower word aligned address */
/*
* handle unaligned start bytes
*/
if ((l = addr - wp) != 0) {
data = 0;
for (i=0, cp=wp; i<l; ++i, ++cp) {
data = (data << 8) | (*(uchar *)cp);
}
for (; i<4 && cnt>0; ++i) {
data = (data << 8) | *src++;
--cnt;
++cp;
}
for (; cnt==0 && i<4; ++i, ++cp) {
data = (data << 8) | (*(uchar *)cp);
}
if ((rc = write_word(info, wp, data)) != 0) {
return (rc);
}
wp += 4;
}
/*
* handle word aligned part
*/
while (cnt >= 4) {
data = 0;
for (i=0; i<4; ++i) {
data = (data << 8) | *src++;
}
if ((rc = write_word(info, wp, data)) != 0) {
return (rc);
}
wp += 4;
cnt -= 4;
}
if (cnt == 0) {
return (0);
}
/*
* handle unaligned tail bytes
*/
data = 0;
for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
data = (data << 8) | *src++;
--cnt;
}
for (; i<4; ++i, ++cp) {
data = (data << 8) | (*(uchar *)cp);
}
return (write_word(info, wp, data));
}
/*-----------------------------------------------------------------------
* Write a word to Flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
static int write_word (flash_info_t *info, ulong dest, ulong data)
{
vu_short *addr = (vu_short*)(info->start[0]);
ulong start;
int flag;
int j;
/* Check if Flash is (sufficiently) erased */
if (((*(vu_long *)dest) & data) != data) {
return (2);
}
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
/* The original routine was designed to write 32 bit words to
* 32 bit wide memory. We have 16 bit wide memory so we do
* two writes. We write the LSB first at dest+2 and then the
* MSB at dest (lousy big endian).
*/
dest += 2;
for(j = 0; j < 2; j++) {
addr[0x0555] = 0xAAAA;
addr[0x02AA] = 0x5555;
addr[0x0555] = 0xA0A0;
__asm__ __volatile__(" sync\n ");
*((vu_short *)dest) = (ushort)data;
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
/* data polling for D7 */
start = get_timer (0);
while (*(vu_short *)dest != (ushort)data) {
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
return (1);
}
}
dest -= 2;
data >>= 16;
}
return (0);
}
/*-----------------------------------------------------------------------
*/

15
board/sandpoint/README Normal file
View File

@@ -0,0 +1,15 @@
This port of U-Boot will run on a Motorola Sandpoint 3 development
system equipped with a Unity X4 PPMC card (MPC8240 CPU) only. It is a
snapshot of work in progress and far from being completed. In order
to run it on the target system, it has to be downloaded using the
DINK32 monitor program that came with your Sandpoint system. Please
note that DINK32 does not accept the S-Record file created by the
U-Boot build process unmodified, because it contains CR/LF line
terminators. You have to strip the CR characters first. There is a
tiny script named 'dinkdl' I created for this purpose.
The Sandpoint port is based on the work of Rob Taylor, who does not
seem to maintain it any more. I can be reached by mail as
tkoeller@gmx.net.
Thomas Koeller