Initial revision
This commit is contained in:
parent
cf356ef708
commit
affae2bff8
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
* (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 <mpc8xx.h>
|
||||
|
||||
#ifndef CFG_ENV_ADDR
|
||||
#define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
|
||||
#endif
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 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) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: "
|
||||
"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,
|
||||
size_b0, size_b0<<20
|
||||
);
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#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) {
|
||||
memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
|
||||
memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
|
||||
BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
|
||||
&flash_info[1]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE + size_b0, &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[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 {
|
||||
memctl->memc_br1 = 0; /* invalidate bank */
|
||||
|
||||
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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
}
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
addr[0] = 0x00300030;
|
||||
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_long*)(info->start[l_sect]);
|
||||
while ((addr[0] & 0x00800080) != 0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,50 @@
|
|||
#include <common.h>
|
||||
#include <board/cogent/dipsw.h>
|
||||
|
||||
unsigned char
|
||||
dipsw_raw(void)
|
||||
{
|
||||
return cma_mb_reg_read(&((cma_mb_dipsw *)CMA_MB_DIPSW_BASE)->dip_val);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
dipsw_cooked(void)
|
||||
{
|
||||
unsigned char val1, val2, mask1, mask2;
|
||||
|
||||
val1 = dipsw_raw();
|
||||
|
||||
/*
|
||||
* we want to mirror the bits because the low bit is switch 1 and high
|
||||
* bit is switch 8 and also invert them because 1=off and 0=on, according
|
||||
* to manual.
|
||||
*
|
||||
* this makes the value more intuitive i.e.
|
||||
* - left most, or high, or top, bit is left most switch (1);
|
||||
* - right most, or low, or bottom, bit is right most switch (8)
|
||||
* - a set bit means "on" and a clear bit means "off"
|
||||
*/
|
||||
|
||||
val2 = 0;
|
||||
for (mask1 = 1 << 7, mask2 = 1; mask1 > 0; mask1 >>= 1, mask2 <<= 1)
|
||||
if ((val1 & mask1) == 0)
|
||||
val2 |= mask2;
|
||||
|
||||
return (val2);
|
||||
}
|
||||
|
||||
void
|
||||
dipsw_init(void)
|
||||
{
|
||||
unsigned char val, mask;
|
||||
|
||||
val = dipsw_cooked();
|
||||
|
||||
printf("|");
|
||||
for (mask = 1 << 7; mask > 0; mask >>= 1)
|
||||
if (val & mask)
|
||||
printf("on |");
|
||||
else
|
||||
printf("off|");
|
||||
printf("\n");
|
||||
}
|
|
@ -0,0 +1,648 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <board/cogent/flash.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CONFIG_CMA302)
|
||||
|
||||
/*
|
||||
* probe for the existence of flash at address "addr"
|
||||
* 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id
|
||||
*/
|
||||
static int
|
||||
c302f_probe_word(c302f_addr_t addr)
|
||||
{
|
||||
/* reset the flash */
|
||||
*addr = C302F_BNK_CMD_RST;
|
||||
|
||||
/* check the manufacturer id */
|
||||
*addr = C302F_BNK_CMD_RD_ID;
|
||||
if (*C302F_BNK_ADDR_MAN(addr) != C302F_BNK_RD_ID_MAN)
|
||||
return 1;
|
||||
|
||||
/* check the device id */
|
||||
*addr = C302F_BNK_CMD_RD_ID;
|
||||
if (*C302F_BNK_ADDR_DEV(addr) != C302F_BNK_RD_ID_DEV)
|
||||
return 2;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("\nMaster Lock Config = 0x%08lx\n",
|
||||
*C302F_BNK_ADDR_CFGM(addr));
|
||||
for (i = 0; i < C302F_BNK_NBLOCKS; i++)
|
||||
printf("Block %2d Lock Config = 0x%08lx\n",
|
||||
i, *C302F_BNK_ADDR_CFG(i, addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* reset the flash again */
|
||||
*addr = C302F_BNK_CMD_RST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* probe for Cogent CMA302 flash module at address "base" and store
|
||||
* info for any found into flash_info entry "fip". Must find at least
|
||||
* one bank.
|
||||
*/
|
||||
static void
|
||||
c302f_probe(flash_info_t *fip, c302f_addr_t base)
|
||||
{
|
||||
c302f_addr_t addr, eaddr;
|
||||
int nbanks;
|
||||
|
||||
fip->size = 0L;
|
||||
fip->sector_count = 0;
|
||||
|
||||
addr = base;
|
||||
eaddr = C302F_BNK_ADDR_BASE(addr, C302F_MAX_BANKS);
|
||||
nbanks = 0;
|
||||
|
||||
while (addr < eaddr) {
|
||||
c302f_addr_t addrw, eaddrw, addrb;
|
||||
int i, osc, nsc;
|
||||
|
||||
addrw = addr;
|
||||
eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
|
||||
|
||||
while (addrw < eaddrw)
|
||||
if (c302f_probe_word(addrw++) != 0)
|
||||
goto out;
|
||||
|
||||
/* bank exists - append info for this bank to *fip */
|
||||
fip->flash_id = FLASH_MAN_INTEL|FLASH_28F008S5;
|
||||
fip->size += C302F_BNK_SIZE;
|
||||
osc = fip->sector_count;
|
||||
fip->sector_count += C302F_BNK_NBLOCKS;
|
||||
if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT)
|
||||
panic("Too many sectors in flash at address 0x%08lx\n",
|
||||
(unsigned long)base);
|
||||
|
||||
addrb = addr;
|
||||
for (i = osc; i < nsc; i++) {
|
||||
fip->start[i] = (ulong)addrb;
|
||||
fip->protect[i] = 0;
|
||||
addrb = C302F_BNK_ADDR_NEXT_BLK(addrb);
|
||||
}
|
||||
|
||||
addr = C302F_BNK_ADDR_NEXT_BNK(addr);
|
||||
nbanks++;
|
||||
}
|
||||
|
||||
out:
|
||||
if (nbanks == 0)
|
||||
panic("ERROR: no flash found at address 0x%08lx\n",
|
||||
(unsigned long)base);
|
||||
}
|
||||
|
||||
static void
|
||||
c302f_reset(flash_info_t *info, int sect)
|
||||
{
|
||||
c302f_addr_t addrw, eaddrw;
|
||||
|
||||
addrw = (c302f_addr_t)info->start[sect];
|
||||
eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
|
||||
|
||||
while (addrw < eaddrw) {
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" writing reset cmd to addr 0x%08lx\n",
|
||||
(unsigned long)addrw);
|
||||
#endif
|
||||
*addrw = C302F_BNK_CMD_RST;
|
||||
addrw++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
c302f_erase_init(flash_info_t *info, int sect)
|
||||
{
|
||||
c302f_addr_t addrw, saddrw, eaddrw;
|
||||
int flag;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("0x%08lx C302F_BNK_CMD_PROG\n", C302F_BNK_CMD_PROG);
|
||||
printf("0x%08lx C302F_BNK_CMD_ERASE1\n", C302F_BNK_CMD_ERASE1);
|
||||
printf("0x%08lx C302F_BNK_CMD_ERASE2\n", C302F_BNK_CMD_ERASE2);
|
||||
printf("0x%08lx C302F_BNK_CMD_CLR_STAT\n", C302F_BNK_CMD_CLR_STAT);
|
||||
printf("0x%08lx C302F_BNK_CMD_RST\n", C302F_BNK_CMD_RST);
|
||||
printf("0x%08lx C302F_BNK_STAT_RDY\n", C302F_BNK_STAT_RDY);
|
||||
printf("0x%08lx C302F_BNK_STAT_ERR\n", C302F_BNK_STAT_ERR);
|
||||
#endif
|
||||
|
||||
saddrw = (c302f_addr_t)info->start[sect];
|
||||
eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("erasing sector %d, start addr = 0x%08lx "
|
||||
"(bank next word addr = 0x%08lx)\n", sect,
|
||||
(unsigned long)saddrw, (unsigned long)eaddrw);
|
||||
#endif
|
||||
|
||||
/* Disable intrs which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
for (addrw = saddrw; addrw < eaddrw; addrw++) {
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" writing erase cmd to addr 0x%08lx\n",
|
||||
(unsigned long)addrw);
|
||||
#endif
|
||||
*addrw = C302F_BNK_CMD_ERASE1;
|
||||
*addrw = C302F_BNK_CMD_ERASE2;
|
||||
}
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
static int
|
||||
c302f_erase_poll(flash_info_t *info, int sect)
|
||||
{
|
||||
c302f_addr_t addrw, saddrw, eaddrw;
|
||||
int sectdone, haderr;
|
||||
|
||||
saddrw = (c302f_addr_t)info->start[sect];
|
||||
eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
|
||||
|
||||
sectdone = 1;
|
||||
haderr = 0;
|
||||
|
||||
for (addrw = saddrw; addrw < eaddrw; addrw++) {
|
||||
c302f_word_t stat = *addrw;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" checking status at addr "
|
||||
"0x%08lx [0x%08lx]\n",
|
||||
(unsigned long)addrw, stat);
|
||||
#endif
|
||||
if ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY)
|
||||
sectdone = 0;
|
||||
else if ((stat & C302F_BNK_STAT_ERR) != 0) {
|
||||
printf(" failed on sector %d "
|
||||
"(stat = 0x%08lx) at "
|
||||
"address 0x%08lx\n",
|
||||
sect, stat,
|
||||
(unsigned long)addrw);
|
||||
*addrw = C302F_BNK_CMD_CLR_STAT;
|
||||
haderr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (haderr)
|
||||
return (-1);
|
||||
else
|
||||
return (sectdone);
|
||||
}
|
||||
|
||||
static int
|
||||
c302f_write_word(c302f_addr_t addr, c302f_word_t value)
|
||||
{
|
||||
c302f_word_t stat;
|
||||
ulong start;
|
||||
int flag, retval;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = C302F_BNK_CMD_PROG;
|
||||
|
||||
*addr = value;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
retval = 0;
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
do {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
stat = *addr;
|
||||
} while ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY);
|
||||
|
||||
if ((stat & C302F_BNK_STAT_ERR) != 0) {
|
||||
printf("flash program failed (stat = 0x%08lx) "
|
||||
"at address 0x%08lx\n", (ulong)stat, (ulong)addr);
|
||||
*addr = C302F_BNK_CMD_CLR_STAT;
|
||||
retval = 3;
|
||||
}
|
||||
|
||||
done:
|
||||
/* reset to read mode */
|
||||
*addr = C302F_BNK_CMD_RST;
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CMA302 */
|
||||
|
||||
unsigned long
|
||||
flash_init(void)
|
||||
{
|
||||
unsigned long total;
|
||||
int i;
|
||||
flash_info_t *fip;
|
||||
|
||||
/* Init: no FLASHes known */
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
fip = &flash_info[0];
|
||||
total = 0L;
|
||||
|
||||
#if defined(CONFIG_CMA302)
|
||||
c302f_probe(fip, (c302f_addr_t)CFG_FLASH_BASE);
|
||||
total += fip->size;
|
||||
fip++;
|
||||
#endif
|
||||
|
||||
#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
|
||||
/* not yet ...
|
||||
cmbf_probe(fip, (cmbf_addr_t)CMA_MB_FLASH_BASE);
|
||||
total += fip->size;
|
||||
fip++;
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* protect monitor and environment sectors
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#ifdef CFG_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,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
return total;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_INTEL: printf ("INTEL "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F008S5: printf ("28F008S5\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 % 4) == 0)
|
||||
printf ("\n ");
|
||||
printf (" %2d - %08lX%s", i,
|
||||
info->start[i],
|
||||
info->protect[i] ? " (RO)" : " "
|
||||
);
|
||||
}
|
||||
printf ("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
int
|
||||
flash_erase(flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
int prot, sect, haderr;
|
||||
ulong start, now, last;
|
||||
void (*erase_init)(flash_info_t *, int);
|
||||
int (*erase_poll)(flash_info_t *, int);
|
||||
void (*reset)(flash_info_t *, int);
|
||||
int rcode = 0;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
|
||||
" Bank # %d: ", s_last - s_first + 1, s_first, s_last,
|
||||
(info - flash_info) + 1);
|
||||
flash_print_info(info);
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
switch (info->flash_id) {
|
||||
|
||||
#if defined(CONFIG_CMA302)
|
||||
case FLASH_MAN_INTEL|FLASH_28F008S5:
|
||||
erase_init = c302f_erase_init;
|
||||
erase_poll = c302f_erase_poll;
|
||||
reset = c302f_reset;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
|
||||
case FLASH_MAN_INTEL|FLASH_28F800_B:
|
||||
case FLASH_MAN_AMD|FLASH_AM29F800B:
|
||||
/* not yet ...
|
||||
erase_init = cmbf_erase_init;
|
||||
erase_poll = cmbf_erase_poll;
|
||||
reset = cmbf_reset;
|
||||
break;
|
||||
*/
|
||||
#endif
|
||||
|
||||
default:
|
||||
printf ("Flash type %08lx not supported - 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 sector%s will not be erased!\n",
|
||||
prot, (prot > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
start = get_timer (0);
|
||||
last = 0;
|
||||
haderr = 0;
|
||||
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
ulong estart;
|
||||
int sectdone;
|
||||
|
||||
(*erase_init)(info, sect);
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
estart = get_timer(start);
|
||||
|
||||
do {
|
||||
now = get_timer(start);
|
||||
|
||||
if (now - estart > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout (sect %d)\n", sect);
|
||||
haderr = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef FLASH_DEBUG
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
sectdone = (*erase_poll)(info, sect);
|
||||
|
||||
if (sectdone < 0) {
|
||||
haderr = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!sectdone);
|
||||
|
||||
if (haderr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (haderr > 0) {
|
||||
printf (" failed\n");
|
||||
rcode = 1;
|
||||
}
|
||||
else
|
||||
printf (" done\n");
|
||||
|
||||
/* reset to read mode */
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
(*reset)(info, sect);
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
* 3 - write error
|
||||
*/
|
||||
|
||||
int
|
||||
write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
ulong cp, wp, data;
|
||||
int i, l, rc;
|
||||
ulong start, now, last;
|
||||
|
||||
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
|
||||
*/
|
||||
start = get_timer (0);
|
||||
last = 0;
|
||||
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;
|
||||
|
||||
/* show that we're waiting */
|
||||
now = get_timer(start);
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* 3 - write error
|
||||
*/
|
||||
static int
|
||||
write_word(flash_info_t *info, ulong dest, ulong data)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*(ulong *)dest & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
switch (info->flash_id) {
|
||||
|
||||
#if defined(CONFIG_CMA302)
|
||||
case FLASH_MAN_INTEL|FLASH_28F008S5:
|
||||
retval = c302f_write_word((c302f_addr_t)dest, (c302f_word_t)data);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
|
||||
case FLASH_MAN_INTEL|FLASH_28F800_B:
|
||||
case FLASH_MAN_AMD|FLASH_AM29F800B:
|
||||
/* not yet ...
|
||||
retval = cmbf_write_word((cmbf_addr_t)dest, (cmbf_word_t)data);
|
||||
*/
|
||||
retval = 3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
printf ("Flash type %08lx not supported - aborted\n",
|
||||
info->flash_id);
|
||||
retval = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* (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 <mpc824x.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define FLASH_BANK_SIZE 0x800000
|
||||
#define MAIN_SECT_SIZE 0x40000
|
||||
#define PARAM_SECT_SIZE 0x8000
|
||||
|
||||
#define BOARD_CTRL_REG 0xFE800013
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
|
||||
|
||||
static int write_data (flash_info_t *info, ulong dest, ulong *data);
|
||||
static void write_via_fpu(vu_long *addr, ulong *data);
|
||||
static __inline__ unsigned long get_msr(void);
|
||||
static __inline__ void set_msr(unsigned long msr);
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#undef DEBUG_FLASH
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#ifdef DEBUG_FLASH
|
||||
#define DEBUGF(fmt,args...) printf(fmt ,##args)
|
||||
#else
|
||||
#define DEBUGF(fmt,args...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init(void)
|
||||
{
|
||||
int i, j;
|
||||
ulong size = 0;
|
||||
volatile unsigned char *bcr = (volatile unsigned char *)(BOARD_CTRL_REG);
|
||||
|
||||
DEBUGF("Write protect was: 0x%02X\n", *bcr);
|
||||
*bcr &= 0x1; /* FWPT must be 0 */
|
||||
*bcr |= 0x6; /* FWP0 = FWP1 = 1 */
|
||||
DEBUGF("Write protect is: 0x%02X\n", *bcr);
|
||||
|
||||
for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
|
||||
vu_long *addr = (vu_long *)(CFG_FLASH_BASE + i * FLASH_BANK_SIZE);
|
||||
|
||||
addr[0] = 0x00900090;
|
||||
|
||||
DEBUGF ("Flash bank # %d:\n"
|
||||
"\tManuf. ID @ 0x%08lX: 0x%08lX\n"
|
||||
"\tDevice ID @ 0x%08lX: 0x%08lX\n",
|
||||
i,
|
||||
(ulong)(&addr[0]), addr[0],
|
||||
(ulong)(&addr[2]), addr[2]);
|
||||
|
||||
if ((addr[0] == addr[1]) && (addr[0] == INTEL_MANUFACT) &&
|
||||
(addr[2] == addr[3]) && (addr[2] == INTEL_ID_28F160F3B))
|
||||
{
|
||||
flash_info[i].flash_id = (FLASH_MAN_INTEL & FLASH_VENDMASK) |
|
||||
(INTEL_ID_28F160F3B & FLASH_TYPEMASK);
|
||||
} else {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
addr[0] = 0xFFFFFFFF;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
DEBUGF ("flash_id = 0x%08lX\n", flash_info[i].flash_id);
|
||||
|
||||
addr[0] = 0xFFFFFFFF;
|
||||
|
||||
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);
|
||||
for (j = 0; j < flash_info[i].sector_count; j++) {
|
||||
if (j <= 7) {
|
||||
flash_info[i].start[j] = CFG_FLASH_BASE +
|
||||
i * FLASH_BANK_SIZE +
|
||||
j * PARAM_SECT_SIZE;
|
||||
} else {
|
||||
flash_info[i].start[j] = CFG_FLASH_BASE +
|
||||
i * FLASH_BANK_SIZE +
|
||||
(j - 7)*MAIN_SECT_SIZE;
|
||||
}
|
||||
}
|
||||
size += flash_info[i].size;
|
||||
}
|
||||
|
||||
/* Protect monitor and environment sectors
|
||||
*/
|
||||
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
|
||||
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + FLASH_BANK_SIZE
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_MONITOR_BASE,
|
||||
CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
|
||||
&flash_info[1]);
|
||||
#else
|
||||
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)
|
||||
#if CFG_ENV_ADDR >= CFG_FLASH_BASE + FLASH_BANK_SIZE
|
||||
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
|
||||
|
||||
Done:
|
||||
return size;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_print_info (flash_info_t * info)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch ((i = info->flash_id & FLASH_VENDMASK)) {
|
||||
case (FLASH_MAN_INTEL & FLASH_VENDMASK):
|
||||
printf ("Intel: ");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown Vendor 0x%04x ", i);
|
||||
break;
|
||||
}
|
||||
|
||||
switch ((i = info->flash_id & FLASH_TYPEMASK)) {
|
||||
case (INTEL_ID_28F160F3B & FLASH_TYPEMASK):
|
||||
printf ("28F160F3B (16Mbit)\n");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown Chip Type 0x%04x\n", i);
|
||||
goto Done;
|
||||
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");
|
||||
|
||||
Done:
|
||||
return;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
int flag, prot, sect;
|
||||
ulong start, now, last;
|
||||
|
||||
DEBUGF ("Erase flash bank %d sect %d ... %d\n",
|
||||
info - &flash_info[0], s_first, s_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_VENDMASK) !=
|
||||
(FLASH_MAN_INTEL & FLASH_VENDMASK)) {
|
||||
printf ("Can erase only Intel flash types - aborted\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 = get_timer (0);
|
||||
last = start;
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
vu_long *addr = (vu_long *)(info->start[sect]);
|
||||
|
||||
DEBUGF ("Erase sect %d @ 0x%08lX\n",
|
||||
sect, (ulong)addr);
|
||||
|
||||
/* Disable interrupts which might cause a timeout
|
||||
* here.
|
||||
*/
|
||||
flag = disable_interrupts();
|
||||
|
||||
addr[0] = 0x00500050; /* clear status register */
|
||||
addr[0] = 0x00200020; /* erase setup */
|
||||
addr[0] = 0x00D000D0; /* erase confirm */
|
||||
|
||||
addr[1] = 0x00500050; /* clear status register */
|
||||
addr[1] = 0x00200020; /* erase setup */
|
||||
addr[1] = 0x00D000D0; /* erase confirm */
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
while (((addr[0] & 0x00800080) != 0x00800080) ||
|
||||
((addr[1] & 0x00800080) != 0x00800080) ) {
|
||||
if ((now=get_timer(start)) >
|
||||
CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
addr[0] = 0x00B000B0; /* suspend erase */
|
||||
addr[0] = 0x00FF00FF; /* to read mode */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
addr[0] = 0x00FF00FF;
|
||||
}
|
||||
}
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
* 4 - Flash not identified
|
||||
*/
|
||||
|
||||
#define FLASH_WIDTH 8 /* flash bus width in bytes */
|
||||
|
||||
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
ulong wp, cp, msr;
|
||||
int l, rc, i;
|
||||
ulong data[2];
|
||||
ulong *datah = &data[0];
|
||||
ulong *datal = &data[1];
|
||||
|
||||
DEBUGF ("Flash write_buff: @ 0x%08lx, src 0x%08lx len %ld\n",
|
||||
addr, (ulong)src, cnt);
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
msr = get_msr();
|
||||
set_msr(msr | MSR_FP);
|
||||
|
||||
wp = (addr & ~(FLASH_WIDTH-1)); /* get lower aligned address */
|
||||
|
||||
/*
|
||||
* handle unaligned start bytes
|
||||
*/
|
||||
if ((l = addr - wp) != 0) {
|
||||
*datah = *datal = 0;
|
||||
|
||||
for (i = 0, cp = wp; i < l; i++, cp++) {
|
||||
if (i >= 4) {
|
||||
*datah = (*datah << 8) |
|
||||
((*datal & 0xFF000000) >> 24);
|
||||
}
|
||||
|
||||
*datal = (*datal << 8) | (*(uchar *)cp);
|
||||
}
|
||||
for (; i < FLASH_WIDTH && cnt > 0; ++i) {
|
||||
char tmp;
|
||||
|
||||
tmp = *src;
|
||||
|
||||
src++;
|
||||
|
||||
if (i >= 4) {
|
||||
*datah = (*datah << 8) |
|
||||
((*datal & 0xFF000000) >> 24);
|
||||
}
|
||||
|
||||
*datal = (*datal << 8) | tmp;
|
||||
|
||||
--cnt; ++cp;
|
||||
}
|
||||
|
||||
for (; cnt == 0 && i < FLASH_WIDTH; ++i, ++cp) {
|
||||
if (i >= 4) {
|
||||
*datah = (*datah << 8) |
|
||||
((*datal & 0xFF000000) >> 24);
|
||||
}
|
||||
|
||||
*datal = (*datah << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
set_msr(msr);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
wp += FLASH_WIDTH;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle FLASH_WIDTH aligned part
|
||||
*/
|
||||
while (cnt >= FLASH_WIDTH) {
|
||||
*datah = *(ulong *)src;
|
||||
*datal = *(ulong *)(src + 4);
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
set_msr(msr);
|
||||
return (rc);
|
||||
}
|
||||
wp += FLASH_WIDTH;
|
||||
cnt -= FLASH_WIDTH;
|
||||
src += FLASH_WIDTH;
|
||||
}
|
||||
|
||||
if (cnt == 0) {
|
||||
set_msr(msr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
*datah = *datal = 0;
|
||||
for (i = 0, cp = wp; i < FLASH_WIDTH && cnt > 0; ++i, ++cp) {
|
||||
char tmp;
|
||||
|
||||
tmp = *src;
|
||||
|
||||
src++;
|
||||
|
||||
if (i >= 4) {
|
||||
*datah = (*datah << 8) | ((*datal & 0xFF000000) >> 24);
|
||||
}
|
||||
|
||||
*datal = (*datal << 8) | tmp;
|
||||
|
||||
--cnt;
|
||||
}
|
||||
|
||||
for (; i < FLASH_WIDTH; ++i, ++cp) {
|
||||
if (i >= 4) {
|
||||
*datah = (*datah << 8) | ((*datal & 0xFF000000) >> 24);
|
||||
}
|
||||
|
||||
*datal = (*datal << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
rc = write_data(info, wp, data);
|
||||
set_msr(msr);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_data (flash_info_t *info, ulong dest, ulong *data)
|
||||
{
|
||||
vu_long *addr = (vu_long *)dest;
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if (((addr[0] & data[0]) != data[0]) ||
|
||||
((addr[1] & data[1]) != data[1]) ) {
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
addr[0] = 0x00400040; /* write setup */
|
||||
write_via_fpu(addr, data);
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
start = get_timer (0);
|
||||
|
||||
while (((addr[0] & 0x00800080) != 0x00800080) ||
|
||||
((addr[1] & 0x00800080) != 0x00800080) ) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
addr[0] = 0x00FF00FF; /* restore read mode */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
addr[0] = 0x00FF00FF; /* restore read mode */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void write_via_fpu(vu_long *addr, ulong *data)
|
||||
{
|
||||
__asm__ __volatile__ ("lfd 1, 0(%0)" : : "r" (data));
|
||||
__asm__ __volatile__ ("stfd 1, 0(%0)" : : "r" (addr));
|
||||
}
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static __inline__ unsigned long get_msr(void)
|
||||
{
|
||||
unsigned long msr;
|
||||
|
||||
__asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :);
|
||||
return msr;
|
||||
}
|
||||
|
||||
static __inline__ void set_msr(unsigned long msr)
|
||||
{
|
||||
__asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
|
||||
}
|
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
* (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 <mpc8xx.h>
|
||||
#include <linux/byteorder/swab.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Protection Flags:
|
||||
*/
|
||||
#define FLAG_PROTECT_SET 0x01
|
||||
#define FLAG_PROTECT_CLEAR 0x02
|
||||
|
||||
/* Board support for 1 or 2 flash devices */
|
||||
#undef FLASH_PORT_WIDTH32
|
||||
#define FLASH_PORT_WIDTH16
|
||||
|
||||
#ifdef FLASH_PORT_WIDTH16
|
||||
#define FLASH_PORT_WIDTH ushort
|
||||
#define FLASH_PORT_WIDTHV vu_short
|
||||
#define SWAP(x) __swab16(x)
|
||||
#else
|
||||
#define FLASH_PORT_WIDTH ulong
|
||||
#define FLASH_PORT_WIDTHV vu_long
|
||||
#define SWAP(x) __swab32(x)
|
||||
#endif
|
||||
|
||||
#define FPW FLASH_PORT_WIDTH
|
||||
#define FPWV FLASH_PORT_WIDTHV
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (FPW *addr, flash_info_t *info);
|
||||
static int write_data (flash_info_t *info, ulong dest, FPW data);
|
||||
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 memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long size_b0;
|
||||
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 - FIXME XXX */
|
||||
size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_FLASH_BASE,
|
||||
CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
return (size_b0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_INTEL: printf ("INTEL "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F640J5 :
|
||||
printf ("28F640J5 \n"); break;
|
||||
default: printf ("Unknown Chip Type=0x%lXh\n",
|
||||
info->flash_id & FLASH_TYPEMASK); 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");
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (FPW *addr, flash_info_t *info)
|
||||
{
|
||||
FPW value;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x5555] = (FPW)0xAA00AA00;
|
||||
addr[0x2AAA] = (FPW)0x55005500;
|
||||
addr[0x5555] = (FPW)0x90009000;
|
||||
|
||||
value = SWAP(addr[0]);
|
||||
|
||||
switch (value) {
|
||||
case (FPW)INTEL_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_INTEL;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
addr[0] = (FPW)0xFF00FF00; /* restore read mode */
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = SWAP(addr[1]); /* device ID no swap !*/
|
||||
|
||||
switch (value) {
|
||||
case (FPW)INTEL_ID_28F640J5 :
|
||||
info->flash_id += FLASH_28F640J5 ;
|
||||
info->sector_count = 64;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (info->sector_count > CFG_MAX_FLASH_SECT) {
|
||||
printf ("** ERROR: sector count %d > max (%d) **\n",
|
||||
info->sector_count, CFG_MAX_FLASH_SECT);
|
||||
info->sector_count = CFG_MAX_FLASH_SECT;
|
||||
}
|
||||
|
||||
addr[0] = (FPW)0xFF00FF00; /* restore read mode */
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
int flag, prot, sect;
|
||||
ulong type, start, now, last;
|
||||
int rc = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
type = (info->flash_id & FLASH_VENDMASK);
|
||||
if ((type != FLASH_MAN_INTEL)) {
|
||||
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");
|
||||
}
|
||||
|
||||
start = get_timer (0);
|
||||
last = start;
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
FPWV *addr = (FPWV *)(info->start[sect]);
|
||||
FPW status;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = (FPW)0x50005000; /* clear status register */
|
||||
*addr = (FPW)0x20002000; /* erase setup */
|
||||
*addr = (FPW)0xD000D000; /* erase confirm */
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
|
||||
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
*addr = (FPW)0xB000B000; /* suspend erase */
|
||||
*addr = (FPW)0xFF00FF00; /* reset to read mode */
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
*addr = (FPW)0xFF00FF00; /* reset to read mode */
|
||||
printf (" done\n");
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
* 4 - Flash not identified
|
||||
*/
|
||||
|
||||
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
ulong cp, wp;
|
||||
FPW data;
|
||||
int count, i, l, rc, port_width;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return 4;
|
||||
}
|
||||
/* get lower word aligned address */
|
||||
#ifdef FLASH_PORT_WIDTH16
|
||||
wp = (addr & ~1);
|
||||
port_width = 2;
|
||||
#else
|
||||
wp = (addr & ~3);
|
||||
port_width = 4;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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<port_width && cnt>0; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
++cp;
|
||||
}
|
||||
for (; cnt==0 && i<port_width; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += port_width;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle word aligned part
|
||||
*/
|
||||
count = 0;
|
||||
while (cnt >= port_width) {
|
||||
data = 0;
|
||||
for (i=0; i<port_width; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
}
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += port_width;
|
||||
cnt -= port_width;
|
||||
if ((wp & 0xfff) == 0)
|
||||
{
|
||||
printf("%08lX",wp);
|
||||
printf("\x1b[8D");
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
data = 0;
|
||||
for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
}
|
||||
for (; i<port_width; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
return (write_data(info, wp, data));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word or halfword to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_data (flash_info_t *info, ulong dest, FPW data)
|
||||
{
|
||||
FPWV *addr = (FPWV *)dest;
|
||||
ulong status;
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*addr & data) != data) {
|
||||
printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = (FPW)0x40004000; /* write setup */
|
||||
*addr = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
start = get_timer (0);
|
||||
|
||||
while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
*addr = (FPW)0xFF00FF00; /* restore read mode */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
*addr = (FPW)0xFF00FF00; /* restore read mode */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* (C) Copyright 2001, 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Frank Panno <fpanno@delphintech.com>, Delphin Technology AG
|
||||
*
|
||||
* Flash Routines for AMD device AM29DL323DB on the EP8260 board.
|
||||
*
|
||||
* This file is based on board/tqm8260/flash.c.
|
||||
*--------------------------------------------------------------------
|
||||
* 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>
|
||||
|
||||
#define V_ULONG(a) (*(volatile unsigned long *)( a ))
|
||||
#define V_BYTE(a) (*(volatile unsigned char *)( a ))
|
||||
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_reset(void)
|
||||
{
|
||||
if( flash_info[0].flash_id != FLASH_UNKNOWN ) {
|
||||
V_ULONG( flash_info[0].start[0] ) = 0x00F000F0;
|
||||
V_ULONG( flash_info[0].start[0] + 4 ) = 0x00F000F0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
ulong flash_get_size( ulong baseaddr, flash_info_t *info )
|
||||
{
|
||||
short i;
|
||||
unsigned long flashtest_h, flashtest_l;
|
||||
|
||||
/* Write auto select command sequence and test FLASH answer */
|
||||
V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG(baseaddr + ((ulong)0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00900090;
|
||||
V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG(baseaddr + 4 + ((ulong)0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00900090;
|
||||
|
||||
flashtest_h = V_ULONG(baseaddr); /* manufacturer ID */
|
||||
flashtest_l = V_ULONG(baseaddr + 4);
|
||||
|
||||
if ((int)flashtest_h == AMD_MANUFACT) {
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
} else {
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
flashtest_h = V_ULONG(baseaddr + 8); /* device ID */
|
||||
flashtest_l = V_ULONG(baseaddr + 12);
|
||||
if (flashtest_h != flashtest_l) {
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return(0);
|
||||
}
|
||||
if (flashtest_h == AMD_ID_DL323B) {
|
||||
info->flash_id += FLASH_AMDL323B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000; /* 4 * 4 MB = 16 MB */
|
||||
} else {
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return(0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
/* set up sector start adress table (bottom sector type) */
|
||||
for (i = 0; i < 8; i++) {
|
||||
info->start[i] = baseaddr + (i * 0x00008000);
|
||||
}
|
||||
for (i = 8; i < info->sector_count; i++) {
|
||||
info->start[i] = baseaddr + (i * 0x00040000) - 0x001C0000;
|
||||
}
|
||||
|
||||
/* check for protected sectors */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
/* read sector protection at sector address, (A7 .. A0) = 0x02 */
|
||||
if ((V_ULONG( info->start[i] + 16 ) & 0x00010001) ||
|
||||
(V_ULONG( info->start[i] + 20 ) & 0x00010001)) {
|
||||
info->protect[i] = 1; /* D0 = 1 if protected */
|
||||
} else {
|
||||
info->protect[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
flash_reset();
|
||||
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(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
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#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 FLASH_MAN_AMD: printf ("AMD "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AMDL323B: printf ("29DL323B (32 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");
|
||||
return;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
l_sect = -1;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
|
||||
V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
|
||||
V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00800080;
|
||||
V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
|
||||
V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
|
||||
V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
|
||||
V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
|
||||
V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00800080;
|
||||
V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
|
||||
V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
|
||||
udelay (1000);
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
V_ULONG( info->start[sect] ) = 0x00300030;
|
||||
V_ULONG( info->start[sect] + 4 ) = 0x00300030;
|
||||
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;
|
||||
while ((V_ULONG( info->start[l_sect] ) & 0x00800080) != 0x00800080 ||
|
||||
(V_ULONG( info->start[l_sect] + 4 ) & 0x00800080) != 0x00800080)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
flash_reset ();
|
||||
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_dword (flash_info_t *, ulong, unsigned char *);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* 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 dp;
|
||||
static unsigned char bb[8];
|
||||
int i, l, rc, cc = cnt;
|
||||
|
||||
dp = (addr & ~7); /* get lower dword aligned address */
|
||||
|
||||
/*
|
||||
* handle unaligned start bytes
|
||||
*/
|
||||
if ((l = addr - dp) != 0) {
|
||||
for (i = 0; i < 8; i++)
|
||||
bb[i] = (i < l || (i-l) >= cc) ? V_BYTE(dp+i) : *src++;
|
||||
if ((rc = write_dword(info, dp, bb)) != 0)
|
||||
{
|
||||
return (rc);
|
||||
}
|
||||
dp += 8;
|
||||
cc -= 8 - l;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle word aligned part
|
||||
*/
|
||||
while (cc >= 8) {
|
||||
if ((rc = write_dword(info, dp, src)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
dp += 8;
|
||||
src += 8;
|
||||
cc -= 8;
|
||||
}
|
||||
|
||||
if (cc <= 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
bb[i] = (i < cc) ? *src++ : V_BYTE(dp+i);
|
||||
}
|
||||
return (write_dword(info, dp, bb));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a dword to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_dword (flash_info_t *info, ulong dest, unsigned char * pdata)
|
||||
{
|
||||
ulong start;
|
||||
ulong cl = 0, ch =0;
|
||||
int flag, i;
|
||||
|
||||
for (ch=0, i=0; i < 4; i++)
|
||||
ch = (ch << 8) + *pdata++; /* high word */
|
||||
for (cl=0, i=0; i < 4; i++)
|
||||
cl = (cl << 8) + *pdata++; /* low word */
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*((vu_long *)dest) & ch) != ch
|
||||
||(*((vu_long *)(dest + 4)) & cl) != cl)
|
||||
{
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
|
||||
V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
|
||||
V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00A000A0;
|
||||
V_ULONG( dest ) = ch;
|
||||
V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
|
||||
V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
|
||||
V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00A000A0;
|
||||
V_ULONG( dest + 4 ) = cl;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while (((V_ULONG( dest ) & 0x00800080) != (ch & 0x00800080)) ||
|
||||
((V_ULONG( dest + 4 ) & 0x00800080) != (cl & 0x00800080))) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#include <common.h>
|
||||
#include <mii_phy.h>
|
||||
#include "ep8260.h"
|
||||
|
||||
#define MII_MDIO 0x01
|
||||
#define MII_MDCK 0x02
|
||||
#define MII_MDIR 0x04
|
||||
|
||||
void
|
||||
mii_discover_phy(void)
|
||||
{
|
||||
int known;
|
||||
unsigned short phy_reg;
|
||||
unsigned long phy_id;
|
||||
|
||||
known = 0;
|
||||
printf("Discovering phy @ 0: ");
|
||||
phy_id = mii_phy_read(2) << 16;
|
||||
phy_id |= mii_phy_read(3);
|
||||
if ((phy_id & 0xFFFFFC00) == 0x00137800) {
|
||||
printf("Level One ");
|
||||
if ((phy_id & 0x000003F0) == 0xE0) {
|
||||
printf("LXT971A Revision %d\n", (int)(phy_id & 0xF));
|
||||
known = 1;
|
||||
}
|
||||
else printf("unknown type\n");
|
||||
}
|
||||
else printf("unknown OUI = 0x%08lX\n", phy_id);
|
||||
|
||||
phy_reg = mii_phy_read(1);
|
||||
if (!(phy_reg & 0x0004)) printf("Link is down\n");
|
||||
if (!(phy_reg & 0x0020)) printf("Auto-negotiation not complete\n");
|
||||
if (phy_reg & 0x0002) printf("Jabber condition detected\n");
|
||||
if (phy_reg & 0x0010) printf("Remote fault condition detected \n");
|
||||
|
||||
if (known) {
|
||||
phy_reg = mii_phy_read(17);
|
||||
if (phy_reg & 0x0400)
|
||||
printf("Phy operating at %d MBit/s in %s-duplex mode\n",
|
||||
phy_reg & 0x4000 ? 100 : 10,
|
||||
phy_reg & 0x0200 ? "full" : "half");
|
||||
else
|
||||
printf("bad link!!\n");
|
||||
/*
|
||||
left off: no link, green 100MBit, yellow 10MBit
|
||||
right off: no activity, green full-duplex, yellow half-duplex
|
||||
*/
|
||||
mii_phy_write(20, 0x0452);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short
|
||||
mii_phy_read(unsigned short reg)
|
||||
{
|
||||
int i;
|
||||
unsigned short tmp, val = 0, adr = 0;
|
||||
t_ep_regs *regs = (t_ep_regs*)CFG_REGS_BASE;
|
||||
|
||||
tmp = 0x6002 | (adr << 7) | (reg << 2);
|
||||
regs->bcsr4 = 0xC3;
|
||||
for (i = 0; i < 64; i++) {
|
||||
regs->bcsr4 ^= MII_MDCK;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
regs->bcsr4 &= ~MII_MDCK;
|
||||
if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
|
||||
else regs->bcsr4 &= ~MII_MDIO;
|
||||
regs->bcsr4 |= MII_MDCK;
|
||||
tmp <<= 1;
|
||||
}
|
||||
regs->bcsr4 |= MII_MDIR;
|
||||
for (i = 0; i < 16; i++) {
|
||||
val <<= 1;
|
||||
regs->bcsr4 = MII_MDIO | (regs->bcsr4 | MII_MDCK);
|
||||
if (regs->bcsr4 & MII_MDIO) val |= 1;
|
||||
regs->bcsr4 = MII_MDIO | (regs->bcsr4 &= ~MII_MDCK);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
mii_phy_write(unsigned short reg, unsigned short val)
|
||||
{
|
||||
int i;
|
||||
unsigned short tmp, adr = 0;
|
||||
t_ep_regs *regs = (t_ep_regs*)CFG_REGS_BASE;
|
||||
|
||||
tmp = 0x5002 | (adr << 7) | (reg << 2);
|
||||
regs->bcsr4 = 0xC3;
|
||||
for (i = 0; i < 64; i++) {
|
||||
regs->bcsr4 ^= MII_MDCK;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
regs->bcsr4 &= ~MII_MDCK;
|
||||
if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
|
||||
else regs->bcsr4 &= ~MII_MDIO;
|
||||
regs->bcsr4 |= MII_MDCK;
|
||||
tmp <<= 1;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
regs->bcsr4 &= ~MII_MDCK;
|
||||
if (val & 0x8000) regs->bcsr4 |= MII_MDIO;
|
||||
else regs->bcsr4 &= ~MII_MDIO;
|
||||
regs->bcsr4 |= MII_MDCK;
|
||||
val <<= 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* include common flash code (for esd boards)
|
||||
*/
|
||||
#include "../common/flash.c"
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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_long *)FLASH_BASE0_PRELIM, &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_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: "
|
||||
"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,
|
||||
size_b0, size_b0<<20
|
||||
);
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
FLASH_BASE0_PRELIM+size_b0-CFG_MONITOR_LEN,
|
||||
FLASH_BASE0_PRELIM+size_b0-1,
|
||||
&flash_info[0]);
|
||||
|
||||
if (size_b1) {
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)(FLASH_BASE0_PRELIM + size_b0),
|
||||
&flash_info[1]);
|
||||
|
||||
flash_get_offsets (FLASH_BASE0_PRELIM + size_b0, &flash_info[1]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
FLASH_BASE0_PRELIM+size_b0+size_b1-CFG_MONITOR_LEN,
|
||||
FLASH_BASE0_PRELIM+size_b0+size_b1-1,
|
||||
&flash_info[1]);
|
||||
/* monitor protection OFF by default (one is enough) */
|
||||
flash_protect(FLAG_PROTECT_CLEAR,
|
||||
FLASH_BASE0_PRELIM+size_b0-CFG_MONITOR_LEN,
|
||||
FLASH_BASE0_PRELIM+size_b0-1,
|
||||
&flash_info[0]);
|
||||
} 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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
|
@ -0,0 +1,646 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
short n;
|
||||
|
||||
/* set up sector start address table */
|
||||
if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
info->start[i] = base + (i * 0x00010000);
|
||||
} else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
|
||||
info->start[i] = base;
|
||||
base += 8 << 10;
|
||||
}
|
||||
while (i < info->sector_count) { /* 64k regular sectors */
|
||||
info->start[i] = base;
|
||||
base += 64 << 10;
|
||||
++i;
|
||||
}
|
||||
} else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
|
||||
/* set sector offsets for top boot block type */
|
||||
base += info->size;
|
||||
i = info->sector_count;
|
||||
for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
|
||||
base -= 8 << 10;
|
||||
--i;
|
||||
info->start[i] = base;
|
||||
}
|
||||
while (i > 0) { /* 64k regular sectors */
|
||||
base -= 64 << 10;
|
||||
--i;
|
||||
info->start[i] = base;
|
||||
}
|
||||
} else {
|
||||
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 * 0x00010000) - 0x00030000;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_print_info (flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
int k;
|
||||
int size;
|
||||
int erased;
|
||||
volatile unsigned long *flash;
|
||||
|
||||
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;
|
||||
case FLASH_MAN_SST: printf ("SST "); 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_AM320T: printf ("AM29LV320T (32 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AM320B: printf ("AM29LV320B (32 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL322T: printf ("AM29DL322T (32 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL322B: printf ("AM29DL322B (32 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL323T: printf ("AM29DL323T (32 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL323B: printf ("AM29DL323B (32 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AM640U: printf ("AM29LV640D (64 M, uniform sector)\n");
|
||||
break;
|
||||
case FLASH_SST800A: printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
|
||||
break;
|
||||
case FLASH_SST160A: printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\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) {
|
||||
#ifdef CFG_FLASH_EMPTY_INFO
|
||||
/*
|
||||
* Check if whole sector is erased
|
||||
*/
|
||||
if (i != (info->sector_count-1))
|
||||
size = info->start[i+1] - info->start[i];
|
||||
else
|
||||
size = info->start[0] + info->size - info->start[i];
|
||||
erased = 1;
|
||||
flash = (volatile unsigned long *)info->start[i];
|
||||
size = size >> 2; /* divide by 4 for longword access */
|
||||
for (k=0; k<size; k++)
|
||||
{
|
||||
if (*flash++ != 0xffffffff)
|
||||
{
|
||||
erased = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((i % 5) == 0)
|
||||
printf ("\n ");
|
||||
/* print empty and read-only info */
|
||||
printf (" %08lX%s%s",
|
||||
info->start[i],
|
||||
erased ? " E" : " ",
|
||||
info->protect[i] ? "RO " : " ");
|
||||
#else
|
||||
if ((i % 5) == 0)
|
||||
printf ("\n ");
|
||||
printf (" %08lX%s",
|
||||
info->start[i],
|
||||
info->protect[i] ? " (RO)" : " ");
|
||||
#endif
|
||||
|
||||
}
|
||||
printf ("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
short n;
|
||||
CFG_FLASH_WORD_SIZE value;
|
||||
ulong base = (ulong)addr;
|
||||
volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)addr;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
|
||||
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00900090;
|
||||
|
||||
value = addr2[CFG_FLASH_READ0];
|
||||
|
||||
switch (value) {
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case (CFG_FLASH_WORD_SIZE)FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
case (CFG_FLASH_WORD_SIZE)SST_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_SST;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr2[CFG_FLASH_READ1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 0.5 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 0.5 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000; break; /* => 4 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000; break; /* => 4 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322T:
|
||||
info->flash_id += FLASH_AMDL322T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000; break; /* => 4 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322B:
|
||||
info->flash_id += FLASH_AMDL322B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000; break; /* => 4 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323T:
|
||||
info->flash_id += FLASH_AMDL323T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000; break; /* => 4 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323B:
|
||||
info->flash_id += FLASH_AMDL323B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000; break; /* => 4 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)AMD_ID_LV640U:
|
||||
info->flash_id += FLASH_AM640U;
|
||||
info->sector_count = 128;
|
||||
info->size = 0x00800000; break; /* => 8 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)SST_ID_xF800A:
|
||||
info->flash_id += FLASH_SST800A;
|
||||
info->sector_count = 16;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (CFG_FLASH_WORD_SIZE)SST_ID_xF160A:
|
||||
info->flash_id += FLASH_SST160A;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* set up sector start address table */
|
||||
if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
info->start[i] = base + (i * 0x00010000);
|
||||
} else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
|
||||
info->start[i] = base;
|
||||
base += 8 << 10;
|
||||
}
|
||||
while (i < info->sector_count) { /* 64k regular sectors */
|
||||
info->start[i] = base;
|
||||
base += 64 << 10;
|
||||
++i;
|
||||
}
|
||||
} else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
|
||||
/* set sector offsets for top boot block type */
|
||||
base += info->size;
|
||||
i = info->sector_count;
|
||||
for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
|
||||
base -= 8 << 10;
|
||||
--i;
|
||||
info->start[i] = base;
|
||||
}
|
||||
while (i > 0) { /* 64k regular sectors */
|
||||
base -= 64 << 10;
|
||||
--i;
|
||||
info->start[i] = base;
|
||||
}
|
||||
} else {
|
||||
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 * 0x00010000) - 0x00030000;
|
||||
}
|
||||
} 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 */
|
||||
addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]);
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
|
||||
info->protect[i] = 0;
|
||||
else
|
||||
info->protect[i] = addr2[CFG_FLASH_READ2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr2 = (CFG_FLASH_WORD_SIZE *)info->start[0];
|
||||
*addr2 = (CFG_FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
|
||||
volatile CFG_FLASH_WORD_SIZE *addr2;
|
||||
int flag, prot, sect, l_sect;
|
||||
ulong start, now, last;
|
||||
int i;
|
||||
|
||||
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) {
|
||||
printf ("Can't erase unknown flash type - aborted\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;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[sect]);
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
|
||||
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
|
||||
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
|
||||
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
|
||||
addr2[0] = (CFG_FLASH_WORD_SIZE)0x00500050; /* block erase */
|
||||
for (i=0; i<50; i++)
|
||||
udelay(1000); /* wait 1 ms */
|
||||
} else {
|
||||
if (sect == s_first) {
|
||||
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
|
||||
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
|
||||
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
|
||||
}
|
||||
addr2[0] = (CFG_FLASH_WORD_SIZE)0x00300030; /* sector erase */
|
||||
}
|
||||
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 = (CFG_FLASH_WORD_SIZE *)(info->start[l_sect]);
|
||||
while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x00800080) != (CFG_FLASH_WORD_SIZE)0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (CFG_FLASH_WORD_SIZE *)info->start[0];
|
||||
addr[0] = (CFG_FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
|
||||
|
||||
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)
|
||||
{
|
||||
volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
|
||||
volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *)dest;
|
||||
volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *)&data;
|
||||
ulong start;
|
||||
int flag;
|
||||
int i;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*((volatile CFG_FLASH_WORD_SIZE *)dest) &
|
||||
(CFG_FLASH_WORD_SIZE)data) != (CFG_FLASH_WORD_SIZE)data) {
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
for (i=0; i<4/sizeof(CFG_FLASH_WORD_SIZE); i++)
|
||||
{
|
||||
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
|
||||
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00A000A0;
|
||||
|
||||
dest2[i] = data2[i];
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((dest2[i] & (CFG_FLASH_WORD_SIZE)0x00800080) !=
|
||||
(data2[i] & (CFG_FLASH_WORD_SIZE)0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* include common flash code (for esd boards)
|
||||
*/
|
||||
#include "../common/flash.c"
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long * addr, flash_info_t * info);
|
||||
static void flash_get_offsets (ulong base, flash_info_t * info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
unsigned long size_b0, size_b1;
|
||||
int i;
|
||||
uint pbcr;
|
||||
unsigned long base_b0, base_b1;
|
||||
int size_val = 0;
|
||||
|
||||
/* 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 - FIXME XXX */
|
||||
|
||||
base_b0 = FLASH_BASE0_PRELIM;
|
||||
size_b0 = flash_get_size ((vu_long *) base_b0, &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);
|
||||
}
|
||||
|
||||
base_b1 = FLASH_BASE1_PRELIM;
|
||||
size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
|
||||
if (size_b1) {
|
||||
mtdcr (ebccfga, pb0cr);
|
||||
pbcr = mfdcr (ebccfgd);
|
||||
mtdcr (ebccfga, pb0cr);
|
||||
base_b1 = -size_b1;
|
||||
switch (size_b1) {
|
||||
case 1 << 20:
|
||||
size_val = 0;
|
||||
break;
|
||||
case 2 << 20:
|
||||
size_val = 1;
|
||||
break;
|
||||
case 4 << 20:
|
||||
size_val = 2;
|
||||
break;
|
||||
case 8 << 20:
|
||||
size_val = 3;
|
||||
break;
|
||||
case 16 << 20:
|
||||
size_val = 4;
|
||||
break;
|
||||
default:
|
||||
size_val = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b1 | (size_val << 17);
|
||||
mtdcr (ebccfgd, pbcr);
|
||||
/* printf("pb1cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
if (size_b0) {
|
||||
mtdcr (ebccfga, pb1cr);
|
||||
pbcr = mfdcr (ebccfgd);
|
||||
mtdcr (ebccfga, pb1cr);
|
||||
base_b0 = base_b1 - size_b0;
|
||||
switch (size_b1) {
|
||||
case 1 << 20:
|
||||
size_val = 0;
|
||||
break;
|
||||
case 2 << 20:
|
||||
size_val = 1;
|
||||
break;
|
||||
case 4 << 20:
|
||||
size_val = 2;
|
||||
break;
|
||||
case 8 << 20:
|
||||
size_val = 3;
|
||||
break;
|
||||
case 16 << 20:
|
||||
size_val = 4;
|
||||
break;
|
||||
}
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
|
||||
mtdcr (ebccfgd, pbcr);
|
||||
/* printf("pb0cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (base_b0, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect (FLAG_PROTECT_SET,
|
||||
base_b0 + size_b0 - CFG_MONITOR_LEN,
|
||||
base_b0 + size_b0 - 1, &flash_info[0]);
|
||||
|
||||
if (size_b1) {
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
|
||||
|
||||
flash_get_offsets (base_b1, &flash_info[1]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect (FLAG_PROTECT_SET,
|
||||
base_b1 + size_b1 - CFG_MONITOR_LEN,
|
||||
base_b1 + size_b1 - 1, &flash_info[1]);
|
||||
/* monitor protection OFF by default (one is enough) */
|
||||
flash_protect (FLAG_PROTECT_CLEAR,
|
||||
base_b0 + size_b0 - CFG_MONITOR_LEN,
|
||||
base_b0 + size_b0 - 1, &flash_info[0]);
|
||||
} 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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <command.h>
|
||||
#include <pci.h>
|
||||
|
||||
#define OK 0
|
||||
#define ERROR (-1)
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
|
||||
extern u_long pci9054_iobase;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* Routines for PLX PCI9054 eeprom access
|
||||
*
|
||||
*/
|
||||
|
||||
static unsigned int PciEepromReadLongVPD(int offs)
|
||||
{
|
||||
unsigned int value;
|
||||
unsigned int ret;
|
||||
int count;
|
||||
|
||||
pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x4c, (offs<<16) | 0x0003);
|
||||
count = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
udelay(10 * 1000);
|
||||
pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x4c, &ret);
|
||||
if ((ret & 0x80000000) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
if (count > 10)
|
||||
{
|
||||
printf("\nTimeout: ret=%08x - Please try again!\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x50, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static int PciEepromWriteLongVPD(int offs, unsigned int value)
|
||||
{
|
||||
unsigned int ret;
|
||||
int count;
|
||||
|
||||
pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x50, value);
|
||||
pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x4c, (offs<<16) | 0x80000003);
|
||||
count = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
udelay(10 * 1000);
|
||||
pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x4c, &ret);
|
||||
if ((ret & 0x80000000) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
if (count > 10)
|
||||
{
|
||||
printf("\nTimeout: ret=%08x - Please try again!\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void showPci9054(void)
|
||||
{
|
||||
int val;
|
||||
int l, i;
|
||||
|
||||
/* read 9054-values */
|
||||
for (l=0; l<6; l++)
|
||||
{
|
||||
printf("%02x: ", l*0x10);
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
pci_read_config_dword(CFG_PCI9054_DEV_FN, l*16+i*4, &val);
|
||||
printf("%08x ", val);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (l=0; l<7; l++)
|
||||
{
|
||||
printf("%02x: ", l*0x10);
|
||||
for (i=0; i<4; i++)
|
||||
printf("%08x ", PciEepromReadLongVPD((i+l*4)*4));
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
static void updatePci9054(void)
|
||||
{
|
||||
int val;
|
||||
|
||||
/*
|
||||
* Set EEPROM write-protect register to 0
|
||||
*/
|
||||
out32(pci9054_iobase+0x0c, in32(pci9054_iobase+0x0c) & 0xffff00ff);
|
||||
|
||||
/* Long Serial EEPROM Load Registers... */
|
||||
val = PciEepromWriteLongVPD(0x00, 0x905410b5);
|
||||
val = PciEepromWriteLongVPD(0x04, 0x09800001); /* other input controller */
|
||||
val = PciEepromWriteLongVPD(0x08, 0x28140100);
|
||||
|
||||
val = PciEepromWriteLongVPD(0x0c, 0x00000000); /* MBOX0... */
|
||||
val = PciEepromWriteLongVPD(0x10, 0x00000000);
|
||||
|
||||
/* las0: fpga access (0x0000.0000 ... 0x0003.ffff) */
|
||||
val = PciEepromWriteLongVPD(0x14, 0xfffc0000); /* LAS0RR... */
|
||||
val = PciEepromWriteLongVPD(0x18, 0x00000001); /* LAS0BA */
|
||||
|
||||
val = PciEepromWriteLongVPD(0x1c, 0x00200000); /* MARBR... */
|
||||
val = PciEepromWriteLongVPD(0x20, 0x00300500); /* LMISC/BIGEND */
|
||||
|
||||
val = PciEepromWriteLongVPD(0x24, 0x00000000); /* EROMRR... */
|
||||
val = PciEepromWriteLongVPD(0x28, 0x00000000); /* EROMBA */
|
||||
|
||||
val = PciEepromWriteLongVPD(0x2c, 0x43030000); /* LBRD0... */
|
||||
|
||||
val = PciEepromWriteLongVPD(0x30, 0x00000000); /* DMRR... */
|
||||
val = PciEepromWriteLongVPD(0x34, 0x00000000);
|
||||
val = PciEepromWriteLongVPD(0x38, 0x00000000);
|
||||
|
||||
val = PciEepromWriteLongVPD(0x3c, 0x00000000); /* DMPBAM... */
|
||||
val = PciEepromWriteLongVPD(0x40, 0x00000000);
|
||||
|
||||
/* Extra Long Serial EEPROM Load Registers... */
|
||||
val = PciEepromWriteLongVPD(0x44, 0x010212fe); /* PCISID... */
|
||||
|
||||
/* las1: 505-sram access (0x0004.0000 ... 0x001f.ffff) */
|
||||
/* Offset to LAS1: Group 1: 0x00040000 */
|
||||
/* Group 2: 0x00080000 */
|
||||
/* Group 3: 0x000c0000 */
|
||||
val = PciEepromWriteLongVPD(0x48, 0xffe00000); /* LAS1RR */
|
||||
val = PciEepromWriteLongVPD(0x4c, 0x00040001); /* LAS1BA */
|
||||
val = PciEepromWriteLongVPD(0x50, 0x00000208); /* LBRD1 */ /* so wars bisher */
|
||||
|
||||
val = PciEepromWriteLongVPD(0x54, 0x00004c06); /* HotSwap... */
|
||||
|
||||
printf("Finished writing defaults into PLX PCI9054 EEPROM!\n");
|
||||
}
|
||||
|
||||
|
||||
static void clearPci9054(void)
|
||||
{
|
||||
int val;
|
||||
|
||||
/*
|
||||
* Set EEPROM write-protect register to 0
|
||||
*/
|
||||
out32(pci9054_iobase+0x0c, in32(pci9054_iobase+0x0c) & 0xffff00ff);
|
||||
|
||||
/* Long Serial EEPROM Load Registers... */
|
||||
val = PciEepromWriteLongVPD(0x00, 0xffffffff);
|
||||
val = PciEepromWriteLongVPD(0x04, 0xffffffff); /* other input controller */
|
||||
|
||||
printf("Finished clearing PLX PCI9054 EEPROM!\n");
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
int do_pci9054(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
|
||||
{
|
||||
if (strcmp(argv[1], "info") == 0)
|
||||
{
|
||||
showPci9054();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "update") == 0)
|
||||
{
|
||||
updatePci9054();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "clear") == 0)
|
||||
{
|
||||
clearPci9054();
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Usage:\n%s\n", cmdtp->usage);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* include common flash code (for esd boards)
|
||||
*/
|
||||
#include "../common/flash.c"
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
unsigned long size_b0;
|
||||
int i;
|
||||
unsigned long base_b0;
|
||||
|
||||
/* 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 - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
/* Setup offsets */
|
||||
flash_get_offsets (-size_b0, &flash_info[0]);
|
||||
|
||||
base_b0 = -size_b0;
|
||||
|
||||
/* Monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
-CFG_MONITOR_LEN,
|
||||
0xffffffff,
|
||||
&flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
return (size_b0);
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* include common flash code (for esd boards)
|
||||
*/
|
||||
#include "../common/flash.c"
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long * addr, flash_info_t * info);
|
||||
static void flash_get_offsets (ulong base, flash_info_t * info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
unsigned long size_b0, size_b1;
|
||||
int i;
|
||||
uint pbcr;
|
||||
unsigned long base_b0, base_b1;
|
||||
|
||||
/* 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 - FIXME XXX */
|
||||
|
||||
base_b0 = FLASH_BASE0_PRELIM;
|
||||
size_b0 = flash_get_size ((vu_long *) base_b0, &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);
|
||||
}
|
||||
|
||||
base_b1 = FLASH_BASE1_PRELIM;
|
||||
size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
|
||||
if (size_b1) {
|
||||
mtdcr (ebccfga, pb0cr);
|
||||
pbcr = mfdcr (ebccfgd);
|
||||
mtdcr (ebccfga, pb0cr);
|
||||
base_b1 = -size_b1;
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b1 |
|
||||
(((size_b1 / 1024 / 1024) - 1) << 17);
|
||||
mtdcr (ebccfgd, pbcr);
|
||||
/* printf("pb1cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
if (size_b0) {
|
||||
mtdcr (ebccfga, pb1cr);
|
||||
pbcr = mfdcr (ebccfgd);
|
||||
mtdcr (ebccfga, pb1cr);
|
||||
base_b0 = base_b1 - size_b0;
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b0 |
|
||||
(((size_b0 / 1024 / 1024) - 1) << 17);
|
||||
mtdcr (ebccfgd, pbcr);
|
||||
/* printf("pb0cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (base_b0, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect (FLAG_PROTECT_SET,
|
||||
base_b0 + size_b0 - CFG_MONITOR_LEN,
|
||||
base_b0 + size_b0 - 1, &flash_info[0]);
|
||||
|
||||
if (size_b1) {
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
|
||||
|
||||
flash_get_offsets (base_b1, &flash_info[1]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect (FLAG_PROTECT_SET,
|
||||
base_b1 + size_b1 - CFG_MONITOR_LEN,
|
||||
base_b1 + size_b1 - 1, &flash_info[1]);
|
||||
/* monitor protection OFF by default (one is enough) */
|
||||
flash_protect (FLAG_PROTECT_CLEAR,
|
||||
base_b0 + size_b0 - CFG_MONITOR_LEN,
|
||||
base_b0 + size_b0 - 1, &flash_info[0]);
|
||||
} 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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* include common flash code (for esd boards)
|
||||
*/
|
||||
#include "../common/flash.c"
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long * addr, flash_info_t * info);
|
||||
static void flash_get_offsets (ulong base, flash_info_t * info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
unsigned long size_b0, size_b1;
|
||||
int i;
|
||||
uint pbcr;
|
||||
unsigned long base_b0, base_b1;
|
||||
int size_val = 0;
|
||||
|
||||
/* 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 - FIXME XXX */
|
||||
|
||||
base_b0 = FLASH_BASE0_PRELIM;
|
||||
size_b0 = flash_get_size ((vu_long *) base_b0, &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);
|
||||
}
|
||||
|
||||
base_b1 = FLASH_BASE1_PRELIM;
|
||||
size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
|
||||
if (size_b1) {
|
||||
mtdcr (ebccfga, pb0cr);
|
||||
pbcr = mfdcr (ebccfgd);
|
||||
mtdcr (ebccfga, pb0cr);
|
||||
base_b1 = -size_b1;
|
||||
switch (size_b1) {
|
||||
case 1 << 20:
|
||||
size_val = 0;
|
||||
break;
|
||||
case 2 << 20:
|
||||
size_val = 1;
|
||||
break;
|
||||
case 4 << 20:
|
||||
size_val = 2;
|
||||
break;
|
||||
case 8 << 20:
|
||||
size_val = 3;
|
||||
break;
|
||||
case 16 << 20:
|
||||
size_val = 4;
|
||||
break;
|
||||
}
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b1 | (size_val << 17);
|
||||
mtdcr (ebccfgd, pbcr);
|
||||
/* printf("pb1cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
if (size_b0) {
|
||||
mtdcr (ebccfga, pb1cr);
|
||||
pbcr = mfdcr (ebccfgd);
|
||||
mtdcr (ebccfga, pb1cr);
|
||||
base_b0 = base_b1 - size_b0;
|
||||
switch (size_b1) {
|
||||
case 1 << 20:
|
||||
size_val = 0;
|
||||
break;
|
||||
case 2 << 20:
|
||||
size_val = 1;
|
||||
break;
|
||||
case 4 << 20:
|
||||
size_val = 2;
|
||||
break;
|
||||
case 8 << 20:
|
||||
size_val = 3;
|
||||
break;
|
||||
case 16 << 20:
|
||||
size_val = 4;
|
||||
break;
|
||||
}
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
|
||||
mtdcr (ebccfgd, pbcr);
|
||||
/* printf("pb0cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (base_b0, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect (FLAG_PROTECT_SET,
|
||||
base_b0 + size_b0 - CFG_MONITOR_LEN,
|
||||
base_b0 + size_b0 - 1, &flash_info[0]);
|
||||
|
||||
if (size_b1) {
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
|
||||
|
||||
flash_get_offsets (base_b1, &flash_info[1]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect (FLAG_PROTECT_SET,
|
||||
base_b1 + size_b1 - CFG_MONITOR_LEN,
|
||||
base_b1 + size_b1 - 1, &flash_info[1]);
|
||||
/* monitor protection OFF by default (one is enough) */
|
||||
flash_protect (FLAG_PROTECT_CLEAR,
|
||||
base_b0 + size_b0 - CFG_MONITOR_LEN,
|
||||
base_b0 + size_b0 - 1, &flash_info[0]);
|
||||
} 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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* 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 <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* include common flash code (for esd boards)
|
||||
*/
|
||||
#include "../common/flash.c"
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long * addr, flash_info_t * info);
|
||||
static void flash_get_offsets (ulong base, flash_info_t * info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
unsigned long size_b0;
|
||||
int i;
|
||||
uint pbcr;
|
||||
unsigned long base_b0;
|
||||
int size_val = 0;
|
||||
|
||||
/* 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 - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
/* Setup offsets */
|
||||
flash_get_offsets (-size_b0, &flash_info[0]);
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
mtdcr(ebccfga, pb0cr);
|
||||
pbcr = mfdcr(ebccfgd);
|
||||
mtdcr(ebccfga, pb0cr);
|
||||
base_b0 = -size_b0;
|
||||
switch (size_b0) {
|
||||
case 1 << 20:
|
||||
size_val = 0;
|
||||
break;
|
||||
case 2 << 20:
|
||||
size_val = 1;
|
||||
break;
|
||||
case 4 << 20:
|
||||
size_val = 2;
|
||||
break;
|
||||
case 8 << 20:
|
||||
size_val = 3;
|
||||
break;
|
||||
case 16 << 20:
|
||||
size_val = 4;
|
||||
break;
|
||||
}
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
|
||||
mtdcr(ebccfgd, pbcr);
|
||||
|
||||
/* Monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
-CFG_MONITOR_LEN,
|
||||
0xffffffff,
|
||||
&flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
return (size_b0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,744 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 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) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: "
|
||||
"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,
|
||||
size_b0, size_b0<<20
|
||||
);
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V | BR_PS_16; /* 16 Bit data port */
|
||||
#else
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
|
||||
#endif
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#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
|
||||
|
||||
if (size_b1) {
|
||||
memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
|
||||
BR_MS_GPCM | BR_V | BR_PS_16;
|
||||
#else
|
||||
memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
|
||||
BR_MS_GPCM | BR_V;
|
||||
#endif
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
|
||||
&flash_info[1]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE + size_b0, &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[1]);
|
||||
#endif
|
||||
} else {
|
||||
memctl->memc_br1 = 0; /* invalidate bank */
|
||||
|
||||
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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00002000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* set up sector start address table */
|
||||
if (info->flash_id & FLASH_BTYPE) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
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 * 0x00010000) - 0x00030000;
|
||||
#else
|
||||
info->start[0] = base + 0x00000000;
|
||||
info->start[1] = base + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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;
|
||||
case FLASH_MAN_SST: printf ("SST "); break;
|
||||
case FLASH_MAN_STM: printf ("STM "); 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;
|
||||
case FLASH_SST200A: printf ("39xF200A (2M = 128K x 16)\n");
|
||||
break;
|
||||
case FLASH_SST400A: printf ("39xF400A (4M = 256K x 16)\n");
|
||||
break;
|
||||
case FLASH_SST800A: printf ("39xF800A (8M = 512K x 16)\n");
|
||||
break;
|
||||
case FLASH_STM800AB: printf ("M29W800AB (8M = 512K x 16)\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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
vu_short *s_addr = (vu_short*)addr;
|
||||
s_addr[0x5555] = 0x00AA;
|
||||
s_addr[0x2AAA] = 0x0055;
|
||||
s_addr[0x5555] = 0x0090;
|
||||
value = s_addr[0];
|
||||
value = value|(value<<16);
|
||||
#else
|
||||
addr[0x5555] = 0x00AA00AA;
|
||||
addr[0x2AAA] = 0x00550055;
|
||||
addr[0x5555] = 0x00900090;
|
||||
value = addr[0];
|
||||
#endif
|
||||
|
||||
switch (value) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
case SST_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_SST;
|
||||
break;
|
||||
case STM_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_STM;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
value = s_addr[1];
|
||||
value = value|(value<<16);
|
||||
#else
|
||||
value = addr[1]; /* device ID */
|
||||
#endif
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00100000; /* => 1 MB */
|
||||
#else
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000; /* => 2 MB */
|
||||
#endif
|
||||
break;
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00200000; /* => 2 MB */
|
||||
#else
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000; /* => 4 MB */
|
||||
#endif
|
||||
|
||||
break;
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
case SST_ID_xF200A:
|
||||
info->flash_id += FLASH_SST200A;
|
||||
info->sector_count = 64; /* 39xF200A ID ( 2M = 128K x 16 ) */
|
||||
info->size = 0x00080000;
|
||||
break;
|
||||
case SST_ID_xF400A:
|
||||
info->flash_id += FLASH_SST400A;
|
||||
info->sector_count = 128; /* 39xF400A ID ( 4M = 256K x 16 ) */
|
||||
info->size = 0x00100000;
|
||||
break;
|
||||
case SST_ID_xF800A:
|
||||
info->flash_id += FLASH_SST800A;
|
||||
info->sector_count = 256; /* 39xF800A ID ( 8M = 512K x 16 ) */
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
case STM_ID_x800AB:
|
||||
info->flash_id += FLASH_STM800AB;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
if (info->sector_count > CFG_MAX_FLASH_SECT) {
|
||||
printf ("** ERROR: sector count %d > max (%d) **\n",
|
||||
info->sector_count, CFG_MAX_FLASH_SECT);
|
||||
info->sector_count = CFG_MAX_FLASH_SECT;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00002000);
|
||||
}
|
||||
} else { /* AMD and Fujitsu types */
|
||||
/* set up sector start address table */
|
||||
if (info->flash_id & FLASH_BTYPE) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
|
||||
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 * 0x00010000) - 0x00030000;
|
||||
#else
|
||||
info->start[0] = base + 0x00000000;
|
||||
info->start[1] = base + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
s_addr = (volatile unsigned short *)(info->start[i]);
|
||||
info->protect[i] = s_addr[2] & 1;
|
||||
#else
|
||||
addr = (volatile unsigned long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
s_addr = (volatile unsigned short *)(info->start[0]);
|
||||
*s_addr = 0x00F0; /* reset bank */
|
||||
#else
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
#endif
|
||||
|
||||
}
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(info->start[0]);
|
||||
int flag, prot, sect;
|
||||
ulong start, now, last;
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
vu_short *s_addr = (vu_short*)addr;
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
/*#ifndef CONFIG_FLASH_16BIT
|
||||
ulong type;
|
||||
type = (info->flash_id & FLASH_VENDMASK);
|
||||
if ((type != FLASH_MAN_SST) && (type != FLASH_MAN_STM)) {
|
||||
printf ("Can't erase unknown flash type %08lx - aborted\n",
|
||||
info->flash_id);
|
||||
return;
|
||||
}
|
||||
#endif*/
|
||||
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 = get_timer (0);
|
||||
last = start;
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
vu_short *s_sect_addr = (vu_short*)(info->start[sect]);
|
||||
#else
|
||||
vu_long *sect_addr = (vu_long*)(info->start[sect]);
|
||||
#endif
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
|
||||
/*printf("\ns_sect_addr=%x",s_sect_addr);*/
|
||||
s_addr[0x5555] = 0x00AA;
|
||||
s_addr[0x2AAA] = 0x0055;
|
||||
s_addr[0x5555] = 0x0080;
|
||||
s_addr[0x5555] = 0x00AA;
|
||||
s_addr[0x2AAA] = 0x0055;
|
||||
s_sect_addr[0] = 0x0030;
|
||||
#else
|
||||
addr[0x5555] = 0x00AA00AA;
|
||||
addr[0x2AAA] = 0x00550055;
|
||||
addr[0x5555] = 0x00800080;
|
||||
addr[0x5555] = 0x00AA00AA;
|
||||
addr[0x2AAA] = 0x00550055;
|
||||
sect_addr[0] = 0x00300030;
|
||||
#endif
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
while ((s_sect_addr[0] & 0x0080) != 0x0080) {
|
||||
#else
|
||||
while ((sect_addr[0] & 0x00800080) != 0x00800080) {
|
||||
#endif
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
s_addr[0] = 0x00F0; /* reset bank */
|
||||
#else
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
#endif
|
||||
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
* 4 - Flash not identified
|
||||
*/
|
||||
|
||||
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
ulong cp, wp, data;
|
||||
int i, l, rc;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
vu_short high_data;
|
||||
vu_short low_data;
|
||||
vu_short *s_addr = (vu_short*)addr;
|
||||
#endif
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*((vu_long *)dest) & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
/* Write the 16 higher-bits */
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
high_data = ((data>>16) & 0x0000ffff);
|
||||
|
||||
s_addr[0x5555] = 0x00AA;
|
||||
s_addr[0x2AAA] = 0x0055;
|
||||
s_addr[0x5555] = 0x00A0;
|
||||
|
||||
*((vu_short *)dest) = high_data;
|
||||
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_short *)dest) & 0x0080) != (high_data & 0x0080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Write the 16 lower-bits */
|
||||
#endif
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
dest += 0x2;
|
||||
low_data = (data & 0x0000ffff);
|
||||
|
||||
s_addr[0x5555] = 0x00AA;
|
||||
s_addr[0x2AAA] = 0x0055;
|
||||
s_addr[0x5555] = 0x00A0;
|
||||
*((vu_short *)dest) = low_data;
|
||||
|
||||
#else
|
||||
addr[0x5555] = 0x00AA00AA;
|
||||
addr[0x2AAA] = 0x00550055;
|
||||
addr[0x5555] = 0x00A000A0;
|
||||
*((vu_long *)dest) = data;
|
||||
#endif
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
while ((*((vu_short *)dest) & 0x0080) != (low_data & 0x0080)) {
|
||||
#else
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
|
||||
#endif
|
||||
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,315 @@
|
|||
#include <common.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <malloc.h>
|
||||
#include <galileo/gt64260R.h>
|
||||
#include <galileo/core.h>
|
||||
|
||||
#define MAX_I2C_RETRYS 10
|
||||
#define I2C_DELAY 1000 /* Should be at least the # of MHz of Tclk */
|
||||
#undef DEBUG_I2C
|
||||
|
||||
#ifdef DEBUG_I2C
|
||||
#define DP(x) x
|
||||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
||||
/* Assuming that there is only one master on the bus (us) */
|
||||
|
||||
static void
|
||||
i2c_init(int speed, int slaveaddr)
|
||||
{
|
||||
unsigned int n, m, freq, margin, power;
|
||||
unsigned int actualFreq, actualN=0, actualM=0;
|
||||
unsigned int control, status;
|
||||
unsigned int minMargin = 0xffffffff;
|
||||
unsigned int tclk = 125000000;
|
||||
|
||||
DP(puts("i2c_init\n"));
|
||||
|
||||
for(n = 0 ; n < 8 ; n++)
|
||||
{
|
||||
for(m = 0 ; m < 16 ; m++)
|
||||
{
|
||||
power = 2<<n; /* power = 2^(n+1) */
|
||||
freq = tclk/(10*(m+1)*power);
|
||||
if (speed > freq)
|
||||
margin = speed - freq;
|
||||
else
|
||||
margin = freq - speed;
|
||||
if(margin < minMargin)
|
||||
{
|
||||
minMargin = margin;
|
||||
actualFreq = freq;
|
||||
actualN = n;
|
||||
actualM = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DP(puts("setup i2c bus\n"));
|
||||
|
||||
/* Setup bus */
|
||||
|
||||
GT_REG_WRITE(I2C_SOFT_RESET, 0);
|
||||
|
||||
DP(puts("udelay...\n"));
|
||||
|
||||
udelay(I2C_DELAY);
|
||||
|
||||
DP(puts("set baudrate\n"));
|
||||
|
||||
GT_REG_WRITE(I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN);
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 2) | (0x1 << 6));
|
||||
|
||||
udelay(I2C_DELAY * 10);
|
||||
|
||||
DP(puts("read control, baudrate\n"));
|
||||
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
GT_REG_READ(I2C_CONTROL, &control);
|
||||
}
|
||||
|
||||
static uchar
|
||||
i2c_start(void)
|
||||
{
|
||||
unsigned int control, status;
|
||||
int count = 0;
|
||||
|
||||
DP(puts("i2c_start\n"));
|
||||
|
||||
/* Set the start bit */
|
||||
|
||||
GT_REG_READ(I2C_CONTROL, &control);
|
||||
control |= (0x1 << 5);
|
||||
GT_REG_WRITE(I2C_CONTROL, control);
|
||||
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
|
||||
count = 0;
|
||||
while ((status & 0xff) != 0x08) {
|
||||
udelay(I2C_DELAY);
|
||||
if (count > 20) {
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
|
||||
return (status);
|
||||
}
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count++;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uchar
|
||||
i2c_select_device(uchar dev_addr, uchar read, int ten_bit)
|
||||
{
|
||||
unsigned int status, data, bits = 7;
|
||||
int count = 0;
|
||||
|
||||
DP(puts("i2c_select_device\n"));
|
||||
|
||||
/* Output slave address */
|
||||
|
||||
if (ten_bit) {
|
||||
bits = 10;
|
||||
}
|
||||
|
||||
data = (dev_addr << 1);
|
||||
/* set the read bit */
|
||||
data |= read;
|
||||
GT_REG_WRITE(I2C_DATA, data);
|
||||
/* assert the address */
|
||||
RESET_REG_BITS(I2C_CONTROL, BIT3);
|
||||
|
||||
udelay(I2C_DELAY);
|
||||
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count = 0;
|
||||
while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) {
|
||||
udelay(I2C_DELAY);
|
||||
if (count > 20) {
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
|
||||
return(status);
|
||||
}
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (bits == 10) {
|
||||
printf("10 bit I2C addressing not yet implemented\n");
|
||||
return (0xff);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uchar
|
||||
i2c_get_data(uchar* return_data, int len) {
|
||||
|
||||
unsigned int data, status;
|
||||
int count = 0;
|
||||
|
||||
DP(puts("i2c_get_data\n"));
|
||||
|
||||
while (len) {
|
||||
|
||||
/* Get and return the data */
|
||||
|
||||
RESET_REG_BITS(I2C_CONTROL, (0x1 << 3));
|
||||
|
||||
udelay(I2C_DELAY * 5);
|
||||
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count++;
|
||||
while ((status & 0xff) != 0x50) {
|
||||
udelay(I2C_DELAY);
|
||||
if(count > 2) {
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
|
||||
return 0;
|
||||
}
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count++;
|
||||
}
|
||||
GT_REG_READ(I2C_DATA, &data);
|
||||
len--;
|
||||
*return_data = (uchar)data;
|
||||
return_data++;
|
||||
}
|
||||
RESET_REG_BITS(I2C_CONTROL, BIT2|BIT3);
|
||||
while ((status & 0xff) != 0x58) {
|
||||
udelay(I2C_DELAY);
|
||||
if(count > 200) {
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
|
||||
return (status);
|
||||
}
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count++;
|
||||
}
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /* stop */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uchar
|
||||
i2c_write_data(unsigned int data, int len)
|
||||
{
|
||||
unsigned int status;
|
||||
int count = 0;
|
||||
|
||||
DP(puts("i2c_write_data\n"));
|
||||
|
||||
if (len > 4)
|
||||
return -1;
|
||||
|
||||
while (len) {
|
||||
/* Set and assert the data */
|
||||
|
||||
GT_REG_WRITE(I2C_DATA, (unsigned int)data);
|
||||
RESET_REG_BITS(I2C_CONTROL, (0x1 << 3));
|
||||
|
||||
udelay(I2C_DELAY);
|
||||
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count++;
|
||||
while ((status & 0xff) != 0x28) {
|
||||
udelay(I2C_DELAY);
|
||||
if(count > 20) {
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
|
||||
return (status);
|
||||
}
|
||||
GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
|
||||
count++;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 3) | (0x1 << 4));
|
||||
GT_REG_WRITE(I2C_CONTROL, (0x1 << 4));
|
||||
|
||||
udelay(I2C_DELAY * 10);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uchar
|
||||
i2c_set_dev_offset(uchar dev_addr, unsigned int offset, int ten_bit)
|
||||
{
|
||||
uchar status;
|
||||
|
||||
DP(puts("i2c_set_dev_offset\n"));
|
||||
|
||||
status = i2c_select_device(dev_addr, 0, ten_bit);
|
||||
if (status) {
|
||||
#ifdef DEBUG_I2C
|
||||
printf("Failed to select device setting offset: 0x%02x\n",
|
||||
status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
status = i2c_write_data(offset, 1);
|
||||
if (status) {
|
||||
#ifdef DEBUG_I2C
|
||||
printf("Failed to write data: 0x%02x\n", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
uchar
|
||||
i2c_read(uchar dev_addr, unsigned int offset, int len, uchar* data,
|
||||
int ten_bit)
|
||||
{
|
||||
uchar status = 0;
|
||||
unsigned int i2cFreq = 400000;
|
||||
|
||||
DP(puts("i2c_read\n"));
|
||||
|
||||
i2c_init(i2cFreq,0);
|
||||
|
||||
status = i2c_start();
|
||||
|
||||
if (status) {
|
||||
#ifdef DEBUG_I2C
|
||||
printf("Transaction start failed: 0x%02x\n", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
status = i2c_set_dev_offset(dev_addr, 0, 0);
|
||||
if (status) {
|
||||
#ifdef DEBUG_I2C
|
||||
printf("Failed to set offset: 0x%02x\n", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
i2c_init(i2cFreq,0);
|
||||
|
||||
status = i2c_start();
|
||||
if (status) {
|
||||
#ifdef DEBUG_I2C
|
||||
printf("Transaction restart failed: 0x%02x\n", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
status = i2c_select_device(dev_addr, 1, ten_bit);
|
||||
if (status) {
|
||||
#ifdef DEBUG_I2C
|
||||
printf("Address not acknowledged: 0x%02x\n", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
status = i2c_get_data(data, len);
|
||||
if (status) {
|
||||
#ifdef DEBUG_I2C
|
||||
printf("Data not recieved: 0x%02x\n", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*
|
||||
* Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <galileo/gt64260R.h>
|
||||
#include <galileo/memory.h>
|
||||
#include "intel_flash.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Protection Flags:
|
||||
*/
|
||||
#define FLAG_PROTECT_SET 0x01
|
||||
#define FLAG_PROTECT_CLEAR 0x02
|
||||
|
||||
static void
|
||||
bank_reset(flash_info_t *info, int sect)
|
||||
{
|
||||
bank_addr_t addrw, eaddrw;
|
||||
|
||||
addrw = (bank_addr_t)info->start[sect];
|
||||
eaddrw = BANK_ADDR_NEXT_WORD(addrw);
|
||||
|
||||
while (addrw < eaddrw) {
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" writing reset cmd to addr 0x%08lx\n",
|
||||
(unsigned long)addrw);
|
||||
#endif
|
||||
*addrw = BANK_CMD_RST;
|
||||
addrw++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bank_erase_init(flash_info_t *info, int sect)
|
||||
{
|
||||
bank_addr_t addrw, saddrw, eaddrw;
|
||||
int flag;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("0x%08x BANK_CMD_PROG\n", BANK_CMD_PROG);
|
||||
printf("0x%08x BANK_CMD_ERASE1\n", BANK_CMD_ERASE1);
|
||||
printf("0x%08x BANK_CMD_ERASE2\n", BANK_CMD_ERASE2);
|
||||
printf("0x%08x BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT);
|
||||
printf("0x%08x BANK_CMD_RST\n", BANK_CMD_RST);
|
||||
printf("0x%08x BANK_STAT_RDY\n", BANK_STAT_RDY);
|
||||
printf("0x%08x BANK_STAT_ERR\n", BANK_STAT_ERR);
|
||||
#endif
|
||||
|
||||
saddrw = (bank_addr_t)info->start[sect];
|
||||
eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("erasing sector %d, start addr = 0x%08lx "
|
||||
"(bank next word addr = 0x%08lx)\n", sect,
|
||||
(unsigned long)saddrw, (unsigned long)eaddrw);
|
||||
#endif
|
||||
|
||||
/* Disable intrs which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
for (addrw = saddrw; addrw < eaddrw; addrw++) {
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" writing erase cmd to addr 0x%08lx\n",
|
||||
(unsigned long)addrw);
|
||||
#endif
|
||||
*addrw = BANK_CMD_ERASE1;
|
||||
*addrw = BANK_CMD_ERASE2;
|
||||
}
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
static int
|
||||
bank_erase_poll(flash_info_t *info, int sect)
|
||||
{
|
||||
bank_addr_t addrw, saddrw, eaddrw;
|
||||
int sectdone, haderr;
|
||||
|
||||
saddrw = (bank_addr_t)info->start[sect];
|
||||
eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
|
||||
|
||||
sectdone = 1;
|
||||
haderr = 0;
|
||||
|
||||
for (addrw = saddrw; addrw < eaddrw; addrw++) {
|
||||
bank_word_t stat = *addrw;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" checking status at addr "
|
||||
"0x%08x [0x%08x]\n",
|
||||
(unsigned long)addrw, stat);
|
||||
#endif
|
||||
if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY)
|
||||
sectdone = 0;
|
||||
else if ((stat & BANK_STAT_ERR) != 0) {
|
||||
printf(" failed on sector %d "
|
||||
"(stat = 0x%08x) at "
|
||||
"address 0x%p\n",
|
||||
sect, stat, addrw);
|
||||
*addrw = BANK_CMD_CLR_STAT;
|
||||
haderr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (haderr)
|
||||
return (-1);
|
||||
else
|
||||
return (sectdone);
|
||||
}
|
||||
|
||||
int
|
||||
write_word_intel(bank_addr_t addr, bank_word_t value)
|
||||
{
|
||||
bank_word_t stat;
|
||||
ulong start;
|
||||
int flag, retval;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = BANK_CMD_PROG;
|
||||
|
||||
*addr = value;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
retval = 0;
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
do {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
stat = *addr;
|
||||
} while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY);
|
||||
|
||||
if ((stat & BANK_STAT_ERR) != 0) {
|
||||
printf("flash program failed (stat = 0x%08lx) "
|
||||
"at address 0x%08lx\n", (ulong)stat, (ulong)addr);
|
||||
*addr = BANK_CMD_CLR_STAT;
|
||||
retval = 3;
|
||||
}
|
||||
|
||||
done:
|
||||
/* reset to read mode */
|
||||
*addr = BANK_CMD_RST;
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
flash_erase_intel(flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
int prot, sect, haderr;
|
||||
ulong start, now, last;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
|
||||
" Bank # %d: ", s_last - s_first + 1, s_first, s_last,
|
||||
(info - flash_info) + 1);
|
||||
flash_print_info(info);
|
||||
#endif
|
||||
|
||||
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 sector%s will not be erased!\n",
|
||||
prot, (prot > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
start = get_timer (0);
|
||||
last = 0;
|
||||
haderr = 0;
|
||||
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
ulong estart;
|
||||
int sectdone;
|
||||
|
||||
bank_erase_init(info, sect);
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
estart = get_timer(start);
|
||||
|
||||
do {
|
||||
now = get_timer(start);
|
||||
|
||||
if (now - estart > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout (sect %d)\n", sect);
|
||||
haderr = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef FLASH_DEBUG
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
sectdone = bank_erase_poll(info, sect);
|
||||
|
||||
if (sectdone < 0) {
|
||||
haderr = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!sectdone);
|
||||
|
||||
if (haderr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (haderr > 0)
|
||||
printf (" failed\n");
|
||||
else
|
||||
printf (" done\n");
|
||||
|
||||
/* reset to read mode */
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
bank_reset(info, sect);
|
||||
}
|
||||
}
|
||||
return haderr;
|
||||
}
|
|
@ -0,0 +1,624 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long total_size;
|
||||
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;
|
||||
}
|
||||
|
||||
total_size = 0;
|
||||
size_b0 = 0xffffffff;
|
||||
|
||||
for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
|
||||
{
|
||||
size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + total_size), &flash_info[i]);
|
||||
|
||||
if (flash_info[i].flash_id == FLASH_UNKNOWN)
|
||||
{
|
||||
printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", i, size_b1, size_b1>>20);
|
||||
}
|
||||
|
||||
/* Is this really needed ? - LP */
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: Bank %d (0x%08lx = %ld MB) > Bank %d (0x%08lx = %ld MB)\n",
|
||||
i, size_b1, size_b1>>20, i-1, size_b0, size_b0>>20);
|
||||
goto out_error;
|
||||
}
|
||||
size_b0 = size_b1;
|
||||
total_size += size_b1;
|
||||
}
|
||||
|
||||
/* Compute the Address Mask */
|
||||
for (i=0; (total_size >> i) != 0; ++i) {};
|
||||
i--;
|
||||
|
||||
if (total_size != (1 << i)) {
|
||||
printf ("## WARNING: Total FLASH size (0x%08lx = %ld MB) is not a power of 2\n",
|
||||
total_size, total_size>>20);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = ((((unsigned long)~1) << i) & OR_AM_MSK) | CFG_OR_TIMING_FLASH;
|
||||
memctl->memc_br0 = CFG_BR0_PRELIM;
|
||||
|
||||
total_size = 0;
|
||||
|
||||
for (i=0; i < CFG_MAX_FLASH_BANKS && flash_info[i].size != 0; ++i)
|
||||
{
|
||||
/* Re-do sizing to get full correct info */
|
||||
/* Why ? - LP */
|
||||
size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + total_size), &flash_info[i]);
|
||||
|
||||
/* This is done by flash_get_size - LP */
|
||||
/* flash_get_offsets (CFG_FLASH_BASE + total_size, &flash_info[i]); */
|
||||
|
||||
#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[i]);
|
||||
#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[i]);
|
||||
#endif
|
||||
|
||||
total_size += size_b1;
|
||||
}
|
||||
|
||||
return (total_size);
|
||||
|
||||
out_error:
|
||||
for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
|
||||
{
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[i].sector_count = -1;
|
||||
flash_info[i].size = 0;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start address table */
|
||||
if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
|
||||
/* set sector offsets for uniform sector type */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00040000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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;
|
||||
case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK)
|
||||
{
|
||||
case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
|
||||
break;
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
#if 0
|
||||
ulong base = (ulong)addr;
|
||||
#endif
|
||||
uchar value;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x90909090;
|
||||
#endif
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value + (value << 16))
|
||||
{
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case AMD_ID_F040B:
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
#else
|
||||
flash_get_offsets ((ulong)addr, info);
|
||||
#endif
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN)
|
||||
{
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
#if 0
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
#else
|
||||
*addr = 0xF0F0F0F0; /* reset bank */
|
||||
#endif
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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 - aborted\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;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x80808080;
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
#endif
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
#if 0
|
||||
addr[0] = 0x00300030;
|
||||
#else
|
||||
addr[0] = 0x30303030;
|
||||
#endif
|
||||
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_long*)(info->start[l_sect]);
|
||||
#if 0
|
||||
while ((addr[0] & 0x00800080) != 0x00800080)
|
||||
#else
|
||||
while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
|
||||
#endif
|
||||
{
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
#if 0
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
#else
|
||||
addr[0] = 0xF0F0F0F0; /* reset bank */
|
||||
#endif
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0xA0A0A0A0;
|
||||
#endif
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
#if 0
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
|
||||
#else
|
||||
while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
|
||||
#endif
|
||||
{
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,42 @@
|
|||
#include <config.h>
|
||||
#include <common.h>
|
||||
|
||||
void
|
||||
signal_delay(unsigned int n)
|
||||
{
|
||||
while (n--);
|
||||
}
|
||||
|
||||
void
|
||||
signal_on(void)
|
||||
{
|
||||
*((volatile uint *)BCSR4) &= ~(1<<(31-3)); /* led on */
|
||||
}
|
||||
|
||||
void
|
||||
signal_off(void)
|
||||
{
|
||||
*((volatile uint *)BCSR4) |= (1<<(31-3)); /* led off */
|
||||
}
|
||||
|
||||
void
|
||||
slow_blink(unsigned int n)
|
||||
{
|
||||
while (n--) {
|
||||
signal_on();
|
||||
signal_delay(0x00400000);
|
||||
signal_off();
|
||||
signal_delay(0x00400000);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fast_blink(unsigned int n)
|
||||
{
|
||||
while (n--) {
|
||||
signal_on();
|
||||
signal_delay(0x00100000);
|
||||
signal_off();
|
||||
signal_delay(0x00100000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/* Detect size */
|
||||
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
/* Setup offsets */
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#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
|
||||
|
||||
size_b1 = 0 ;
|
||||
|
||||
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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Fix this to support variable sector sizes
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start address table */
|
||||
if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
info->start[i] = base + (i * 0x00010000);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_print_info (flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN)
|
||||
{
|
||||
puts ("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;
|
||||
case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK)
|
||||
{
|
||||
case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
if (info->size >> 20) {
|
||||
printf (" Size: %ld MB in %d Sectors\n",
|
||||
info->size >> 20,
|
||||
info->sector_count);
|
||||
} else {
|
||||
printf (" Size: %ld KB in %d Sectors\n",
|
||||
info->size >> 10,
|
||||
info->sector_count);
|
||||
}
|
||||
|
||||
puts (" Sector Start Addresses:");
|
||||
|
||||
for (i=0; i<info->sector_count; ++i)
|
||||
{
|
||||
if ((i % 5) == 0)
|
||||
{
|
||||
puts ("\n ");
|
||||
}
|
||||
|
||||
printf (" %08lX%s",
|
||||
info->start[i],
|
||||
info->protect[i] ? " (RO)" : " ");
|
||||
}
|
||||
|
||||
putc ('\n');
|
||||
return;
|
||||
}
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
volatile unsigned char *caddr;
|
||||
char value;
|
||||
|
||||
caddr = (volatile unsigned char *)addr ;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
|
||||
#if 0
|
||||
printf("Base address is: %08x\n", caddr);
|
||||
#endif
|
||||
|
||||
caddr[0x0555] = 0xAA;
|
||||
caddr[0x02AA] = 0x55;
|
||||
caddr[0x0555] = 0x90;
|
||||
|
||||
value = caddr[0];
|
||||
|
||||
#if 0
|
||||
printf("Manufact ID: %02x\n", value);
|
||||
#endif
|
||||
switch (value)
|
||||
{
|
||||
case 0x01:
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
value = caddr[1]; /* device ID */
|
||||
#if 0
|
||||
printf("Device ID: %02x\n", value);
|
||||
#endif
|
||||
switch (value)
|
||||
{
|
||||
case AMD_ID_LV040B:
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512Kb */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
flash_get_offsets ((ulong)addr, &flash_info[0]);
|
||||
|
||||
/* 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 */
|
||||
caddr = (volatile unsigned char *)(info->start[i]);
|
||||
info->protect[i] = caddr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN)
|
||||
{
|
||||
caddr = (volatile unsigned char *)info->start[0];
|
||||
*caddr = 0xF0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
volatile unsigned char *addr = (volatile unsigned 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;
|
||||
}
|
||||
|
||||
if ((info->flash_id == FLASH_UNKNOWN) ||
|
||||
(info->flash_id > FLASH_AMD_COMP)) {
|
||||
printf ("Can't erase unknown flash type - aborted\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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (volatile unsigned 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 DONE;
|
||||
|
||||
start = get_timer (0);
|
||||
last = start;
|
||||
addr = (volatile unsigned char *)(info->start[l_sect]);
|
||||
|
||||
while ((addr[0] & 0xFF) != 0xFF)
|
||||
{
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned char *)info->start[0];
|
||||
|
||||
addr[0] = 0xF0; /* reset bank */
|
||||
|
||||
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)
|
||||
{
|
||||
volatile unsigned char *addr = (volatile unsigned char*)(info->start[0]),
|
||||
*cdest,*cdata;
|
||||
ulong start;
|
||||
int flag, count = 4 ;
|
||||
|
||||
cdest = (volatile unsigned char *)dest ;
|
||||
cdata = (volatile unsigned char *)&data ;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*((vu_long *)dest) & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
while(count--)
|
||||
{
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
addr[0x0555] = 0xAA;
|
||||
addr[0x02AA] = 0x55;
|
||||
addr[0x0555] = 0xA0;
|
||||
|
||||
*cdest = *cdata;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*cdest ^ *cdata) & 0x80)
|
||||
{
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
cdata++ ;
|
||||
cdest++ ;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,335 @@
|
|||
/* Module for handling DALLAS DS2438, smart battery monitor
|
||||
Chip can store up to 40 bytes of user data in EEPROM,
|
||||
perform temp, voltage and current measurements.
|
||||
Chip also contains a unique serial number.
|
||||
|
||||
Always read/write LSb first
|
||||
|
||||
For documentaion, see data sheet for DS2438, 2438.pdf
|
||||
|
||||
By Thomas.Lange@corelatus.com 001025 */
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <mpc8xx.h>
|
||||
|
||||
#include <../board/gth/ee_dev.h>
|
||||
|
||||
/* We dont have kernel functions */
|
||||
#define printk printf
|
||||
#define KERN_DEBUG
|
||||
#define KERN_ERR
|
||||
#define EIO 1
|
||||
|
||||
static int Debug = 0;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lookup table ripped from DS app note 17, understanding and using
|
||||
* cyclic redundancy checks...
|
||||
*/
|
||||
|
||||
static u8 crc_lookup[256] = {
|
||||
0, 94, 188, 226, 97, 63, 221, 131,
|
||||
194, 156, 126, 32, 163, 253, 31, 65,
|
||||
157, 195, 33, 127, 252, 162, 64, 30,
|
||||
95, 1, 227, 189, 62, 96, 130, 220,
|
||||
35, 125, 159, 193, 66, 28, 254, 160,
|
||||
225, 191, 93, 3, 128, 222, 60, 98,
|
||||
190, 224, 2, 92, 223, 129, 99, 61,
|
||||
124, 34, 192, 158, 29, 67, 161, 255,
|
||||
70, 24, 250, 164, 39, 121, 155, 197,
|
||||
132, 218, 56, 102, 229, 187, 89, 7,
|
||||
219, 133, 103, 57, 186, 228, 6, 88,
|
||||
25, 71, 165, 251, 120, 38, 196, 154,
|
||||
101, 59, 217, 135, 4, 90, 184, 230,
|
||||
167, 249, 27, 69, 198, 152, 122, 36,
|
||||
248, 166, 68, 26, 153, 199, 37, 123,
|
||||
58, 100, 134, 216, 91, 5, 231, 185,
|
||||
140, 210, 48, 110, 237, 179, 81, 15,
|
||||
78, 16, 242, 172, 47, 113, 147, 205,
|
||||
17, 79, 173, 243, 112, 46, 204, 146,
|
||||
211, 141, 111, 49, 178, 236, 14, 80,
|
||||
175, 241, 19, 77, 206, 144, 114, 44,
|
||||
109, 51, 209, 143, 12, 82, 176, 238,
|
||||
50, 108, 142, 208, 83, 13, 239, 177,
|
||||
240, 174, 76, 18, 145, 207, 45, 115,
|
||||
202, 148, 118, 40, 171, 245, 23, 73,
|
||||
8, 86, 180, 234, 105, 55, 213, 139,
|
||||
87, 9, 235, 181, 54, 104, 138, 212,
|
||||
149, 203, 41, 119, 244, 170, 72, 22,
|
||||
233, 183, 85, 11, 136, 214, 52, 106,
|
||||
43, 117, 151, 201, 74, 20, 246, 168,
|
||||
116, 42, 200, 150, 21, 75, 169, 247,
|
||||
182, 232, 10, 84, 215, 137, 107, 53
|
||||
};
|
||||
|
||||
static u8 make_new_crc( u8 Old_crc, u8 New_value ){
|
||||
/* Compute a new checksum with new byte, using previous checksum as input
|
||||
See DS app note 17, understanding and using cyclic redundancy checks...
|
||||
Also see DS2438, page 11 */
|
||||
return( crc_lookup[Old_crc ^ New_value ]);
|
||||
}
|
||||
|
||||
int ee_crc_ok( u8 *Buffer, int Len, u8 Crc ){
|
||||
/* Check if the checksum for this buffer is correct */
|
||||
u8 Curr_crc=0;
|
||||
int i;
|
||||
u8 *Curr_byte = Buffer;
|
||||
|
||||
for(i=0;i<Len;i++){
|
||||
Curr_crc = make_new_crc( Curr_crc, *Curr_byte);
|
||||
Curr_byte++;
|
||||
}
|
||||
E_DEBUG("Calculated CRC = 0x%x, read = 0x%x\n", Curr_crc, Crc);
|
||||
|
||||
if(Curr_crc == Crc){
|
||||
/* Good */
|
||||
return(TRUE);
|
||||
}
|
||||
printk(KERN_ERR"EE checksum error, Calculated CRC = 0x%x, read = 0x%x\n",
|
||||
Curr_crc, Crc);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
set_idle(void){
|
||||
/* Send idle and keep start time
|
||||
Continous 1 is idle */
|
||||
WRITE_PORT(1);
|
||||
}
|
||||
|
||||
static int
|
||||
do_reset(void){
|
||||
/* Release reset and verify that chip responds with presence pulse */
|
||||
int Retries = 0;
|
||||
while(Retries<5){
|
||||
udelay(RESET_LOW_TIME);
|
||||
|
||||
/* Send reset */
|
||||
WRITE_PORT(0);
|
||||
udelay(RESET_LOW_TIME);
|
||||
|
||||
/* Release reset */
|
||||
WRITE_PORT(1);
|
||||
|
||||
/* Wait for EEPROM to drive output */
|
||||
udelay(PRESENCE_TIMEOUT);
|
||||
if(!READ_PORT){
|
||||
/* Ok, EEPROM is driving a 0 */
|
||||
E_DEBUG("Presence detected\n");
|
||||
if(Retries){
|
||||
E_DEBUG("Retries %d\n",Retries);
|
||||
}
|
||||
/* Make sure chip releases pin */
|
||||
udelay(PRESENCE_LOW_TIME);
|
||||
return 0;
|
||||
}
|
||||
Retries++;
|
||||
}
|
||||
|
||||
printk(KERN_ERR"EEPROM did not respond when releasing reset\n");
|
||||
|
||||
/* Make sure chip releases pin */
|
||||
udelay(PRESENCE_LOW_TIME);
|
||||
|
||||
/* Set to idle again */
|
||||
set_idle();
|
||||
|
||||
return(-EIO);
|
||||
}
|
||||
|
||||
static u8
|
||||
read_byte(void){
|
||||
/* Read a single byte from EEPROM
|
||||
Read LSb first */
|
||||
int i;
|
||||
int Value;
|
||||
u8 Result=0;
|
||||
#ifndef CFG_IMMR
|
||||
u32 Flags;
|
||||
#endif
|
||||
|
||||
E_DEBUG("Reading byte\n");
|
||||
|
||||
for(i=0;i<8;i++){
|
||||
/* Small delay between pulses */
|
||||
udelay(1);
|
||||
|
||||
#ifndef CFG_IMMR
|
||||
/* Disable irq */
|
||||
save_flags(Flags);
|
||||
cli();
|
||||
#endif
|
||||
|
||||
/* Pull down pin short time to start read
|
||||
See page 26 in data sheet */
|
||||
|
||||
WRITE_PORT(0);
|
||||
udelay(READ_LOW);
|
||||
WRITE_PORT(1);
|
||||
|
||||
/* Wait for chip to drive pin */
|
||||
udelay(READ_TIMEOUT);
|
||||
|
||||
Value = READ_PORT;
|
||||
if(Value)
|
||||
Value=1;
|
||||
|
||||
#ifndef CFG_IMMR
|
||||
/* Enable irq */
|
||||
restore_flags(Flags);
|
||||
#endif
|
||||
|
||||
/* Wait for chip to release pin */
|
||||
udelay(TOTAL_READ_LOW-READ_TIMEOUT);
|
||||
|
||||
/* LSb first */
|
||||
Result|=Value<<i;
|
||||
}
|
||||
|
||||
E_DEBUG("Read byte 0x%x\n",Result);
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void
|
||||
write_byte(u8 Byte){
|
||||
/* Write a single byte to EEPROM
|
||||
Write LSb first */
|
||||
int i;
|
||||
int Value;
|
||||
#ifndef CFG_IMMR
|
||||
u32 Flags;
|
||||
#endif
|
||||
|
||||
E_DEBUG("Writing byte 0x%x\n",Byte);
|
||||
|
||||
for(i=0;i<8;i++){
|
||||
/* Small delay between pulses */
|
||||
udelay(1);
|
||||
Value = Byte&1;
|
||||
|
||||
#ifndef CFG_IMMR
|
||||
/* Disable irq */
|
||||
save_flags(Flags);
|
||||
cli();
|
||||
#endif
|
||||
|
||||
/* Pull down pin short time for a 1, long time for a 0
|
||||
See page 26 in data sheet */
|
||||
|
||||
WRITE_PORT(0);
|
||||
if(Value){
|
||||
/* Write a 1 */
|
||||
udelay(WRITE_1_LOW);
|
||||
}
|
||||
else{
|
||||
/* Write a 0 */
|
||||
udelay(WRITE_0_LOW);
|
||||
}
|
||||
|
||||
WRITE_PORT(1);
|
||||
|
||||
#ifndef CFG_IMMR
|
||||
/* Enable irq */
|
||||
restore_flags(Flags);
|
||||
#endif
|
||||
|
||||
if(Value)
|
||||
/* Wait for chip to read the 1 */
|
||||
udelay(TOTAL_WRITE_LOW-WRITE_1_LOW);
|
||||
Byte>>=1;
|
||||
}
|
||||
}
|
||||
|
||||
int ee_do_command( u8 *Tx, int Tx_len, u8 *Rx, int Rx_len, int Send_skip ){
|
||||
/* Execute this command string, including
|
||||
giving reset and setting to idle after command
|
||||
if Rx_len is set, we read out data from EEPROM */
|
||||
int i;
|
||||
|
||||
E_DEBUG("Command, Tx_len %d, Rx_len %d\n", Tx_len, Rx_len );
|
||||
|
||||
if(do_reset()){
|
||||
/* Failed! */
|
||||
return(-EIO);
|
||||
}
|
||||
|
||||
if(Send_skip)
|
||||
/* Always send SKIP_ROM first to tell chip we are sending a command,
|
||||
except when we read out rom data for chip */
|
||||
write_byte(SKIP_ROM);
|
||||
|
||||
/* Always have Tx data */
|
||||
for(i=0;i<Tx_len;i++){
|
||||
write_byte(Tx[i]);
|
||||
}
|
||||
|
||||
if(Rx_len){
|
||||
for(i=0;i<Rx_len;i++){
|
||||
Rx[i]=read_byte();
|
||||
}
|
||||
}
|
||||
|
||||
set_idle();
|
||||
|
||||
E_DEBUG("Command done\n");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int ee_init_data(void){
|
||||
int i;
|
||||
u8 Tx[10];
|
||||
int tmp;
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
|
||||
while(0){
|
||||
tmp = 1-tmp;
|
||||
if(tmp)
|
||||
immap->im_ioport.iop_padat &= ~PA_FRONT_LED;
|
||||
else
|
||||
immap->im_ioport.iop_padat |= PA_FRONT_LED;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* Set port to open drain to be able to read data from
|
||||
port without setting it to input */
|
||||
PORT_B_PAR &= ~PB_EEPROM;
|
||||
PORT_B_ODR |= PB_EEPROM;
|
||||
SET_PORT_B_OUTPUT(PB_EEPROM);
|
||||
|
||||
/* Set idle mode */
|
||||
set_idle();
|
||||
|
||||
/* Copy all User EEPROM data to scratchpad */
|
||||
for(i=0;i<USER_PAGES;i++){
|
||||
Tx[0]=RECALL_MEMORY;
|
||||
Tx[1]=EE_USER_PAGE_0+i;
|
||||
if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO);
|
||||
}
|
||||
|
||||
/* Make sure chip doesnt store measurements in NVRAM */
|
||||
Tx[0]=WRITE_SCRATCHPAD;
|
||||
Tx[1]=0; /* Page */
|
||||
Tx[2]=9;
|
||||
if(ee_do_command(Tx,3,NULL,0,TRUE)) return(-EIO);
|
||||
|
||||
Tx[0]=COPY_SCRATCHPAD;
|
||||
if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO);
|
||||
|
||||
/* FIXME check status bit instead
|
||||
Could take 10 ms to store in EEPROM */
|
||||
for(i=0;i<10;i++){
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
|
@ -0,0 +1,649 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Protection Flags:
|
||||
*/
|
||||
#define FLAG_PROTECT_SET 0x01
|
||||
#define FLAG_PROTECT_CLEAR 0x02
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long size_b0, size_b1;
|
||||
int i;
|
||||
|
||||
/*printf("faking");*/
|
||||
|
||||
return(0x1fffff);
|
||||
|
||||
/* 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 - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (FLASH_BASE1_PRELIM != 0x0) {
|
||||
size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,size_b0, size_b0<<20);
|
||||
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
size_b1 = 0;
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR0_PRELIM;
|
||||
memctl->memc_br0 = CFG_BR0_PRELIM;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
|
||||
/* monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_MONITOR_BASE,
|
||||
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
if (size_b1)
|
||||
{
|
||||
/* memctl->memc_or1 = CFG_OR1_PRELIM;
|
||||
memctl->memc_br1 = CFG_BR1_PRELIM; */
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
|
||||
&flash_info[1]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
|
||||
|
||||
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
|
||||
/* monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_MONITOR_BASE,
|
||||
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[1]);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* memctl->memc_or1 = CFG_OR1_PRELIM;
|
||||
FIXME memctl->memc_br1 = CFG_BR1_PRELIM; */
|
||||
|
||||
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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start adress table */
|
||||
if (info->flash_id & FLASH_BTYPE)
|
||||
{
|
||||
/* set sector offsets for bottom boot block type */
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
{
|
||||
info->start[i] = base + (i * 0x00040000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
info->start[i] = base + i * 0x00040000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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) {
|
||||
|
||||
#if 0
|
||||
case FLASH_AM040B:
|
||||
printf ("AM29F040B (4 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AM040T:
|
||||
printf ("AM29F040T (4 Mbit, top boot sect)\n");
|
||||
break;
|
||||
#endif
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
#if 0
|
||||
ulong base = (ulong)addr;
|
||||
#endif
|
||||
uchar value;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x90909090;
|
||||
#endif
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case AMD_MANUFACT:case 0x01:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value)
|
||||
{
|
||||
#if 0
|
||||
case AMD_ID_F040B:
|
||||
info->flash_id += FLASH_AM040B;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
#endif
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* set up sector start adress table */
|
||||
if (info->flash_id & FLASH_BTYPE) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
info->start[0] = base + 0x00000000;
|
||||
info->start[1] = base + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
#else
|
||||
flash_get_offsets ((ulong)addr, &flash_info[0]);
|
||||
#endif
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN)
|
||||
{
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
#if 0
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
#else
|
||||
*addr = 0xF0F0F0F0; /* reset bank */
|
||||
#endif
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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 - aborted\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;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x80808080;
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
#endif
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
#if 0
|
||||
addr[0] = 0x00300030;
|
||||
#else
|
||||
addr[0] = 0x30303030;
|
||||
#endif
|
||||
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_long*)(info->start[l_sect]);
|
||||
#if 0
|
||||
while ((addr[0] & 0x00800080) != 0x00800080)
|
||||
#else
|
||||
while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
|
||||
#endif
|
||||
{
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
#if 0
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
#else
|
||||
addr[0] = 0xF0F0F0F0; /* reset bank */
|
||||
#endif
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0xA0A0A0A0;
|
||||
#endif
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
#if 0
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
|
||||
#else
|
||||
while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
|
||||
#endif
|
||||
{
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_byte (flash_info_t *info, ulong dest, uchar data);
|
||||
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 memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long size;
|
||||
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 - FIXME XXX */
|
||||
|
||||
size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
|
||||
|
||||
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
|
||||
printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
|
||||
size, size<<20);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) |
|
||||
(memctl->memc_br0 & ~(BR_BA_MSK));
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#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
|
||||
|
||||
flash_info[0].size = size;
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 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 * 0x00010000) - 0x00030000;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
uchar value;
|
||||
vu_char *caddr = (vu_char *)addr;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
caddr[0x0AAA] = 0xAA;
|
||||
caddr[0x0555] = 0x55;
|
||||
caddr[0x0AAA] = 0x90;
|
||||
|
||||
value = caddr[0];
|
||||
switch (value) {
|
||||
case (AMD_MANUFACT & 0xFF):
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case (FUJ_MANUFACT & 0xFF):
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = caddr[2]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case (AMD_ID_LV400T & 0xFF):
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512 kB */
|
||||
|
||||
case (AMD_ID_LV400B & 0xFF):
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512 kB */
|
||||
|
||||
case (AMD_ID_LV800T & 0xFF):
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (AMD_ID_LV800B & 0xFF):
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (AMD_ID_LV160T & 0xFF):
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case (AMD_ID_LV160B & 0xFF):
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case (AMD_ID_LV320T & 0xFF):
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case (AMD_ID_LV320B & 0xFF):
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* 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 * 0x00010000) - 0x00030000;
|
||||
}
|
||||
} 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: D0 = 1 if protected */
|
||||
caddr = (volatile unsigned char *)(info->start[i]);
|
||||
info->protect[i] = caddr[4] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
caddr = (vu_char *)info->start[0];
|
||||
|
||||
*caddr = 0xF0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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[0x0AAA] = 0xAA;
|
||||
addr[0x0555] = 0x55;
|
||||
addr[0x0AAA] = 0x80;
|
||||
addr[0x0AAA] = 0xAA;
|
||||
addr[0x0555] = 0x55;
|
||||
|
||||
/* 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 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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (vu_char *)info->start[0];
|
||||
addr[0] = 0xF0; /* reset bank */
|
||||
|
||||
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)
|
||||
{
|
||||
int rc;
|
||||
|
||||
while (cnt > 0) {
|
||||
if ((rc = write_byte(info, addr++, *src++)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
--cnt;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word 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[0x0AAA] = 0xAA;
|
||||
addr[0x0555] = 0x55;
|
||||
addr[0x0AAA] = 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);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,597 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Murray Jensen, CSIRO Manufacturing Science and Technology,
|
||||
* <Murray.Jensen@cmst.csiro.au>
|
||||
*
|
||||
* 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 <mpc8260.h>
|
||||
|
||||
/* imports from fetch.c */
|
||||
extern int fetch_and_parse(bd_t *, char *, ulong, int (*)(uchar *, uchar *));
|
||||
|
||||
int
|
||||
eeprom_load(unsigned offset, hymod_eeprom_t *ep)
|
||||
{
|
||||
uchar data[HYMOD_EEPROM_SIZE], *dp, *edp;
|
||||
hymod_eehdr_t *hp;
|
||||
ulong len, crc;
|
||||
|
||||
memset(ep, 0, sizeof *ep);
|
||||
memset(data, 0, HYMOD_EEPROM_SIZE);
|
||||
crc = 0;
|
||||
|
||||
hp = (hymod_eehdr_t *)data;
|
||||
eeprom_read(CFG_DEF_EEPROM_ADDR, offset, (uchar *)hp, sizeof (*hp));
|
||||
offset += sizeof (*hp);
|
||||
|
||||
if (hp->id != HYMOD_EEPROM_ID || hp->ver > HYMOD_EEPROM_VER ||
|
||||
(len = hp->len) > HYMOD_EEPROM_MAXLEN)
|
||||
return (0);
|
||||
|
||||
dp = (uchar *)(hp + 1); edp = dp + len;
|
||||
eeprom_read(CFG_DEF_EEPROM_ADDR, offset, dp, len);
|
||||
offset += len;
|
||||
|
||||
eeprom_read(CFG_DEF_EEPROM_ADDR, offset, (uchar *)&crc, sizeof (ulong));
|
||||
|
||||
if (crc32(0, data, edp - data) != crc)
|
||||
return (0);
|
||||
|
||||
ep->ver = hp->ver;
|
||||
|
||||
for (;;) {
|
||||
hymod_eerec_t *rp = (hymod_eerec_t *)dp;
|
||||
ulong rtyp;
|
||||
uchar rlen, *rdat;
|
||||
uint rsiz;
|
||||
|
||||
if (rp->small.topbit == 0) {
|
||||
rtyp = rp->small.type;
|
||||
rlen = rp->small.len;
|
||||
rdat = rp->small.data;
|
||||
rsiz = offsetof(hymod_eerec_t, small.data) + rlen;
|
||||
}
|
||||
else if (rp->medium.nxtbit == 0) {
|
||||
rtyp = rp->medium.type;
|
||||
rlen = rp->medium.len;
|
||||
rdat = rp->medium.data;
|
||||
rsiz = offsetof(hymod_eerec_t, medium.data) + rlen;
|
||||
}
|
||||
else {
|
||||
rtyp = rp->large.type;
|
||||
rlen = rp->large.len;
|
||||
rdat = rp->large.data;
|
||||
rsiz = offsetof(hymod_eerec_t, large.data) + rlen;
|
||||
}
|
||||
|
||||
if (rtyp == 0)
|
||||
break;
|
||||
|
||||
dp += rsiz;
|
||||
if (dp > edp) /* error? */
|
||||
break;
|
||||
|
||||
switch (rtyp) {
|
||||
|
||||
case HYMOD_EEREC_SERNO: /* serial number */
|
||||
if (rlen == sizeof (ulong))
|
||||
memcpy(&ep->serno, rdat, sizeof (ulong));
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_DATE: /* date */
|
||||
if (rlen == sizeof (hymod_date_t))
|
||||
memcpy(&ep->date, rdat, sizeof (hymod_date_t));
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_BATCH: /* batch */
|
||||
if (rlen <= HYMOD_MAX_BATCH)
|
||||
memcpy(ep->batch, rdat, ep->batchlen = rlen);
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_TYPE: /* board type */
|
||||
if (rlen == 1)
|
||||
ep->bdtype = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_REV: /* board revision */
|
||||
if (rlen == 1)
|
||||
ep->bdrev = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_SDRAM: /* sdram size(s) */
|
||||
if (rlen > 0 && rlen <= HYMOD_MAX_SDRAM) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rlen; i++)
|
||||
ep->sdramsz[i] = rdat[i];
|
||||
ep->nsdram = rlen;
|
||||
}
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_FLASH: /* flash size(s) */
|
||||
if (rlen > 0 && rlen <= HYMOD_MAX_FLASH) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rlen; i++)
|
||||
ep->flashsz[i] = rdat[i];
|
||||
ep->nflash = rlen;
|
||||
}
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_ZBT: /* zbt ram size(s) */
|
||||
if (rlen > 0 && rlen <= HYMOD_MAX_ZBT) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rlen; i++)
|
||||
ep->zbtsz[i] = rdat[i];
|
||||
ep->nzbt = rlen;
|
||||
}
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_XLXTYP: /* xilinx fpga type(s) */
|
||||
if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rlen; i++)
|
||||
ep->xlx[i].type = rdat[i];
|
||||
ep->nxlx = rlen;
|
||||
}
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_XLXSPD: /* xilinx fpga speed(s) */
|
||||
if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rlen; i++)
|
||||
ep->xlx[i].speed = rdat[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_XLXTMP: /* xilinx fpga temperature(s) */
|
||||
if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rlen; i++)
|
||||
ep->xlx[i].temp = rdat[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_XLXGRD: /* xilinx fpga grade(s) */
|
||||
if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rlen; i++)
|
||||
ep->xlx[i].grade = rdat[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_CPUTYP: /* CPU type */
|
||||
if (rlen == 1)
|
||||
ep->mpc.type = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_CPUSPD: /* CPU speed */
|
||||
if (rlen == 1)
|
||||
ep->mpc.cpuspd = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_CPMSPD: /* CPM speed */
|
||||
if (rlen == 1)
|
||||
ep->mpc.cpmspd = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_BUSSPD: /* bus speed */
|
||||
if (rlen == 1)
|
||||
ep->mpc.busspd = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_HSTYPE: /* high-speed serial chip type */
|
||||
if (rlen == 1)
|
||||
ep->hss.type = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_HSCHIN: /* high-speed serial input channels */
|
||||
if (rlen == 1)
|
||||
ep->hss.nchin = *rdat;
|
||||
break;
|
||||
|
||||
case HYMOD_EEREC_HSCHOUT: /* high-speed serial output channels */
|
||||
if (rlen == 1)
|
||||
ep->hss.nchout = *rdat;
|
||||
break;
|
||||
|
||||
default: /* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* maps an ascii "name=value" into a binary eeprom data record */
|
||||
typedef
|
||||
struct _eerec_map {
|
||||
char *name;
|
||||
uint type;
|
||||
uchar *(*handler)(struct _eerec_map *, uchar *, uchar *, uchar *);
|
||||
uint length;
|
||||
uint maxlen;
|
||||
}
|
||||
eerec_map_t;
|
||||
|
||||
static uchar *
|
||||
uint_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
|
||||
{
|
||||
uchar *eval;
|
||||
union {
|
||||
uchar cval[4];
|
||||
ushort sval[2];
|
||||
ulong lval;
|
||||
} rdata;
|
||||
|
||||
rdata.lval = simple_strtol(value, (char **)&eval, 10);
|
||||
|
||||
if (eval == value || *eval != '\0') {
|
||||
printf("%s record (%s) is not a valid uint\n", rp->name, value);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (dp + 2 + rp->length > edp) {
|
||||
printf("can't fit %s record into eeprom\n", rp->name);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*dp++ = rp->type;
|
||||
*dp++ = rp->length;
|
||||
|
||||
switch (rp->length) {
|
||||
|
||||
case 1:
|
||||
if (rdata.lval >= 256) {
|
||||
printf("%s record value (%lu) out of range (0-255)\n",
|
||||
rp->name, rdata.lval);
|
||||
return (NULL);
|
||||
}
|
||||
*dp++ = rdata.cval[3];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (rdata.lval >= 65536) {
|
||||
printf("%s record value (%lu) out of range (0-65535)\n",
|
||||
rp->name, rdata.lval);
|
||||
return (NULL);
|
||||
}
|
||||
memcpy(dp, &rdata.sval[1], 2);
|
||||
dp += 2;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
memcpy(dp, &rdata.lval, 4);
|
||||
dp += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("huh? rp->length not 1, 2 or 4! (%d)\n", rp->length);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (dp);
|
||||
}
|
||||
|
||||
static uchar *
|
||||
date_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
|
||||
{
|
||||
hymod_date_t date;
|
||||
uchar *p = value, *ep;
|
||||
|
||||
date.year = simple_strtol(p, (char **)&ep, 10);
|
||||
if (ep == p || *ep++ != '-') {
|
||||
bad_date:
|
||||
printf("%s record (%s) is not a valid date\n", rp->name, value);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
date.month = simple_strtol(p = ep, (char **)&ep, 10);
|
||||
if (ep == p || *ep++ != '-' || date.month == 0 || date.month > 12)
|
||||
goto bad_date;
|
||||
|
||||
date.day = simple_strtol(p = ep, (char **)&ep, 10);
|
||||
if (ep == p || *ep != '\0' || date.day == 0 || date.day > 31)
|
||||
goto bad_date;
|
||||
|
||||
if (dp + 2 + sizeof (hymod_date_t) > edp) {
|
||||
printf("can't fit %s record into eeprom\n", rp->name);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*dp++ = rp->type;
|
||||
*dp++ = sizeof (hymod_date_t);
|
||||
memcpy(dp, &date, sizeof (hymod_date_t));
|
||||
dp += sizeof (hymod_date_t);
|
||||
|
||||
return (dp);
|
||||
}
|
||||
|
||||
static uchar *
|
||||
string_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
|
||||
{
|
||||
uint len;
|
||||
|
||||
if ((len = strlen(value)) > rp->maxlen) {
|
||||
printf("%s record (%s) string is too long (%d>%d)\n",
|
||||
rp->name, value, len, rp->maxlen);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (dp + 2 + len > edp) {
|
||||
printf("can't fit %s record into eeprom\n", rp->name);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*dp++ = rp->type;
|
||||
*dp++ = len;
|
||||
memcpy(dp, value, len);
|
||||
dp += len;
|
||||
|
||||
return (dp);
|
||||
}
|
||||
|
||||
static uchar *
|
||||
bytes_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
|
||||
{
|
||||
uchar bytes[HYMOD_MAX_BYTES], nbytes = 0;
|
||||
uchar *p = value, *ep;
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (nbytes >= HYMOD_MAX_BYTES) {
|
||||
printf("%s record (%s) byte array too long\n", rp->name, value);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
bytes[nbytes++] = simple_strtol(p, (char **)&ep, 10);
|
||||
|
||||
if (ep == p || (*ep != '\0' && *ep != ',')) {
|
||||
printf("%s record (%s) byte array has invalid uint\n",
|
||||
rp->name, value);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (*ep++ == '\0')
|
||||
break;
|
||||
|
||||
p = ep;
|
||||
}
|
||||
|
||||
if (dp + 2 + nbytes > edp) {
|
||||
printf("can't fit %s record into eeprom\n", rp->name);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*dp++ = rp->type;
|
||||
*dp++ = nbytes;
|
||||
memcpy(dp, bytes, nbytes);
|
||||
dp += nbytes;
|
||||
|
||||
return (dp);
|
||||
}
|
||||
|
||||
static eerec_map_t eerec_map[] = {
|
||||
/* name type handler len max */
|
||||
{ "serno", HYMOD_EEREC_SERNO, uint_handler, 4, 0 },
|
||||
{ "date", HYMOD_EEREC_DATE, date_handler, 4, 0 },
|
||||
{ "batch", HYMOD_EEREC_BATCH, string_handler, 0, HYMOD_MAX_BATCH },
|
||||
{ "type", HYMOD_EEREC_TYPE, uint_handler, 1, 0 },
|
||||
{ "rev", HYMOD_EEREC_REV, uint_handler, 1, 0 },
|
||||
{ "sdram", HYMOD_EEREC_SDRAM, bytes_handler, 0, HYMOD_MAX_SDRAM },
|
||||
{ "flash", HYMOD_EEREC_FLASH, bytes_handler, 0, HYMOD_MAX_FLASH },
|
||||
{ "zbt", HYMOD_EEREC_ZBT, bytes_handler, 0, HYMOD_MAX_ZBT },
|
||||
{ "xlxtyp", HYMOD_EEREC_XLXTYP, bytes_handler, 0, HYMOD_MAX_XLX },
|
||||
{ "xlxspd", HYMOD_EEREC_XLXSPD, bytes_handler, 0, HYMOD_MAX_XLX },
|
||||
{ "xlxtmp", HYMOD_EEREC_XLXTMP, bytes_handler, 0, HYMOD_MAX_XLX },
|
||||
{ "xlxgrd", HYMOD_EEREC_XLXGRD, bytes_handler, 0, HYMOD_MAX_XLX },
|
||||
{ "cputyp", HYMOD_EEREC_CPUTYP, uint_handler, 1, 0 },
|
||||
{ "cpuspd", HYMOD_EEREC_CPUSPD, uint_handler, 1, 0 },
|
||||
{ "cpmspd", HYMOD_EEREC_CPMSPD, uint_handler, 1, 0 },
|
||||
{ "busspd", HYMOD_EEREC_BUSSPD, uint_handler, 1, 0 },
|
||||
{ "hstype", HYMOD_EEREC_HSTYPE, uint_handler, 1, 0 },
|
||||
{ "hschin", HYMOD_EEREC_HSCHIN, uint_handler, 1, 0 },
|
||||
{ "hschout", HYMOD_EEREC_HSCHOUT, uint_handler, 1, 0 },
|
||||
};
|
||||
|
||||
static int neerecs = sizeof eerec_map / sizeof eerec_map[0];
|
||||
|
||||
static uchar data[HYMOD_EEPROM_SIZE], *sdp, *dp, *edp;
|
||||
|
||||
static int
|
||||
eeprom_fetch_callback(uchar *name, uchar *value)
|
||||
{
|
||||
eerec_map_t *rp;
|
||||
|
||||
for (rp = eerec_map; rp < &eerec_map[neerecs]; rp++)
|
||||
if (strcmp(name, rp->name) == 0)
|
||||
break;
|
||||
|
||||
if (rp >= &eerec_map[neerecs])
|
||||
return (0);
|
||||
|
||||
if ((dp = (*rp->handler)(rp, value, dp, edp)) == NULL)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
eeprom_fetch(unsigned offset, bd_t *bd, char *filename, ulong addr)
|
||||
{
|
||||
hymod_eehdr_t *hp = (hymod_eehdr_t *)&data[0];
|
||||
ulong crc;
|
||||
|
||||
hp->id = HYMOD_EEPROM_ID;
|
||||
hp->ver = HYMOD_EEPROM_VER;
|
||||
|
||||
dp = sdp = (uchar *)(hp + 1);
|
||||
edp = dp + HYMOD_EEPROM_MAXLEN;
|
||||
|
||||
if (fetch_and_parse(bd, filename, addr, eeprom_fetch_callback) == 0)
|
||||
return (0);
|
||||
|
||||
hp->len = dp - sdp;
|
||||
|
||||
crc = crc32(0, data, dp - data);
|
||||
memcpy(dp, &crc, sizeof (ulong));
|
||||
dp += sizeof (ulong);
|
||||
|
||||
eeprom_write(CFG_DEF_EEPROM_ADDR, offset, data, dp - data);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static char *type_vals[] = {
|
||||
"NONE", "IO", "CLP", "DSP", "INPUT", "ALT-INPUT", "DISPLAY"
|
||||
};
|
||||
|
||||
static char *xlxtyp_vals[] = {
|
||||
"NONE", "XCV300E", "XCV400E", "XCV600E"
|
||||
};
|
||||
|
||||
static char *xlxspd_vals[] = {
|
||||
"NONE", "6", "7", "8"
|
||||
};
|
||||
|
||||
static char *xlxtmp_vals[] = {
|
||||
"NONE", "COM", "IND"
|
||||
};
|
||||
|
||||
static char *xlxgrd_vals[] = {
|
||||
"NONE", "NORMAL", "ENGSAMP"
|
||||
};
|
||||
|
||||
static char *cputyp_vals[] = {
|
||||
"NONE", "MPC8260"
|
||||
};
|
||||
|
||||
static char *clk_vals[] = {
|
||||
"NONE", "33", "66", "100", "133", "166", "200"
|
||||
};
|
||||
|
||||
static char *hstype_vals[] = {
|
||||
"NONE", "AMCC-S2064A"
|
||||
};
|
||||
|
||||
static void
|
||||
print_mem(char *l, char *s, uchar n, uchar a[])
|
||||
{
|
||||
if (n > 0) {
|
||||
if (n == 1)
|
||||
printf("%s%dMB %s", s, 1 << (a[0] - 20), l);
|
||||
else {
|
||||
ulong t = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
t += 1 << (a[i] - 20);
|
||||
|
||||
printf("%s%luMB %s (%d banks:", s, t, l, n);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
printf("%dMB%s", 1 << (a[i] - 20), (i == n - 1) ? ")" : ",");
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("%sNO %s", s, l);
|
||||
}
|
||||
|
||||
void
|
||||
eeprom_print(hymod_eeprom_t *ep)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf(" Hymod %s board, rev %03d\n",
|
||||
type_vals[ep->bdtype], ep->bdrev);
|
||||
|
||||
printf(" serial #: %010lu, date %04d-%02d-%02d",
|
||||
ep->serno, ep->date.year, ep->date.month, ep->date.day);
|
||||
if (ep->batchlen > 0)
|
||||
printf(", batch \"%.*s\"", ep->batchlen, ep->batch);
|
||||
puts("\n");
|
||||
|
||||
switch (ep->bdtype) {
|
||||
|
||||
case HYMOD_BDTYPE_IO:
|
||||
case HYMOD_BDTYPE_CLP:
|
||||
case HYMOD_BDTYPE_DSP:
|
||||
printf(" Motorola %s CPU, speeds: %s/%s/%s",
|
||||
cputyp_vals[ep->mpc.type], clk_vals[ep->mpc.cpuspd],
|
||||
clk_vals[ep->mpc.cpmspd], clk_vals[ep->mpc.busspd]);
|
||||
|
||||
print_mem("SDRAM", ", ", ep->nsdram, ep->sdramsz);
|
||||
|
||||
print_mem("FLASH", ", ", ep->nflash, ep->flashsz);
|
||||
|
||||
puts("\n");
|
||||
|
||||
print_mem("ZBT", " ", ep->nzbt, ep->zbtsz);
|
||||
|
||||
if (ep->nxlx > 0) {
|
||||
hymod_xlx_t *xp;
|
||||
|
||||
if (ep->nxlx == 1) {
|
||||
xp = &ep->xlx[0];
|
||||
printf(", Xilinx %s FPGA (%s/%s/%s)",
|
||||
xlxtyp_vals[xp->type], xlxspd_vals[xp->speed],
|
||||
xlxtmp_vals[xp->temp], xlxgrd_vals[xp->grade]);
|
||||
}
|
||||
else {
|
||||
printf(", %d Xilinx FPGAs (", ep->nxlx);
|
||||
for (i = 0; i < ep->nxlx; i++) {
|
||||
xp = &ep->xlx[i];
|
||||
printf("%s[%s/%s/%s]%s",
|
||||
xlxtyp_vals[xp->type], xlxspd_vals[xp->speed],
|
||||
xlxtmp_vals[xp->temp], xlxgrd_vals[xp->grade],
|
||||
(i == ep->nxlx - 1) ? ")" : ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
puts(", NO FPGAs");
|
||||
|
||||
puts("\n");
|
||||
|
||||
if (ep->hss.type > 0)
|
||||
printf(" High Speed Serial: %s, %d input%s, %d output%s\n",
|
||||
hstype_vals[ep->hss.type],
|
||||
ep->hss.nchin, (ep->hss.nchin == 1 ? "" : "s"),
|
||||
ep->hss.nchout, (ep->hss.nchout == 1 ? "" : "s"));
|
||||
break;
|
||||
|
||||
case HYMOD_BDTYPE_INPUT:
|
||||
case HYMOD_BDTYPE_ALTINPUT:
|
||||
case HYMOD_BDTYPE_DISPLAY:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* crap! */
|
||||
printf(" UNKNOWN BOARD TYPE: %d\n", ep->bdtype);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,745 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*
|
||||
* Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mpc8260.h>
|
||||
#include <board/hymod/flash.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Protection Flags:
|
||||
*/
|
||||
#define FLAG_PROTECT_SET 0x01
|
||||
#define FLAG_PROTECT_CLEAR 0x02
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
#if 0
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
#endif
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* probe for the existence of flash at bank word address "addr"
|
||||
* 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id
|
||||
*/
|
||||
static int
|
||||
bank_probe_word(bank_addr_t addr)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* reset the flash */
|
||||
*addr = BANK_CMD_RST;
|
||||
|
||||
/* check the manufacturer id */
|
||||
*addr = BANK_CMD_RD_ID;
|
||||
if (*BANK_ADDR_REG_MAN(addr) != BANK_RD_ID_MAN) {
|
||||
retval = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check the device id */
|
||||
*addr = BANK_CMD_RD_ID;
|
||||
if (*BANK_ADDR_REG_DEV(addr) != BANK_RD_ID_DEV) {
|
||||
retval = -2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = CFG_FLASH_TYPE;
|
||||
|
||||
out:
|
||||
/* reset the flash again */
|
||||
*addr = BANK_CMD_RST;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* probe for flash banks at address "base" and store info for any found
|
||||
* into flash_info entry "fip". Must find at least one bank.
|
||||
*/
|
||||
static void
|
||||
bank_probe(flash_info_t *fip, bank_addr_t base)
|
||||
{
|
||||
bank_addr_t addr, eaddr;
|
||||
int nbanks;
|
||||
|
||||
fip->flash_id = FLASH_UNKNOWN;
|
||||
fip->size = 0L;
|
||||
fip->sector_count = 0;
|
||||
|
||||
addr = base;
|
||||
eaddr = BANK_ADDR_BASE(addr, MAX_BANKS);
|
||||
nbanks = 0;
|
||||
|
||||
while (addr < eaddr) {
|
||||
bank_addr_t addrw, eaddrw, addrb;
|
||||
int i, osc, nsc, curtype = -1;
|
||||
|
||||
addrw = addr;
|
||||
eaddrw = BANK_ADDR_NEXT_WORD(addrw);
|
||||
|
||||
while (addrw < eaddrw) {
|
||||
int thistype;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" probing for flash at addr 0x%08lx\n",
|
||||
(unsigned long)addrw);
|
||||
#endif
|
||||
if ((thistype = bank_probe_word(addrw++)) < 0)
|
||||
goto out;
|
||||
|
||||
if (curtype < 0)
|
||||
curtype = thistype;
|
||||
else {
|
||||
if (thistype != curtype) {
|
||||
printf("Differing flash type found!\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curtype < 0)
|
||||
goto out;
|
||||
|
||||
/* bank exists - append info for this bank to *fip */
|
||||
fip->flash_id = FLASH_MAN_INTEL|curtype;
|
||||
fip->size += BANK_SIZE;
|
||||
osc = fip->sector_count;
|
||||
fip->sector_count += BANK_NBLOCKS;
|
||||
if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT)
|
||||
panic("Too many sectors in flash at address 0x%08lx\n",
|
||||
(unsigned long)base);
|
||||
|
||||
addrb = addr;
|
||||
for (i = osc; i < nsc; i++) {
|
||||
fip->start[i] = (ulong)addrb;
|
||||
fip->protect[i] = 0;
|
||||
addrb = BANK_ADDR_NEXT_BLK(addrb);
|
||||
}
|
||||
|
||||
addr = BANK_ADDR_NEXT_BANK(addr);
|
||||
nbanks++;
|
||||
}
|
||||
|
||||
out:
|
||||
if (nbanks == 0)
|
||||
panic("ERROR: no flash found at address 0x%08lx\n",
|
||||
(unsigned long)base);
|
||||
}
|
||||
|
||||
static void
|
||||
bank_reset(flash_info_t *info, int sect)
|
||||
{
|
||||
bank_addr_t addrw, eaddrw;
|
||||
|
||||
addrw = (bank_addr_t)info->start[sect];
|
||||
eaddrw = BANK_ADDR_NEXT_WORD(addrw);
|
||||
|
||||
while (addrw < eaddrw) {
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" writing reset cmd to addr 0x%08lx\n",
|
||||
(unsigned long)addrw);
|
||||
#endif
|
||||
*addrw = BANK_CMD_RST;
|
||||
addrw++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bank_erase_init(flash_info_t *info, int sect)
|
||||
{
|
||||
bank_addr_t addrw, saddrw, eaddrw;
|
||||
int flag;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("0x%08lx BANK_CMD_PROG\n", BANK_CMD_PROG);
|
||||
printf("0x%08lx BANK_CMD_ERASE1\n", BANK_CMD_ERASE1);
|
||||
printf("0x%08lx BANK_CMD_ERASE2\n", BANK_CMD_ERASE2);
|
||||
printf("0x%08lx BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT);
|
||||
printf("0x%08lx BANK_CMD_RST\n", BANK_CMD_RST);
|
||||
printf("0x%08lx BANK_STAT_RDY\n", BANK_STAT_RDY);
|
||||
printf("0x%08lx BANK_STAT_ERR\n", BANK_STAT_ERR);
|
||||
#endif
|
||||
|
||||
saddrw = (bank_addr_t)info->start[sect];
|
||||
eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("erasing sector %d, start addr = 0x%08lx "
|
||||
"(bank next word addr = 0x%08lx)\n", sect,
|
||||
(unsigned long)saddrw, (unsigned long)eaddrw);
|
||||
#endif
|
||||
|
||||
/* Disable intrs which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
for (addrw = saddrw; addrw < eaddrw; addrw++) {
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" writing erase cmd to addr 0x%08lx\n",
|
||||
(unsigned long)addrw);
|
||||
#endif
|
||||
*addrw = BANK_CMD_ERASE1;
|
||||
*addrw = BANK_CMD_ERASE2;
|
||||
}
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
static int
|
||||
bank_erase_poll(flash_info_t *info, int sect)
|
||||
{
|
||||
bank_addr_t addrw, saddrw, eaddrw;
|
||||
int sectdone, haderr;
|
||||
|
||||
saddrw = (bank_addr_t)info->start[sect];
|
||||
eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
|
||||
|
||||
sectdone = 1;
|
||||
haderr = 0;
|
||||
|
||||
for (addrw = saddrw; addrw < eaddrw; addrw++) {
|
||||
bank_word_t stat = *addrw;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf(" checking status at addr "
|
||||
"0x%08lx [0x%08lx]\n",
|
||||
(unsigned long)addrw, stat);
|
||||
#endif
|
||||
if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY)
|
||||
sectdone = 0;
|
||||
else if ((stat & BANK_STAT_ERR) != 0) {
|
||||
printf(" failed on sector %d "
|
||||
"(stat = 0x%08lx) at "
|
||||
"address 0x%08lx\n",
|
||||
sect, stat,
|
||||
(unsigned long)addrw);
|
||||
*addrw = BANK_CMD_CLR_STAT;
|
||||
haderr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (haderr)
|
||||
return (-1);
|
||||
else
|
||||
return (sectdone);
|
||||
}
|
||||
|
||||
static int
|
||||
bank_write_word(bank_addr_t addr, bank_word_t value)
|
||||
{
|
||||
bank_word_t stat;
|
||||
ulong start;
|
||||
int flag, retval;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = BANK_CMD_PROG;
|
||||
|
||||
*addr = value;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
retval = 0;
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
do {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
stat = *addr;
|
||||
} while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY);
|
||||
|
||||
if ((stat & BANK_STAT_ERR) != 0) {
|
||||
printf("flash program failed (stat = 0x%08lx) "
|
||||
"at address 0x%08lx\n", (ulong)stat, (ulong)addr);
|
||||
*addr = BANK_CMD_CLR_STAT;
|
||||
retval = 3;
|
||||
}
|
||||
|
||||
done:
|
||||
/* reset to read mode */
|
||||
*addr = BANK_CMD_RST;
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
flash_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Init: no FLASHes known */
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
bank_probe(&flash_info[0], (bank_addr_t)CFG_FLASH_BASE);
|
||||
|
||||
/*
|
||||
* protect monitor and environment sectors
|
||||
*/
|
||||
|
||||
#if CFG_MONITOR_BASE == CFG_FLASH_BASE
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_MONITOR_BASE,
|
||||
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
#if defined(CFG_FLASH_ENV_ADDR)
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_FLASH_ENV_ADDR,
|
||||
#if defined(CFG_FLASH_ENV_BUF)
|
||||
CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_BUF - 1,
|
||||
#else
|
||||
CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_SIZE - 1,
|
||||
#endif
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
return flash_info[0].size;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
#if 0
|
||||
static void
|
||||
flash_get_offsets(ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start adress table */
|
||||
if (info->flash_id & FLASH_BTYPE) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
info->start[0] = base + 0x00000000;
|
||||
info->start[1] = base + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_INTEL: printf ("INTEL "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F320J5: printf ("28F320J5 (32 Mbit, 2 x 16bit)\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!
|
||||
*/
|
||||
#if 0
|
||||
static ulong
|
||||
flash_get_size(vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* set up sector start adress table */
|
||||
if (info->flash_id & FLASH_BTYPE) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
info->start[0] = base + 0x00000000;
|
||||
info->start[1] = base + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
flash_erase(flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
int prot, sect, haderr;
|
||||
ulong start, now, last;
|
||||
int rcode = 0;
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
|
||||
" Bank # %d: ", s_last - s_first + 1, s_first, s_last,
|
||||
(info - flash_info) + 1);
|
||||
flash_print_info(info);
|
||||
#endif
|
||||
|
||||
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 sector%s will not be erased!\n",
|
||||
prot, (prot > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
start = get_timer (0);
|
||||
last = 0;
|
||||
haderr = 0;
|
||||
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
ulong estart;
|
||||
int sectdone;
|
||||
|
||||
bank_erase_init(info, sect);
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
estart = get_timer(start);
|
||||
|
||||
do {
|
||||
now = get_timer(start);
|
||||
|
||||
if (now - estart > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout (sect %d)\n", sect);
|
||||
haderr = 1;
|
||||
rcode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef FLASH_DEBUG
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
sectdone = bank_erase_poll(info, sect);
|
||||
|
||||
if (sectdone < 0) {
|
||||
haderr = 1;
|
||||
rcode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!sectdone);
|
||||
|
||||
if (haderr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (haderr > 0)
|
||||
printf (" failed\n");
|
||||
else
|
||||
printf (" done\n");
|
||||
|
||||
/* reset to read mode */
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
bank_reset(info, sect);
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* 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)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*(ulong *)dest & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
retval = bank_write_word((bank_addr_t)dest, (bank_word_t)data);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,617 @@
|
|||
/*
|
||||
* (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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 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) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
if (FLASH_BASE1_PRELIM != 0x0) {
|
||||
size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: Bank 1 (0x%08lx = %ld MB)"
|
||||
" > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1 >> 20,
|
||||
size_b0, size_b0 >> 20);
|
||||
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
size_b1 = 0;
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#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
|
||||
|
||||
/* ICU862 Board has only one Flash Bank */
|
||||
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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start address table */
|
||||
if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) ||
|
||||
((info->flash_id & FLASH_TYPEMASK) == FLASH_AM033C)) {
|
||||
/* set sector offsets for uniform sector type */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00040000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_print_info (flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
puts ("missing or unknown FLASH type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_VENDMASK) {
|
||||
case FLASH_MAN_AMD: puts ("AMD "); break;
|
||||
case FLASH_MAN_FUJ: puts ("FUJITSU "); break;
|
||||
case FLASH_MAN_BM: puts ("BRIGHT MICRO "); break;
|
||||
default: puts ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AM040: puts ("29F040/29LV040 (4 Mbit, uniform sectors)\n");
|
||||
break;
|
||||
case FLASH_AM400B: puts ("AM29LV400B (4 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AM400T: puts ("AM29LV400T (4 Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_AM800B: puts ("AM29LV800B (8 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AM800T: puts ("AM29LV800T (8 Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_AM160B: puts ("AM29LV160B (16 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AM160T: puts ("AM29LV160T (16 Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_AM320B: puts ("AM29LV320B (32 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AM320T: puts ("AM29LV320T (32 Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_AM033C: puts ("AM29LV033C (32 Mbit)\n");
|
||||
break;
|
||||
default: puts ("Unknown Chip Type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf (" Size: %ld MB in %d Sectors\n",
|
||||
info->size >> 20, info->sector_count);
|
||||
|
||||
puts (" Sector Start Addresses:");
|
||||
|
||||
for (i=0; i<info->sector_count; ++i) {
|
||||
if ((i % 5) == 0) {
|
||||
puts ("\n ");
|
||||
}
|
||||
|
||||
printf (" %08lX%s",
|
||||
info->start[i],
|
||||
info->protect[i] ? " (RO)" : " "
|
||||
);
|
||||
}
|
||||
|
||||
puts ("\n");
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
#if 0
|
||||
ulong base = (ulong)addr;
|
||||
#endif
|
||||
uchar value;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x90909090;
|
||||
#endif
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value + (value << 16)) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_F040B:
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
case AMD_ID_LV033C:
|
||||
info->flash_id += FLASH_AM033C;
|
||||
info->sector_count = 64;
|
||||
info->size = 0x01000000;
|
||||
break; /* => 16Mb */
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
#else
|
||||
flash_get_offsets ((ulong)addr, &flash_info[0]);
|
||||
#endif
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
#if 1
|
||||
/* We don't know why it happens, but on ICU Board *
|
||||
* for AMD29033C flash we need to resend the command of *
|
||||
* reading flash protection for upper 8 Mb of flash */
|
||||
if ( i == 32 ) {
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x90909090;
|
||||
}
|
||||
#endif
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
#if 0
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
#else
|
||||
*addr = 0xF0F0F0F0; /* reset bank */
|
||||
#endif
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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) {
|
||||
puts ("- missing\n");
|
||||
} else {
|
||||
puts ("- no sectors to erase\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((info->flash_id == FLASH_UNKNOWN) ||
|
||||
(info->flash_id > FLASH_AMD_COMP)) {
|
||||
puts ("Can't erase unknown flash type - aborted\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 {
|
||||
puts ("\n");
|
||||
}
|
||||
|
||||
l_sect = -1;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x80808080;
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
#endif
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
#if 0
|
||||
addr[0] = 0x00300030;
|
||||
#else
|
||||
addr[0] = 0x30303030;
|
||||
#endif
|
||||
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_long*)(info->start[l_sect]);
|
||||
#if 0
|
||||
while ((addr[0] & 0x00800080) != 0x00800080)
|
||||
#else
|
||||
while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
|
||||
#endif
|
||||
{
|
||||
if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
puts ("Timeout\n");
|
||||
return 1;
|
||||
}
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
#if 0
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
#else
|
||||
addr[0] = 0xF0F0F0F0; /* reset bank */
|
||||
#endif
|
||||
|
||||
puts (" 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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
#if 0
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
#else
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0xA0A0A0A0;
|
||||
#endif
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
#if 0
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
|
||||
#else
|
||||
while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
|
||||
#endif
|
||||
{
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,456 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 memctl8xx_t *memctl = &immap->im_memctl;
|
||||
volatile ip860_bcsr_t *bcsr = (ip860_bcsr_t *)BCSR_BASE;
|
||||
unsigned long size;
|
||||
int i;
|
||||
|
||||
/* Init: enable write,
|
||||
* or we cannot even write flash commands
|
||||
*/
|
||||
bcsr->bd_ctrl |= BD_CTRL_FLWE;
|
||||
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
size = flash_get_size((vu_long *)FLASH_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, size<<20);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
|
||||
memctl->memc_br1 = (CFG_FLASH_BASE & BR_BA_MSK) |
|
||||
(memctl->memc_br1 & ~(BR_BA_MSK));
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size;
|
||||
|
||||
#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_SECT_SIZE-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* all possible flash types
|
||||
* (28F016SV, 28F160S3, 28F320S3)
|
||||
* have the same erase block size: 64 kB per chip,
|
||||
* of 128 kB per bank
|
||||
*/
|
||||
|
||||
/* set up sector start address table */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base;
|
||||
base += 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_INTEL: printf ("Intel "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F016SV: printf ("28F016SV (16 Mbit, 32 x 64k)\n");
|
||||
break;
|
||||
case FLASH_28F160S3: printf ("28F160S3 (16 Mbit, 32 x 512K)\n");
|
||||
break;
|
||||
case FLASH_28F320S3: printf ("28F320S3 (32 Mbit, 64 x 512K)\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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
/* Write "Intelligent Identifier" command: read Manufacturer ID */
|
||||
*addr = 0x90909090;
|
||||
|
||||
value = addr[0];
|
||||
switch (value) {
|
||||
case (MT_MANUFACT & 0x00FF00FF): /* MT or => Intel */
|
||||
case (INTEL_ALT_MANU & 0x00FF00FF):
|
||||
info->flash_id = FLASH_MAN_INTEL;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case (INTEL_ID_28F016S):
|
||||
info->flash_id += FLASH_28F016SV;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 2x2 MB */
|
||||
|
||||
case (INTEL_ID_28F160S3):
|
||||
info->flash_id += FLASH_28F160S3;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 2x2 MB */
|
||||
|
||||
case (INTEL_ID_28F320S3):
|
||||
info->flash_id += FLASH_28F320S3;
|
||||
info->sector_count = 64;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 2x4 MB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* set up sector start address table */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000);
|
||||
/* don't know how to check sector protection */
|
||||
info->protect[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (vu_long *)info->start[0];
|
||||
|
||||
*addr = 0xFFFFFF; /* reset bank to read array mode */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
|
||||
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");
|
||||
}
|
||||
|
||||
start = get_timer (0);
|
||||
last = start;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
vu_long *addr = (vu_long *)(info->start[sect]);
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
/* Single Block Erase Command */
|
||||
*addr = 0x20202020;
|
||||
/* Confirm */
|
||||
*addr = 0xD0D0D0D0;
|
||||
/* Resume Command, as per errata update */
|
||||
*addr = 0xD0D0D0D0;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
while ((*addr & 0x00800080) != 0x00800080) {
|
||||
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
*addr = 0xFFFFFFFF; /* reset bank */
|
||||
return 1;
|
||||
}
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset to read mode */
|
||||
*addr = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
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_long *addr = (vu_long *)dest;
|
||||
ulong start, csr;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*addr & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
/* Write Command */
|
||||
*addr = 0x10101010;
|
||||
|
||||
/* Write Data */
|
||||
*addr = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
flag = 0;
|
||||
while (((csr = *addr) & 0x00800080) != 0x00800080) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (csr & 0x00400040) {
|
||||
printf ("CSR indicates write error (%08lx) at %08lx\n", csr, (ulong)addr);
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
/* Clear Status Registers Command */
|
||||
*addr = 0x50505050;
|
||||
/* Reset to read array mode */
|
||||
*addr = 0xFFFFFFFF;
|
||||
|
||||
return (flag);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* 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);
|
||||
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 memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long size_b0;
|
||||
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 - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
|
||||
|
||||
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
|
||||
printf ("## Unknown FLASH on Bank 0: "
|
||||
"ID 0x%lx, Size = 0x%08lx = %ld MB\n",
|
||||
flash_info[0].flash_id,
|
||||
size_b0, size_b0<<20);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | \
|
||||
BR_MS_GPCM | BR_PS_16 | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
#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_SECT_SIZE-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
return (size_b0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_VENDMASK) {
|
||||
case FLASH_MAN_MT:
|
||||
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) * 0x00020000);
|
||||
}
|
||||
} 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 * 0x00020000;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case FLASH_MAN_SST:
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00002000);
|
||||
}
|
||||
return;
|
||||
|
||||
case FLASH_MAN_AMD:
|
||||
case FLASH_MAN_FUJ:
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
return;
|
||||
default:
|
||||
printf ("Don't know sector ofsets for flash type 0x%lx\n",
|
||||
info->flash_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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;
|
||||
case FLASH_MAN_SST: printf ("SST "); break;
|
||||
case FLASH_MAN_STM: printf ("STM "); break;
|
||||
case FLASH_MAN_MT: printf ("MT "); break;
|
||||
case FLASH_MAN_INTEL: printf ("Intel "); 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;
|
||||
case FLASH_SST200A: printf ("39xF200A (2M = 128K x 16)\n");
|
||||
break;
|
||||
case FLASH_SST400A: printf ("39xF400A (4M = 256K x 16)\n");
|
||||
break;
|
||||
case FLASH_SST800A: printf ("39xF800A (8M = 512K x 16)\n");
|
||||
break;
|
||||
case FLASH_STM800AB: printf ("M29W800AB (8M = 512K x 16)\n");
|
||||
break;
|
||||
case FLASH_28F008S5: printf ("28F008S5 (1M = 64K x 16)\n");
|
||||
break;
|
||||
case FLASH_28F400_T: printf ("28F400B3 (4Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_28F400_B: printf ("28F400B3 (4Mbit, bottom boot sector)\n");
|
||||
break;
|
||||
default: printf ("Unknown Chip Type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (info->size >= (1 << 20)) {
|
||||
i = 20;
|
||||
} else {
|
||||
i = 10;
|
||||
}
|
||||
printf (" Size: %ld %cB in %d Sectors\n",
|
||||
info->size >> i,
|
||||
(i == 20) ? 'M' : 'k',
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
ushort value;
|
||||
vu_short *saddr = (vu_short *)addr;
|
||||
|
||||
/* Read Manufacturer ID */
|
||||
saddr[0] = 0x0090;
|
||||
value = saddr[0];
|
||||
|
||||
switch (value) {
|
||||
case (AMD_MANUFACT & 0xFFFF):
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case (FUJ_MANUFACT & 0xFFFF):
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
case (SST_MANUFACT & 0xFFFF):
|
||||
info->flash_id = FLASH_MAN_SST;
|
||||
break;
|
||||
case (STM_MANUFACT & 0xFFFF):
|
||||
info->flash_id = FLASH_MAN_STM;
|
||||
break;
|
||||
case (MT_MANUFACT & 0xFFFF):
|
||||
info->flash_id = FLASH_MAN_MT;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
saddr[0] = 0x00FF; /* restore read mode */
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = saddr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case (AMD_ID_LV400T & 0xFFFF):
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (AMD_ID_LV400B & 0xFFFF):
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (AMD_ID_LV800T & 0xFFFF):
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case (AMD_ID_LV800B & 0xFFFF):
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case (AMD_ID_LV160T & 0xFFFF):
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case (AMD_ID_LV160B & 0xFFFF):
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case (AMD_ID_LV320T & 0xFFFF):
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case (AMD_ID_LV320B & 0xFFFF):
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
case (SST_ID_xF200A & 0xFFFF):
|
||||
info->flash_id += FLASH_SST200A;
|
||||
info->sector_count = 64; /* 39xF200A ID ( 2M = 128K x 16 ) */
|
||||
info->size = 0x00080000;
|
||||
break;
|
||||
case (SST_ID_xF400A & 0xFFFF):
|
||||
info->flash_id += FLASH_SST400A;
|
||||
info->sector_count = 128; /* 39xF400A ID ( 4M = 256K x 16 ) */
|
||||
info->size = 0x00100000;
|
||||
break;
|
||||
case (SST_ID_xF800A & 0xFFFF):
|
||||
info->flash_id += FLASH_SST800A;
|
||||
info->sector_count = 256; /* 39xF800A ID ( 8M = 512K x 16 ) */
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
case (STM_ID_x800AB & 0xFFFF):
|
||||
info->flash_id += FLASH_STM800AB;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
case (MT_ID_28F400_T & 0xFFFF):
|
||||
info->flash_id += FLASH_28F400_T;
|
||||
info->sector_count = 7;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512 kB */
|
||||
case (MT_ID_28F400_B & 0xFFFF):
|
||||
info->flash_id += FLASH_28F400_B;
|
||||
info->sector_count = 7;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512 kB */
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
saddr[0] = 0x00FF; /* restore read mode */
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
if (info->sector_count > CFG_MAX_FLASH_SECT) {
|
||||
printf ("** ERROR: sector count %d > max (%d) **\n",
|
||||
info->sector_count, CFG_MAX_FLASH_SECT);
|
||||
info->sector_count = CFG_MAX_FLASH_SECT;
|
||||
}
|
||||
|
||||
saddr[0] = 0x00FF; /* restore read mode */
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MT) {
|
||||
printf ("Can erase only MT flash types - aborted\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 = get_timer (0);
|
||||
last = start;
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
vu_short *addr = (vu_short *)(info->start[sect]);
|
||||
unsigned short status;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = 0x0050; /* clear status register */
|
||||
*addr = 0x0020; /* erase setup */
|
||||
*addr = 0x00D0; /* erase confirm */
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
while (((status = *addr) & 0x0080) != 0x0080) {
|
||||
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
*addr = 0x00FF; /* reset to read mode */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
*addr = 0x00FF; /* reset to read mode */
|
||||
}
|
||||
}
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
* 4 - Flash not identified
|
||||
*/
|
||||
|
||||
#define FLASH_WIDTH 2 /* flash bus width in bytes */
|
||||
|
||||
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
ulong cp, wp, data;
|
||||
int i, l, rc;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
wp = (addr & ~(FLASH_WIDTH-1)); /* get lower FLASH_WIDTH 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<FLASH_WIDTH && cnt>0; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
++cp;
|
||||
}
|
||||
for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += FLASH_WIDTH;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle FLASH_WIDTH aligned part
|
||||
*/
|
||||
while (cnt >= FLASH_WIDTH) {
|
||||
data = 0;
|
||||
for (i=0; i<FLASH_WIDTH; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
}
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += FLASH_WIDTH;
|
||||
cnt -= FLASH_WIDTH;
|
||||
}
|
||||
|
||||
if (cnt == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
data = 0;
|
||||
for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
}
|
||||
for (; i<FLASH_WIDTH; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
return (write_data(info, wp, data));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_data (flash_info_t *info, ulong dest, ulong data)
|
||||
{
|
||||
vu_short *addr = (vu_short *)dest;
|
||||
ushort sdata = (ushort)data;
|
||||
ushort status;
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*addr & sdata) != sdata) {
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = 0x0040; /* write setup */
|
||||
*addr = sdata;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
start = get_timer (0);
|
||||
|
||||
while (((status = *addr) & 0x0080) != 0x0080) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
*addr = 0x00FF; /* restore read mode */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
*addr = 0x00FF; /* restore read mode */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* (C) Copyright 2000, 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Derived from ../tqm8xx/flash.c
|
||||
* [Torsten Stevens, FHG IMS; Bruno Achauer, Exet AG]
|
||||
*/
|
||||
|
||||
#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)
|
||||
# endif
|
||||
# ifndef CFG_ENV_SIZE
|
||||
# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
|
||||
# endif
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#undef DEBUG_FLASH
|
||||
|
||||
#ifdef DEBUG_FLASH
|
||||
#define DEBUGF(fmt,args...) printf(fmt ,##args)
|
||||
#else
|
||||
#define DEBUGF(fmt,args...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 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) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
|
||||
|
||||
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
|
||||
printf ("## Unknown FLASH on Bank 0: "
|
||||
"ID 0x%lx, Size = 0x%08lx = %ld MB\n",
|
||||
flash_info[0].flash_id,
|
||||
size_b0, size_b0<<20);
|
||||
}
|
||||
|
||||
DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE5_PRELIM);
|
||||
|
||||
size_b1 = flash_get_size((vu_long *)FLASH_BASE5_PRELIM, &flash_info[1]);
|
||||
|
||||
DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: "
|
||||
"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,
|
||||
size_b0, size_b0<<20
|
||||
);
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
DEBUGF ("## Before remap: "
|
||||
"BR0: 0x%08x OR0: 0x%08x "
|
||||
"BR1: 0x%08x OR1: 0x%08x\n",
|
||||
memctl->memc_br0, memctl->memc_or0,
|
||||
memctl->memc_br1, memctl->memc_or1);
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | \
|
||||
BR_MS_GPCM | BR_PS_32 | BR_V;
|
||||
|
||||
DEBUGF("## 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]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
#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_SECT_SIZE-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
if (size_b1) {
|
||||
memctl->memc_or5 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
|
||||
memctl->memc_br5 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
|
||||
BR_MS_GPCM | BR_PS_32 | BR_V;
|
||||
|
||||
DEBUGF("## BR5: 0x%08x OR5: 0x%08x\n",
|
||||
memctl->memc_br5, memctl->memc_or5);
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
|
||||
&flash_info[1]);
|
||||
|
||||
flash_info[1].size = size_b1;
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE + size_b0, &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[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_SECT_SIZE-1,
|
||||
&flash_info[1]);
|
||||
#endif
|
||||
} else {
|
||||
memctl->memc_br5 = 0; /* invalidate bank */
|
||||
memctl->memc_or5 = 0; /* invalidate bank */
|
||||
|
||||
DEBUGF("## DISABLE BR5: 0x%08x OR5: 0x%08x\n",
|
||||
memctl->memc_br5, memctl->memc_or5);
|
||||
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[1].size = 0;
|
||||
}
|
||||
|
||||
DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
addr[0] = 0x00300030;
|
||||
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_long*)(info->start[l_sect]);
|
||||
while ((addr[0] & 0x00800080) != 0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
* (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.
|
||||
*
|
||||
* Flash Routines for AM290[48]0B 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 "vpd.h"
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (vu_long *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, totsize;
|
||||
int i;
|
||||
ulong addr;
|
||||
|
||||
/* Init: no FLASHes known */
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
totsize = 0;
|
||||
addr = 0xfc000000;
|
||||
for(i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
|
||||
size = flash_get_size((vu_long *)addr, &flash_info[i]);
|
||||
if (flash_info[i].flash_id == FLASH_UNKNOWN)
|
||||
break;
|
||||
totsize += size;
|
||||
addr += size;
|
||||
}
|
||||
|
||||
addr = 0xfe000000;
|
||||
for(i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
|
||||
|
||||
size = flash_get_size((vu_long *)addr, &flash_info[i]);
|
||||
if (flash_info[i].flash_id == FLASH_UNKNOWN)
|
||||
break;
|
||||
totsize += size;
|
||||
addr += size;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
return (totsize);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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) {
|
||||
case 0x1:
|
||||
printf ("AMD ");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown Vendor ");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case AMD_ID_F040B:
|
||||
printf ("AM29F040B (4 Mbit)\n");
|
||||
break;
|
||||
case AMD_ID_F080B:
|
||||
printf ("AM29F080B (8 Mbit)\n");
|
||||
break;
|
||||
case AMD_ID_F016D:
|
||||
printf ("AM29F016D (16 Mbit)\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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong vendor, devid;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x90909090;
|
||||
|
||||
vendor = addr[0];
|
||||
devid = addr[1] & 0xff;
|
||||
|
||||
/* only support AMD */
|
||||
if (vendor != 0x01010101) {
|
||||
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: %08lx\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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (vu_long *)info->start[0];
|
||||
addr[0] = 0xF0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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");
|
||||
}
|
||||
|
||||
l_sect = -1;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
addr[0x0555] = 0XAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0x80808080;
|
||||
addr[0x0555] = 0XAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
addr[0] = 0x30303030;
|
||||
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_long*)(info->start[l_sect]);
|
||||
while ((addr[0] & 0x80808080) != 0x80808080) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
addr[0] = 0xF0F0F0F0; /* reset bank */
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
addr[0x0555] = 0xAAAAAAAA;
|
||||
addr[0x02AA] = 0x55555555;
|
||||
addr[0x0555] = 0xA0A0A0A0;
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* Code in faintly related to linux/arch/ppc/8xx_io:
|
||||
* MPC8xx CPM I2C interface. Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
|
||||
*
|
||||
* This file implements functions to read the MBX's Vital Product Data
|
||||
* (VPD). I can't use the more general i2c code in mpc8xx/... since I need
|
||||
* the VPD at a time where there is no RAM available yet. Hence the VPD is
|
||||
* read into a special area in the DPRAM (see config_MBX.h::CFG_DPRAMVPD).
|
||||
*
|
||||
* -----------------------------------------------------------------
|
||||
* 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>
|
||||
#ifdef CONFIG_8xx
|
||||
#include <commproc.h>
|
||||
#endif
|
||||
#include "vpd.h"
|
||||
|
||||
/* Location of receive/transmit buffer descriptors
|
||||
* Allocate one transmit bd and one receive bd.
|
||||
* IIC_BD_FREE points to free bd space which we'll use as tx buffer.
|
||||
*/
|
||||
#define IIC_BD_TX1 (BD_IIC_START + 0*sizeof(cbd_t))
|
||||
#define IIC_BD_TX2 (BD_IIC_START + 1*sizeof(cbd_t))
|
||||
#define IIC_BD_RX (BD_IIC_START + 2*sizeof(cbd_t))
|
||||
#define IIC_BD_FREE (BD_IIC_START + 3*sizeof(cbd_t))
|
||||
|
||||
/* FIXME -- replace 0x2000 with offsetof */
|
||||
#define VPD_P ((vpd_t *)(CFG_IMMR + 0x2000 + CFG_DPRAMVPD))
|
||||
|
||||
/* transmit/receive buffers */
|
||||
#define IIC_RX_LENGTH 128
|
||||
|
||||
#define WITH_MICROCODE_PATCH
|
||||
|
||||
vpd_packet_t * vpd_find_packet(u_char ident)
|
||||
{
|
||||
vpd_packet_t *packet;
|
||||
vpd_t *vpd = VPD_P;
|
||||
|
||||
packet = (vpd_packet_t *)&vpd->packets;
|
||||
while ((packet->identifier != ident) && packet->identifier != 0xFF)
|
||||
{
|
||||
packet = (vpd_packet_t *)((char *)packet + packet->size + 2);
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
void vpd_init(void)
|
||||
{
|
||||
volatile immap_t *im = (immap_t *)CFG_IMMR;
|
||||
volatile cpm8xx_t *cp = &(im->im_cpm);
|
||||
volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c);
|
||||
volatile iic_t *iip;
|
||||
#ifdef WITH_MICROCODE_PATCH
|
||||
ulong reloc = 0;
|
||||
#endif
|
||||
|
||||
iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
|
||||
|
||||
/*
|
||||
* kludge: when running from flash, no microcode patch can be
|
||||
* installed. However, the DPMEM usually contains non-zero
|
||||
* garbage at the relocatable patch base location, so lets clear
|
||||
* it now. This way the rest of the code can support the microcode
|
||||
* patch dynamically.
|
||||
*/
|
||||
if ((ulong)vpd_init & 0xff000000)
|
||||
iip->iic_rpbase = 0;
|
||||
|
||||
#ifdef WITH_MICROCODE_PATCH
|
||||
/* Check for and use a microcode relocation patch. */
|
||||
if ((reloc = iip->iic_rpbase))
|
||||
iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
|
||||
#endif
|
||||
/* Initialize Port B IIC pins */
|
||||
cp->cp_pbpar |= 0x00000030;
|
||||
cp->cp_pbdir |= 0x00000030;
|
||||
cp->cp_pbodr |= 0x00000030;
|
||||
|
||||
i2c->i2c_i2mod = 0x04; /* filter clock */
|
||||
i2c->i2c_i2add = 0x34; /* select an arbitrary (unique) address */
|
||||
i2c->i2c_i2brg = 0x07; /* make clock run maximum slow */
|
||||
i2c->i2c_i2cmr = 0x00; /* disable interrupts */
|
||||
i2c->i2c_i2cer = 0x1f; /* clear events */
|
||||
i2c->i2c_i2com = 0x01; /* configure i2c to work as master */
|
||||
|
||||
if (vpd_read(0xa4, (uchar*)VPD_P, VPD_EEPROM_SIZE, 0) != VPD_EEPROM_SIZE)
|
||||
{
|
||||
hang();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Read from I2C.
|
||||
* This is a two step process. First, we send the "dummy" write
|
||||
* to set the device offset for the read. Second, we perform
|
||||
* the read operation.
|
||||
*/
|
||||
int vpd_read(uint iic_device, uchar *buf, int count, int offset)
|
||||
{
|
||||
volatile immap_t *im = (immap_t *)CFG_IMMR;
|
||||
volatile cpm8xx_t *cp = &(im->im_cpm);
|
||||
volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c);
|
||||
volatile iic_t *iip;
|
||||
volatile cbd_t *tbdf1, *tbdf2, *rbdf;
|
||||
uchar *tb;
|
||||
uchar event;
|
||||
#ifdef WITH_MICROCODE_PATCH
|
||||
ulong reloc = 0;
|
||||
#endif
|
||||
|
||||
iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
|
||||
#ifdef WITH_MICROCODE_PATCH
|
||||
/* Check for and use a microcode relocation patch. */
|
||||
if ((reloc = iip->iic_rpbase))
|
||||
iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
|
||||
#endif
|
||||
tbdf1 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX1];
|
||||
tbdf2 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX2];
|
||||
rbdf = (cbd_t *)&cp->cp_dpmem[IIC_BD_RX];
|
||||
|
||||
/* Send a "dummy write" operation. This is a write request with
|
||||
* only the offset sent, followed by another start condition.
|
||||
* This will ensure we start reading from the first location
|
||||
* of the EEPROM.
|
||||
*/
|
||||
tb = (uchar*)&cp->cp_dpmem[IIC_BD_FREE];
|
||||
tb[0] = iic_device & 0xfe; /* device address */
|
||||
tb[1] = offset; /* offset */
|
||||
tbdf1->cbd_bufaddr = (uint)tb;
|
||||
tbdf1->cbd_datlen = 2;
|
||||
tbdf1->cbd_sc = 0x8400;
|
||||
|
||||
tb += 2;
|
||||
tb[0] = iic_device | 1; /* device address */
|
||||
tbdf2->cbd_bufaddr = (uint)tb;
|
||||
tbdf2->cbd_datlen = count+1;
|
||||
tbdf2->cbd_sc = 0xbc00;
|
||||
|
||||
rbdf->cbd_bufaddr = (uint)buf;
|
||||
rbdf->cbd_datlen = 0;
|
||||
rbdf->cbd_sc = 0xb000;
|
||||
|
||||
iip->iic_tbase = IIC_BD_TX1;
|
||||
iip->iic_tbptr = IIC_BD_TX1;
|
||||
iip->iic_rbase = IIC_BD_RX;
|
||||
iip->iic_rbptr = IIC_BD_RX;
|
||||
iip->iic_rfcr = 0x15;
|
||||
iip->iic_tfcr = 0x15;
|
||||
iip->iic_mrblr = count;
|
||||
iip->iic_rstate = 0;
|
||||
iip->iic_tstate = 0;
|
||||
|
||||
i2c->i2c_i2cer = 0x1f; /* clear event mask */
|
||||
i2c->i2c_i2mod |= 1; /* enable iic operation */
|
||||
i2c->i2c_i2com |= 0x80; /* start master */
|
||||
|
||||
/* wait for IIC transfer */
|
||||
do {
|
||||
__asm__ volatile ("eieio");
|
||||
event = i2c->i2c_i2cer;
|
||||
} while (event == 0);
|
||||
|
||||
if ((event & 0x10) || (event & 0x04)) {
|
||||
count = -1;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
bailout:
|
||||
i2c->i2c_i2mod &= ~1; /* turn off iic operation */
|
||||
i2c->i2c_i2cer = 0x1f; /* clear event mask */
|
||||
|
||||
return count;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef FLASH_LIB_H
|
||||
#define FLASH_LIB_H
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/* PIO operations max */
|
||||
#define FLASH_PROGRAM_POLLS 100000
|
||||
|
||||
/* 10 Seconds default */
|
||||
#define FLASH_ERASE_SECTOR_TIMEOUT (10*1000 /*SEC*/ )
|
||||
|
||||
/* Flash device info structure */
|
||||
typedef struct flash_dev_s {
|
||||
char name[24]; /* Bank Name */
|
||||
int bank; /* Bank 0 or 1 */
|
||||
unsigned int base; /* Base address */
|
||||
int sectors; /* Sector count */
|
||||
int lgSectorSize; /* Log2(usable bytes/sector) */
|
||||
int vendorID; /* Expected vendor ID */
|
||||
int deviceID; /* Expected device ID */
|
||||
int found; /* Set if found by flashLibInit */
|
||||
int swap; /* Set for bank 1 if byte swap req'd */
|
||||
} flash_dev_t;
|
||||
|
||||
#define FLASH_MAX_POS(dev) \
|
||||
((dev)->sectors << (dev)->lgSectorSize)
|
||||
|
||||
#define FLASH_SECTOR_POS(dev, sector) \
|
||||
((sector) << (dev)->lgSectorSize)
|
||||
|
||||
/* AMD 29F040 */
|
||||
#define FLASH0_BANK 0
|
||||
#define FLASH0_VENDOR_ID 0x01
|
||||
#define FLASH0_DEVICE_ID 0x49
|
||||
|
||||
/* AMD29LV160DB */
|
||||
#define FLASH1_BANK 1
|
||||
#define FLASH1_VENDOR_ID 0x0001
|
||||
#define FLASH1_DEVICE_ID 0x2249
|
||||
|
||||
extern flash_dev_t flashDev[];
|
||||
extern int flashDevCount;
|
||||
|
||||
/*
|
||||
* Device pointers
|
||||
*
|
||||
* These must be kept in sync with the table in flashLib.c.
|
||||
*/
|
||||
#define FLASH_DEV_BANK0_SA0 (&flashDev[0])
|
||||
#define FLASH_DEV_BANK0_SA1 (&flashDev[1])
|
||||
#define FLASH_DEV_BANK0_SA2 (&flashDev[2])
|
||||
#define FLASH_DEV_BANK0_LOW (&flashDev[3]) /* 960K */
|
||||
#define FLASH_DEV_BANK0_BOOT (&flashDev[4]) /* PLCC */
|
||||
#define FLASH_DEV_BANK0_HIGH (&flashDev[5]) /* 512K PLCC shadow */
|
||||
|
||||
unsigned long flash_init(void);
|
||||
int flashEraseSector(flash_dev_t *dev, int sector);
|
||||
int flashErase(flash_dev_t *dev);
|
||||
int flashRead(flash_dev_t *dev, int pos, char *buf, int len);
|
||||
int flashWrite(flash_dev_t *dev, int pos, char *buf, int len);
|
||||
int flashWritable(flash_dev_t *dev, int pos, int len);
|
||||
int flashDiag(flash_dev_t *dev);
|
||||
int flashDiagAll(void);
|
||||
|
||||
ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
void flash_print_info (flash_info_t *info);
|
||||
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);
|
||||
|
||||
/*
|
||||
* Flash info indices.
|
||||
*/
|
||||
#define FLASH_BANK_KERNEL 0
|
||||
#define FLASH_BANK_BOOT 1
|
||||
#define FLASH_BANK_AUX 2
|
||||
#define FIRST_SECTOR 0
|
||||
|
||||
#endif /* !FLASH_LIB_H */
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* (C) Copyright 2000, 2001
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2001, Stuart Hughes, Lineo Inc, stuarth@lineo.com
|
||||
* Add support the Sharp chips on the mpc8260ads.
|
||||
* I started with board/ip860/flash.c and made changes I found in
|
||||
* the MTD project by David Schleef.
|
||||
*
|
||||
* 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>
|
||||
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
static int clear_block_lock_bit(vu_long * addr);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
#ifndef CONFIG_MPC8260ADS
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
volatile ip860_bcsr_t *bcsr = (ip860_bcsr_t *)BCSR_BASE;
|
||||
#endif
|
||||
unsigned long size;
|
||||
int i;
|
||||
|
||||
/* Init: enable write,
|
||||
* or we cannot even write flash commands
|
||||
*/
|
||||
#ifndef CONFIG_MPC8260ADS
|
||||
bcsr->bd_ctrl |= BD_CTRL_FLWE;
|
||||
#endif
|
||||
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
|
||||
/* set the default sector offset */
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
size = flash_get_size((vu_long *)FLASH_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, size<<20);
|
||||
}
|
||||
#ifndef CONFIG_MPC8260ADS
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
|
||||
memctl->memc_br1 = (CFG_FLASH_BASE & BR_BA_MSK) |
|
||||
(memctl->memc_br1 & ~(BR_BA_MSK));
|
||||
#endif
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size;
|
||||
|
||||
#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_SECT_SIZE-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_INTEL: printf ("Intel "); break;
|
||||
case FLASH_MAN_SHARP: printf ("Sharp "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F016SV: printf ("28F016SV (16 Mbit, 32 x 64k)\n");
|
||||
break;
|
||||
case FLASH_28F160S3: printf ("28F160S3 (16 Mbit, 32 x 512K)\n");
|
||||
break;
|
||||
case FLASH_28F320S3: printf ("28F320S3 (32 Mbit, 64 x 512K)\n");
|
||||
break;
|
||||
case FLASH_LH28F016SCT: printf ("28F016SC (16 Mbit, 32 x 64K)\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");
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
ulong sector_offset;
|
||||
|
||||
/* Write "Intelligent Identifier" command: read Manufacturer ID */
|
||||
*addr = 0x90909090;
|
||||
|
||||
value = addr[0] & 0x00FF00FF;
|
||||
switch (value) {
|
||||
case MT_MANUFACT: /* SHARP, MT or => Intel */
|
||||
case INTEL_ALT_MANU:
|
||||
info->flash_id = FLASH_MAN_INTEL;
|
||||
break;
|
||||
default:
|
||||
printf("unknown manufacturer: %x\n", (unsigned int)value);
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case (INTEL_ID_28F016S):
|
||||
info->flash_id += FLASH_28F016SV;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00400000;
|
||||
sector_offset = 0x20000;
|
||||
break; /* => 2x2 MB */
|
||||
|
||||
case (INTEL_ID_28F160S3):
|
||||
info->flash_id += FLASH_28F160S3;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00400000;
|
||||
sector_offset = 0x20000;
|
||||
break; /* => 2x2 MB */
|
||||
|
||||
case (INTEL_ID_28F320S3):
|
||||
info->flash_id += FLASH_28F320S3;
|
||||
info->sector_count = 64;
|
||||
info->size = 0x00800000;
|
||||
sector_offset = 0x20000;
|
||||
break; /* => 2x4 MB */
|
||||
|
||||
case SHARP_ID_28F016SCL:
|
||||
case SHARP_ID_28F016SCZ:
|
||||
info->flash_id = FLASH_MAN_SHARP | FLASH_LH28F016SCT;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00800000;
|
||||
sector_offset = 0x40000;
|
||||
break; /* => 4x2 MB */
|
||||
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* set up sector start address table */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base;
|
||||
base += sector_offset;
|
||||
/* don't know how to check sector protection */
|
||||
info->protect[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (vu_long *)info->start[0];
|
||||
|
||||
*addr = 0xFFFFFF; /* reset bank to read array mode */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ( ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL)
|
||||
&& ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_SHARP) ) {
|
||||
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");
|
||||
}
|
||||
|
||||
/* Make Sure Block Lock Bit is not set. */
|
||||
if(clear_block_lock_bit((vu_long *)(info->start[s_first]))){
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
vu_long *addr = (vu_long *)(info->start[sect]);
|
||||
|
||||
last = start = get_timer (0);
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
/* Reset Array */
|
||||
*addr = 0xffffffff;
|
||||
/* Clear Status Register */
|
||||
*addr = 0x50505050;
|
||||
/* Single Block Erase Command */
|
||||
*addr = 0x20202020;
|
||||
/* Confirm */
|
||||
*addr = 0xD0D0D0D0;
|
||||
|
||||
if((info->flash_id & FLASH_TYPEMASK) != FLASH_LH28F016SCT) {
|
||||
/* Resume Command, as per errata update */
|
||||
*addr = 0xD0D0D0D0;
|
||||
}
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
while ((*addr & 0x80808080) != 0x80808080) {
|
||||
if(*addr & 0x20202020){
|
||||
printf("Error in Block Erase - Lock Bit may be set!\n");
|
||||
printf("Status Register = 0x%X\n", (uint)*addr);
|
||||
*addr = 0xFFFFFFFF; /* reset bank */
|
||||
return 1;
|
||||
}
|
||||
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
*addr = 0xFFFFFFFF; /* reset bank */
|
||||
return 1;
|
||||
}
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset to read mode */
|
||||
*addr = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
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_long *addr = (vu_long *)dest;
|
||||
ulong start, csr;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*addr & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
/* Write Command */
|
||||
*addr = 0x10101010;
|
||||
|
||||
/* Write Data */
|
||||
*addr = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
flag = 0;
|
||||
while (((csr = *addr) & 0x80808080) != 0x80808080) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (csr & 0x40404040) {
|
||||
printf ("CSR indicates write error (%08lx) at %08lx\n", csr, (ulong)addr);
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
/* Clear Status Registers Command */
|
||||
*addr = 0x50505050;
|
||||
/* Reset to read array mode */
|
||||
*addr = 0xFFFFFFFF;
|
||||
|
||||
return (flag);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Clear Block Lock Bit, returns:
|
||||
* 0 - OK
|
||||
* 1 - Timeout
|
||||
*/
|
||||
|
||||
static int clear_block_lock_bit(vu_long * addr)
|
||||
{
|
||||
ulong start, now;
|
||||
|
||||
/* Reset Array */
|
||||
*addr = 0xffffffff;
|
||||
/* Clear Status Register */
|
||||
*addr = 0x50505050;
|
||||
|
||||
*addr = 0x60606060;
|
||||
*addr = 0xd0d0d0d0;
|
||||
|
||||
start = get_timer (0);
|
||||
while(*addr != 0x80808080){
|
||||
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout on clearing Block Lock Bit\n");
|
||||
*addr = 0xFFFFFFFF; /* reset bank */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,860 @@
|
|||
/*
|
||||
* (C) Copyright 2000, 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified 4/5/2001
|
||||
* Wait for completion of each sector erase command issued
|
||||
* 4/5/2001
|
||||
* Chris Hallinan - DS4.COM, Inc. - clh@net1plus.com
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified 3/7/2001
|
||||
* - adopted for pip405, Denis Peter, MPL AG Switzerland
|
||||
* TODO:
|
||||
* clean-up
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
#ifdef CONFIG_PIP405
|
||||
#include "../pip405/pip405.h"
|
||||
#endif
|
||||
#ifdef CONFIG_MIP405
|
||||
#include "../mip405/mip405.h"
|
||||
#endif
|
||||
#include "common_util.h"
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
|
||||
void unlock_intel_sectors(flash_info_t *info,ulong addr,ulong cnt);
|
||||
|
||||
|
||||
#ifdef CONFIG_ADCIOP
|
||||
#define ADDR0 0x0aa9
|
||||
#define ADDR1 0x0556
|
||||
#define FLASH_WORD_SIZE unsigned char
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPCI405
|
||||
#define ADDR0 0x5555
|
||||
#define ADDR1 0x2aaa
|
||||
#define FLASH_WORD_SIZE unsigned short
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PIP405
|
||||
#define ADDR0 0x5555
|
||||
#define ADDR1 0x2aaa
|
||||
#define FLASH_WORD_SIZE unsigned short
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MIP405
|
||||
#define ADDR0 0x5555
|
||||
#define ADDR1 0x2aaa
|
||||
#define FLASH_WORD_SIZE unsigned short
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
unsigned long size_b0, size_b1;
|
||||
int i;
|
||||
unsigned long pbcr;
|
||||
unsigned long base_b0, base_b1;
|
||||
unsigned char rc;
|
||||
|
||||
rc=switch_cs(FALSE); /* map Flash High */
|
||||
|
||||
if(rc)
|
||||
printf("(MPS Boot) ");
|
||||
else
|
||||
printf("(Flash Boot) ");
|
||||
/* 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 - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
/* Only one bank */
|
||||
if (CFG_MAX_FLASH_BANKS == 1)
|
||||
{
|
||||
/* Setup offsets */
|
||||
/* flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]); */
|
||||
/* Monitor protection ON by default */
|
||||
#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
|
||||
size_b1 = 0 ;
|
||||
flash_info[0].size = size_b0;
|
||||
}
|
||||
|
||||
/* 2 banks */
|
||||
else
|
||||
{
|
||||
size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
|
||||
if (size_b1)
|
||||
{
|
||||
mtdcr(ebccfga, pb0cr);
|
||||
pbcr = mfdcr(ebccfgd);
|
||||
mtdcr(ebccfga, pb0cr);
|
||||
base_b1 = -size_b1;
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b1 | (((size_b1/1024/1024)-1)<<17);
|
||||
mtdcr(ebccfgd, pbcr);
|
||||
/* printf("pb1cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
if (size_b0)
|
||||
{
|
||||
mtdcr(ebccfga, pb1cr);
|
||||
pbcr = mfdcr(ebccfgd);
|
||||
mtdcr(ebccfga, pb1cr);
|
||||
base_b0 = base_b1 - size_b0;
|
||||
pbcr = (pbcr & 0x0001ffff) | base_b0 | (((size_b0/1024/1024)-1)<<17);
|
||||
mtdcr(ebccfgd, pbcr);
|
||||
/* printf("pb0cr = %x\n", pbcr); */
|
||||
}
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)base_b0, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (base_b0, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
base_b0+size_b0-CFG_MONITOR_LEN,
|
||||
base_b0+size_b0-1,
|
||||
&flash_info[0]);
|
||||
|
||||
if (size_b1) {
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)base_b1, &flash_info[1]);
|
||||
|
||||
flash_get_offsets (base_b1, &flash_info[1]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
base_b1+size_b1-CFG_MONITOR_LEN,
|
||||
base_b1+size_b1-1,
|
||||
&flash_info[1]);
|
||||
/* monitor protection OFF by default (one is enough) */
|
||||
(void)flash_protect(FLAG_PROTECT_CLEAR,
|
||||
base_b0+size_b0-CFG_MONITOR_LEN,
|
||||
base_b0+size_b0-1,
|
||||
&flash_info[0]);
|
||||
} 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;
|
||||
}/* else 2 banks */
|
||||
switch_cs(rc); /* switch mode back */
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start address table */
|
||||
if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
|
||||
(info->flash_id == FLASH_AM040)){
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
info->start[i] = base + (i * 0x00010000);
|
||||
}
|
||||
else {
|
||||
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 * 0x00010000) - 0x00030000;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_print_info (flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
int k;
|
||||
int size;
|
||||
int erased;
|
||||
volatile unsigned long *flash;
|
||||
|
||||
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;
|
||||
case FLASH_MAN_SST: printf ("SST "); break;
|
||||
case FLASH_MAN_INTEL: printf ("Intel "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AM040: printf ("AM29F040 (512 Kbit, uniform sector size)\n");
|
||||
break;
|
||||
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;
|
||||
case FLASH_SST800A: printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
|
||||
break;
|
||||
case FLASH_SST160A: printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
|
||||
break;
|
||||
case FLASH_INTEL320T: printf ("TE28F320C3 (32 Mbit, top sector size)\n");
|
||||
break;
|
||||
default: printf ("Unknown Chip Type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf (" Size: %ld KB in %d Sectors\n",
|
||||
info->size >> 10, info->sector_count);
|
||||
|
||||
printf (" Sector Start Addresses:");
|
||||
for (i=0; i<info->sector_count; ++i) {
|
||||
/*
|
||||
* Check if whole sector is erased
|
||||
*/
|
||||
if (i != (info->sector_count-1))
|
||||
size = info->start[i+1] - info->start[i];
|
||||
else
|
||||
size = info->start[0] + info->size - info->start[i];
|
||||
erased = 1;
|
||||
flash = (volatile unsigned long *)info->start[i];
|
||||
size = size >> 2; /* divide by 4 for longword access */
|
||||
for (k=0; k<size; k++)
|
||||
{
|
||||
if (*flash++ != 0xffffffff)
|
||||
{
|
||||
erased = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i % 5) == 0)
|
||||
printf ("\n ");
|
||||
#if 0 /* test-only */
|
||||
printf (" %08lX%s",
|
||||
info->start[i],
|
||||
info->protect[i] ? " (RO)" : " "
|
||||
#else
|
||||
printf (" %08lX%s%s",
|
||||
info->start[i],
|
||||
erased ? " E" : " ",
|
||||
info->protect[i] ? "RO " : " "
|
||||
#endif
|
||||
);
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
FLASH_WORD_SIZE value;
|
||||
ulong base = (ulong)addr;
|
||||
volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)addr;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
|
||||
addr2[ADDR0] = (FLASH_WORD_SIZE)0x00900090;
|
||||
|
||||
value = addr2[0];
|
||||
/* printf("flash_get_size value: %x\n",value); */
|
||||
switch (value) {
|
||||
case (FLASH_WORD_SIZE)AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case (FLASH_WORD_SIZE)FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
case (FLASH_WORD_SIZE)INTEL_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_INTEL;
|
||||
break;
|
||||
case (FLASH_WORD_SIZE)SST_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_SST;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
value = addr2[1]; /* device ID */
|
||||
/* printf("Device value %x\n",value); */
|
||||
switch (value) {
|
||||
case (FLASH_WORD_SIZE)AMD_ID_F040B:
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x0080000; /* => 512 ko */
|
||||
break;
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 0.5 MB */
|
||||
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 0.5 MB */
|
||||
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case (FLASH_WORD_SIZE)AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#endif
|
||||
case (FLASH_WORD_SIZE)SST_ID_xF800A:
|
||||
info->flash_id += FLASH_SST800A;
|
||||
info->sector_count = 16;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
case (FLASH_WORD_SIZE)INTEL_ID_28F320C3T:
|
||||
info->flash_id += FLASH_INTEL320T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
|
||||
case (FLASH_WORD_SIZE)SST_ID_xF160A:
|
||||
info->flash_id += FLASH_SST160A;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* set up sector start address table */
|
||||
if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
|
||||
(info->flash_id == FLASH_AM040)){
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
info->start[i] = base + (i * 0x00010000);
|
||||
} else {
|
||||
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 * 0x00010000) - 0x00030000;
|
||||
}
|
||||
else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
if(info->sector_count==71) {
|
||||
|
||||
info->start[i--] = base + info->size - 0x00002000;
|
||||
info->start[i--] = base + info->size - 0x00004000;
|
||||
info->start[i--] = base + info->size - 0x00006000;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000A000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x0000E000;
|
||||
for (; i >= 0; i--)
|
||||
info->start[i] = base + i * 0x000010000;
|
||||
}
|
||||
else {
|
||||
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 */
|
||||
addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
|
||||
info->protect[i] = 0;
|
||||
else
|
||||
info->protect[i] = addr2[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
#if 0 /* test-only */
|
||||
#ifdef CONFIG_ADCIOP
|
||||
addr2 = (volatile unsigned char *)info->start[0];
|
||||
addr2[ADDR0] = 0xAA;
|
||||
addr2[ADDR1] = 0x55;
|
||||
addr2[ADDR0] = 0xF0; /* reset bank */
|
||||
#else
|
||||
addr2 = (FLASH_WORD_SIZE *)info->start[0];
|
||||
*addr2 = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
|
||||
#endif
|
||||
#else /* test-only */
|
||||
addr2 = (FLASH_WORD_SIZE *)info->start[0];
|
||||
*addr2 = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
|
||||
#endif /* test-only */
|
||||
}
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
int wait_for_DQ7(flash_info_t *info, int sect)
|
||||
{
|
||||
ulong start, now, last;
|
||||
volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
|
||||
|
||||
start = get_timer (0);
|
||||
last = start;
|
||||
while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_wait_for_DQ7(flash_info_t *info, int sect)
|
||||
{
|
||||
ulong start, now, last;
|
||||
volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
|
||||
|
||||
start = get_timer (0);
|
||||
last = start;
|
||||
while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
addr[0]=(FLASH_WORD_SIZE)0x00500050;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
|
||||
volatile FLASH_WORD_SIZE *addr2;
|
||||
int flag, prot, sect, l_sect;
|
||||
int i;
|
||||
|
||||
|
||||
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) {
|
||||
printf ("Can't erase unknown flash type - aborted\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;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
|
||||
/* printf("Erasing sector %p\n", addr2); */ /* CLH */
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
|
||||
addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
|
||||
addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
|
||||
addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00500050; /* block erase */
|
||||
for (i=0; i<50; i++)
|
||||
udelay(1000); /* wait 1 ms */
|
||||
wait_for_DQ7(info, sect);
|
||||
}
|
||||
else {
|
||||
if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00600060; /* unlock sector */
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00D000D0; /* sector erase */
|
||||
intel_wait_for_DQ7(info, sect);
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00200020; /* sector erase */
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00D000D0; /* sector erase */
|
||||
intel_wait_for_DQ7(info, sect);
|
||||
}
|
||||
else {
|
||||
addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
|
||||
addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
|
||||
addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00300030; /* sector erase */
|
||||
wait_for_DQ7(info, sect);
|
||||
}
|
||||
}
|
||||
l_sect = sect;
|
||||
/*
|
||||
* Wait for each sector to complete, it's more
|
||||
* reliable. According to AMD Spec, you must
|
||||
* issue all erase commands within a specified
|
||||
* timeout. This has been seen to fail, especially
|
||||
* if printf()s are included (for debug)!!
|
||||
*/
|
||||
/* wait_for_DQ7(info, sect); */
|
||||
}
|
||||
}
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* We wait for the last triggered sector
|
||||
*/
|
||||
if (l_sect < 0)
|
||||
goto DONE;
|
||||
wait_for_DQ7(info, l_sect);
|
||||
|
||||
DONE:
|
||||
#endif
|
||||
/* reset to read mode */
|
||||
addr = (FLASH_WORD_SIZE *)info->start[0];
|
||||
addr[0] = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
|
||||
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unlock_intel_sectors(flash_info_t *info,ulong addr,ulong cnt)
|
||||
{
|
||||
int i;
|
||||
volatile FLASH_WORD_SIZE *addr2;
|
||||
long c;
|
||||
c= (long)cnt;
|
||||
for(i=info->sector_count-1;i>0;i--)
|
||||
{
|
||||
if(addr>=info->start[i])
|
||||
break;
|
||||
}
|
||||
do {
|
||||
addr2 = (FLASH_WORD_SIZE *)(info->start[i]);
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00600060; /* unlock sector setup */
|
||||
addr2[0] = (FLASH_WORD_SIZE)0x00D000D0; /* unlock sector */
|
||||
intel_wait_for_DQ7(info, i);
|
||||
i++;
|
||||
c-=(info->start[i]-info->start[i-1]);
|
||||
}while(c>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;
|
||||
|
||||
if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
|
||||
unlock_intel_sectors(info,addr,cnt);
|
||||
}
|
||||
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;
|
||||
if((wp % 0x10000)==0)
|
||||
printf("."); /* show Progress */
|
||||
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);
|
||||
}
|
||||
rc=write_word(info, wp, data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static FLASH_WORD_SIZE *read_val = (FLASH_WORD_SIZE *)0x200000;
|
||||
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data)
|
||||
{
|
||||
volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)(info->start[0]);
|
||||
volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *)dest;
|
||||
volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data;
|
||||
ulong start;
|
||||
int flag;
|
||||
int i;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*((volatile FLASH_WORD_SIZE *)dest) &
|
||||
(FLASH_WORD_SIZE)data) != (FLASH_WORD_SIZE)data) {
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
for (i=0; i<4/sizeof(FLASH_WORD_SIZE); i++)
|
||||
{
|
||||
if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
|
||||
/* intel style writting */
|
||||
dest2[i] = (FLASH_WORD_SIZE)0x00500050;
|
||||
dest2[i] = (FLASH_WORD_SIZE)0x00400040;
|
||||
*read_val++ = data2[i];
|
||||
dest2[i] = data2[i];
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
udelay(10);
|
||||
while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080)
|
||||
{
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT)
|
||||
return (1);
|
||||
}
|
||||
dest2[i] = (FLASH_WORD_SIZE)0x00FF00FF; /* return to read mode */
|
||||
udelay(10);
|
||||
dest2[i] = (FLASH_WORD_SIZE)0x00FF00FF; /* return to read mode */
|
||||
if(dest2[i]!=data2[i])
|
||||
printf("Error at %p 0x%04X != 0x%04X\n",&dest2[i],dest2[i],data2[i]);
|
||||
}
|
||||
else {
|
||||
addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
|
||||
addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
|
||||
addr2[ADDR0] = (FLASH_WORD_SIZE)0x00A000A0;
|
||||
dest2[i] = data2[i];
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) !=
|
||||
(data2[i] & (FLASH_WORD_SIZE)0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Denis Peter, MPL AG Switzerland
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* TODO: clean-up
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <devices.h>
|
||||
#include "isa.h"
|
||||
#include "piix4_pci.h"
|
||||
#include "kbd.h"
|
||||
#include "video.h"
|
||||
|
||||
extern int drv_isa_kbd_init (void);
|
||||
|
||||
#undef ISA_DEBUG
|
||||
|
||||
#ifdef ISA_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* fdc (logical device 0) */
|
||||
const SIO_LOGDEV_TABLE sio_fdc[] = {
|
||||
{0x60, 3}, /* set IO to FDPort (3F0) */
|
||||
{0x61, 0xF0}, /* set IO to FDPort (3F0) */
|
||||
{0x70, 06}, /* set IRQ 6 for FDPort */
|
||||
{0x74, 02}, /* set DMA 2 for FDPort */
|
||||
{0xF0, 0x05}, /* set to PS2 type */
|
||||
{0xF1, 0x00}, /* default value */
|
||||
{0x30, 1}, /* and activate the device */
|
||||
{0xFF, 0} /* end of device table */
|
||||
};
|
||||
/* paralell port (logical device 3) */
|
||||
const SIO_LOGDEV_TABLE sio_pport[] = {
|
||||
{0x60, 3}, /* set IO to PPort (378) */
|
||||
{0x61, 0x78}, /* set IO to PPort (378) */
|
||||
{0x70, 07}, /* set IRQ 7 for PPort */
|
||||
{0xF1, 00}, /* set PPort to normal */
|
||||
{0x30, 1}, /* and activate the device */
|
||||
{0xFF, 0} /* end of device table */
|
||||
};
|
||||
/* paralell port (logical device 3) Floppy assigned to lpt */
|
||||
const SIO_LOGDEV_TABLE sio_pport_fdc[] = {
|
||||
{0x60, 3}, /* set IO to PPort (378) */
|
||||
{0x61, 0x78}, /* set IO to PPort (378) */
|
||||
{0x70, 07}, /* set IRQ 7 for PPort */
|
||||
{0xF1, 02}, /* set PPort to Floppy */
|
||||
{0x30, 1}, /* and activate the device */
|
||||
{0xFF, 0} /* end of device table */
|
||||
};
|
||||
/* uart 1 (logical device 4) */
|
||||
const SIO_LOGDEV_TABLE sio_com1[] = {
|
||||
{0x60, 3}, /* set IO to COM1 (3F8) */
|
||||
{0x61, 0xF8}, /* set IO to COM1 (3F8) */
|
||||
{0x70, 04}, /* set IRQ 4 for COM1 */
|
||||
{0x30, 1}, /* and activate the device */
|
||||
{0xFF, 0} /* end of device table */
|
||||
};
|
||||
/* uart 2 (logical device 5) */
|
||||
const SIO_LOGDEV_TABLE sio_com2[] = {
|
||||
{0x60, 2}, /* set IO to COM2 (2F8) */
|
||||
{0x61, 0xF8}, /* set IO to COM2 (2F8) */
|
||||
{0x70, 03}, /* set IRQ 3 for COM2 */
|
||||
{0x30, 1}, /* and activate the device */
|
||||
{0xFF, 0} /* end of device table */
|
||||
};
|
||||
|
||||
/* keyboard controller (logical device 7) */
|
||||
const SIO_LOGDEV_TABLE sio_keyboard[] = {
|
||||
{0x70, 1}, /* set IRQ 1 for keyboard */
|
||||
{0x72, 12}, /* set IRQ 12 for mouse */
|
||||
{0xF0, 0}, /* disable Port92 (this is a PowerPC!!) */
|
||||
{0x30, 1}, /* and activate the device */
|
||||
{0xFF, 0} /* end of device table */
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Config SuperIO FDC37C672
|
||||
********************************************************************************/
|
||||
unsigned char open_cfg_super_IO(int address)
|
||||
{
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address,0x55); /* open config */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address,0x20); /* set address to DEV ID */
|
||||
if(in8(CFG_ISA_IO_BASE_ADDRESS | address | 0x1)==0x40) /* ok Device ID is correct */
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void close_cfg_super_IO(int address)
|
||||
{
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address,0xAA); /* close config */
|
||||
}
|
||||
|
||||
|
||||
unsigned char read_cfg_super_IO(int address, unsigned char function, unsigned char regaddr)
|
||||
{
|
||||
/* assuming config reg is open */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
|
||||
return in8(CFG_ISA_IO_BASE_ADDRESS | address | 1);
|
||||
}
|
||||
|
||||
void write_cfg_super_IO(int address, unsigned char function, unsigned char regaddr, unsigned char data)
|
||||
{
|
||||
/* assuming config reg is open */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,data); /* writes the data */
|
||||
}
|
||||
|
||||
void isa_write_table(SIO_LOGDEV_TABLE *ldt,unsigned char ldev)
|
||||
{
|
||||
while (ldt->index != 0xFF) {
|
||||
write_cfg_super_IO(SIO_CFG_PORT, ldev, ldt->index, ldt->val);
|
||||
ldt++;
|
||||
} /* endwhile */
|
||||
}
|
||||
|
||||
void isa_sio_loadtable(void)
|
||||
{
|
||||
unsigned char *s = getenv("floppy");
|
||||
/* setup Floppy device 0*/
|
||||
isa_write_table((SIO_LOGDEV_TABLE *)&sio_fdc,0);
|
||||
/* setup parallel port device 3 */
|
||||
if(s && !strncmp(s, "lpt", 3)) {
|
||||
printf("SIO: Floppy assigned to LPT\n");
|
||||
/* floppy is assigned to the LPT */
|
||||
isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport_fdc,3);
|
||||
}
|
||||
else {
|
||||
/*printf("Floppy assigned to internal port\n");*/
|
||||
isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport,3);
|
||||
}
|
||||
/* setup Com1 port device 4 */
|
||||
isa_write_table((SIO_LOGDEV_TABLE *)&sio_com1,4);
|
||||
/* setup Com2 port device 5 */
|
||||
isa_write_table((SIO_LOGDEV_TABLE *)&sio_com2,5);
|
||||
/* setup keyboards device 7 */
|
||||
isa_write_table((SIO_LOGDEV_TABLE *)&sio_keyboard,7);
|
||||
}
|
||||
|
||||
|
||||
void isa_sio_setup(void)
|
||||
{
|
||||
if(open_cfg_super_IO(SIO_CFG_PORT)==TRUE)
|
||||
{
|
||||
isa_sio_loadtable();
|
||||
close_cfg_super_IO(0x3F0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* IRQ Controller
|
||||
* we use the Vector mode
|
||||
*/
|
||||
|
||||
struct isa_irq_action {
|
||||
interrupt_handler_t *handler;
|
||||
void *arg;
|
||||
int count;
|
||||
};
|
||||
|
||||
static struct isa_irq_action isa_irqs[16];
|
||||
|
||||
|
||||
/*
|
||||
* This contains the irq mask for both 8259A irq controllers,
|
||||
*/
|
||||
static unsigned int cached_irq_mask = 0xffff;
|
||||
|
||||
#define cached_imr1 (unsigned char)cached_irq_mask
|
||||
#define cached_imr2 (unsigned char)(cached_irq_mask>>8)
|
||||
#define IMR_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_OCW1
|
||||
#define IMR_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_OCW1
|
||||
#define ICW1_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW1
|
||||
#define ICW1_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW1
|
||||
#define ICW2_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW2
|
||||
#define ICW2_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW2
|
||||
#define ICW3_1 ICW2_1
|
||||
#define ICW3_2 ICW2_2
|
||||
#define ICW4_1 ICW2_1
|
||||
#define ICW4_2 ICW2_2
|
||||
#define ISR_1 ICW1_1
|
||||
#define ISR_2 ICW1_2
|
||||
|
||||
|
||||
void disable_8259A_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int mask = 1 << irq;
|
||||
|
||||
cached_irq_mask |= mask;
|
||||
if (irq & 8)
|
||||
out8(IMR_2,cached_imr2);
|
||||
else
|
||||
out8(IMR_1,cached_imr1);
|
||||
}
|
||||
|
||||
void enable_8259A_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int mask = ~(1 << irq);
|
||||
|
||||
cached_irq_mask &= mask;
|
||||
if (irq & 8)
|
||||
out8(IMR_2,cached_imr2);
|
||||
else
|
||||
out8(IMR_1,cached_imr1);
|
||||
}
|
||||
/*
|
||||
int i8259A_irq_pending(unsigned int irq)
|
||||
{
|
||||
unsigned int mask = 1<<irq;
|
||||
int ret;
|
||||
|
||||
if (irq < 8)
|
||||
ret = inb(0x20) & mask;
|
||||
else
|
||||
ret = inb(0xA0) & (mask >> 8);
|
||||
spin_unlock_irqrestore(&i8259A_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function assumes to be called rarely. Switching between
|
||||
* 8259A registers is slow.
|
||||
*/
|
||||
int i8259A_irq_real(unsigned int irq)
|
||||
{
|
||||
int value;
|
||||
int irqmask = 1<<irq;
|
||||
|
||||
if (irq < 8) {
|
||||
out8(ISR_1,0x0B); /* ISR register */
|
||||
value = in8(ISR_1) & irqmask;
|
||||
out8(ISR_1,0x0A); /* back to the IRR register */
|
||||
return value;
|
||||
}
|
||||
out8(ISR_2,0x0B); /* ISR register */
|
||||
value = in8(ISR_2) & (irqmask >> 8);
|
||||
out8(ISR_2,0x0A); /* back to the IRR register */
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Careful! The 8259A is a fragile beast, it pretty
|
||||
* much _has_ to be done exactly like this (mask it
|
||||
* first, _then_ send the EOI, and the order of EOI
|
||||
* to the two 8259s is important!
|
||||
*/
|
||||
void mask_and_ack_8259A(unsigned int irq)
|
||||
{
|
||||
unsigned int irqmask = 1 << irq;
|
||||
unsigned int temp_irqmask = cached_irq_mask;
|
||||
/*
|
||||
* Lightweight spurious IRQ detection. We do not want
|
||||
* to overdo spurious IRQ handling - it's usually a sign
|
||||
* of hardware problems, so we only do the checks we can
|
||||
* do without slowing down good hardware unnecesserily.
|
||||
*
|
||||
* Note that IRQ7 and IRQ15 (the two spurious IRQs
|
||||
* usually resulting from the 8259A-1|2 PICs) occur
|
||||
* even if the IRQ is masked in the 8259A. Thus we
|
||||
* can check spurious 8259A IRQs without doing the
|
||||
* quite slow i8259A_irq_real() call for every IRQ.
|
||||
* This does not cover 100% of spurious interrupts,
|
||||
* but should be enough to warn the user that there
|
||||
* is something bad going on ...
|
||||
*/
|
||||
if (temp_irqmask & irqmask)
|
||||
goto spurious_8259A_irq;
|
||||
temp_irqmask |= irqmask;
|
||||
|
||||
handle_real_irq:
|
||||
if (irq & 8) {
|
||||
in8(IMR_2); /* DUMMY - (do we need this?) */
|
||||
out8(IMR_2,(unsigned char)(temp_irqmask>>8));
|
||||
out8(ISR_2,0x60+(irq&7));/* 'Specific EOI' to slave */
|
||||
out8(ISR_1,0x62); /* 'Specific EOI' to master-IRQ2 */
|
||||
out8(IMR_2,cached_imr2); /* turn it on again */
|
||||
} else {
|
||||
in8(IMR_1); /* DUMMY - (do we need this?) */
|
||||
out8(IMR_1,(unsigned char)temp_irqmask);
|
||||
out8(ISR_1,0x60+irq); /* 'Specific EOI' to master */
|
||||
out8(IMR_1,cached_imr1); /* turn it on again */
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
spurious_8259A_irq:
|
||||
/*
|
||||
* this is the slow path - should happen rarely.
|
||||
*/
|
||||
if (i8259A_irq_real(irq))
|
||||
/*
|
||||
* oops, the IRQ _is_ in service according to the
|
||||
* 8259A - not spurious, go handle it.
|
||||
*/
|
||||
goto handle_real_irq;
|
||||
|
||||
{
|
||||
static int spurious_irq_mask;
|
||||
/*
|
||||
* At this point we can be sure the IRQ is spurious,
|
||||
* lets ACK and report it. [once per IRQ]
|
||||
*/
|
||||
if (!(spurious_irq_mask & irqmask)) {
|
||||
PRINTF("spurious 8259A interrupt: IRQ%d.\n", irq);
|
||||
spurious_irq_mask |= irqmask;
|
||||
}
|
||||
/* irq_err_count++; */
|
||||
/*
|
||||
* Theoretically we do not have to handle this IRQ,
|
||||
* but in Linux this does not cause problems and is
|
||||
* simpler for us.
|
||||
*/
|
||||
goto handle_real_irq;
|
||||
}
|
||||
}
|
||||
|
||||
void init_8259A(void)
|
||||
{
|
||||
out8(IMR_1,0xff); /* mask all of 8259A-1 */
|
||||
out8(IMR_2,0xff); /* mask all of 8259A-2 */
|
||||
|
||||
out8(ICW1_1,0x11); /* ICW1: select 8259A-1 init */
|
||||
out8(ICW2_1,0x20 + 0); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
|
||||
out8(ICW3_1,0x04); /* 8259A-1 (the master) has a slave on IR2 */
|
||||
out8(ICW4_1,0x01); /* master expects normal EOI */
|
||||
out8(ICW1_2,0x11); /* ICW2: select 8259A-2 init */
|
||||
out8(ICW2_2,0x20 + 8); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
|
||||
out8(ICW3_2,0x02); /* 8259A-2 is a slave on master's IR2 */
|
||||
out8(ICW4_2,0x01); /* (slave's support for AEOI in flat mode
|
||||
is to be investigated) */
|
||||
udelay(10000); /* wait for 8259A to initialize */
|
||||
out8(IMR_1,cached_imr1); /* restore master IRQ mask */
|
||||
udelay(10000); /* wait for 8259A to initialize */
|
||||
out8(IMR_2,cached_imr2); /* restore slave IRQ mask */
|
||||
}
|
||||
|
||||
|
||||
#define PCI_INT_ACK_ADDR 0xEED00000
|
||||
|
||||
int handle_isa_int(void)
|
||||
{
|
||||
unsigned long irqack;
|
||||
unsigned char isr1,isr2,irq;
|
||||
/* first we acknokledge the int via the PCI bus */
|
||||
irqack=in32(PCI_INT_ACK_ADDR);
|
||||
/* now we get the ISRs */
|
||||
isr2=in8(ISR_2);
|
||||
isr1=in8(ISR_1);
|
||||
irq=(unsigned char)irqack;
|
||||
if((irq==7)&&((isr1&0x80)==0)) {
|
||||
PRINTF("IRQ7 detected but not in ISR\n");
|
||||
}
|
||||
else {
|
||||
/* we should handle cascaded interrupts here also */
|
||||
/* printf("ISA Irq %d\n",irq); */
|
||||
isa_irqs[irq].count++;
|
||||
if (isa_irqs[irq].handler != NULL)
|
||||
(*isa_irqs[irq].handler)(isa_irqs[irq].arg); /* call isr */
|
||||
else
|
||||
{
|
||||
PRINTF ("bogus interrupt vector 0x%x\n", irq);
|
||||
}
|
||||
}
|
||||
/* issue EOI instruction to clear the IRQ */
|
||||
mask_and_ack_8259A(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Install and free an ISA interrupt handler.
|
||||
*/
|
||||
|
||||
void isa_irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
|
||||
{
|
||||
if (isa_irqs[vec].handler != NULL) {
|
||||
printf ("ISA Interrupt vector %d: handler 0x%x replacing 0x%x\n",
|
||||
vec, (uint)handler, (uint)isa_irqs[vec].handler);
|
||||
}
|
||||
isa_irqs[vec].handler = handler;
|
||||
isa_irqs[vec].arg = arg;
|
||||
enable_8259A_irq(vec);
|
||||
PRINTF ("Install ISA IRQ %d ==> %p, @ %p mask=%04x\n", vec, handler, &isa_irqs[vec].handler,cached_irq_mask);
|
||||
|
||||
}
|
||||
|
||||
void isa_irq_free_handler(int vec)
|
||||
{
|
||||
disable_8259A_irq(vec);
|
||||
isa_irqs[vec].handler = NULL;
|
||||
isa_irqs[vec].arg = NULL;
|
||||
printf ("Free ISA IRQ %d mask=%04x\n", vec, cached_irq_mask);
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
void isa_init_irq_contr(void)
|
||||
{
|
||||
int i;
|
||||
/* disable all Interrupts */
|
||||
/* first write icws controller 1 */
|
||||
for(i=0;i<16;i++)
|
||||
{
|
||||
isa_irqs[i].handler=NULL;
|
||||
isa_irqs[i].arg=NULL;
|
||||
isa_irqs[i].count=0;
|
||||
}
|
||||
init_8259A();
|
||||
out8(IMR_2,0xFF);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Init the ISA bus and devices.
|
||||
*/
|
||||
|
||||
|
||||
int isa_init(void)
|
||||
{
|
||||
isa_sio_setup();
|
||||
drv_isa_kbd_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,655 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* Source partly derived from:
|
||||
* linux/drivers/char/pc_keyb.c
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <devices.h>
|
||||
#include "isa.h"
|
||||
#include "kbd.h"
|
||||
|
||||
|
||||
unsigned char kbd_read_status(void);
|
||||
unsigned char kbd_read_input(void);
|
||||
void kbd_send_data(unsigned char data);
|
||||
void disable_8259A_irq(unsigned int irq);
|
||||
void enable_8259A_irq(unsigned int irq);
|
||||
|
||||
/* used only by send_data - set by keyboard_interrupt */
|
||||
|
||||
|
||||
#undef KBG_DEBUG
|
||||
|
||||
#ifdef KBG_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
#define KBD_STAT_KOBF 0x01
|
||||
#define KBD_STAT_IBF 0x02
|
||||
#define KBD_STAT_SYS 0x04
|
||||
#define KBD_STAT_CD 0x08
|
||||
#define KBD_STAT_LOCK 0x10
|
||||
#define KBD_STAT_MOBF 0x20
|
||||
#define KBD_STAT_TI_OUT 0x40
|
||||
#define KBD_STAT_PARERR 0x80
|
||||
|
||||
#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */
|
||||
#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
|
||||
#define KBD_TIMEOUT 2000 /* Timeout in ms for keyboard command acknowledge */
|
||||
/*
|
||||
* Keyboard Controller Commands
|
||||
*/
|
||||
|
||||
#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
|
||||
#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
|
||||
#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
|
||||
#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
|
||||
#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
|
||||
#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
|
||||
#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
|
||||
#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
|
||||
#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
|
||||
#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
|
||||
#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
|
||||
initiated by the auxiliary device */
|
||||
#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
|
||||
|
||||
/*
|
||||
* Keyboard Commands
|
||||
*/
|
||||
|
||||
#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
|
||||
#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
|
||||
#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
|
||||
#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */
|
||||
#define KBD_CMD_RESET 0xFF /* Reset */
|
||||
|
||||
/*
|
||||
* Keyboard Replies
|
||||
*/
|
||||
|
||||
#define KBD_REPLY_POR 0xAA /* Power on reset */
|
||||
#define KBD_REPLY_ACK 0xFA /* Command ACK */
|
||||
#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
|
||||
|
||||
/*
|
||||
* Status Register Bits
|
||||
*/
|
||||
|
||||
#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
|
||||
#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
|
||||
#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
|
||||
#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
|
||||
#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
|
||||
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
|
||||
#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
|
||||
#define KBD_STAT_PERR 0x80 /* Parity error */
|
||||
|
||||
#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
|
||||
|
||||
/*
|
||||
* Controller Mode Register Bits
|
||||
*/
|
||||
|
||||
#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
|
||||
#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
|
||||
#define KBD_MODE_SYS 0x04 /* The system flag (?) */
|
||||
#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
|
||||
#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
|
||||
#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
|
||||
#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
|
||||
#define KBD_MODE_RFU 0x80
|
||||
|
||||
|
||||
#define KDB_DATA_PORT 0x60
|
||||
#define KDB_COMMAND_PORT 0x64
|
||||
|
||||
#define LED_SCR 0x01 /* scroll lock led */
|
||||
#define LED_CAP 0x04 /* caps lock led */
|
||||
#define LED_NUM 0x02 /* num lock led */
|
||||
|
||||
#define KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
|
||||
|
||||
|
||||
|
||||
|
||||
static volatile char kbd_buffer[KBD_BUFFER_LEN];
|
||||
static volatile int in_pointer = 0;
|
||||
static volatile int out_pointer = 0;
|
||||
|
||||
|
||||
static unsigned char num_lock = 0;
|
||||
static unsigned char caps_lock = 0;
|
||||
static unsigned char scroll_lock = 0;
|
||||
static unsigned char shift = 0;
|
||||
static unsigned char ctrl = 0;
|
||||
static unsigned char alt = 0;
|
||||
static unsigned char e0 = 0;
|
||||
static unsigned char leds = 0;
|
||||
|
||||
#define DEVNAME "kbd"
|
||||
|
||||
/* Simple translation table for the keys */
|
||||
|
||||
static unsigned char kbd_plain_xlate[] = {
|
||||
0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', /* 0x00 - 0x0f */
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's', /* 0x10 - 0x1f */
|
||||
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
|
||||
'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
|
||||
'\r',0xff,0xff
|
||||
};
|
||||
|
||||
static unsigned char kbd_shift_xlate[] = {
|
||||
0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', /* 0x00 - 0x0f */
|
||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S', /* 0x10 - 0x1f */
|
||||
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V', /* 0x20 - 0x2f */
|
||||
'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
|
||||
'\r',0xff,0xff
|
||||
};
|
||||
|
||||
static unsigned char kbd_ctrl_xlate[] = {
|
||||
0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t', /* 0x00 - 0x0f */
|
||||
0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13, /* 0x10 - 0x1f */
|
||||
0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16, /* 0x20 - 0x2f */
|
||||
0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
|
||||
'\r',0xff,0xff
|
||||
};
|
||||
|
||||
/******************************************************************
|
||||
* Init
|
||||
******************************************************************/
|
||||
int isa_kbd_init(void)
|
||||
{
|
||||
char* result;
|
||||
result=kbd_initialize();
|
||||
if(result==NULL) {
|
||||
PRINTF("AT Keyboard initialized\n");
|
||||
irq_install_handler(25, (interrupt_handler_t *)handle_isa_int, NULL);
|
||||
isa_irq_install_handler(KBD_INTERRUPT, (interrupt_handler_t *)kbd_interrupt, NULL);
|
||||
return (1);
|
||||
}
|
||||
else {
|
||||
printf("%s\n",result);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
|
||||
extern int overwrite_console (void);
|
||||
#else
|
||||
int overwrite_console (void)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int drv_isa_kbd_init (void)
|
||||
{
|
||||
int error;
|
||||
device_t kbddev ;
|
||||
char *stdinname = getenv ("stdin");
|
||||
|
||||
if(isa_kbd_init()==-1)
|
||||
return -1;
|
||||
memset (&kbddev, 0, sizeof(kbddev));
|
||||
strcpy(kbddev.name, DEVNAME);
|
||||
kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
|
||||
kbddev.putc = NULL ;
|
||||
kbddev.puts = NULL ;
|
||||
kbddev.getc = kbd_getc ;
|
||||
kbddev.tstc = kbd_testc ;
|
||||
|
||||
error = device_register (&kbddev);
|
||||
if(error==0) {
|
||||
/* check if this is the standard input device */
|
||||
if(strcmp(stdinname,DEVNAME)==0) {
|
||||
/* reassign the console */
|
||||
if(overwrite_console()) {
|
||||
return 1;
|
||||
}
|
||||
error=console_assign(stdin,DEVNAME);
|
||||
if(error==0)
|
||||
return 1;
|
||||
else
|
||||
return error;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Queue handling
|
||||
******************************************************************/
|
||||
/* puts character in the queue and sets up the in and out pointer */
|
||||
void kbd_put_queue(char data)
|
||||
{
|
||||
if((in_pointer+1)==KBD_BUFFER_LEN) {
|
||||
if(out_pointer==0) {
|
||||
return; /* buffer full */
|
||||
} else{
|
||||
in_pointer=0;
|
||||
}
|
||||
} else {
|
||||
if((in_pointer+1)==out_pointer)
|
||||
return; /* buffer full */
|
||||
in_pointer++;
|
||||
}
|
||||
kbd_buffer[in_pointer]=data;
|
||||
return;
|
||||
}
|
||||
|
||||
/* test if a character is in the queue */
|
||||
int kbd_testc(void)
|
||||
{
|
||||
if(in_pointer==out_pointer)
|
||||
return(0); /* no data */
|
||||
else
|
||||
return(1);
|
||||
}
|
||||
/* gets the character from the queue */
|
||||
int kbd_getc(void)
|
||||
{
|
||||
char c;
|
||||
while(in_pointer==out_pointer);
|
||||
if((out_pointer+1)==KBD_BUFFER_LEN)
|
||||
out_pointer=0;
|
||||
else
|
||||
out_pointer++;
|
||||
c=kbd_buffer[out_pointer];
|
||||
return (int)c;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* set LEDs */
|
||||
|
||||
void kbd_set_leds(void)
|
||||
{
|
||||
if(caps_lock==0)
|
||||
leds&=~LED_CAP; /* switch caps_lock off */
|
||||
else
|
||||
leds|=LED_CAP; /* switch on LED */
|
||||
if(num_lock==0)
|
||||
leds&=~LED_NUM; /* switch LED off */
|
||||
else
|
||||
leds|=LED_NUM; /* switch on LED */
|
||||
if(scroll_lock==0)
|
||||
leds&=~LED_SCR; /* switch LED off */
|
||||
else
|
||||
leds|=LED_SCR; /* switch on LED */
|
||||
kbd_send_data(KBD_CMD_SET_LEDS);
|
||||
kbd_send_data(leds);
|
||||
}
|
||||
|
||||
|
||||
void handle_keyboard_event(unsigned char scancode)
|
||||
{
|
||||
unsigned char keycode;
|
||||
|
||||
/* Convert scancode to keycode */
|
||||
PRINTF("scancode %x\n",scancode);
|
||||
if(scancode==0xe0) {
|
||||
e0=1; /* special charakters */
|
||||
return;
|
||||
}
|
||||
if(e0==1) {
|
||||
e0=0; /* delete flag */
|
||||
if(!( ((scancode&0x7F)==0x38)|| /* the right ctrl key */
|
||||
((scancode&0x7F)==0x1D)|| /* the right alt key */
|
||||
((scancode&0x7F)==0x35)|| /* the right '/' key */
|
||||
((scancode&0x7F)==0x1C) )) /* the right enter key */
|
||||
/* we swallow unknown e0 codes */
|
||||
return;
|
||||
}
|
||||
/* special cntrl keys */
|
||||
switch(scancode)
|
||||
{
|
||||
case 0x2A:
|
||||
case 0x36: /* shift pressed */
|
||||
shift=1;
|
||||
return; /* do nothing else */
|
||||
case 0xAA:
|
||||
case 0xB6: /* shift released */
|
||||
shift=0;
|
||||
return; /* do nothing else */
|
||||
case 0x38: /* alt pressed */
|
||||
alt=1;
|
||||
return; /* do nothing else */
|
||||
case 0xB8: /* alt released */
|
||||
alt=0;
|
||||
return; /* do nothing else */
|
||||
case 0x1d: /* ctrl pressed */
|
||||
ctrl=1;
|
||||
return; /* do nothing else */
|
||||
case 0x9d: /* ctrl released */
|
||||
ctrl=0;
|
||||
return; /* do nothing else */
|
||||
case 0x46: /* scrollock pressed */
|
||||
scroll_lock=~scroll_lock;
|
||||
kbd_set_leds();
|
||||
return; /* do nothing else */
|
||||
case 0x3A: /* capslock pressed */
|
||||
caps_lock=~caps_lock;
|
||||
kbd_set_leds();
|
||||
return;
|
||||
case 0x45: /* numlock pressed */
|
||||
num_lock=~num_lock;
|
||||
kbd_set_leds();
|
||||
return;
|
||||
case 0xC6: /* scroll lock released */
|
||||
case 0xC5: /* num lock released */
|
||||
case 0xBA: /* caps lock released */
|
||||
return; /* just swallow */
|
||||
}
|
||||
if((scancode&0x80)==0x80) /* key released */
|
||||
return;
|
||||
/* now, decide which table we need */
|
||||
if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
/* setup plain code first */
|
||||
keycode=kbd_plain_xlate[scancode];
|
||||
if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
|
||||
if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown caps-locked scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
keycode=kbd_shift_xlate[scancode];
|
||||
if(keycode<'A') { /* we only want the alphas capital */
|
||||
keycode=kbd_plain_xlate[scancode];
|
||||
}
|
||||
}
|
||||
if(shift==1) { /* shift overwrites caps_lock */
|
||||
if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown shifted scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
keycode=kbd_shift_xlate[scancode];
|
||||
}
|
||||
if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
|
||||
if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown ctrl scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
keycode=kbd_ctrl_xlate[scancode];
|
||||
}
|
||||
/* check if valid keycode */
|
||||
if(keycode==0xff) {
|
||||
PRINTF("unkown scancode %X\n",scancode);
|
||||
return; /* swallow unknown codes */
|
||||
}
|
||||
|
||||
kbd_put_queue(keycode);
|
||||
PRINTF("%x\n",keycode);
|
||||
}
|
||||
|
||||
/*
|
||||
* This reads the keyboard status port, and does the
|
||||
* appropriate action.
|
||||
*
|
||||
*/
|
||||
unsigned char handle_kbd_event(void)
|
||||
{
|
||||
unsigned char status = kbd_read_status();
|
||||
unsigned int work = 10000;
|
||||
|
||||
while ((--work > 0) && (status & KBD_STAT_OBF)) {
|
||||
unsigned char scancode;
|
||||
|
||||
scancode = kbd_read_input();
|
||||
|
||||
/* Error bytes must be ignored to make the
|
||||
Synaptics touchpads compaq use work */
|
||||
/* Ignore error bytes */
|
||||
if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
|
||||
{
|
||||
if (status & KBD_STAT_MOUSE_OBF)
|
||||
; /* not supported: handle_mouse_event(scancode); */
|
||||
else
|
||||
handle_keyboard_event(scancode);
|
||||
}
|
||||
status = kbd_read_status();
|
||||
}
|
||||
if (!work)
|
||||
PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Lowlevel Part of keyboard section
|
||||
*/
|
||||
unsigned char kbd_read_status(void)
|
||||
{
|
||||
return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
|
||||
}
|
||||
|
||||
unsigned char kbd_read_input(void)
|
||||
{
|
||||
return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
|
||||
}
|
||||
|
||||
void kbd_write_command(unsigned char cmd)
|
||||
{
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
|
||||
}
|
||||
|
||||
void kbd_write_output(unsigned char data)
|
||||
{
|
||||
out8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
|
||||
}
|
||||
|
||||
int kbd_read_data(void)
|
||||
{
|
||||
int val;
|
||||
unsigned char status;
|
||||
|
||||
val=-1;
|
||||
status = kbd_read_status();
|
||||
if (status & KBD_STAT_OBF) {
|
||||
val = kbd_read_input();
|
||||
if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
|
||||
val = -2;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int kbd_wait_for_input(void)
|
||||
{
|
||||
unsigned long timeout;
|
||||
int val;
|
||||
|
||||
timeout = KBD_TIMEOUT;
|
||||
val=kbd_read_data();
|
||||
while(val < 0)
|
||||
{
|
||||
if(timeout--==0)
|
||||
return -1;
|
||||
udelay(1000);
|
||||
val=kbd_read_data();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
int kb_wait(void)
|
||||
{
|
||||
unsigned long timeout = KBC_TIMEOUT * 10;
|
||||
|
||||
do {
|
||||
unsigned char status = handle_kbd_event();
|
||||
if (!(status & KBD_STAT_IBF))
|
||||
return 0; /* ok */
|
||||
udelay(1000);
|
||||
timeout--;
|
||||
} while (timeout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void kbd_write_command_w(int data)
|
||||
{
|
||||
if(kb_wait())
|
||||
PRINTF("timeout in kbd_write_command_w\n");
|
||||
kbd_write_command(data);
|
||||
}
|
||||
|
||||
void kbd_write_output_w(int data)
|
||||
{
|
||||
if(kb_wait())
|
||||
PRINTF("timeout in kbd_write_output_w\n");
|
||||
kbd_write_output(data);
|
||||
}
|
||||
|
||||
void kbd_send_data(unsigned char data)
|
||||
{
|
||||
unsigned char status;
|
||||
disable_8259A_irq(1); /* disable interrupt */
|
||||
kbd_write_output_w(data);
|
||||
status = kbd_wait_for_input();
|
||||
if (status == KBD_REPLY_ACK)
|
||||
enable_8259A_irq(1); /* enable interrupt */
|
||||
}
|
||||
|
||||
|
||||
char * kbd_initialize(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
in_pointer = 0; /* delete in Buffer */
|
||||
out_pointer = 0;
|
||||
/*
|
||||
* Test the keyboard interface.
|
||||
* This seems to be the only way to get it going.
|
||||
* If the test is successful a x55 is placed in the input buffer.
|
||||
*/
|
||||
kbd_write_command_w(KBD_CCMD_SELF_TEST);
|
||||
if (kbd_wait_for_input() != 0x55)
|
||||
return "Kbd: failed self test";
|
||||
/*
|
||||
* Perform a keyboard interface test. This causes the controller
|
||||
* to test the keyboard clock and data lines. The results of the
|
||||
* test are placed in the input buffer.
|
||||
*/
|
||||
kbd_write_command_w(KBD_CCMD_KBD_TEST);
|
||||
if (kbd_wait_for_input() != 0x00)
|
||||
return "Kbd: interface failed self test";
|
||||
/*
|
||||
* Enable the keyboard by allowing the keyboard clock to run.
|
||||
*/
|
||||
kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
|
||||
status = kbd_wait_for_input();
|
||||
/*
|
||||
* Reset keyboard. If the read times out
|
||||
* then the assumption is that no keyboard is
|
||||
* plugged into the machine.
|
||||
* This defaults the keyboard to scan-code set 2.
|
||||
*
|
||||
* Set up to try again if the keyboard asks for RESEND.
|
||||
*/
|
||||
do {
|
||||
kbd_write_output_w(KBD_CMD_RESET);
|
||||
status = kbd_wait_for_input();
|
||||
if (status == KBD_REPLY_ACK)
|
||||
break;
|
||||
if (status != KBD_REPLY_RESEND)
|
||||
{
|
||||
PRINTF("status: %X\n",status);
|
||||
return "Kbd: reset failed, no ACK";
|
||||
}
|
||||
} while (1);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_POR)
|
||||
return "Kbd: reset failed, no POR";
|
||||
|
||||
/*
|
||||
* Set keyboard controller mode. During this, the keyboard should be
|
||||
* in the disabled state.
|
||||
*
|
||||
* Set up to try again if the keyboard asks for RESEND.
|
||||
*/
|
||||
do {
|
||||
kbd_write_output_w(KBD_CMD_DISABLE);
|
||||
status = kbd_wait_for_input();
|
||||
if (status == KBD_REPLY_ACK)
|
||||
break;
|
||||
if (status != KBD_REPLY_RESEND)
|
||||
return "Kbd: disable keyboard: no ACK";
|
||||
} while (1);
|
||||
|
||||
kbd_write_command_w(KBD_CCMD_WRITE_MODE);
|
||||
kbd_write_output_w(KBD_MODE_KBD_INT
|
||||
| KBD_MODE_SYS
|
||||
| KBD_MODE_DISABLE_MOUSE
|
||||
| KBD_MODE_KCC);
|
||||
|
||||
/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
|
||||
kbd_write_command_w(KBD_CCMD_READ_MODE);
|
||||
if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
|
||||
/*
|
||||
* If the controller does not support conversion,
|
||||
* Set the keyboard to scan-code set 1.
|
||||
*/
|
||||
kbd_write_output_w(0xF0);
|
||||
kbd_wait_for_input();
|
||||
kbd_write_output_w(0x01);
|
||||
kbd_wait_for_input();
|
||||
}
|
||||
kbd_write_output_w(KBD_CMD_ENABLE);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_ACK)
|
||||
return "Kbd: enable keyboard: no ACK";
|
||||
|
||||
/*
|
||||
* Finally, set the typematic rate to maximum.
|
||||
*/
|
||||
kbd_write_output_w(KBD_CMD_SET_RATE);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_ACK)
|
||||
return "Kbd: Set rate: no ACK";
|
||||
kbd_write_output_w(0x00);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_ACK)
|
||||
return "Kbd: Set rate: no ACK";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kbd_interrupt(void)
|
||||
{
|
||||
handle_kbd_event();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* eof */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,513 @@
|
|||
/*
|
||||
* (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 <mpc824x.h>
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#undef DEBUG_FLASH
|
||||
|
||||
#ifdef DEBUG_FLASH
|
||||
#define DEBUGF(fmt,args...) printf(fmt ,##args)
|
||||
#else
|
||||
#define DEBUGF(fmt,args...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_char *addr, flash_info_t *info);
|
||||
static int write_data (flash_info_t *info, uchar *dest, uchar data);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* don't ask. its stupid, but more than one soul has had to live with this mistake
|
||||
* "swaptab[i]" is the value of "i" with the bits reversed.
|
||||
*/
|
||||
|
||||
#define MUSENKI_BROKEN_FLASH 1
|
||||
|
||||
#ifdef MUSENKI_BROKEN_FLASH
|
||||
unsigned char swaptab[256] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
|
||||
};
|
||||
|
||||
#define BS(b) (swaptab[b])
|
||||
|
||||
#else
|
||||
|
||||
#define BS(b) (b)
|
||||
|
||||
#endif
|
||||
|
||||
#define BYTEME(x) ((x) & 0xFF)
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",CFG_FLASH_BASE0_PRELIM);
|
||||
|
||||
size_b0 = flash_get_size((vu_char *)CFG_FLASH_BASE0_PRELIM, &flash_info[0]);
|
||||
|
||||
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
|
||||
printf ("## Unknown FLASH on Bank 0: "
|
||||
"ID 0x%lx, Size = 0x%08lx = %ld MB\n",
|
||||
flash_info[0].flash_id,
|
||||
size_b0, size_b0<<20);
|
||||
}
|
||||
|
||||
DEBUGF("## Get flash bank 2 size @ 0x%08x\n",CFG_FLASH_BASE1_PRELIM);
|
||||
size_b1 = flash_get_size((vu_char *)CFG_FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
|
||||
DEBUGF("protect monitor %x @ %x\n", CFG_MONITOR_BASE, CFG_MONITOR_LEN);
|
||||
/* 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 */
|
||||
DEBUGF("protect environtment %x @ %x\n", CFG_ENV_ADDR, CFG_ENV_SECT_SIZE);
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_ENV_ADDR,
|
||||
CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
if (size_b1) {
|
||||
flash_info[1].size = size_b1;
|
||||
flash_get_offsets (CFG_FLASH_BASE + size_b0, &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[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_SECT_SIZE-1,
|
||||
&flash_info[1]);
|
||||
#endif
|
||||
} else {
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[1].size = 0;
|
||||
}
|
||||
|
||||
DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_VENDMASK) {
|
||||
case FLASH_MAN_INTEL:
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base;
|
||||
base += 0x00020000; /* 128k per bank */
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
printf ("Don't know sector ofsets for flash type 0x%lx\n", info->flash_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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;
|
||||
case FLASH_MAN_SST: printf ("SST "); break;
|
||||
case FLASH_MAN_STM: printf ("STM "); break;
|
||||
case FLASH_MAN_INTEL: printf ("Intel "); break;
|
||||
case FLASH_MAN_MT: printf ("MT "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F320J3A: printf ("28F320J3A (32Mbit = 128K x 32)\n");
|
||||
break;
|
||||
case FLASH_28F640J3A: printf ("28F640J3A (64Mbit = 128K x 64)\n");
|
||||
break;
|
||||
case FLASH_28F128J3A: printf ("28F128J3A (128Mbit = 128K x 128)\n");
|
||||
break;
|
||||
default: printf ("Unknown Chip Type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (info->size >= (1 << 20)) {
|
||||
i = 20;
|
||||
} else {
|
||||
i = 10;
|
||||
}
|
||||
printf (" Size: %ld %cB in %d Sectors\n",
|
||||
info->size >> i,
|
||||
(i == 20) ? 'M' : 'k',
|
||||
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_char *addr, flash_info_t *info)
|
||||
{
|
||||
vu_char manuf, device;
|
||||
|
||||
addr[0] = BS(0x90);
|
||||
manuf = BS(addr[0]);
|
||||
DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (vu_char *)addr, manuf);
|
||||
|
||||
switch (manuf) {
|
||||
case BYTEME(AMD_MANUFACT):
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case BYTEME(FUJ_MANUFACT):
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
case BYTEME(SST_MANUFACT):
|
||||
info->flash_id = FLASH_MAN_SST;
|
||||
break;
|
||||
case BYTEME(STM_MANUFACT):
|
||||
info->flash_id = FLASH_MAN_STM;
|
||||
break;
|
||||
case BYTEME(INTEL_MANUFACT):
|
||||
info->flash_id = FLASH_MAN_INTEL;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
addr[0] = BS(0xFF); /* restore read mode, (yes, BS is a NOP) */
|
||||
return 0; /* no or unknown flash */
|
||||
}
|
||||
|
||||
device = BS(addr[2]); /* device ID */
|
||||
|
||||
DEBUGF("Device ID @ 0x%08x: 0x%08x\n", (&addr[1]), device);
|
||||
|
||||
switch (device) {
|
||||
case BYTEME(INTEL_ID_28F320J3A):
|
||||
info->flash_id += FLASH_28F320J3A;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case BYTEME(INTEL_ID_28F640J3A):
|
||||
info->flash_id += FLASH_28F640J3A;
|
||||
info->sector_count = 64;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case BYTEME(INTEL_ID_28F128J3A):
|
||||
info->flash_id += FLASH_28F128J3A;
|
||||
info->sector_count = 128;
|
||||
info->size = 0x01000000;
|
||||
break; /* => 16 MB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
addr[0] = BS(0xFF); /* restore read mode (yes, a NOP) */
|
||||
return 0; /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
if (info->sector_count > CFG_MAX_FLASH_SECT) {
|
||||
printf ("** ERROR: sector count %d > max (%d) **\n",
|
||||
info->sector_count, CFG_MAX_FLASH_SECT);
|
||||
info->sector_count = CFG_MAX_FLASH_SECT;
|
||||
}
|
||||
|
||||
addr[0] = BS(0xFF); /* restore read mode */
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
|
||||
printf ("Can erase only Intel flash types - aborted\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 = get_timer (0);
|
||||
last = start;
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
vu_char *addr = (vu_char *)(info->start[sect]);
|
||||
unsigned long status;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = BS(0x50); /* clear status register */
|
||||
*addr = BS(0x20); /* erase setup */
|
||||
*addr = BS(0xD0); /* erase confirm */
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag) {
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) {
|
||||
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
*addr = BS(0xB0); /* suspend erase */
|
||||
*addr = BS(0xFF); /* reset to read mode */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
*addr = BS(0xFF); /* reset to read mode */
|
||||
}
|
||||
}
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
* 4 - Flash not identified
|
||||
*/
|
||||
|
||||
#define FLASH_WIDTH 1 /* flash bus width in bytes */
|
||||
|
||||
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
uchar *wp = (uchar *)addr;
|
||||
int rc;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
while (cnt > 0) {
|
||||
if ((rc = write_data(info, wp, *src)) != 0) {
|
||||
return rc;
|
||||
}
|
||||
wp++;
|
||||
src++;
|
||||
cnt--;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_data (flash_info_t *info, uchar *dest, uchar data)
|
||||
{
|
||||
vu_char *addr = (vu_char *)dest;
|
||||
ulong status;
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((BS(*addr) & data) != data) {
|
||||
return 2;
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = BS(0x40); /* write setup */
|
||||
*addr = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag) {
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
start = get_timer (0);
|
||||
|
||||
while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
*addr = BS(0xFF); /* restore read mode */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
*addr = BS(0xFF); /* restore read mode */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
|
||||
*
|
||||
* (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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
extern u_long *my_sernum; /* from nx823.c */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Protection Flags:
|
||||
*/
|
||||
#define FLAG_PROTECT_SET 0x01
|
||||
#define FLAG_PROTECT_CLEAR 0x02
|
||||
|
||||
/* Board support for 1 or 2 flash devices */
|
||||
#undef FLASH_PORT_WIDTH32
|
||||
#define FLASH_PORT_WIDTH16
|
||||
|
||||
#ifdef FLASH_PORT_WIDTH16
|
||||
#define FLASH_PORT_WIDTH ushort
|
||||
#define FLASH_PORT_WIDTHV vu_short
|
||||
#else
|
||||
#define FLASH_PORT_WIDTH ulong
|
||||
#define FLASH_PORT_WIDTHV vu_long
|
||||
#endif
|
||||
|
||||
#define FPW FLASH_PORT_WIDTH
|
||||
#define FPWV FLASH_PORT_WIDTHV
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (FPW *addr, flash_info_t *info);
|
||||
static int write_data (flash_info_t *info, ulong dest, FPW data);
|
||||
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 memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long size_b0;
|
||||
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 - FIXME XXX */
|
||||
size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
(void)flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_FLASH_BASE,
|
||||
CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
return (size_b0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_INTEL: printf ("INTEL "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F320J3A:
|
||||
printf ("28F320J3A\n"); break;
|
||||
case FLASH_28F640J3A:
|
||||
printf ("28F640J3A\n"); break;
|
||||
case FLASH_28F128J3A:
|
||||
printf ("28F128J3A\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 (FPW *addr, flash_info_t *info)
|
||||
{
|
||||
FPW value;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x5555] = (FPW)0x00AA00AA;
|
||||
addr[0x2AAA] = (FPW)0x00550055;
|
||||
addr[0x5555] = (FPW)0x00900090;
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value) {
|
||||
case (FPW)INTEL_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_INTEL;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
addr[0] = (FPW)0x00FF00FF; /* restore read mode */
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case (FPW)INTEL_ID_28F320J3A:
|
||||
info->flash_id += FLASH_28F320J3A;
|
||||
info->sector_count = 32;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F640J3A:
|
||||
info->flash_id += FLASH_28F640J3A;
|
||||
info->sector_count = 64;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F128J3A:
|
||||
info->flash_id += FLASH_28F128J3A;
|
||||
info->sector_count = 128;
|
||||
info->size = 0x01000000;
|
||||
break; /* => 16 MB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (info->sector_count > CFG_MAX_FLASH_SECT) {
|
||||
printf ("** ERROR: sector count %d > max (%d) **\n",
|
||||
info->sector_count, CFG_MAX_FLASH_SECT);
|
||||
info->sector_count = CFG_MAX_FLASH_SECT;
|
||||
}
|
||||
|
||||
addr[0] = (FPW)0x00FF00FF; /* restore read mode */
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
int flag, prot, sect;
|
||||
ulong type, start, now, last;
|
||||
int rcode = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
type = (info->flash_id & FLASH_VENDMASK);
|
||||
if ((type != FLASH_MAN_INTEL)) {
|
||||
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");
|
||||
}
|
||||
|
||||
start = get_timer (0);
|
||||
last = start;
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
FPWV *addr = (FPWV *)(info->start[sect]);
|
||||
FPW status;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = (FPW)0x00500050; /* clear status register */
|
||||
*addr = (FPW)0x00200020; /* erase setup */
|
||||
*addr = (FPW)0x00D000D0; /* erase confirm */
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 80us - let's wait 1 ms */
|
||||
udelay (1000);
|
||||
|
||||
while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) {
|
||||
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
*addr = (FPW)0x00B000B0; /* suspend erase */
|
||||
*addr = (FPW)0x00FF00FF; /* reset to read mode */
|
||||
rcode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
*addr = (FPW)0x00FF00FF; /* reset to read mode */
|
||||
printf (" done\n");
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
* 4 - Flash not identified
|
||||
*/
|
||||
|
||||
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
ulong cp, wp;
|
||||
FPW data;
|
||||
int count, i, l, rc, port_width;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return 4;
|
||||
}
|
||||
/* get lower word aligned address */
|
||||
#ifdef FLASH_PORT_WIDTH16
|
||||
wp = (addr & ~1);
|
||||
port_width = 2;
|
||||
#else
|
||||
wp = (addr & ~3);
|
||||
port_width = 4;
|
||||
#endif
|
||||
|
||||
/* save sernum if needed */
|
||||
if (addr >= CFG_FLASH_SN_SECTOR && addr < CFG_FLASH_SN_BASE)
|
||||
{
|
||||
u_long dest = CFG_FLASH_SN_BASE;
|
||||
u_short *sn = (u_short *)my_sernum;
|
||||
|
||||
printf("(saving sernum)");
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ((rc = write_data(info, dest, sn[i])) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
dest += port_width;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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<port_width && cnt>0; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
++cp;
|
||||
}
|
||||
for (; cnt==0 && i<port_width; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += port_width;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle word aligned part
|
||||
*/
|
||||
count = 0;
|
||||
while (cnt >= port_width) {
|
||||
data = 0;
|
||||
for (i=0; i<port_width; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
}
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += port_width;
|
||||
cnt -= port_width;
|
||||
if (count++ > 0x800)
|
||||
{
|
||||
putc('.');
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
data = 0;
|
||||
for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
}
|
||||
for (; i<port_width; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
return (write_data(info, wp, data));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word or halfword to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_data (flash_info_t *info, ulong dest, FPW data)
|
||||
{
|
||||
FPWV *addr = (FPWV *)dest;
|
||||
ulong status;
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*addr & data) != data) {
|
||||
printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*addr = (FPW)0x00400040; /* write setup */
|
||||
*addr = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
start = get_timer (0);
|
||||
|
||||
while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
*addr = (FPW)0x00FF00FF; /* restore read mode */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
*addr = (FPW)0x00FF00FF; /* restore read mode */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* 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 <config.h>
|
||||
#include <common.h>
|
||||
#include <flash.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#undef DEBUG_FLASH
|
||||
|
||||
#ifdef DEBUG_FLASH
|
||||
#define DEBUGF(fmt,args...) printf(fmt ,##args)
|
||||
#else
|
||||
#define DEBUGF(fmt,args...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
|
||||
|
||||
static ulong flash_get_size (ulong addr, flash_info_t *info);
|
||||
static int flash_get_offsets (ulong base, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
static void flash_reset (ulong addr);
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long flash_size = 0;
|
||||
|
||||
/* Init: no FLASHes known */
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[i].sector_count = 0;
|
||||
flash_info[i].size = 0;
|
||||
}
|
||||
|
||||
DEBUGF("\n## Get flash size @ 0x%08x\n", CFG_FLASH_BASE);
|
||||
|
||||
flash_size = flash_get_size (CFG_FLASH_BASE, flash_info);
|
||||
|
||||
DEBUGF("## Flash bank size: %08lx\n", flash_size);
|
||||
|
||||
if (flash_size) {
|
||||
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE && \
|
||||
CFG_MONITOR_BASE < CFG_FLASH_BASE + CFG_FLASH_MAX_SIZE
|
||||
/* 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_SECT_SIZE - 1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
puts ("Warning: the BOOT Flash is not initialised !");
|
||||
}
|
||||
|
||||
return flash_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
static ulong flash_get_size (ulong addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
uchar value;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
out8(addr + 0x0555, 0xAA);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x02AA, 0x55);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x0555, 0x90);
|
||||
iobarrier_rw();
|
||||
|
||||
value = in8(addr);
|
||||
iobarrier_rw();
|
||||
|
||||
DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
|
||||
|
||||
switch (value | (value << 16)) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
|
||||
case STM_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_STM;
|
||||
break;
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
flash_reset (addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = in8(addr + 1); /* device ID */
|
||||
iobarrier_rw();
|
||||
|
||||
DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_F040B:
|
||||
DEBUGF("Am29F040B\n");
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512 kB */
|
||||
|
||||
case AMD_ID_LV040B:
|
||||
DEBUGF("Am29LV040B\n");
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512 kB */
|
||||
|
||||
case AMD_ID_LV400T:
|
||||
DEBUGF("Am29LV400T\n");
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
DEBUGF("Am29LV400B\n");
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
DEBUGF("Am29LV800T\n");
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
DEBUGF("Am29LV400B\n");
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
DEBUGF("Am29LV160T\n");
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
DEBUGF("Am29LV160B\n");
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV320T:
|
||||
DEBUGF("Am29LV320T\n");
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
#if 0
|
||||
/* Has the same ID as AMD_ID_LV320T, to be fixed */
|
||||
case AMD_ID_LV320B:
|
||||
DEBUGF("Am29LV320B\n");
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
|
||||
case AMD_ID_LV033C:
|
||||
DEBUGF("Am29LV033C\n");
|
||||
info->flash_id += FLASH_AM033C;
|
||||
info->sector_count = 64;
|
||||
info->size = 0x01000000;
|
||||
break; /* => 16Mb */
|
||||
|
||||
case STM_ID_F040B:
|
||||
DEBUGF("M29F040B\n");
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00080000;
|
||||
break; /* => 512 kB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
flash_reset (addr);
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
if (info->sector_count > CFG_MAX_FLASH_SECT) {
|
||||
printf ("** ERROR: sector count %d > max (%d) **\n",
|
||||
info->sector_count, CFG_MAX_FLASH_SECT);
|
||||
info->sector_count = CFG_MAX_FLASH_SECT;
|
||||
}
|
||||
|
||||
if (! flash_get_offsets (addr, info)) {
|
||||
flash_reset (addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
value = in8(info->start[i] + 2);
|
||||
iobarrier_rw();
|
||||
info->protect[i] = (value & 1) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset bank to read mode
|
||||
*/
|
||||
flash_reset (addr);
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
static int flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AM040:
|
||||
/* set sector offsets for uniform sector type */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + i * info->size /
|
||||
info->sector_count;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
volatile ulong addr = 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) {
|
||||
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();
|
||||
|
||||
out8(addr + 0x555, 0xAA);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x2AA, 0x55);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x555, 0x80);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x555, 0xAA);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x2AA, 0x55);
|
||||
iobarrier_rw();
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = info->start[sect];
|
||||
out8(addr, 0x30);
|
||||
iobarrier_rw();
|
||||
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 = info->start[l_sect];
|
||||
|
||||
DEBUGF ("Start erase timeout: %d\n", CFG_FLASH_ERASE_TOUT);
|
||||
|
||||
while ((in8(addr) & 0x80) != 0x80) {
|
||||
if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
flash_reset (info->start[0]);
|
||||
return 1;
|
||||
}
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
iobarrier_rw();
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
flash_reset (info->start[0]);
|
||||
|
||||
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)
|
||||
{
|
||||
volatile ulong addr = info->start[0];
|
||||
ulong start;
|
||||
int i;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((in32(dest) & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* write each byte out */
|
||||
for (i = 0; i < 4; i++) {
|
||||
char *data_ch = (char *)&data;
|
||||
int flag = disable_interrupts();
|
||||
|
||||
out8(addr + 0x555, 0xAA);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x2AA, 0x55);
|
||||
iobarrier_rw();
|
||||
out8(addr + 0x555, 0xA0);
|
||||
iobarrier_rw();
|
||||
out8(dest+i, data_ch[i]);
|
||||
iobarrier_rw();
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
flash_reset (addr);
|
||||
return (1);
|
||||
}
|
||||
iobarrier_rw();
|
||||
}
|
||||
}
|
||||
|
||||
flash_reset (addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset bank to read mode
|
||||
*/
|
||||
static void flash_reset (ulong addr)
|
||||
{
|
||||
out8(addr, 0xF0); /* reset bank */
|
||||
iobarrier_rw();
|
||||
}
|
||||
|
||||
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;
|
||||
case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
|
||||
case FLASH_MAN_STM: printf ("SGS THOMSON "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
if (info->size % 0x100000 == 0) {
|
||||
printf (" Size: %ld MB in %d Sectors\n",
|
||||
info->size / 0x100000, info->sector_count);
|
||||
} else if (info->size % 0x400 == 0) {
|
||||
printf (" Size: %ld KB in %d Sectors\n",
|
||||
info->size / 0x400, info->sector_count);
|
||||
} else {
|
||||
printf (" Size: %ld B 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[i],
|
||||
info->protect[i] ? " (RO)" : " "
|
||||
);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _PCIPPC2_H_
|
||||
#define _PCIPPC2_H_
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
#define FPGA(r, p) (pcippc2_fpga0_phys + HW_FPGA0_##r##_##p)
|
||||
#define UART(r) (pcippc2_fpga0_phys + HW_FPGA0_UART1 + NS16550_##r * 4)
|
||||
#define RTC(r) (pcippc2_fpga1_phys + HW_FPGA1_RTC + r)
|
||||
|
||||
extern u32 pcippc2_fpga0_phys;
|
||||
extern u32 pcippc2_fpga1_phys;
|
||||
|
||||
extern u32 pcippc2_sdram_size (void);
|
||||
|
||||
extern void pcippc2_fpga_init (void);
|
||||
|
||||
extern void cpc710_pci_init (void);
|
||||
extern void cpc710_pci_enable_timeout (void);
|
||||
|
||||
extern unsigned long
|
||||
cpc710_ram_init (void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* 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 <config.h>
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "pci.h"
|
||||
|
||||
#include "hardware.h"
|
||||
#include "pcippc2.h"
|
||||
|
||||
u32 pcippc2_fpga0_phys;
|
||||
u32 pcippc2_fpga1_phys;
|
||||
|
||||
void pcippc2_fpga_init (void)
|
||||
{
|
||||
pci_dev_t bdf = pci_find_device(FPGA_VENDOR_ID, FPGA_DEVICE_ID, 0);
|
||||
unsigned int addr;
|
||||
u16 cmd;
|
||||
|
||||
if (bdf == -1)
|
||||
{
|
||||
puts("Unable to find FPGA !\n");
|
||||
hang();
|
||||
}
|
||||
|
||||
pci_read_config_word(bdf, PCI_COMMAND, &cmd);
|
||||
if ((cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) != (PCI_COMMAND_MEMORY | PCI_COMMAND_IO))
|
||||
{
|
||||
puts("FPGA is not configured !\n");
|
||||
hang();
|
||||
}
|
||||
|
||||
pci_read_config_dword(bdf, PCI_BASE_ADDRESS_0, &addr);
|
||||
if (addr & 0x1)
|
||||
{
|
||||
/* IO space
|
||||
*/
|
||||
pcippc2_fpga0_phys = pci_io_to_phys(bdf, addr & 0xfffffffc);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Memory space
|
||||
*/
|
||||
pcippc2_fpga0_phys = pci_mem_to_phys(bdf, addr & 0xfffffff0);
|
||||
}
|
||||
|
||||
pci_read_config_dword(bdf, PCI_BASE_ADDRESS_1, &addr);
|
||||
if (addr & 0x1)
|
||||
{
|
||||
/* IO space
|
||||
*/
|
||||
pcippc2_fpga1_phys = pci_io_to_phys(bdf, addr & 0xfffffffc);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Memory space
|
||||
*/
|
||||
pcippc2_fpga1_phys = pci_mem_to_phys(bdf, addr & 0xfffffff0);
|
||||
}
|
||||
|
||||
/* Interrupts are not used
|
||||
*/
|
||||
out32(FPGA(INT, INTR_MASK), 0xffffffff);
|
||||
iobarrier_rw();
|
||||
}
|
|
@ -0,0 +1,434 @@
|
|||
/*
|
||||
* (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.
|
||||
*
|
||||
* Flash Routines for AMD 29F080B devices
|
||||
* Added support for 64bit and AMD 29DL323B
|
||||
*
|
||||
*--------------------------------------------------------------------
|
||||
* 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 <asm/io.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
|
||||
|
||||
#define RD_SWP32(x) in_le32((volatile u32*)x)
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (vu_long *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;
|
||||
int i;
|
||||
|
||||
/* Init: no FLASHes known */
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* for now, only support the 4 MB Flash SIMM */
|
||||
size = flash_get_size((vu_long *)CFG_FLASH0_BASE, &flash_info[0]);
|
||||
|
||||
/*
|
||||
* protect monitor and environment sectors
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#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*/ (CFG_FLASH0_SIZE * 1024 * 1024);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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 (AMD_MANUFACT & FLASH_VENDMASK):
|
||||
printf ("AMD ");
|
||||
break;
|
||||
case (FUJ_MANUFACT & FLASH_VENDMASK):
|
||||
printf ("FUJITSU ");
|
||||
break;
|
||||
case (SST_MANUFACT & FLASH_VENDMASK):
|
||||
printf ("SST ");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown Vendor ");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case (AMD_ID_DL323B & FLASH_TYPEMASK):
|
||||
printf("AM29DL323B (32 MBit)\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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
vu_long vendor[2], devid[2];
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
/* Reset and Write auto select command: read Manufacturer ID */
|
||||
addr[0] = 0xf0f0f0f0;
|
||||
addr[2 * 0x0555] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA] = 0x55555555;
|
||||
addr[2 * 0x0555] = 0x90909090;
|
||||
addr[1] = 0xf0f0f0f0;
|
||||
addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA + 1] = 0x55555555;
|
||||
addr[2 * 0x0555 + 1] = 0x90909090;
|
||||
udelay (1000);
|
||||
|
||||
vendor[0] = RD_SWP32(&addr[0]);
|
||||
vendor[1] = RD_SWP32(&addr[1]);
|
||||
if (vendor[0] != vendor[1] || vendor[0] != AMD_MANUFACT) {
|
||||
info->size = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
devid[0] = RD_SWP32(&addr[2]);
|
||||
devid[1] = RD_SWP32(&addr[3]);
|
||||
|
||||
if (devid[0] == AMD_ID_DL323B) {
|
||||
/*
|
||||
* we have 2 Banks
|
||||
* Bank 1 (23 Sectors): 0-7=8kbyte, 8-22=64kbyte
|
||||
* Bank 2 (48 Sectors): 23-70=64kbyte
|
||||
*/
|
||||
info->flash_id = (AMD_MANUFACT & FLASH_VENDMASK) |
|
||||
(AMD_ID_DL323B & FLASH_TYPEMASK);
|
||||
info->sector_count = 71;
|
||||
info->size = 4 * (8 * 8 + 63 * 64) * 1024;
|
||||
}
|
||||
else {
|
||||
info->size = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* set up sector start address table */
|
||||
for (i = 0; i < 8; i++) {
|
||||
info->start[i] = base + (i * 0x8000);
|
||||
}
|
||||
for (i = 8; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x40000) + 8 * 0x8000 - 8 * 0x40000;
|
||||
}
|
||||
|
||||
/* check for protected sectors */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
/* read sector protection at sector address */
|
||||
addr = (volatile unsigned long *)(info->start[i]);
|
||||
addr[2 * 0x0555] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA] = 0x55555555;
|
||||
addr[2 * 0x0555] = 0x90909090;
|
||||
addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA + 1] = 0x55555555;
|
||||
addr[2 * 0x0555 + 1] = 0x90909090;
|
||||
udelay (1000);
|
||||
base = RD_SWP32(&addr[4]);
|
||||
base |= RD_SWP32(&addr[5]);
|
||||
info->protect[i] = base & 0x00010001 ? 1 : 0;
|
||||
}
|
||||
addr = (vu_long*)info->start[0];
|
||||
|
||||
out:
|
||||
/* reset command */
|
||||
addr[0] = 0xf0f0f0f0;
|
||||
addr[1] = 0xf0f0f0f0;
|
||||
|
||||
return info->size;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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");
|
||||
}
|
||||
|
||||
l_sect = -1;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
addr[2 * 0x0555] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA] = 0x55555555;
|
||||
addr[2 * 0x0555] = 0x80808080;
|
||||
addr[2 * 0x0555] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA] = 0x55555555;
|
||||
addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA + 1] = 0x55555555;
|
||||
addr[2 * 0x0555 + 1] = 0x80808080;
|
||||
addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA + 1] = 0x55555555;
|
||||
udelay (100);
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
addr[0] = 0x30303030;
|
||||
addr[1] = 0x30303030;
|
||||
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_long*)(info->start[l_sect]);
|
||||
while ( (addr[0] & 0x80808080) != 0x80808080 ||
|
||||
(addr[1] & 0x80808080) != 0x80808080) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
addr[0] = 0xF0F0F0F0; /* reset bank */
|
||||
addr[1] = 0xF0F0F0F0; /* reset bank */
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
if ((dest & 0x00000004) == 0) {
|
||||
addr[2 * 0x0555] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA] = 0x55555555;
|
||||
addr[2 * 0x0555] = 0xA0A0A0A0;
|
||||
}
|
||||
else {
|
||||
addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
|
||||
addr[2 * 0x02AA + 1] = 0x55555555;
|
||||
addr[2 * 0x0555 + 1] = 0xA0A0A0A0;
|
||||
}
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,108 @@
|
|||
#include <common.h>
|
||||
#include <mii_phy.h>
|
||||
#include "rpxsuper.h"
|
||||
|
||||
#define MII_MDIO 0x01
|
||||
#define MII_MDCK 0x02
|
||||
#define MII_MDIR 0x04
|
||||
|
||||
void
|
||||
mii_discover_phy(void)
|
||||
{
|
||||
int known;
|
||||
unsigned short phy_reg;
|
||||
unsigned long phy_id;
|
||||
|
||||
known = 0;
|
||||
printf("Discovering phy @ 0: ");
|
||||
phy_id = mii_phy_read(2) << 16;
|
||||
phy_id |= mii_phy_read(3);
|
||||
if ((phy_id & 0xFFFFFC00) == 0x00137800) {
|
||||
printf("Level One ");
|
||||
if ((phy_id & 0x000003F0) == 0xE0) {
|
||||
printf("LXT971A Revision %d\n", (int)(phy_id & 0xF));
|
||||
known = 1;
|
||||
}
|
||||
else printf("unknown type\n");
|
||||
}
|
||||
else printf("unknown OUI = 0x%08lX\n", phy_id);
|
||||
|
||||
phy_reg = mii_phy_read(1);
|
||||
if (!(phy_reg & 0x0004)) printf("Link is down\n");
|
||||
if (!(phy_reg & 0x0020)) printf("Auto-negotiation not complete\n");
|
||||
if (phy_reg & 0x0002) printf("Jabber condition detected\n");
|
||||
if (phy_reg & 0x0010) printf("Remote fault condition detected \n");
|
||||
|
||||
if (known) {
|
||||
phy_reg = mii_phy_read(17);
|
||||
if (phy_reg & 0x0400)
|
||||
printf("Phy operating at %d MBit/s in %s-duplex mode\n",
|
||||
phy_reg & 0x4000 ? 100 : 10,
|
||||
phy_reg & 0x0200 ? "full" : "half");
|
||||
else
|
||||
printf("bad link!!\n");
|
||||
/*
|
||||
left off: no link, green 100MBit, yellow 10MBit
|
||||
right off: no activity, green full-duplex, yellow half-duplex
|
||||
*/
|
||||
mii_phy_write(20, 0x0452);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short
|
||||
mii_phy_read(unsigned short reg)
|
||||
{
|
||||
int i;
|
||||
unsigned short tmp, val = 0, adr = 0;
|
||||
t_rpx_regs *regs = (t_rpx_regs*)CFG_REGS_BASE;
|
||||
|
||||
tmp = 0x6002 | (adr << 7) | (reg << 2);
|
||||
regs->bcsr4 = 0xC3;
|
||||
for (i = 0; i < 64; i++) {
|
||||
regs->bcsr4 ^= MII_MDCK;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
regs->bcsr4 &= ~MII_MDCK;
|
||||
if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
|
||||
else regs->bcsr4 &= ~MII_MDIO;
|
||||
regs->bcsr4 |= MII_MDCK;
|
||||
tmp <<= 1;
|
||||
}
|
||||
regs->bcsr4 |= MII_MDIR;
|
||||
for (i = 0; i < 16; i++) {
|
||||
val <<= 1;
|
||||
regs->bcsr4 = MII_MDIO | (regs->bcsr4 | MII_MDCK);
|
||||
if (regs->bcsr4 & MII_MDIO) val |= 1;
|
||||
regs->bcsr4 = MII_MDIO | (regs->bcsr4 &= ~MII_MDCK);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
mii_phy_write(unsigned short reg, unsigned short val)
|
||||
{
|
||||
int i;
|
||||
unsigned short tmp, adr = 0;
|
||||
t_rpx_regs *regs = (t_rpx_regs*)CFG_REGS_BASE;
|
||||
|
||||
tmp = 0x5002 | (adr << 7) | (reg << 2);
|
||||
regs->bcsr4 = 0xC3;
|
||||
for (i = 0; i < 64; i++) {
|
||||
regs->bcsr4 ^= MII_MDCK;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
regs->bcsr4 &= ~MII_MDCK;
|
||||
if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
|
||||
else regs->bcsr4 &= ~MII_MDIO;
|
||||
regs->bcsr4 |= MII_MDCK;
|
||||
tmp <<= 1;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
regs->bcsr4 &= ~MII_MDCK;
|
||||
if (val & 0x8000) regs->bcsr4 |= MII_MDIO;
|
||||
else regs->bcsr4 &= ~MII_MDIO;
|
||||
regs->bcsr4 |= MII_MDCK;
|
||||
val <<= 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* (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.
|
||||
*
|
||||
* Flash Routines for AM290[48]0B 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 hardware ids */
|
||||
#define VENDOR_AMD 0x0001
|
||||
#define AMD_29DL323C_B 0x2253
|
||||
|
||||
/* Define this to include autoselect sequence in flash_init(). Does NOT
|
||||
* work when executing from flash itself, so this should be turned
|
||||
* on only when debugging the RAM version.
|
||||
*/
|
||||
#undef WITH_AUTOSELECT
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if 1
|
||||
#define D(x)
|
||||
#else
|
||||
#define D(x) printf x
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static unsigned char write_ull(flash_info_t *info,
|
||||
unsigned long address,
|
||||
volatile unsigned long long data);
|
||||
|
||||
/* from flash_asm.S */
|
||||
extern void ull_write(unsigned long long volatile *address,
|
||||
unsigned long long volatile *data);
|
||||
extern void ull_read(unsigned long long volatile *address,
|
||||
unsigned long long volatile *data);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
int i;
|
||||
ulong addr;
|
||||
|
||||
#ifdef WITH_AUTOSELECT
|
||||
{
|
||||
unsigned long long *f_addr = (unsigned long long *)PHYS_FLASH;
|
||||
unsigned long long f_command, vendor, device;
|
||||
/* Perform Autoselect */
|
||||
f_command = 0x00AA00AA00AA00AAULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
f_command = 0x0055005500550055ULL;
|
||||
ull_write(&f_addr[0x2AA], &f_command);
|
||||
f_command = 0x0090009000900090ULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
ull_read(&f_addr[0], &vendor);
|
||||
vendor &= 0xffff;
|
||||
ull_read(&f_addr[1], &device);
|
||||
device &= 0xffff;
|
||||
f_command = 0x00F000F000F000F0ULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
if (vendor != VENDOR_AMD || device != AMD_29DL323C_B)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init: no FLASHes known */
|
||||
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* 1st bank: 8 x 32 KB sectors */
|
||||
flash_info[0].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
|
||||
flash_info[0].sector_count = 8;
|
||||
flash_info[0].size = flash_info[0].sector_count * 32 * 1024;
|
||||
addr = PHYS_FLASH;
|
||||
for(i = 0; i < flash_info[0].sector_count; i++) {
|
||||
flash_info[0].start[i] = addr;
|
||||
addr += flash_info[0].size / flash_info[0].sector_count;
|
||||
}
|
||||
/* 1st bank: 63 x 256 KB sectors */
|
||||
flash_info[1].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
|
||||
flash_info[1].sector_count = 63;
|
||||
flash_info[1].size = flash_info[1].sector_count * 256 * 1024;
|
||||
for(i = 0; i < flash_info[1].sector_count; i++) {
|
||||
flash_info[1].start[i] = addr;
|
||||
addr += flash_info[1].size / flash_info[1].sector_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* protect monitor and environment sectors
|
||||
*/
|
||||
|
||||
#if CFG_MONITOR_BASE >= PHYS_FLASH
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_MONITOR_BASE,
|
||||
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[0]);
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_MONITOR_BASE,
|
||||
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[1]);
|
||||
#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
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_ENV_ADDR,
|
||||
CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
|
||||
&flash_info[0]);
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
CFG_ENV_ADDR,
|
||||
CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
|
||||
&flash_info[1]);
|
||||
#endif
|
||||
|
||||
return flash_info[0].size + flash_info[1].size;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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) {
|
||||
case VENDOR_AMD:
|
||||
printf ("AMD ");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown Vendor ");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case AMD_29DL323C_B:
|
||||
printf ("AM29DL323CB (32 Mbit)\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;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
int flag, prot, sect, l_sect;
|
||||
ulong start;
|
||||
unsigned long long volatile *f_addr;
|
||||
unsigned long long volatile f_command;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
f_addr = (unsigned long long *)info->start[0];
|
||||
f_command = 0x00AA00AA00AA00AAULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
f_command = 0x0055005500550055ULL;
|
||||
ull_write(&f_addr[0x2AA], &f_command);
|
||||
f_command = 0x0080008000800080ULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
f_command = 0x00AA00AA00AA00AAULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
f_command = 0x0055005500550055ULL;
|
||||
ull_write(&f_addr[0x2AA], &f_command);
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (l_sect = -1, sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
|
||||
f_addr =
|
||||
(unsigned long long *)(info->start[sect]);
|
||||
f_command = 0x0030003000300030ULL;
|
||||
ull_write(f_addr, &f_command);
|
||||
l_sect = sect;
|
||||
}
|
||||
}
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
start = get_timer (0);
|
||||
do
|
||||
{
|
||||
if (get_timer(start) > CFG_FLASH_ERASE_TOUT)
|
||||
{ /* write reset command, command address is unimportant */
|
||||
/* this command turns the flash back to read mode */
|
||||
f_addr =
|
||||
(unsigned long long *)(info->start[l_sect]);
|
||||
f_command = 0x00F000F000F000F0ULL;
|
||||
ull_write(f_addr, &f_command);
|
||||
printf (" timeout\n");
|
||||
return 1;
|
||||
}
|
||||
} while(*f_addr != 0xFFFFFFFFFFFFFFFFULL);
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned long cp, wp;
|
||||
unsigned long long data;
|
||||
int i, l, rc;
|
||||
|
||||
wp = (addr & ~7); /* get lower long long 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<8 && cnt>0; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
++cp;
|
||||
}
|
||||
for (; cnt==0 && i<8; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
if ((rc = write_ull(info, wp, data)) != 0) {
|
||||
return rc;
|
||||
}
|
||||
wp += 4;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle long long aligned part
|
||||
*/
|
||||
while (cnt >= 8) {
|
||||
data = 0;
|
||||
for (i=0; i<8; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
}
|
||||
if ((rc = write_ull(info, wp, data)) != 0) {
|
||||
return rc;
|
||||
}
|
||||
wp += 8;
|
||||
cnt -= 8;
|
||||
}
|
||||
|
||||
if (cnt == 0) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
data = 0;
|
||||
for (i=0, cp=wp; i<8 && cnt>0; ++i, ++cp) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
}
|
||||
for (; i<8; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
return write_ull(info, wp, data);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* FUNCTION NAME: write_ull
|
||||
*
|
||||
* DESCRIPTION: writes 8 bytes to flash
|
||||
*
|
||||
* EXTERNAL EFFECT: nothing
|
||||
*
|
||||
* PARAMETERS: 32 bit long pointer to address, 64 bit long pointer to data
|
||||
*
|
||||
* RETURNS: 0 if OK, 1 if timeout, 4 if parameter error
|
||||
*--------------------------------------------------------------------------*/
|
||||
|
||||
static unsigned char write_ull(flash_info_t *info,
|
||||
unsigned long address,
|
||||
volatile unsigned long long data)
|
||||
{
|
||||
static unsigned long long f_command;
|
||||
static unsigned long long *f_addr;
|
||||
ulong start;
|
||||
|
||||
/* address muss be 8-aligned! */
|
||||
if (address & 0x7)
|
||||
return ERR_ALIGN;
|
||||
|
||||
f_addr = (unsigned long long *)info->start[0];
|
||||
f_command = 0x00AA00AA00AA00AAULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
f_command = 0x0055005500550055ULL;
|
||||
ull_write(&f_addr[0x2AA], &f_command);
|
||||
f_command = 0x00A000A000A000A0ULL;
|
||||
ull_write(&f_addr[0x555], &f_command);
|
||||
|
||||
f_addr = (unsigned long long *)address;
|
||||
f_command = data;
|
||||
ull_write(f_addr, &f_command);
|
||||
|
||||
start = get_timer (0);
|
||||
do
|
||||
{
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT)
|
||||
{
|
||||
/* write reset command, command address is unimportant */
|
||||
/* this command turns the flash back to read mode */
|
||||
f_addr = (unsigned long long *)info->start[0];
|
||||
f_command = 0x00F000F000F000F0ULL;
|
||||
ull_write(f_addr, &f_command);
|
||||
return ERR_TIMOUT;
|
||||
}
|
||||
} while(*((unsigned long long *)address) != data);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
* (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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 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) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: "
|
||||
"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,
|
||||
size_b0, size_b0<<20
|
||||
);
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#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
|
||||
|
||||
if (size_b1) {
|
||||
memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
|
||||
memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
|
||||
BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
|
||||
&flash_info[1]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE + size_b0, &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[1]);
|
||||
#endif
|
||||
} else {
|
||||
memctl->memc_br1 = 0; /* invalidate bank */
|
||||
|
||||
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;
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
addr[0] = 0x00300030;
|
||||
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_long*)(info->start[l_sect]);
|
||||
while ((addr[0] & 0x00800080) != 0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,653 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <commproc.h>
|
||||
|
||||
#include "atm.h"
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#define SYNC __asm__("sync")
|
||||
#define ALIGN(p, a) ((char *)(((uint32)(p)+(a)-1) & ~((uint32)(a)-1)))
|
||||
|
||||
#define FALSE 1
|
||||
#define TRUE 0
|
||||
#define OK 0
|
||||
#define ERROR -1
|
||||
|
||||
struct atm_connection_t g_conn[NUM_CONNECTIONS] =
|
||||
{
|
||||
{ NULL, 10, NULL, 10, NULL, NULL, NULL, NULL }, /* OAM */
|
||||
};
|
||||
|
||||
struct atm_driver_t g_atm =
|
||||
{
|
||||
FALSE, /* loaded */
|
||||
FALSE, /* started */
|
||||
NULL, /* csram */
|
||||
0, /* csram_size */
|
||||
NULL, /* am_top */
|
||||
NULL, /* ap_top */
|
||||
NULL, /* int_reload_ptr */
|
||||
NULL, /* int_serv_ptr */
|
||||
NULL, /* rbd_base_ptr */
|
||||
NULL, /* tbd_base_ptr */
|
||||
0 /* linerate */
|
||||
};
|
||||
|
||||
char csram[1024]; /* more than enough for doing nothing*/
|
||||
|
||||
int atmLoad(void);
|
||||
void atmUnload(void);
|
||||
int atmMemInit(void);
|
||||
void atmIntInit(void);
|
||||
void atmApcInit(void);
|
||||
void atmAmtInit(void);
|
||||
void atmCpmInit(void);
|
||||
void atmUtpInit(void);
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmLoad
|
||||
*
|
||||
* DESCRIPTION: Basic ATM initialization.
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
****************************************************************************/
|
||||
int atmLoad()
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
|
||||
volatile iop8xx_t *iop = &immap->im_ioport;
|
||||
|
||||
timers->cpmt_tgcr &= 0x0FFF; SYNC; /* Disable Timer 4 */
|
||||
immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC; /* Disable SCC4 */
|
||||
iop->iop_pdpar &= 0x3FFF; SYNC; /* Disable SAR and UTOPIA */
|
||||
|
||||
if ( atmMemInit() != OK ) return ERROR;
|
||||
|
||||
atmIntInit();
|
||||
atmApcInit();
|
||||
atmAmtInit();
|
||||
atmCpmInit();
|
||||
atmUtpInit();
|
||||
|
||||
g_atm.loaded = TRUE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmUnload
|
||||
*
|
||||
* DESCRIPTION: Disables ATM and UTOPIA.
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
****************************************************************************/
|
||||
void atmUnload()
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
|
||||
volatile iop8xx_t *iop = &immap->im_ioport;
|
||||
|
||||
timers->cpmt_tgcr &= 0x0FFF; SYNC; /* Disable Timer 4 */
|
||||
immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC; /* Disable SCC4 */
|
||||
iop->iop_pdpar &= 0x3FFF; SYNC; /* Disable SAR and UTOPIA */
|
||||
g_atm.loaded = FALSE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmMemInit
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* The ATM driver uses the following resources:
|
||||
*
|
||||
* A. Memory in DPRAM to hold
|
||||
*
|
||||
* 1/ CT = Connection Table ( RCT & TCT )
|
||||
* 2/ TCTE = Transmit Connection Table Extension
|
||||
* 3/ MPHYPT = Multi-PHY Pointing Table
|
||||
* 4/ APCP = APC Parameter Table
|
||||
* 5/ APCT_PRIO_1 = APC Table ( priority 1 for AAL1/2 )
|
||||
* 6/ APCT_PRIO_2 = APC Table ( priority 2 for VBR )
|
||||
* 7/ APCT_PRIO_3 = APC Table ( priority 3 for UBR )
|
||||
* 8/ TQ = Transmit Queue
|
||||
* 9/ AM = Address Matching Table
|
||||
* 10/ AP = Address Pointing Table
|
||||
*
|
||||
* B. Memory in cache safe RAM to hold
|
||||
*
|
||||
* 1/ INT = Interrupt Queue
|
||||
* 2/ RBD = Receive Buffer Descriptors
|
||||
* 3/ TBD = Transmit Buffer Descriptors
|
||||
*
|
||||
* This function
|
||||
* 1. clears the ATM DPRAM area,
|
||||
* 2. Allocates and clears cache safe memory,
|
||||
* 3. Initializes 'g_conn'.
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
****************************************************************************/
|
||||
int atmMemInit()
|
||||
{
|
||||
int i;
|
||||
unsigned immr = CFG_IMMR;
|
||||
int total_num_rbd = 0;
|
||||
int total_num_tbd = 0;
|
||||
|
||||
memset((char *)CFG_IMMR + 0x2000 + ATM_DPRAM_BEGIN, 0x00, ATM_DPRAM_SIZE);
|
||||
|
||||
g_atm.csram_size = NUM_INT_ENTRIES * SIZE_OF_INT_ENTRY;
|
||||
|
||||
for ( i = 0; i < NUM_CONNECTIONS; ++i ) {
|
||||
total_num_rbd += g_conn[i].num_rbd;
|
||||
total_num_tbd += g_conn[i].num_tbd;
|
||||
}
|
||||
|
||||
g_atm.csram_size += total_num_rbd * SIZE_OF_RBD + total_num_tbd * SIZE_OF_TBD + 4;
|
||||
|
||||
g_atm.csram = &csram[0];
|
||||
memset(&(g_atm.csram), 0x00, g_atm.csram_size);
|
||||
|
||||
g_atm.int_reload_ptr = (uint32 *)ALIGN(g_atm.csram, 4);
|
||||
g_atm.rbd_base_ptr = (struct atm_bd_t *)(g_atm.int_reload_ptr + NUM_INT_ENTRIES);
|
||||
g_atm.tbd_base_ptr = (struct atm_bd_t *)(g_atm.rbd_base_ptr + total_num_rbd);
|
||||
|
||||
g_conn[0].rbd_ptr = g_atm.rbd_base_ptr;
|
||||
g_conn[0].tbd_ptr = g_atm.tbd_base_ptr;
|
||||
g_conn[0].ct_ptr = CT_PTR(immr);
|
||||
g_conn[0].tcte_ptr = TCTE_PTR(immr);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmIntInit
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Initialization of the MPC860 ESAR Interrupt Queue.
|
||||
* This function
|
||||
* - clears all entries in the INT,
|
||||
* - sets the WRAP bit of the last INT entry,
|
||||
* - initializes the 'int_serv_ptr' attribuut of the AtmDriver structure
|
||||
* to the first INT entry.
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
* REMARKS:
|
||||
*
|
||||
* - The INT resides in external cache safe memory.
|
||||
* - The base address of the INT is stored in g_atm.int_reload_ptr.
|
||||
* - The number of entries in the INT is given by NUM_INT_ENTRIES.
|
||||
* - The INTBASE field in SAR Parameter RAM is set by atmCpmInit().
|
||||
*
|
||||
****************************************************************************/
|
||||
void atmIntInit()
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < NUM_INT_ENTRIES - 1; ++i) g_atm.int_reload_ptr[i] = 0;
|
||||
g_atm.int_reload_ptr[i] = INT_WRAP;
|
||||
g_atm.int_serv_ptr = g_atm.int_reload_ptr;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmApcInit
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function initializes the following ATM Pace Controller related
|
||||
* data structures:
|
||||
*
|
||||
* - 1 MPHY Pointing Table (contains only one entry)
|
||||
* - 3 APC Parameter Tables (one PHY with 3 priorities)
|
||||
* - 3 APC Tables (one table for each priority)
|
||||
* - 1 Transmit Queue (one transmit queue per PHY)
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
****************************************************************************/
|
||||
void atmApcInit()
|
||||
{
|
||||
int i;
|
||||
/* unsigned immr = CFG_IMMR; */
|
||||
uint16 * mphypt_ptr = MPHYPT_PTR(CFG_IMMR);
|
||||
struct apc_params_t * apcp_ptr = APCP_PTR(CFG_IMMR);
|
||||
uint16 * apct_prio1_ptr = APCT1_PTR(CFG_IMMR);
|
||||
uint16 * tq_ptr = TQ_PTR(CFG_IMMR);
|
||||
/***************************************************/
|
||||
/* Initialize MPHY Pointing Table (only one entry) */
|
||||
/***************************************************/
|
||||
*mphypt_ptr = APCP_BASE;
|
||||
|
||||
/********************************************/
|
||||
/* Initialize APC parameters for priority 1 */
|
||||
/********************************************/
|
||||
apcp_ptr->apct_base1 = APCT_PRIO_1_BASE;
|
||||
apcp_ptr->apct_end1 = APCT_PRIO_1_BASE + NUM_APCT_PRIO_1_ENTRIES * 2;
|
||||
apcp_ptr->apct_ptr1 = APCT_PRIO_1_BASE;
|
||||
apcp_ptr->apct_sptr1 = APCT_PRIO_1_BASE;
|
||||
apcp_ptr->etqbase = TQ_BASE;
|
||||
apcp_ptr->etqend = TQ_BASE + ( NUM_TQ_ENTRIES - 1 ) * 2;
|
||||
apcp_ptr->etqaptr = TQ_BASE;
|
||||
apcp_ptr->etqtptr = TQ_BASE;
|
||||
apcp_ptr->apc_mi = 8;
|
||||
apcp_ptr->ncits = 0x0100; /* NCITS = 1 */
|
||||
apcp_ptr->apcnt = 0;
|
||||
apcp_ptr->reserved1 = 0;
|
||||
apcp_ptr->eapcst = 0x2009; /* LAST, ESAR, MPHY */
|
||||
apcp_ptr->ptp_counter = 0;
|
||||
apcp_ptr->ptp_txch = 0;
|
||||
apcp_ptr->reserved2 = 0;
|
||||
|
||||
|
||||
/***************************************************/
|
||||
/* Initialize APC Tables with empty slots (0xFFFF) */
|
||||
/***************************************************/
|
||||
for ( i = 0; i < NUM_APCT_PRIO_1_ENTRIES; ++i ) *(apct_prio1_ptr++) = 0xFFFF;
|
||||
|
||||
/************************/
|
||||
/* Clear Transmit Queue */
|
||||
/************************/
|
||||
for ( i = 0; i < NUM_TQ_ENTRIES; ++i ) *(tq_ptr++) = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmAmtInit
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function clears the first entry in the Address Matching Table and
|
||||
* lets the first entry in the Address Pointing table point to the first
|
||||
* entry in the TCT table (i.e. the raw cell channel).
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
* REMARKS:
|
||||
*
|
||||
* The values for the AMBASE, AMEND and APBASE registers in SAR parameter
|
||||
* RAM are initialized by atmCpmInit().
|
||||
*
|
||||
****************************************************************************/
|
||||
void atmAmtInit()
|
||||
{
|
||||
unsigned immr = CFG_IMMR;
|
||||
|
||||
g_atm.am_top = AM_PTR(immr);
|
||||
g_atm.ap_top = AP_PTR(immr);
|
||||
|
||||
*(g_atm.ap_top--) = CT_BASE;
|
||||
*(g_atm.am_top--) = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmCpmInit
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function initializes the Utopia Interface Parameter RAM Map
|
||||
* (SCC4, ATM Protocol) of the Communication Processor Modudule.
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
****************************************************************************/
|
||||
void atmCpmInit()
|
||||
{
|
||||
unsigned immr = CFG_IMMR;
|
||||
|
||||
memset((char *)immr + 0x3F00, 0x00, 0xC0);
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* RBDBASE - Receive buffer descriptors base address */
|
||||
/* The RBDs reside in cache safe external memory. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*RBDBASE(immr) = (uint32)g_atm.rbd_base_ptr;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* SRFCR - SAR receive function code */
|
||||
/* 0-2 rsvd = 000 */
|
||||
/* 3-4 BO = 11 Byte ordering (big endian). */
|
||||
/* 5-7 FC = 000 Value driven on the address type signals AT[1-3] */
|
||||
/* when the SDMA channel accesses memory. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*SRFCR(immr) = 0x18;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* SRSTATE - SAR receive status */
|
||||
/* 0 EXT = 0 Extended mode off. */
|
||||
/* 1 ACP = 0 Valid only if EXT = 1. */
|
||||
/* 2 EC = 0 Standard 53-byte ATM cell. */
|
||||
/* 3 SNC = 0 In sync. Must be set to 0 during initialization. */
|
||||
/* 4 ESAR = 1 Enhanced SAR functionality enabled. */
|
||||
/* 5 MCF = 1 Management Cell Filter active. */
|
||||
/* 6 SER = 0 UTOPIA mode. */
|
||||
/* 7 MPY = 1 Multiple PHY mode. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*SRSTATE(immr) = 0x0D;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* MRBLR - Maximum receive buffer length register. */
|
||||
/* Must be cleared for ATM operation (see also SMRBLR). */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*MRBLR(immr) = 0;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* RSTATE - SCC internal receive state parameters */
|
||||
/* The first byte must be initialized with the value of SRFCR. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*RSTATE(immr) = (uint32)(*SRFCR(immr)) << 24;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* STFCR - SAR transmit function code */
|
||||
/* 0-2 rsvd = 000 */
|
||||
/* 3-4 BO = 11 Byte ordering (big endian). */
|
||||
/* 5-7 FC = 000 Value driven on the address type signals AT[1-3] */
|
||||
/* when the SDMA channel accesses memory. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*STFCR(immr) = 0x18;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* SRSTATE - SAR transmit status */
|
||||
/* 0 EXT = 0 : Extended mode off */
|
||||
/* 1 rsvd = 0 : */
|
||||
/* 2 EC = 0 : Standard 53-byte ATM cell */
|
||||
/* 3 rsvd = 0 : */
|
||||
/* 4 ESAR = 1 : Enhanced SAR functionality enabled */
|
||||
/* 5 rsvd = 0 : */
|
||||
/* 6 SER = 0 : UTOPIA mode */
|
||||
/* 7 MPY = 1 : Multiple PHY mode */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*STSTATE(immr) = 0x09;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* TBDBASE - Transmit buffer descriptors base address */
|
||||
/* The TBDs reside in cache safe external memory. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*TBDBASE(immr) = (uint32)g_atm.tbd_base_ptr;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* TSTATE - SCC internal transmit state parameters */
|
||||
/* The first byte must be initialized with the value of STFCR. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*TSTATE(immr) = (uint32)(*STFCR(immr)) << 24;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* CTBASE - Connection table base address */
|
||||
/* Offset from the beginning of DPRAM (64-byte aligned). */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*CTBASE(immr) = CT_BASE;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* INTBASE - Interrupt queue base pointer. */
|
||||
/* The interrupt queue resides in cache safe external memory. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*INTBASE(immr) = (uint32)g_atm.int_reload_ptr;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* INTPTR - Pointer into interrupt queue. */
|
||||
/* Initialize to INTBASE. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*INTPTR(immr) = *INTBASE(immr);
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* C_MASK - Constant mask for CRC32 */
|
||||
/* Must be initialized to 0xDEBB20E3. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*C_MASK(immr) = 0xDEBB20E3;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* INT_ICNT - Interrupt threshold value */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*INT_ICNT(immr) = 1;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* INT_CNT - Interrupt counter */
|
||||
/* Initalize to INT_ICNT. Decremented for each interrupt entry */
|
||||
/* reported in the interrupt queue. On zero an interrupt is */
|
||||
/* signaled to the host by setting the GINT bit in the event */
|
||||
/* register. The counter is reinitialized with INT_ICNT. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*INT_CNT(immr) = *INT_ICNT(immr);
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* SMRBLR - SAR maximum receive buffer length register. */
|
||||
/* Must be a multiple of 48 bytes. Common for all ATM connections. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*SMRBLR(immr) = SAR_RXB_SIZE;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* APCST - APC status register. */
|
||||
/* 0 rsvd 0 */
|
||||
/* 1-2 CSER 11 Initialize with the same value as NSER. */
|
||||
/* 3-4 NSER 11 Next serial or UTOPIA channel. */
|
||||
/* 5-7 rsvd 000 */
|
||||
/* 8-10 rsvd 000 */
|
||||
/* 11 rsvd 0 */
|
||||
/* 12 ESAR 1 UTOPIA Level 2 MPHY enabled. */
|
||||
/* 13 DIS 0 APC disable. Must be initiazed to 0. */
|
||||
/* 14 PL2 0 Not used. */
|
||||
/* 15 MPY 1 Multiple PHY mode on. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*APCST(immr) = 0x7809;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* APCPTR - Pointer to the APC parameter table */
|
||||
/* In MPHY master mode this parameter points to the MPHY pointing */
|
||||
/* table. 2-byte aligned. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*APCPTR(immr) = MPHYPT_BASE;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* HMASK - Header mask */
|
||||
/* Each incoming cell is masked with HMASK before being compared */
|
||||
/* to the entries in the address matching table. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*HMASK(immr) = AM_HMASK;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* AMBASE - Address matching table base address */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*AMBASE(immr) = AM_BASE;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* AMEND - Address matching table end address */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*AMEND(immr) = AM_BASE;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* APBASE - Address pointing table base address */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*APBASE(immr) = AP_BASE;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* MPHYST - MPHY status register */
|
||||
/* 0-1 rsvd 00 */
|
||||
/* 2-6 NMPHY 00000 1 PHY */
|
||||
/* 7-9 rsvd 000 */
|
||||
/* 10-14 CMPHY 00000 Initialize with same value as NMPHY */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*MPHYST(immr) = 0x0000;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* TCTEBASE - Transmit connection table extension base address */
|
||||
/* Offset from the beginning of DPRAM (32-byte aligned). */
|
||||
/*-----------------------------------------------------------------*/
|
||||
*TCTEBASE(immr) = TCTE_BASE;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* Clear not used registers. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: atmUtpInit
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function initializes the ATM interface for
|
||||
*
|
||||
* - UTOPIA mode
|
||||
* - muxed bus
|
||||
* - master operation
|
||||
* - multi PHY (because of a bug in the MPC860P rev. E.0)
|
||||
* - internal clock = SYSCLK / 2
|
||||
*
|
||||
* EXTERNAL EFFECTS:
|
||||
*
|
||||
* After calling this function, the MPC860ESAR UTOPIA bus is
|
||||
* active and uses the following ports/pins:
|
||||
*
|
||||
* Port Pin Signal Description
|
||||
* ------ --- ------- -------------------------------------------
|
||||
* PB[15] R17 TxClav Transmit cell available input/output signal
|
||||
* PC[15] D16 RxClav Receive cell available input/output signal
|
||||
* PD[15] U17 UTPB[0] UTOPIA bus bit 0 input/output signal
|
||||
* PD[14] V19 UTPB[1] UTOPIA bus bit 1 input/output signal
|
||||
* PD[13] V18 UTPB[2] UTOPIA bus bit 2 input/output signal
|
||||
* PD[12] R16 UTPB[3] UTOPIA bus bit 3 input/output signal
|
||||
* PD[11] T16 RXENB Receive enable input/output signal
|
||||
* PD[10] W18 TXENB Transmit enable input/output signal
|
||||
* PD[9] V17 UTPCLK UTOPIA clock input/output signal
|
||||
* PD[7] T15 UTPB[4] UTOPIA bus bit 4 input/output signal
|
||||
* PD[6] V16 UTPB[5] UTOPIA bus bit 5 input/output signal
|
||||
* PD[5] U15 UTPB[6] UTOPIA bus bit 6 input/output signal
|
||||
* PD[4] U16 UTPB[7] UTOPIA bus bit 7 input/output signal
|
||||
* PD[3] W16 SOC Start of cell input/output signal
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
* REMARK:
|
||||
*
|
||||
* The ATM parameters and data structures must be configured before
|
||||
* initializing the UTOPIA port. The UTOPIA port activates immediately
|
||||
* upon initialization, and if its associated data structures are not
|
||||
* initialized, the CPM will lock up.
|
||||
*
|
||||
****************************************************************************/
|
||||
void atmUtpInit()
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
volatile iop8xx_t *iop = &immap->im_ioport;
|
||||
volatile car8xx_t *car = &immap->im_clkrst;
|
||||
volatile cpm8xx_t *cpm = &immap->im_cpm;
|
||||
int flag;
|
||||
|
||||
flag = disable_interrupts();
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* SCCR - System Clock Control Register */
|
||||
/* */
|
||||
/* The UTOPIA clock can be selected to be internal clock or */
|
||||
/* external clock (selected by the UTOPIA mode register). */
|
||||
/* In case of internal clock, the UTOPIA clock is derived from */
|
||||
/* the system frequency divided by two dividers. */
|
||||
/* Bits 27-31 of the SCCR register are defined to control the */
|
||||
/* UTOPIA clock. */
|
||||
/* */
|
||||
/* SCCR[27:29] DFUTP Division factor. Divide the system clock */
|
||||
/* by 2^DFUTP. */
|
||||
/* SCCR[30:31] DFAUTP Additional division factor. Divide the */
|
||||
/* system clock by the following value: */
|
||||
/* 00 = divide by 1 */
|
||||
/* 00 = divide by 3 */
|
||||
/* 10 = divide by 5 */
|
||||
/* 11 = divide by 7 */
|
||||
/* */
|
||||
/* Note that the UTOPIA clock must be programmed as to operate */
|
||||
/* within the range SYSCLK/10 .. 50Mhz. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
car->car_sccr &= 0xFFFFFFE0;
|
||||
car->car_sccr |= 0x00000008; /* UTPCLK = SYSCLK / 4 */
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* RCCR - RISC Controller Configuration Register */
|
||||
/* */
|
||||
/* RCCR[8] DR1M IDMA Request 0 Mode */
|
||||
/* 0 = edge sensitive */
|
||||
/* 1 = level sensitive */
|
||||
/* RCCR[9] DR0M IDMA Request 0 Mode */
|
||||
/* 0 = edge sensitive */
|
||||
/* 1 = level sensitive */
|
||||
/* RCCR[10:11] DRQP IDMA Request Priority */
|
||||
/* 00 = IDMA req. have more prio. than SCCs */
|
||||
/* 01 = IDMA req. have less prio. then SCCs */
|
||||
/* 10 = IDMA requests have the lowest prio. */
|
||||
/* 11 = reserved */
|
||||
/* */
|
||||
/* The RCCR[DR0M] and RCCR[DR1M] bits must be set to enable UTOPIA */
|
||||
/* operation. Also, program RCCR[DPQP] to 01 to give SCC transfers */
|
||||
/* higher priority. */
|
||||
/*-----------------------------------------------------------------*/
|
||||
cpm->cp_rccr &= 0xFF0F;
|
||||
cpm->cp_rccr |= 0x00D0;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* Port B - TxClav Signal */
|
||||
/*-----------------------------------------------------------------*/
|
||||
cpm->cp_pbpar |= 0x00010000; /* PBPAR[15] = 1 */
|
||||
cpm->cp_pbdir &= 0xFFFEFFFF; /* PBDIR[15] = 0 */
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* UTOPIA Mode Register */
|
||||
/* */
|
||||
/* - muxed bus (master operation only) */
|
||||
/* - multi PHY (because of a bug in the MPC860P rev.E.0) */
|
||||
/* - internal clock */
|
||||
/* - no loopback */
|
||||
/* - do no activate statistical counters */
|
||||
/*-----------------------------------------------------------------*/
|
||||
iop->utmode = 0x00000004; SYNC;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* Port D - UTOPIA Data and Control Signals */
|
||||
/* */
|
||||
/* 15-12 UTPB[0:3] UTOPIA bus bit 0 - 3 input/output signals */
|
||||
/* 11 RXENB UTOPIA receive enable input/output signal */
|
||||
/* 10 TXENB UTOPIA transmit enable input/output signal */
|
||||
/* 9 TUPCLK UTOPIA clock input/output signal */
|
||||
/* 8 MII-MDC Used by MII in simult. MII and UTOPIA operation */
|
||||
/* 7-4 UTPB[4:7] UTOPIA bus bit 4 - 7 input/output signals */
|
||||
/* 3 SOC UTOPIA Start of cell input/output signal */
|
||||
/* 2 Reserved */
|
||||
/* 1 Enable UTOPIA mode */
|
||||
/* 0 Enable SAR */
|
||||
/*-----------------------------------------------------------------*/
|
||||
iop->iop_pdpar |= 0xDF7F; SYNC;
|
||||
iop->iop_pddir &= 0x2080; SYNC;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* Port C - RxClav Signal */
|
||||
/*-----------------------------------------------------------------*/
|
||||
iop->iop_pcpar |= 0x0001; /* PCPAR[15] = 1 */
|
||||
iop->iop_pcdir &= 0xFFFE; /* PCDIR[15] = 0 */
|
||||
iop->iop_pcso &= 0xFFFE; /* PCSO[15] = 0 */
|
||||
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
}
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* (C) Copyright 2000, 2001, 2002
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long size;
|
||||
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 - FIXME XXX */
|
||||
|
||||
size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
|
||||
|
||||
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
|
||||
printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
|
||||
size, size<<20);
|
||||
}
|
||||
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size;
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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");
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
|
||||
value = addr[0];
|
||||
|
||||
switch (value) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
addr[0] = 0x00300030;
|
||||
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_long*)(info->start[l_sect]);
|
||||
while ((addr[0] & 0x00800080) != 0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* (C) Copyright 2001, 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* Flash Routines for AMD devices on the TQM8260 board
|
||||
*
|
||||
*--------------------------------------------------------------------
|
||||
* 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>
|
||||
|
||||
#define V_ULONG(a) (*(volatile unsigned long *)( a ))
|
||||
#define V_BYTE(a) (*(volatile unsigned char *)( a ))
|
||||
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_reset (void)
|
||||
{
|
||||
if (flash_info[0].flash_id != FLASH_UNKNOWN) {
|
||||
V_ULONG (flash_info[0].start[0]) = 0x00F000F0;
|
||||
V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
ulong flash_get_size (ulong baseaddr, flash_info_t * info)
|
||||
{
|
||||
short i;
|
||||
unsigned long flashtest_h, flashtest_l;
|
||||
|
||||
/* Write auto select command sequence and test FLASH answer */
|
||||
V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
|
||||
V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;
|
||||
|
||||
flashtest_h = V_ULONG (baseaddr); /* manufacturer ID */
|
||||
flashtest_l = V_ULONG (baseaddr + 4);
|
||||
|
||||
switch ((int) flashtest_h) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
flashtest_h = V_ULONG (baseaddr + 8); /* device ID */
|
||||
flashtest_l = V_ULONG (baseaddr + 12);
|
||||
if (flashtest_h != flashtest_l) {
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
} else {
|
||||
switch (flashtest_h) {
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00400000;
|
||||
break; /* 4 * 1 MB = 4 MB */
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00400000;
|
||||
break; /* 4 * 1 MB = 4 MB */
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00800000;
|
||||
break; /* 4 * 2 MB = 8 MB */
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00800000;
|
||||
break; /* 4 * 2 MB = 8 MB */
|
||||
case AMD_ID_DL322T:
|
||||
info->flash_id += FLASH_AMDL322T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_DL322B:
|
||||
info->flash_id += FLASH_AMDL322B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_DL323T:
|
||||
info->flash_id += FLASH_AMDL323T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_DL323B:
|
||||
info->flash_id += FLASH_AMDL323B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_LV640U:
|
||||
info->flash_id += FLASH_AM640U;
|
||||
info->sector_count = 128;
|
||||
info->size = 0x02000000;
|
||||
break; /* 4 * 8 MB = 32 MB */
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
}
|
||||
|
||||
if (flashtest_h == AMD_ID_LV640U) {
|
||||
|
||||
/* set up sector start adress table (uniform sector type) */
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
info->start[i] = baseaddr + (i * 0x00040000);
|
||||
|
||||
} else if (info->flash_id & FLASH_BTYPE) {
|
||||
|
||||
/* set up sector start adress table (bottom sector type) */
|
||||
info->start[0] = baseaddr + 0x00000000;
|
||||
info->start[1] = baseaddr + 0x00010000;
|
||||
info->start[2] = baseaddr + 0x00018000;
|
||||
info->start[3] = baseaddr + 0x00020000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* set up sector start adress table (top sector type) */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = baseaddr + info->size - 0x00010000;
|
||||
info->start[i--] = baseaddr + info->size - 0x00018000;
|
||||
info->start[i--] = baseaddr + info->size - 0x00020000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = baseaddr + i * 0x00040000;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for protected sectors */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
/* read sector protection at sector address, (A7 .. A0) = 0x02 */
|
||||
if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
|
||||
(V_ULONG (info->start[i] + 20) & 0x00010001)) {
|
||||
info->protect[i] = 1; /* D0 = 1 if protected */
|
||||
} else {
|
||||
info->protect[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
flash_reset ();
|
||||
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 (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
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#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 & 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_AM800T:
|
||||
printf ("29LV800T (8 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AM800B:
|
||||
printf ("29LV800T (8 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AM160T:
|
||||
printf ("29LV160T (16 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AM160B:
|
||||
printf ("29LV160B (16 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL322T:
|
||||
printf ("29DL322T (32 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL322B:
|
||||
printf ("29DL322B (32 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL323T:
|
||||
printf ("29DL323T (32 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL323B:
|
||||
printf ("29DL323B (32 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AM640U:
|
||||
printf ("29LV640D (64 M, uniform 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;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
int flash_erase (flash_info_t * info, int s_first, int s_last)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
l_sect = -1;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts ();
|
||||
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080;
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
|
||||
udelay (1000);
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
V_ULONG (info->start[sect]) = 0x00300030;
|
||||
V_ULONG (info->start[sect] + 4) = 0x00300030;
|
||||
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;
|
||||
while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 ||
|
||||
(V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
flash_reset ();
|
||||
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_dword (flash_info_t *, ulong, unsigned char *);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* 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 dp;
|
||||
static unsigned char bb[8];
|
||||
int i, l, rc, cc = cnt;
|
||||
|
||||
dp = (addr & ~7); /* get lower dword aligned address */
|
||||
|
||||
/*
|
||||
* handle unaligned start bytes
|
||||
*/
|
||||
if ((l = addr - dp) != 0) {
|
||||
for (i = 0; i < 8; i++)
|
||||
bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++;
|
||||
if ((rc = write_dword (info, dp, bb)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
dp += 8;
|
||||
cc -= 8 - l;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle word aligned part
|
||||
*/
|
||||
while (cc >= 8) {
|
||||
if ((rc = write_dword (info, dp, src)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
dp += 8;
|
||||
src += 8;
|
||||
cc -= 8;
|
||||
}
|
||||
|
||||
if (cc <= 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i);
|
||||
}
|
||||
return (write_dword (info, dp, bb));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a dword to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata)
|
||||
{
|
||||
ulong start, cl, ch;
|
||||
int flag, i;
|
||||
|
||||
for (ch = 0, i = 0; i < 4; i++)
|
||||
ch = (ch << 8) + *pdata++; /* high word */
|
||||
for (cl = 0, i = 0; i < 4; i++)
|
||||
cl = (cl << 8) + *pdata++; /* low word */
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*((vu_long *) dest) & ch) != ch
|
||||
|| (*((vu_long *) (dest + 4)) & cl) != cl) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts ();
|
||||
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0;
|
||||
V_ULONG (dest) = ch;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0;
|
||||
V_ULONG (dest + 4) = cl;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts ();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) ||
|
||||
((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) {
|
||||
if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,700 @@
|
|||
/*
|
||||
* (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 <mpc8xx.h>
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#undef DEBUG_FLASH
|
||||
|
||||
#ifdef DEBUG_FLASH
|
||||
#define DEBUGF(fmt,args...) printf(fmt ,##args)
|
||||
#else
|
||||
#define DEBUGF(fmt,args...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
|
||||
flash_info_t flash_info[CFG_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);
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*
|
||||
* The PCU E uses an address map where flash banks are aligned top
|
||||
* down, so that the "first" flash bank ends at top of memory, and
|
||||
* the monitor entry point is at address (0xFFF00100). The second
|
||||
* flash bank is mapped immediately below bank 0.
|
||||
*
|
||||
* This is NOT in conformance to the "official" memory map!
|
||||
*
|
||||
*/
|
||||
|
||||
#define PCU_MONITOR_BASE ( (flash_info[0].start[0] + flash_info[0].size - 1) \
|
||||
- (0xFFFFFFFF - CFG_MONITOR_BASE) )
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long base, 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;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
/*
|
||||
* Warning:
|
||||
*
|
||||
* Since the PCU E memory map assigns flash banks top down,
|
||||
* we swap the numbering later if both banks are equipped,
|
||||
* so they look like a contiguous area of memory.
|
||||
*/
|
||||
DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE6_PRELIM);
|
||||
size_b1 = flash_get_size((vu_long *)FLASH_BASE6_PRELIM, &flash_info[1]);
|
||||
|
||||
DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n", size_b0, size_b1);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: "
|
||||
"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,
|
||||
size_b0, size_b0<<20
|
||||
);
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
DEBUGF ("## Before remap: "
|
||||
"BR0: 0x%08x OR0: 0x%08x "
|
||||
"BR6: 0x%08x OR6: 0x%08x\n",
|
||||
memctl->memc_br0, memctl->memc_or0,
|
||||
memctl->memc_br6, memctl->memc_or6);
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
base = 0 - size_b0;
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
|
||||
memctl->memc_br0 = (base & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
|
||||
|
||||
DEBUGF("## 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 *)base, &flash_info[0]);
|
||||
base = 0 - size_b0;
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
flash_get_offsets (base, &flash_info[0]);
|
||||
|
||||
/* monitor protection ON by default */
|
||||
flash_protect(FLAG_PROTECT_SET,
|
||||
PCU_MONITOR_BASE,
|
||||
PCU_MONITOR_BASE+CFG_MONITOR_LEN-1,
|
||||
&flash_info[0]);
|
||||
|
||||
#ifdef CFG_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,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
if (size_b1) {
|
||||
flash_info_t tmp_info;
|
||||
|
||||
memctl->memc_or6 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
|
||||
memctl->memc_br6 = ((base - size_b1) & BR_BA_MSK) |
|
||||
BR_PS_16 | BR_MS_GPCM | BR_V;
|
||||
|
||||
DEBUGF("## New BR6: 0x%08x OR6: 0x%08x\n",
|
||||
memctl->memc_br6, memctl->memc_or6);
|
||||
|
||||
/* Re-do sizing to get full correct info */
|
||||
size_b1 = flash_get_size((vu_long *)(base - size_b1),
|
||||
&flash_info[1]);
|
||||
base -= size_b1;
|
||||
|
||||
flash_get_offsets (base, &flash_info[1]);
|
||||
|
||||
flash_info[1].size = size_b1;
|
||||
|
||||
#ifdef CFG_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,
|
||||
&flash_info[1]);
|
||||
#endif
|
||||
/*
|
||||
* Swap bank numbers so that addresses are in ascending order
|
||||
*/
|
||||
tmp_info = flash_info[0];
|
||||
flash_info[0] = flash_info[1];
|
||||
flash_info[1] = tmp_info;
|
||||
} else {
|
||||
memctl->memc_br1 = 0; /* invalidate bank */
|
||||
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].sector_count = -1;
|
||||
}
|
||||
|
||||
|
||||
DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
short n;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_AMD) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AMDL322T:
|
||||
case FLASH_AMDL323T:
|
||||
case FLASH_AMDL324T:
|
||||
/* set sector offsets for top boot block type */
|
||||
|
||||
base += info->size;
|
||||
i = info->sector_count;
|
||||
for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
|
||||
base -= 8 << 10;
|
||||
--i;
|
||||
info->start[i] = base;
|
||||
}
|
||||
while (i > 0) { /* 64k regular sectors */
|
||||
base -= 64 << 10;
|
||||
--i;
|
||||
info->start[i] = base;
|
||||
}
|
||||
return;
|
||||
case FLASH_AMDL322B:
|
||||
case FLASH_AMDL323B:
|
||||
case FLASH_AMDL324B:
|
||||
/* set sector offsets for bottom boot block type */
|
||||
for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
|
||||
info->start[i] = base;
|
||||
base += 8 << 10;
|
||||
}
|
||||
while (base < info->size) { /* 64k regular sectors */
|
||||
info->start[i] = base;
|
||||
base += 64 << 10;
|
||||
++i;
|
||||
}
|
||||
return;
|
||||
case FLASH_AMDL640:
|
||||
/* set sector offsets for dual boot block type */
|
||||
for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
|
||||
info->start[i] = base;
|
||||
base += 8 << 10;
|
||||
}
|
||||
n = info->sector_count - 8;
|
||||
while (i < n) { /* 64k regular sectors */
|
||||
info->start[i] = base;
|
||||
base += 64 << 10;
|
||||
++i;
|
||||
}
|
||||
while (i < info->sector_count) { /* 8 x 8k boot sectors */
|
||||
info->start[i] = base;
|
||||
base += 8 << 10;
|
||||
++i;
|
||||
}
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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_AMDL322B: printf ("AM29DL322B (32 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AMDL322T: printf ("AM29DL322T (32 Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL323B: printf ("AM29DL323B (32 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AMDL323T: printf ("AM29DL323T (32 Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL324B: printf ("AM29DL324B (32 Mbit, bottom boot sect)\n");
|
||||
break;
|
||||
case FLASH_AMDL324T: printf ("AM29DL324T (32 Mbit, top boot sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL640: printf ("AM29DL640D (64 Mbit, dual boot sector)\n");
|
||||
break;
|
||||
default: printf ("Unknown Chip Type 0x%lX\n",
|
||||
info->flash_id);
|
||||
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_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ushort value;
|
||||
vu_short *saddr = (vu_short *)addr;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
saddr[0x0555] = 0x00AA;
|
||||
saddr[0x02AA] = 0x0055;
|
||||
saddr[0x0555] = 0x0090;
|
||||
|
||||
value = saddr[0];
|
||||
|
||||
DEBUGF("Manuf. ID @ 0x%08lx: 0x%04x\n", (ulong)addr, value);
|
||||
|
||||
switch (value) {
|
||||
case (AMD_MANUFACT & 0xFFFF):
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case (FUJ_MANUFACT & 0xFFFF):
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
DEBUGF("Unknown Manufacturer ID\n");
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = saddr[1]; /* device ID */
|
||||
|
||||
DEBUGF("Device ID @ 0x%08lx: 0x%04x\n", (ulong)(&addr[1]), value);
|
||||
|
||||
switch (value) {
|
||||
|
||||
case (AMD_ID_DL322T & 0xFFFF):
|
||||
info->flash_id += FLASH_AMDL322T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case (AMD_ID_DL322B & 0xFFFF):
|
||||
info->flash_id += FLASH_AMDL322B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case (AMD_ID_DL323T & 0xFFFF):
|
||||
info->flash_id += FLASH_AMDL323T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case (AMD_ID_DL323B & 0xFFFF):
|
||||
info->flash_id += FLASH_AMDL323B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case (AMD_ID_DL324T & 0xFFFF):
|
||||
info->flash_id += FLASH_AMDL324T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case (AMD_ID_DL324B & 0xFFFF):
|
||||
info->flash_id += FLASH_AMDL324B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 8 MB */
|
||||
case (AMD_ID_DL640 & 0xFFFF):
|
||||
info->flash_id += FLASH_AMDL640;
|
||||
info->sector_count = 142;
|
||||
info->size = 0x00800000;
|
||||
break;
|
||||
default:
|
||||
DEBUGF("Unknown Device ID\n");
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
|
||||
}
|
||||
|
||||
flash_get_offsets ((ulong)addr, info);
|
||||
|
||||
/* check for protected sectors */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
#if 0
|
||||
/* read sector protection at sector address, (A7 .. A0) = 0x02 */
|
||||
/* D0 = 1 if protected */
|
||||
saddr = (vu_short *)(info->start[i]);
|
||||
info->protect[i] = saddr[2] & 1;
|
||||
#else
|
||||
info->protect[i] =0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (info->sector_count > CFG_MAX_FLASH_SECT) {
|
||||
printf ("** ERROR: sector count %d > max (%d) **\n",
|
||||
info->sector_count, CFG_MAX_FLASH_SECT);
|
||||
info->sector_count = CFG_MAX_FLASH_SECT;
|
||||
}
|
||||
|
||||
saddr = (vu_short *)info->start[0];
|
||||
*saddr = 0x00F0; /* restore read mode */
|
||||
|
||||
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] = 0x00AA;
|
||||
addr[0x02AA] = 0x0055;
|
||||
addr[0x0555] = 0x0080;
|
||||
addr[0x0555] = 0x00AA;
|
||||
addr[0x02AA] = 0x0055;
|
||||
|
||||
/* 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] = 0x0030;
|
||||
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");
|
||||
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] = 0x00F0; /* reset bank */
|
||||
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
|
||||
#define FLASH_WIDTH 2 /* flash bus width in bytes */
|
||||
|
||||
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
ulong cp, wp, data;
|
||||
int i, l, rc;
|
||||
|
||||
wp = (addr & ~(FLASH_WIDTH-1)); /* get lower FLASH_WIDTH 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<FLASH_WIDTH && cnt>0; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
++cp;
|
||||
}
|
||||
for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += FLASH_WIDTH;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle FLASH_WIDTH aligned part
|
||||
*/
|
||||
while (cnt >= FLASH_WIDTH) {
|
||||
data = 0;
|
||||
for (i=0; i<FLASH_WIDTH; ++i) {
|
||||
data = (data << 8) | *src++;
|
||||
}
|
||||
if ((rc = write_data(info, wp, data)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
wp += FLASH_WIDTH;
|
||||
cnt -= FLASH_WIDTH;
|
||||
}
|
||||
|
||||
if (cnt == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
data = 0;
|
||||
for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
|
||||
data = (data << 8) | *src++;
|
||||
--cnt;
|
||||
}
|
||||
for (; i<FLASH_WIDTH; ++i, ++cp) {
|
||||
data = (data << 8) | (*(uchar *)cp);
|
||||
}
|
||||
|
||||
return (write_data(info, wp, data));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_data (flash_info_t *info, ulong dest, ulong data)
|
||||
{
|
||||
vu_short *addr = (vu_short*)(info->start[0]);
|
||||
vu_short *sdest = (vu_short *)dest;
|
||||
ushort sdata = (ushort)data;
|
||||
ushort sval;
|
||||
ulong start, passed;
|
||||
int flag, rc;
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*sdest & sdata) != sdata) {
|
||||
return (2);
|
||||
}
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
addr[0x0555] = 0x00AA;
|
||||
addr[0x02AA] = 0x0055;
|
||||
addr[0x0555] = 0x00A0;
|
||||
|
||||
#ifdef WORKAROUND_FOR_BROKEN_HARDWARE
|
||||
/* work around the timeout bugs */
|
||||
udelay(20);
|
||||
#endif
|
||||
|
||||
*sdest = sdata;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
rc = 0;
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
|
||||
for (passed=0; passed < CFG_FLASH_WRITE_TOUT; passed=get_timer(start)) {
|
||||
|
||||
sval = *sdest;
|
||||
|
||||
if ((sval & 0x0080) == (sdata & 0x0080))
|
||||
break;
|
||||
|
||||
if ((sval & 0x0020) == 0) /* DQ5: Timeout? */
|
||||
continue;
|
||||
|
||||
sval = *sdest;
|
||||
|
||||
if ((sval & 0x0080) != (sdata & 0x0080))
|
||||
rc = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
DEBUGF ("Program cycle failed @ addr 0x%08lX: val %04X data %04X\n",
|
||||
dest, sval, sdata);
|
||||
}
|
||||
|
||||
if (passed >= CFG_FLASH_WRITE_TOUT) {
|
||||
DEBUGF ("Timeout @ addr 0x%08lX: val %04X data %04X\n",
|
||||
dest, sval, sdata);
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
/* reset to read mode */
|
||||
addr = (vu_short *)info->start[0];
|
||||
addr[0] = 0x00F0; /* reset bank */
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,746 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
|
||||
* has nothing to do with the flash chip being 8-bit or 16-bit.
|
||||
*/
|
||||
#ifdef CONFIG_FLASH_16BIT
|
||||
typedef unsigned short FLASH_PORT_WIDTH;
|
||||
typedef volatile unsigned short FLASH_PORT_WIDTHV;
|
||||
#define FLASH_ID_MASK 0xFFFF
|
||||
#else
|
||||
typedef unsigned long FLASH_PORT_WIDTH;
|
||||
typedef volatile unsigned long FLASH_PORT_WIDTHV;
|
||||
#define FLASH_ID_MASK 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
#define FPW FLASH_PORT_WIDTH
|
||||
#define FPWV FLASH_PORT_WIDTHV
|
||||
|
||||
#define ORMASK(size) ((-size) & OR_AM_MSK)
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size(FPWV *addr, flash_info_t *info);
|
||||
static void flash_reset(flash_info_t *info);
|
||||
static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);
|
||||
static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
|
||||
static void flash_get_offsets(ulong base, flash_info_t *info);
|
||||
#ifdef CFG_FLASH_PROTECTION
|
||||
static void flash_sync_real_protect(flash_info_t *info);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* flash_init()
|
||||
*
|
||||
* sets up flash_info and returns size of FLASH (bytes)
|
||||
*/
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
unsigned long size_b;
|
||||
int i;
|
||||
|
||||
/* Init: no FLASHes known */
|
||||
for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
size_b = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b;
|
||||
|
||||
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
|
||||
printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",size_b);
|
||||
}
|
||||
|
||||
/* Remap FLASH according to real size, so only at proper address */
|
||||
memctl->memc_or0 = (memctl->memc_or0 & ~OR_AM_MSK) | ORMASK(size_b);
|
||||
|
||||
/* Do this again (was done already in flast_get_size), just
|
||||
* in case we move it when remap the FLASH.
|
||||
*/
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
#ifdef CFG_FLASH_PROTECTION
|
||||
/* read the hardware protection status (if any) into the
|
||||
* protection array in flash_info.
|
||||
*/
|
||||
flash_sync_real_protect(&flash_info[0]);
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
return (size_b);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_reset(flash_info_t *info)
|
||||
{
|
||||
FPWV *base = (FPWV *)(info->start[0]);
|
||||
|
||||
/* Put FLASH back in read mode */
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
|
||||
*base = (FPW)0x00FF00FF; /* Intel Read Mode */
|
||||
else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
|
||||
*base = (FPW)0x00F000F0; /* AMD Read Mode */
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start address table */
|
||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
|
||||
&& (info->flash_id & FLASH_BTYPE)) {
|
||||
int bootsect_size; /* number of bytes/boot sector */
|
||||
int sect_size; /* number of bytes/regular sector */
|
||||
|
||||
bootsect_size = 0x00002000 * (sizeof(FPW)/2);
|
||||
sect_size = 0x00010000 * (sizeof(FPW)/2);
|
||||
|
||||
/* set sector offsets for bottom boot block type */
|
||||
for (i = 0; i < 8; ++i) {
|
||||
info->start[i] = base + (i * bootsect_size);
|
||||
}
|
||||
for (i = 8; i < info->sector_count; i++) {
|
||||
info->start[i] = base + ((i - 7) * sect_size);
|
||||
}
|
||||
}
|
||||
else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
|
||||
&& (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
|
||||
|
||||
int sect_size; /* number of bytes/sector */
|
||||
|
||||
sect_size = 0x00010000 * (sizeof(FPW)/2);
|
||||
|
||||
/* set up sector start address table (uniform sector type) */
|
||||
for( i = 0; i < info->sector_count; i++ )
|
||||
info->start[i] = base + (i * sect_size);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void flash_print_info (flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
uchar *boottype;
|
||||
uchar *bootletter;
|
||||
uchar *fmt;
|
||||
uchar botbootletter[] = "B";
|
||||
uchar topbootletter[] = "T";
|
||||
uchar botboottype[] = "bottom boot sector";
|
||||
uchar topboottype[] = "top boot sector";
|
||||
|
||||
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_BM: printf ("BRIGHT MICRO "); break;
|
||||
case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
|
||||
case FLASH_MAN_SST: printf ("SST "); break;
|
||||
case FLASH_MAN_STM: printf ("STM "); break;
|
||||
case FLASH_MAN_INTEL: printf ("INTEL "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
/* check for top or bottom boot, if it applies */
|
||||
if (info->flash_id & FLASH_BTYPE) {
|
||||
boottype = botboottype;
|
||||
bootletter = botbootletter;
|
||||
}
|
||||
else {
|
||||
boottype = topboottype;
|
||||
bootletter = topbootletter;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AM640U:
|
||||
fmt = "29LV641D (64 Mbit, uniform sectors)\n";
|
||||
break;
|
||||
case FLASH_28F800C3B:
|
||||
case FLASH_28F800C3T:
|
||||
fmt = "28F800C3%s (8 Mbit, %s)\n";
|
||||
break;
|
||||
case FLASH_INTEL800B:
|
||||
case FLASH_INTEL800T:
|
||||
fmt = "28F800B3%s (8 Mbit, %s)\n";
|
||||
break;
|
||||
case FLASH_28F160C3B:
|
||||
case FLASH_28F160C3T:
|
||||
fmt = "28F160C3%s (16 Mbit, %s)\n";
|
||||
break;
|
||||
case FLASH_INTEL160B:
|
||||
case FLASH_INTEL160T:
|
||||
fmt = "28F160B3%s (16 Mbit, %s)\n";
|
||||
break;
|
||||
case FLASH_28F320C3B:
|
||||
case FLASH_28F320C3T:
|
||||
fmt = "28F320C3%s (32 Mbit, %s)\n";
|
||||
break;
|
||||
case FLASH_INTEL320B:
|
||||
case FLASH_INTEL320T:
|
||||
fmt = "28F320B3%s (32 Mbit, %s)\n";
|
||||
break;
|
||||
case FLASH_28F640C3B:
|
||||
case FLASH_28F640C3T:
|
||||
fmt = "28F640C3%s (64 Mbit, %s)\n";
|
||||
break;
|
||||
case FLASH_INTEL640B:
|
||||
case FLASH_INTEL640T:
|
||||
fmt = "28F640B3%s (64 Mbit, %s)\n";
|
||||
break;
|
||||
default:
|
||||
fmt = "Unknown Chip Type\n";
|
||||
break;
|
||||
}
|
||||
|
||||
printf (fmt, bootletter, boottype);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
ulong flash_get_size (FPWV *addr, flash_info_t *info)
|
||||
{
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
|
||||
/* Write auto select command sequence and test FLASH answer */
|
||||
addr[0x0555] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
|
||||
addr[0x02AA] = (FPW)0x00550055; /* for AMD, Intel ignores this */
|
||||
addr[0x0555] = (FPW)0x00900090; /* selects Intel or AMD */
|
||||
|
||||
/* The manufacturer codes are only 1 byte, so just use 1 byte.
|
||||
* This works for any bus width and any FLASH device width.
|
||||
*/
|
||||
switch (addr[0] & 0xff) {
|
||||
|
||||
case (uchar)AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
|
||||
case (uchar)INTEL_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_INTEL;
|
||||
break;
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
|
||||
if (info->flash_id != FLASH_UNKNOWN) switch (addr[1]) {
|
||||
|
||||
case (FPW)AMD_ID_LV640U: /* 29LV640 and 29LV641 have same ID */
|
||||
info->flash_id += FLASH_AM640U;
|
||||
info->sector_count = 128;
|
||||
info->size = 0x00800000 * (sizeof(FPW)/2);
|
||||
break; /* => 8 or 16 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F800C3B:
|
||||
info->flash_id += FLASH_28F800C3B;
|
||||
info->sector_count = 23;
|
||||
info->size = 0x00100000 * (sizeof(FPW)/2);
|
||||
break; /* => 1 or 2 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F800B3B:
|
||||
info->flash_id += FLASH_INTEL800B;
|
||||
info->sector_count = 23;
|
||||
info->size = 0x00100000 * (sizeof(FPW)/2);
|
||||
break; /* => 1 or 2 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F160C3B:
|
||||
info->flash_id += FLASH_28F160C3B;
|
||||
info->sector_count = 39;
|
||||
info->size = 0x00200000 * (sizeof(FPW)/2);
|
||||
break; /* => 2 or 4 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F160B3B:
|
||||
info->flash_id += FLASH_INTEL160B;
|
||||
info->sector_count = 39;
|
||||
info->size = 0x00200000 * (sizeof(FPW)/2);
|
||||
break; /* => 2 or 4 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F320C3B:
|
||||
info->flash_id += FLASH_28F320C3B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000 * (sizeof(FPW)/2);
|
||||
break; /* => 4 or 8 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F320B3B:
|
||||
info->flash_id += FLASH_INTEL320B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x00400000 * (sizeof(FPW)/2);
|
||||
break; /* => 4 or 8 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F640C3B:
|
||||
info->flash_id += FLASH_28F640C3B;
|
||||
info->sector_count = 135;
|
||||
info->size = 0x00800000 * (sizeof(FPW)/2);
|
||||
break; /* => 8 or 16 MB */
|
||||
|
||||
case (FPW)INTEL_ID_28F640B3B:
|
||||
info->flash_id += FLASH_INTEL640B;
|
||||
info->sector_count = 135;
|
||||
info->size = 0x00800000 * (sizeof(FPW)/2);
|
||||
break; /* => 8 or 16 MB */
|
||||
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* => no or unknown flash */
|
||||
}
|
||||
|
||||
flash_get_offsets((ulong)addr, info);
|
||||
|
||||
/* Put FLASH back in read mode */
|
||||
flash_reset(info);
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
#ifdef CFG_FLASH_PROTECTION
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void flash_sync_real_protect(flash_info_t *info)
|
||||
{
|
||||
FPWV *addr = (FPWV *)(info->start[0]);
|
||||
FPWV *sect;
|
||||
int i;
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F800C3B:
|
||||
case FLASH_28F800C3T:
|
||||
case FLASH_28F160C3B:
|
||||
case FLASH_28F160C3T:
|
||||
case FLASH_28F320C3B:
|
||||
case FLASH_28F320C3T:
|
||||
case FLASH_28F640C3B:
|
||||
case FLASH_28F640C3T:
|
||||
/* check for protected sectors */
|
||||
*addr = (FPW)0x00900090;
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
/* read sector protection at sector address, (A7 .. A0) = 0x02.
|
||||
* D0 = 1 for each device if protected.
|
||||
* If at least one device is protected the sector is marked
|
||||
* protected, but mixed protected and unprotected devices
|
||||
* within a sector should never happen.
|
||||
*/
|
||||
sect = (FPWV *)(info->start[i]);
|
||||
info->protect[i] = (sect[2] & (FPW)(0x00010001)) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Put FLASH back in read mode */
|
||||
flash_reset(info);
|
||||
break;
|
||||
|
||||
case FLASH_AM640U:
|
||||
default:
|
||||
/* no hardware protect that we support */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
FPWV *addr;
|
||||
int flag, prot, sect;
|
||||
int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
|
||||
ulong start, now, last;
|
||||
int rcode = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_INTEL800B:
|
||||
case FLASH_INTEL160B:
|
||||
case FLASH_INTEL320B:
|
||||
case FLASH_INTEL640B:
|
||||
case FLASH_28F800C3B:
|
||||
case FLASH_28F160C3B:
|
||||
case FLASH_28F320C3B:
|
||||
case FLASH_28F640C3B:
|
||||
case FLASH_AM640U:
|
||||
break;
|
||||
case FLASH_UNKNOWN:
|
||||
default:
|
||||
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");
|
||||
}
|
||||
|
||||
start = get_timer(0);
|
||||
last = start;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
|
||||
|
||||
if (info->protect[sect] != 0) /* protected, skip it */
|
||||
continue;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
addr = (FPWV *)(info->start[sect]);
|
||||
if (intel) {
|
||||
*addr = (FPW)0x00500050; /* clear status register */
|
||||
*addr = (FPW)0x00200020; /* erase setup */
|
||||
*addr = (FPW)0x00D000D0; /* erase confirm */
|
||||
}
|
||||
else {
|
||||
/* must be AMD style if not Intel */
|
||||
FPWV *base; /* first address in bank */
|
||||
|
||||
base = (FPWV *)(info->start[0]);
|
||||
base[0x0555] = (FPW)0x00AA00AA; /* unlock */
|
||||
base[0x02AA] = (FPW)0x00550055; /* unlock */
|
||||
base[0x0555] = (FPW)0x00800080; /* erase mode */
|
||||
base[0x0555] = (FPW)0x00AA00AA; /* unlock */
|
||||
base[0x02AA] = (FPW)0x00550055; /* unlock */
|
||||
*addr = (FPW)0x00300030; /* erase sector */
|
||||
}
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* wait at least 50us for AMD, 80us for Intel.
|
||||
* Let's wait 1 ms.
|
||||
*/
|
||||
udelay (1000);
|
||||
|
||||
while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
|
||||
if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
|
||||
printf ("Timeout\n");
|
||||
|
||||
if (intel) {
|
||||
/* suspend erase */
|
||||
*addr = (FPW)0x00B000B0;
|
||||
}
|
||||
|
||||
flash_reset(info); /* reset to read mode */
|
||||
rcode = 1; /* failed */
|
||||
break;
|
||||
}
|
||||
|
||||
/* show that we're waiting */
|
||||
if ((now - last) > 1000) { /* every second */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
flash_reset(info); /* reset to read mode */
|
||||
}
|
||||
|
||||
printf (" done\n");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* 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)
|
||||
{
|
||||
FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
|
||||
int bytes; /* number of bytes to program in current word */
|
||||
int left; /* number of bytes left to program */
|
||||
int i, res;
|
||||
|
||||
for (left = cnt, res = 0;
|
||||
left > 0 && res == 0;
|
||||
addr += sizeof(data), left -= sizeof(data) - bytes) {
|
||||
|
||||
bytes = addr & (sizeof(data) - 1);
|
||||
addr &= ~(sizeof(data) - 1);
|
||||
|
||||
/* combine source and destination data so can program
|
||||
* an entire word of 16 or 32 bits
|
||||
*/
|
||||
for (i = 0; i < sizeof(data); i++) {
|
||||
data <<= 8;
|
||||
if (i < bytes || i - bytes >= left )
|
||||
data += *((uchar *)addr + i);
|
||||
else
|
||||
data += *src++;
|
||||
}
|
||||
|
||||
/* write one word to the flash */
|
||||
switch (info->flash_id & FLASH_VENDMASK) {
|
||||
case FLASH_MAN_AMD:
|
||||
res = write_word_amd(info, (FPWV *)addr, data);
|
||||
break;
|
||||
case FLASH_MAN_INTEL:
|
||||
res = write_word_intel(info, (FPWV *)addr, data);
|
||||
break;
|
||||
default:
|
||||
/* unknown flash type, error! */
|
||||
printf ("missing or unknown FLASH type\n");
|
||||
res = 1; /* not really a timeout, but gives error */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word to Flash for AMD FLASH
|
||||
* A word is 16 or 32 bits, whichever the bus width of the flash bank
|
||||
* (not an individual chip) is.
|
||||
*
|
||||
* returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
|
||||
{
|
||||
ulong start;
|
||||
int flag;
|
||||
int res = 0; /* result, assume success */
|
||||
FPWV *base; /* first address in flash bank */
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*dest & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
|
||||
base = (FPWV *)(info->start[0]);
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
base[0x0555] = (FPW)0x00AA00AA; /* unlock */
|
||||
base[0x02AA] = (FPW)0x00550055; /* unlock */
|
||||
base[0x0555] = (FPW)0x00A000A0; /* selects program mode */
|
||||
|
||||
*dest = data; /* start programming the data */
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
start = get_timer (0);
|
||||
|
||||
/* data polling for D7 */
|
||||
while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
*dest = (FPW)0x00F000F0; /* reset bank */
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a word to Flash for Intel FLASH
|
||||
* A word is 16 or 32 bits, whichever the bus width of the flash bank
|
||||
* (not an individual chip) is.
|
||||
*
|
||||
* returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_word_intel (flash_info_t *info, FPWV *dest, FPW data)
|
||||
{
|
||||
ulong start;
|
||||
int flag;
|
||||
int res = 0; /* result, assume success */
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*dest & data) != data) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts();
|
||||
|
||||
*dest = (FPW)0x00500050; /* clear status register */
|
||||
*dest = (FPW)0x00FF00FF; /* make sure in read mode */
|
||||
*dest = (FPW)0x00400040; /* program setup */
|
||||
|
||||
*dest = data; /* start programming the data */
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
start = get_timer (0);
|
||||
|
||||
while (res == 0 && (*dest & (FPW)0x00800080) != (FPW)0x00800080) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
*dest = (FPW)0x00B000B0; /* Suspend program */
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 0 && (*dest & (FPW)0x00100010))
|
||||
res = 1; /* write failed, time out error is close enough */
|
||||
|
||||
*dest = (FPW)0x00500050; /* clear status register */
|
||||
*dest = (FPW)0x00FF00FF; /* make sure in read mode */
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
#ifdef CFG_FLASH_PROTECTION
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
int flash_real_protect (flash_info_t * info, long sector, int prot)
|
||||
{
|
||||
int rcode = 0; /* assume success */
|
||||
FPWV *addr; /* address of sector */
|
||||
FPW value;
|
||||
|
||||
addr = (FPWV *) (info->start[sector]);
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_28F800C3B:
|
||||
case FLASH_28F800C3T:
|
||||
case FLASH_28F160C3B:
|
||||
case FLASH_28F160C3T:
|
||||
case FLASH_28F320C3B:
|
||||
case FLASH_28F320C3T:
|
||||
case FLASH_28F640C3B:
|
||||
case FLASH_28F640C3T:
|
||||
flash_reset (info); /* make sure in read mode */
|
||||
*addr = (FPW) 0x00600060L; /* lock command setup */
|
||||
if (prot)
|
||||
*addr = (FPW) 0x00010001L; /* lock sector */
|
||||
else
|
||||
*addr = (FPW) 0x00D000D0L; /* unlock sector */
|
||||
flash_reset (info); /* reset to read mode */
|
||||
|
||||
/* now see if it really is locked/unlocked as requested */
|
||||
*addr = (FPW) 0x00900090;
|
||||
/* read sector protection at sector address, (A7 .. A0) = 0x02.
|
||||
* D0 = 1 for each device if protected.
|
||||
* If at least one device is protected the sector is marked
|
||||
* protected, but return failure. Mixed protected and
|
||||
* unprotected devices within a sector should never happen.
|
||||
*/
|
||||
value = addr[2] & (FPW) 0x00010001;
|
||||
if (value == 0)
|
||||
info->protect[sector] = 0;
|
||||
else if (value == (FPW) 0x00010001)
|
||||
info->protect[sector] = 1;
|
||||
else {
|
||||
/* error, mixed protected and unprotected */
|
||||
rcode = 1;
|
||||
info->protect[sector] = 1;
|
||||
}
|
||||
if (info->protect[sector] != prot)
|
||||
rcode = 1; /* failed to protect/unprotect as requested */
|
||||
|
||||
/* reload all protection bits from hardware for now */
|
||||
flash_sync_real_protect (info);
|
||||
break;
|
||||
|
||||
case FLASH_AM640U:
|
||||
default:
|
||||
/* no hardware protect that we support */
|
||||
info->protect[sector] = prot;
|
||||
break;
|
||||
}
|
||||
|
||||
return rcode;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned long flash_init (void)
|
||||
{
|
||||
/* All Speech Design board memory (DRAM and EPROM) initialisation is
|
||||
done in dram_init().
|
||||
The caller of ths function here expects the total size and will hang,
|
||||
if we give here back 0. So we return the EPROM size. */
|
||||
|
||||
return (1024 * 1024); /* 1 MB */
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void flash_print_info (flash_info_t *info)
|
||||
{
|
||||
printf("no FLASH memory in MPC823TS board\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* (C) Copyright 2001, 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* Flash Routines for AMD devices on the TQM8260 board
|
||||
*
|
||||
*--------------------------------------------------------------------
|
||||
* 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>
|
||||
|
||||
#define V_ULONG(a) (*(volatile unsigned long *)( a ))
|
||||
#define V_BYTE(a) (*(volatile unsigned char *)( a ))
|
||||
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void flash_reset (void)
|
||||
{
|
||||
if (flash_info[0].flash_id != FLASH_UNKNOWN) {
|
||||
V_ULONG (flash_info[0].start[0]) = 0x00F000F0;
|
||||
V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
ulong flash_get_size (ulong baseaddr, flash_info_t * info)
|
||||
{
|
||||
short i;
|
||||
unsigned long flashtest_h, flashtest_l;
|
||||
|
||||
/* Write auto select command sequence and test FLASH answer */
|
||||
V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
|
||||
V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;
|
||||
|
||||
flashtest_h = V_ULONG (baseaddr); /* manufacturer ID */
|
||||
flashtest_l = V_ULONG (baseaddr + 4);
|
||||
|
||||
switch ((int) flashtest_h) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
flashtest_h = V_ULONG (baseaddr + 8); /* device ID */
|
||||
flashtest_l = V_ULONG (baseaddr + 12);
|
||||
if (flashtest_h != flashtest_l) {
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
} else {
|
||||
switch (flashtest_h) {
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00400000;
|
||||
break; /* 4 * 1 MB = 4 MB */
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00400000;
|
||||
break; /* 4 * 1 MB = 4 MB */
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00800000;
|
||||
break; /* 4 * 2 MB = 8 MB */
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00800000;
|
||||
break; /* 4 * 2 MB = 8 MB */
|
||||
case AMD_ID_DL322T:
|
||||
info->flash_id += FLASH_AMDL322T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_DL322B:
|
||||
info->flash_id += FLASH_AMDL322B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_DL323T:
|
||||
info->flash_id += FLASH_AMDL323T;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_DL323B:
|
||||
info->flash_id += FLASH_AMDL323B;
|
||||
info->sector_count = 71;
|
||||
info->size = 0x01000000;
|
||||
break; /* 4 * 4 MB = 16 MB */
|
||||
case AMD_ID_LV640U:
|
||||
info->flash_id += FLASH_AM640U;
|
||||
info->sector_count = 128;
|
||||
info->size = 0x02000000;
|
||||
break; /* 4 * 8 MB = 32 MB */
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
}
|
||||
|
||||
if (flashtest_h == AMD_ID_LV640U) {
|
||||
|
||||
/* set up sector start adress table (uniform sector type) */
|
||||
for (i = 0; i < info->sector_count; i++)
|
||||
info->start[i] = baseaddr + (i * 0x00040000);
|
||||
|
||||
} else if (info->flash_id & FLASH_BTYPE) {
|
||||
|
||||
/* set up sector start adress table (bottom sector type) */
|
||||
info->start[0] = baseaddr + 0x00000000;
|
||||
info->start[1] = baseaddr + 0x00010000;
|
||||
info->start[2] = baseaddr + 0x00018000;
|
||||
info->start[3] = baseaddr + 0x00020000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* set up sector start adress table (top sector type) */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = baseaddr + info->size - 0x00010000;
|
||||
info->start[i--] = baseaddr + info->size - 0x00018000;
|
||||
info->start[i--] = baseaddr + info->size - 0x00020000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = baseaddr + i * 0x00040000;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for protected sectors */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
/* read sector protection at sector address, (A7 .. A0) = 0x02 */
|
||||
if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
|
||||
(V_ULONG (info->start[i] + 20) & 0x00010001)) {
|
||||
info->protect[i] = 1; /* D0 = 1 if protected */
|
||||
} else {
|
||||
info->protect[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
flash_reset ();
|
||||
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 (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
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#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 & 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_AM800T:
|
||||
printf ("29LV800T (8 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AM800B:
|
||||
printf ("29LV800T (8 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AM160T:
|
||||
printf ("29LV160T (16 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AM160B:
|
||||
printf ("29LV160B (16 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL322T:
|
||||
printf ("29DL322T (32 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL322B:
|
||||
printf ("29DL322B (32 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL323T:
|
||||
printf ("29DL323T (32 M, top sector)\n");
|
||||
break;
|
||||
case FLASH_AMDL323B:
|
||||
printf ("29DL323B (32 M, bottom sector)\n");
|
||||
break;
|
||||
case FLASH_AM640U:
|
||||
printf ("29LV640D (64 M, uniform 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;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
int flash_erase (flash_info_t * info, int s_first, int s_last)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
l_sect = -1;
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts ();
|
||||
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080;
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
|
||||
udelay (1000);
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect <= s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
V_ULONG (info->start[sect]) = 0x00300030;
|
||||
V_ULONG (info->start[sect] + 4) = 0x00300030;
|
||||
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;
|
||||
while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 ||
|
||||
(V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
flash_reset ();
|
||||
|
||||
printf (" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_dword (flash_info_t *, ulong, unsigned char *);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* 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 dp;
|
||||
static unsigned char bb[8];
|
||||
int i, l, rc, cc = cnt;
|
||||
|
||||
dp = (addr & ~7); /* get lower dword aligned address */
|
||||
|
||||
/*
|
||||
* handle unaligned start bytes
|
||||
*/
|
||||
if ((l = addr - dp) != 0) {
|
||||
for (i = 0; i < 8; i++)
|
||||
bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++;
|
||||
if ((rc = write_dword (info, dp, bb)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
dp += 8;
|
||||
cc -= 8 - l;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle word aligned part
|
||||
*/
|
||||
while (cc >= 8) {
|
||||
if ((rc = write_dword (info, dp, src)) != 0) {
|
||||
return (rc);
|
||||
}
|
||||
dp += 8;
|
||||
src += 8;
|
||||
cc -= 8;
|
||||
}
|
||||
|
||||
if (cc <= 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unaligned tail bytes
|
||||
*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i);
|
||||
}
|
||||
return (write_dword (info, dp, bb));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Write a dword to Flash, returns:
|
||||
* 0 - OK
|
||||
* 1 - write timeout
|
||||
* 2 - Flash not erased
|
||||
*/
|
||||
static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata)
|
||||
{
|
||||
ulong start, cl, ch;
|
||||
int flag, i;
|
||||
|
||||
for (ch = 0, i = 0; i < 4; i++)
|
||||
ch = (ch << 8) + *pdata++; /* high word */
|
||||
for (cl = 0, i = 0; i < 4; i++)
|
||||
cl = (cl << 8) + *pdata++; /* low word */
|
||||
|
||||
/* Check if Flash is (sufficiently) erased */
|
||||
if ((*((vu_long *) dest) & ch) != ch
|
||||
|| (*((vu_long *) (dest + 4)) & cl) != cl) {
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* Disable interrupts which might cause a timeout here */
|
||||
flag = disable_interrupts ();
|
||||
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0;
|
||||
V_ULONG (dest) = ch;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
|
||||
V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
|
||||
V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0;
|
||||
V_ULONG (dest + 4) = cl;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts ();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) ||
|
||||
((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) {
|
||||
if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Wave 7 Optics, Inc.
|
||||
*
|
||||
* 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 <config.h>
|
||||
#include <command.h>
|
||||
#include <cmd_elf.h>
|
||||
|
||||
/*
|
||||
* FIXME: Add code to test image and it's header.
|
||||
*/
|
||||
static int
|
||||
image_check(ulong addr)
|
||||
{
|
||||
return valid_elf_image(addr);
|
||||
}
|
||||
|
||||
void
|
||||
init_fsboot(void)
|
||||
{
|
||||
char *envp;
|
||||
ulong loadaddr;
|
||||
ulong testaddr;
|
||||
ulong alt_loadaddr;
|
||||
char buf[9];
|
||||
|
||||
/*
|
||||
* Get test image address
|
||||
*/
|
||||
if ((envp = getenv("testaddr")) != NULL)
|
||||
testaddr = simple_strtoul(envp, NULL, 16);
|
||||
else
|
||||
testaddr = -1;
|
||||
|
||||
/*
|
||||
* Are we going to test boot and image?
|
||||
*/
|
||||
if ((testaddr != -1) && image_check(testaddr)) {
|
||||
|
||||
/* Set alt_loadaddr */
|
||||
alt_loadaddr = testaddr;
|
||||
sprintf(buf, "%lX", alt_loadaddr);
|
||||
setenv("alt_loadaddr", buf);
|
||||
|
||||
/* Clear test_addr */
|
||||
setenv("testaddr", NULL);
|
||||
|
||||
/*
|
||||
* Save current environment with alt_loadaddr,
|
||||
* and cleared testaddr.
|
||||
*/
|
||||
saveenv();
|
||||
|
||||
/*
|
||||
* Setup temporary loadaddr to alt_loadaddr
|
||||
* XXX - DO NOT SAVE ENVIRONMENT!
|
||||
*/
|
||||
loadaddr = alt_loadaddr;
|
||||
sprintf(buf, "%lX", loadaddr);
|
||||
setenv("loadaddr", buf);
|
||||
|
||||
} else { /* Normal boot */
|
||||
setenv("alt_loadaddr", NULL); /* Clear alt_loadaddr */
|
||||
setenv("testaddr", NULL); /* Clear testaddr */
|
||||
saveenv();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* W7O board level hardware watchdog.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
|
||||
#ifdef CONFIG_HW_WATCHDOG
|
||||
#include <watchdog.h>
|
||||
|
||||
void hw_watchdog_reset(void)
|
||||
{
|
||||
volatile ushort *hwd = (ushort *)(CFG_W7O_EBC_PB7CR & 0xfff00000);
|
||||
|
||||
/*
|
||||
* Read the LMG's hwd register and toggle the
|
||||
* watchdog bit to reset it. On the LMC, just
|
||||
* reading it is enough, but toggling the bit
|
||||
* doen't hurt either.
|
||||
*/
|
||||
*hwd = *hwd ^ 0x8000;
|
||||
|
||||
} /* hw_watchdog_reset() */
|
||||
|
||||
#endif /* CONFIG_HW_WATCHDOG */
|
||||
|
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* (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 <mpc8xx.h>
|
||||
|
||||
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
#if defined(CFG_ENV_IS_IN_FLASH)
|
||||
# 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
|
||||
# ifndef CFG_ENV_SECT_SIZE
|
||||
# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#undef DEBUG_FLASH
|
||||
|
||||
#ifdef DEBUG_FLASH
|
||||
#define DEBUGF(fmt,args...) printf(fmt ,##args)
|
||||
#else
|
||||
#define DEBUGF(fmt,args...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info);
|
||||
static int write_word (flash_info_t *info, ulong dest, ulong data);
|
||||
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 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) {
|
||||
flash_info[i].flash_id = FLASH_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Static FLASH Bank configuration here - FIXME XXX */
|
||||
|
||||
DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
|
||||
|
||||
size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &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);
|
||||
}
|
||||
|
||||
#if defined(FLASH_BASE1_PRELIM) && (FLASH_BASE1_PRELIM != 0)
|
||||
DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE1_PRELIM);
|
||||
|
||||
size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
|
||||
|
||||
if (size_b1 > size_b0) {
|
||||
printf ("## ERROR: "
|
||||
"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
|
||||
size_b1, size_b1<<20,
|
||||
size_b0, size_b0<<20
|
||||
);
|
||||
flash_info[0].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[0].sector_count = -1;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[0].size = 0;
|
||||
flash_info[1].size = 0;
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
size_b1 = 0;
|
||||
#endif /* FLASH_BASE1_PRELIM */
|
||||
|
||||
DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
|
||||
|
||||
DEBUGF ("## Before remap: "
|
||||
"BR0: 0x%08x OR0: 0x%08x "
|
||||
"BR1: 0x%08x OR1: 0x%08x\n",
|
||||
memctl->memc_br0, memctl->memc_or0,
|
||||
memctl->memc_br1, memctl->memc_or1);
|
||||
|
||||
/* Remap FLASH according to real size */
|
||||
memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
|
||||
memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
|
||||
|
||||
DEBUGF("## 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]);
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
|
||||
|
||||
flash_info[0].size = size_b0;
|
||||
|
||||
#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_SECT_SIZE-1,
|
||||
&flash_info[0]);
|
||||
#endif
|
||||
|
||||
if (size_b1) {
|
||||
memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & OR_AM_MSK);
|
||||
memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
|
||||
BR_MS_GPCM | BR_V;
|
||||
|
||||
DEBUGF("## 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),
|
||||
&flash_info[1]);
|
||||
|
||||
flash_info[1].size = size_b1;
|
||||
|
||||
flash_get_offsets (CFG_FLASH_BASE + size_b0, &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[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_SECT_SIZE-1,
|
||||
&flash_info[1]);
|
||||
#endif
|
||||
} else {
|
||||
#ifndef CONFIG_AMX_RAM_EXT
|
||||
memctl->memc_br1 = 0; /* invalidate bank */
|
||||
memctl->memc_or1 = 0; /* invalidate bank */
|
||||
#endif
|
||||
|
||||
DEBUGF("## DISABLE BR1: 0x%08x OR1: 0x%08x\n",
|
||||
memctl->memc_br1, memctl->memc_or1);
|
||||
|
||||
flash_info[1].flash_id = FLASH_UNKNOWN;
|
||||
flash_info[1].sector_count = -1;
|
||||
flash_info[1].size = 0;
|
||||
}
|
||||
|
||||
DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
|
||||
|
||||
return (size_b0 + size_b1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
static void flash_get_offsets (ulong base, flash_info_t *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set up sector start address table */
|
||||
if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
|
||||
/* set sector offsets for uniform sector type */
|
||||
for (i = 0; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00040000);
|
||||
}
|
||||
} else if (info->flash_id & FLASH_BTYPE) {
|
||||
/* set sector offsets for bottom boot block type */
|
||||
info->start[0] = base + 0x00000000;
|
||||
info->start[1] = base + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
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;
|
||||
case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
|
||||
default: printf ("Unknown Vendor "); break;
|
||||
}
|
||||
|
||||
switch (info->flash_id & FLASH_TYPEMASK) {
|
||||
case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
|
||||
break;
|
||||
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");
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code cannot be run from FLASH!
|
||||
*/
|
||||
|
||||
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
|
||||
{
|
||||
short i;
|
||||
ulong value;
|
||||
ulong base = (ulong)addr;
|
||||
|
||||
/* Write auto select command: read Manufacturer ID */
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00900090;
|
||||
|
||||
value = addr[0];
|
||||
|
||||
DEBUGF("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value);
|
||||
|
||||
switch (value) {
|
||||
case AMD_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_AMD;
|
||||
break;
|
||||
case FUJ_MANUFACT:
|
||||
info->flash_id = FLASH_MAN_FUJ;
|
||||
break;
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
info->sector_count = 0;
|
||||
info->size = 0;
|
||||
return (0); /* no or unknown flash */
|
||||
}
|
||||
|
||||
value = addr[1]; /* device ID */
|
||||
|
||||
DEBUGF("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value);
|
||||
|
||||
switch (value) {
|
||||
case AMD_ID_F040B:
|
||||
info->flash_id += FLASH_AM040;
|
||||
info->sector_count = 8;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV400T:
|
||||
info->flash_id += FLASH_AM400T;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV400B:
|
||||
info->flash_id += FLASH_AM400B;
|
||||
info->sector_count = 11;
|
||||
info->size = 0x00100000;
|
||||
break; /* => 1 MB */
|
||||
|
||||
case AMD_ID_LV800T:
|
||||
info->flash_id += FLASH_AM800T;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV800B:
|
||||
info->flash_id += FLASH_AM800B;
|
||||
info->sector_count = 19;
|
||||
info->size = 0x00200000;
|
||||
break; /* => 2 MB */
|
||||
|
||||
case AMD_ID_LV160T:
|
||||
info->flash_id += FLASH_AM160T;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
|
||||
case AMD_ID_LV160B:
|
||||
info->flash_id += FLASH_AM160B;
|
||||
info->sector_count = 35;
|
||||
info->size = 0x00400000;
|
||||
break; /* => 4 MB */
|
||||
#if 0 /* enable when device IDs are available */
|
||||
case AMD_ID_LV320T:
|
||||
info->flash_id += FLASH_AM320T;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
|
||||
case AMD_ID_LV320B:
|
||||
info->flash_id += FLASH_AM320B;
|
||||
info->sector_count = 67;
|
||||
info->size = 0x00800000;
|
||||
break; /* => 8 MB */
|
||||
#endif
|
||||
default:
|
||||
info->flash_id = FLASH_UNKNOWN;
|
||||
return (0); /* => no or unknown flash */
|
||||
}
|
||||
|
||||
/* 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 + 0x00008000;
|
||||
info->start[2] = base + 0x0000C000;
|
||||
info->start[3] = base + 0x00010000;
|
||||
for (i = 4; i < info->sector_count; i++) {
|
||||
info->start[i] = base + (i * 0x00020000) - 0x00060000;
|
||||
}
|
||||
} else {
|
||||
/* set sector offsets for top boot block type */
|
||||
i = info->sector_count - 1;
|
||||
info->start[i--] = base + info->size - 0x00008000;
|
||||
info->start[i--] = base + info->size - 0x0000C000;
|
||||
info->start[i--] = base + info->size - 0x00010000;
|
||||
for (; i >= 0; i--) {
|
||||
info->start[i] = base + i * 0x00020000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 long *)(info->start[i]);
|
||||
info->protect[i] = addr[2] & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent writes to uninitialized FLASH.
|
||||
*/
|
||||
if (info->flash_id != FLASH_UNKNOWN) {
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
|
||||
*addr = 0x00F000F0; /* reset bank */
|
||||
}
|
||||
|
||||
return (info->size);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int flash_erase (flash_info_t *info, int s_first, int s_last)
|
||||
{
|
||||
vu_long *addr = (vu_long*)(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] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00800080;
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
|
||||
/* Start erase on unprotected sectors */
|
||||
for (sect = s_first; sect<=s_last; sect++) {
|
||||
if (info->protect[sect] == 0) { /* not protected */
|
||||
addr = (vu_long*)(info->start[sect]);
|
||||
addr[0] = 0x00300030;
|
||||
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_long*)(info->start[l_sect]);
|
||||
while ((addr[0] & 0x00800080) != 0x00800080) {
|
||||
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 */
|
||||
putc ('.');
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* reset to read mode */
|
||||
addr = (volatile unsigned long *)info->start[0];
|
||||
addr[0] = 0x00F000F0; /* reset bank */
|
||||
|
||||
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_long *addr = (vu_long*)(info->start[0]);
|
||||
ulong start;
|
||||
int flag;
|
||||
|
||||
/* 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();
|
||||
|
||||
addr[0x0555] = 0x00AA00AA;
|
||||
addr[0x02AA] = 0x00550055;
|
||||
addr[0x0555] = 0x00A000A0;
|
||||
|
||||
*((vu_long *)dest) = data;
|
||||
|
||||
/* re-enable interrupts if necessary */
|
||||
if (flag)
|
||||
enable_interrupts();
|
||||
|
||||
/* data polling for D7 */
|
||||
start = get_timer (0);
|
||||
while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
|
||||
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* ECC algorithm for M-systems disk on chip. We use the excellent Reed
|
||||
* Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
|
||||
* GNU GPL License. The rest is simply to convert the disk on chip
|
||||
* syndrom into a standard syndom.
|
||||
*
|
||||
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
|
||||
* Copyright (C) 2000 Netgem S.A.
|
||||
*
|
||||
* $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $
|
||||
*
|
||||
* 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 <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <linux/mtd/doc2000.h>
|
||||
|
||||
#undef ECC_DEBUG
|
||||
#undef PSYCHO_DEBUG
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_DOC)
|
||||
|
||||
#define min(x,y) ((x)<(y)?(x):(y))
|
||||
|
||||
/* need to undef it (from asm/termbits.h) */
|
||||
#undef B0
|
||||
|
||||
#define MM 10 /* Symbol size in bits */
|
||||
#define KK (1023-4) /* Number of data symbols per block */
|
||||
#define B0 510 /* First root of generator polynomial, alpha form */
|
||||
#define PRIM 1 /* power of alpha used to generate roots of generator poly */
|
||||
#define NN ((1 << MM) - 1)
|
||||
|
||||
typedef unsigned short dtype;
|
||||
|
||||
/* 1+x^3+x^10 */
|
||||
static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
/* This defines the type used to store an element of the Galois Field
|
||||
* used by the code. Make sure this is something larger than a char if
|
||||
* if anything larger than GF(256) is used.
|
||||
*
|
||||
* Note: unsigned char will work up to GF(256) but int seems to run
|
||||
* faster on the Pentium.
|
||||
*/
|
||||
typedef int gf;
|
||||
|
||||
/* No legal value in index form represents zero, so
|
||||
* we need a special value for this purpose
|
||||
*/
|
||||
#define A0 (NN)
|
||||
|
||||
/* Compute x % NN, where NN is 2**MM - 1,
|
||||
* without a slow divide
|
||||
*/
|
||||
static inline gf
|
||||
modnn(int x)
|
||||
{
|
||||
while (x >= NN) {
|
||||
x -= NN;
|
||||
x = (x >> MM) + (x & NN);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
#define CLEAR(a,n) {\
|
||||
int ci;\
|
||||
for(ci=(n)-1;ci >=0;ci--)\
|
||||
(a)[ci] = 0;\
|
||||
}
|
||||
|
||||
#define COPY(a,b,n) {\
|
||||
int ci;\
|
||||
for(ci=(n)-1;ci >=0;ci--)\
|
||||
(a)[ci] = (b)[ci];\
|
||||
}
|
||||
|
||||
#define COPYDOWN(a,b,n) {\
|
||||
int ci;\
|
||||
for(ci=(n)-1;ci >=0;ci--)\
|
||||
(a)[ci] = (b)[ci];\
|
||||
}
|
||||
|
||||
#define Ldec 1
|
||||
|
||||
/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
|
||||
lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
|
||||
polynomial form -> index form index_of[j=alpha**i] = i
|
||||
alpha=2 is the primitive element of GF(2**m)
|
||||
HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
|
||||
Let @ represent the primitive element commonly called "alpha" that
|
||||
is the root of the primitive polynomial p(x). Then in GF(2^m), for any
|
||||
0 <= i <= 2^m-2,
|
||||
@^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
|
||||
where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
|
||||
of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
|
||||
example the polynomial representation of @^5 would be given by the binary
|
||||
representation of the integer "alpha_to[5]".
|
||||
Similarily, index_of[] can be used as follows:
|
||||
As above, let @ represent the primitive element of GF(2^m) that is
|
||||
the root of the primitive polynomial p(x). In order to find the power
|
||||
of @ (alpha) that has the polynomial representation
|
||||
a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
|
||||
we consider the integer "i" whose binary representation with a(0) being LSB
|
||||
and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
|
||||
"index_of[i]". Now, @^index_of[i] is that element whose polynomial
|
||||
representation is (a(0),a(1),a(2),...,a(m-1)).
|
||||
NOTE:
|
||||
The element alpha_to[2^m-1] = 0 always signifying that the
|
||||
representation of "@^infinity" = 0 is (0,0,0,...,0).
|
||||
Similarily, the element index_of[0] = A0 always signifying
|
||||
that the power of alpha which has the polynomial representation
|
||||
(0,0,...,0) is "infinity".
|
||||
|
||||
*/
|
||||
|
||||
static void
|
||||
generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
|
||||
{
|
||||
register int i, mask;
|
||||
|
||||
mask = 1;
|
||||
Alpha_to[MM] = 0;
|
||||
for (i = 0; i < MM; i++) {
|
||||
Alpha_to[i] = mask;
|
||||
Index_of[Alpha_to[i]] = i;
|
||||
/* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
|
||||
if (Pp[i] != 0)
|
||||
Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */
|
||||
mask <<= 1; /* single left-shift */
|
||||
}
|
||||
Index_of[Alpha_to[MM]] = MM;
|
||||
/*
|
||||
* Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
|
||||
* poly-repr of @^i shifted left one-bit and accounting for any @^MM
|
||||
* term that may occur when poly-repr of @^i is shifted.
|
||||
*/
|
||||
mask >>= 1;
|
||||
for (i = MM + 1; i < NN; i++) {
|
||||
if (Alpha_to[i - 1] >= mask)
|
||||
Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
|
||||
else
|
||||
Alpha_to[i] = Alpha_to[i - 1] << 1;
|
||||
Index_of[Alpha_to[i]] = i;
|
||||
}
|
||||
Index_of[0] = A0;
|
||||
Alpha_to[NN] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
|
||||
* of the feedback shift register after having processed the data and
|
||||
* the ECC.
|
||||
*
|
||||
* Return number of symbols corrected, or -1 if codeword is illegal
|
||||
* or uncorrectable. If eras_pos is non-null, the detected error locations
|
||||
* are written back. NOTE! This array must be at least NN-KK elements long.
|
||||
* The corrected data are written in eras_val[]. They must be xor with the data
|
||||
* to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
|
||||
*
|
||||
* First "no_eras" erasures are declared by the calling program. Then, the
|
||||
* maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
|
||||
* If the number of channel errors is not greater than "t_after_eras" the
|
||||
* transmitted codeword will be recovered. Details of algorithm can be found
|
||||
* in R. Blahut's "Theory ... of Error-Correcting Codes".
|
||||
|
||||
* Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
|
||||
* will result. The decoder *could* check for this condition, but it would involve
|
||||
* extra time on every decoding operation.
|
||||
* */
|
||||
static int
|
||||
eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
|
||||
gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK],
|
||||
int no_eras)
|
||||
{
|
||||
int deg_lambda, el, deg_omega;
|
||||
int i, j, r,k;
|
||||
gf u,q,tmp,num1,num2,den,discr_r;
|
||||
gf lambda[NN-KK + 1], s[NN-KK + 1]; /* Err+Eras Locator poly
|
||||
* and syndrome poly */
|
||||
gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
|
||||
gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
|
||||
int syn_error, count;
|
||||
|
||||
syn_error = 0;
|
||||
for(i=0;i<NN-KK;i++)
|
||||
syn_error |= bb[i];
|
||||
|
||||
if (!syn_error) {
|
||||
/* if remainder is zero, data[] is a codeword and there are no
|
||||
* errors to correct. So return data[] unmodified
|
||||
*/
|
||||
count = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for(i=1;i<=NN-KK;i++){
|
||||
s[i] = bb[0];
|
||||
}
|
||||
for(j=1;j<NN-KK;j++){
|
||||
if(bb[j] == 0)
|
||||
continue;
|
||||
tmp = Index_of[bb[j]];
|
||||
|
||||
for(i=1;i<=NN-KK;i++)
|
||||
s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
|
||||
}
|
||||
|
||||
/* undo the feedback register implicit multiplication and convert
|
||||
syndromes to index form */
|
||||
|
||||
for(i=1;i<=NN-KK;i++) {
|
||||
tmp = Index_of[s[i]];
|
||||
if (tmp != A0)
|
||||
tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
|
||||
s[i] = tmp;
|
||||
}
|
||||
|
||||
CLEAR(&lambda[1],NN-KK);
|
||||
lambda[0] = 1;
|
||||
|
||||
if (no_eras > 0) {
|
||||
/* Init lambda to be the erasure locator polynomial */
|
||||
lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
|
||||
for (i = 1; i < no_eras; i++) {
|
||||
u = modnn(PRIM*eras_pos[i]);
|
||||
for (j = i+1; j > 0; j--) {
|
||||
tmp = Index_of[lambda[j - 1]];
|
||||
if(tmp != A0)
|
||||
lambda[j] ^= Alpha_to[modnn(u + tmp)];
|
||||
}
|
||||
}
|
||||
#ifdef ECC_DEBUG
|
||||
/* Test code that verifies the erasure locator polynomial just constructed
|
||||
Needed only for decoder debugging. */
|
||||
|
||||
/* find roots of the erasure location polynomial */
|
||||
for(i=1;i<=no_eras;i++)
|
||||
reg[i] = Index_of[lambda[i]];
|
||||
count = 0;
|
||||
for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
|
||||
q = 1;
|
||||
for (j = 1; j <= no_eras; j++)
|
||||
if (reg[j] != A0) {
|
||||
reg[j] = modnn(reg[j] + j);
|
||||
q ^= Alpha_to[reg[j]];
|
||||
}
|
||||
if (q != 0)
|
||||
continue;
|
||||
/* store root and error location number indices */
|
||||
root[count] = i;
|
||||
loc[count] = k;
|
||||
count++;
|
||||
}
|
||||
if (count != no_eras) {
|
||||
printf("\n lambda(x) is WRONG\n");
|
||||
count = -1;
|
||||
goto finish;
|
||||
}
|
||||
#ifdef PSYCHO_DEBUG
|
||||
printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
|
||||
for (i = 0; i < count; i++)
|
||||
printf("%d ", loc[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
for(i=0;i<NN-KK+1;i++)
|
||||
b[i] = Index_of[lambda[i]];
|
||||
|
||||
/*
|
||||
* Begin Berlekamp-Massey algorithm to determine error+erasure
|
||||
* locator polynomial
|
||||
*/
|
||||
r = no_eras;
|
||||
el = no_eras;
|
||||
while (++r <= NN-KK) { /* r is the step number */
|
||||
/* Compute discrepancy at the r-th step in poly-form */
|
||||
discr_r = 0;
|
||||
for (i = 0; i < r; i++){
|
||||
if ((lambda[i] != 0) && (s[r - i] != A0)) {
|
||||
discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
|
||||
}
|
||||
}
|
||||
discr_r = Index_of[discr_r]; /* Index form */
|
||||
if (discr_r == A0) {
|
||||
/* 2 lines below: B(x) <-- x*B(x) */
|
||||
COPYDOWN(&b[1],b,NN-KK);
|
||||
b[0] = A0;
|
||||
} else {
|
||||
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for (i = 0 ; i < NN-KK; i++) {
|
||||
if(b[i] != A0)
|
||||
t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
|
||||
else
|
||||
t[i+1] = lambda[i+1];
|
||||
}
|
||||
if (2 * el <= r + no_eras - 1) {
|
||||
el = r + no_eras - el;
|
||||
/*
|
||||
* 2 lines below: B(x) <-- inv(discr_r) *
|
||||
* lambda(x)
|
||||
*/
|
||||
for (i = 0; i <= NN-KK; i++)
|
||||
b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
|
||||
} else {
|
||||
/* 2 lines below: B(x) <-- x*B(x) */
|
||||
COPYDOWN(&b[1],b,NN-KK);
|
||||
b[0] = A0;
|
||||
}
|
||||
COPY(lambda,t,NN-KK+1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert lambda to index form and compute deg(lambda(x)) */
|
||||
deg_lambda = 0;
|
||||
for(i=0;i<NN-KK+1;i++){
|
||||
lambda[i] = Index_of[lambda[i]];
|
||||
if(lambda[i] != A0)
|
||||
deg_lambda = i;
|
||||
}
|
||||
/*
|
||||
* Find roots of the error+erasure locator polynomial by Chien
|
||||
* Search
|
||||
*/
|
||||
COPY(®[1],&lambda[1],NN-KK);
|
||||
count = 0; /* Number of roots of lambda(x) */
|
||||
for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
|
||||
q = 1;
|
||||
for (j = deg_lambda; j > 0; j--){
|
||||
if (reg[j] != A0) {
|
||||
reg[j] = modnn(reg[j] + j);
|
||||
q ^= Alpha_to[reg[j]];
|
||||
}
|
||||
}
|
||||
if (q != 0)
|
||||
continue;
|
||||
/* store root (index-form) and error location number */
|
||||
root[count] = i;
|
||||
loc[count] = k;
|
||||
/* If we've already found max possible roots,
|
||||
* abort the search to save time
|
||||
*/
|
||||
if(++count == deg_lambda)
|
||||
break;
|
||||
}
|
||||
if (deg_lambda != count) {
|
||||
/*
|
||||
* deg(lambda) unequal to number of roots => uncorrectable
|
||||
* error detected
|
||||
*/
|
||||
count = -1;
|
||||
goto finish;
|
||||
}
|
||||
/*
|
||||
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
|
||||
* x**(NN-KK)). in index form. Also find deg(omega).
|
||||
*/
|
||||
deg_omega = 0;
|
||||
for (i = 0; i < NN-KK;i++){
|
||||
tmp = 0;
|
||||
j = (deg_lambda < i) ? deg_lambda : i;
|
||||
for(;j >= 0; j--){
|
||||
if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
|
||||
tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
|
||||
}
|
||||
if(tmp != 0)
|
||||
deg_omega = i;
|
||||
omega[i] = Index_of[tmp];
|
||||
}
|
||||
omega[NN-KK] = A0;
|
||||
|
||||
/*
|
||||
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
|
||||
* inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
|
||||
*/
|
||||
for (j = count-1; j >=0; j--) {
|
||||
num1 = 0;
|
||||
for (i = deg_omega; i >= 0; i--) {
|
||||
if (omega[i] != A0)
|
||||
num1 ^= Alpha_to[modnn(omega[i] + i * root[j])];
|
||||
}
|
||||
num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
|
||||
den = 0;
|
||||
|
||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
||||
for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
|
||||
if(lambda[i+1] != A0)
|
||||
den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
|
||||
}
|
||||
if (den == 0) {
|
||||
#ifdef ECC_DEBUG
|
||||
printf("\n ERROR: denominator = 0\n");
|
||||
#endif
|
||||
/* Convert to dual- basis */
|
||||
count = -1;
|
||||
goto finish;
|
||||
}
|
||||
/* Apply error to data */
|
||||
if (num1 != 0) {
|
||||
eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
|
||||
} else {
|
||||
eras_val[j] = 0;
|
||||
}
|
||||
}
|
||||
finish:
|
||||
for(i=0;i<count;i++)
|
||||
eras_pos[i] = loc[i];
|
||||
return count;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* The DOC specific code begins here */
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
/* The sector bytes are packed into NB_DATA MM bits words */
|
||||
#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
|
||||
|
||||
/*
|
||||
* Correct the errors in 'sector[]' by using 'ecc1[]' which is the
|
||||
* content of the feedback shift register applyied to the sector and
|
||||
* the ECC. Return the number of errors corrected (and correct them in
|
||||
* sector), or -1 if error
|
||||
*/
|
||||
int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
|
||||
{
|
||||
int parity, i, nb_errors;
|
||||
gf bb[NN - KK + 1];
|
||||
gf error_val[NN-KK];
|
||||
int error_pos[NN-KK], pos, bitpos, index, val;
|
||||
dtype *Alpha_to, *Index_of;
|
||||
|
||||
/* init log and exp tables here to save memory. However, it is slower */
|
||||
Alpha_to = malloc((NN + 1) * sizeof(dtype));
|
||||
if (!Alpha_to)
|
||||
return -1;
|
||||
|
||||
Index_of = malloc((NN + 1) * sizeof(dtype));
|
||||
if (!Index_of) {
|
||||
free(Alpha_to);
|
||||
return -1;
|
||||
}
|
||||
|
||||
generate_gf(Alpha_to, Index_of);
|
||||
|
||||
parity = ecc1[1];
|
||||
|
||||
bb[0] = (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
|
||||
bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
|
||||
bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
|
||||
bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
|
||||
|
||||
nb_errors = eras_dec_rs(Alpha_to, Index_of, bb,
|
||||
error_val, error_pos, 0);
|
||||
if (nb_errors <= 0)
|
||||
goto the_end;
|
||||
|
||||
/* correct the errors */
|
||||
for(i=0;i<nb_errors;i++) {
|
||||
pos = error_pos[i];
|
||||
if (pos >= NB_DATA && pos < KK) {
|
||||
nb_errors = -1;
|
||||
goto the_end;
|
||||
}
|
||||
if (pos < NB_DATA) {
|
||||
/* extract bit position (MSB first) */
|
||||
pos = 10 * (NB_DATA - 1 - pos) - 6;
|
||||
/* now correct the following 10 bits. At most two bytes
|
||||
can be modified since pos is even */
|
||||
index = (pos >> 3) ^ 1;
|
||||
bitpos = pos & 7;
|
||||
if ((index >= 0 && index < SECTOR_SIZE) ||
|
||||
index == (SECTOR_SIZE + 1)) {
|
||||
val = error_val[i] >> (2 + bitpos);
|
||||
parity ^= val;
|
||||
if (index < SECTOR_SIZE)
|
||||
sector[index] ^= val;
|
||||
}
|
||||
index = ((pos >> 3) + 1) ^ 1;
|
||||
bitpos = (bitpos + 10) & 7;
|
||||
if (bitpos == 0)
|
||||
bitpos = 8;
|
||||
if ((index >= 0 && index < SECTOR_SIZE) ||
|
||||
index == (SECTOR_SIZE + 1)) {
|
||||
val = error_val[i] << (8 - bitpos);
|
||||
parity ^= val;
|
||||
if (index < SECTOR_SIZE)
|
||||
sector[index] ^= val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* use parity to test extra errors */
|
||||
if ((parity & 0xff) != 0)
|
||||
nb_errors = -1;
|
||||
|
||||
the_end:
|
||||
free(Alpha_to);
|
||||
free(Index_of);
|
||||
return nb_errors;
|
||||
}
|
||||
|
||||
#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <flash.h>
|
||||
|
||||
#if !defined(CFG_NO_FLASH)
|
||||
|
||||
extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Set protection status for monitor sectors
|
||||
*
|
||||
* The monitor is always located in the _first_ Flash bank.
|
||||
* If necessary you have to map the second bank at lower addresses.
|
||||
*/
|
||||
void
|
||||
flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
|
||||
{
|
||||
ulong b_end = info->start[0] + info->size - 1; /* bank end address */
|
||||
short s_end = info->sector_count - 1; /* index of last sector */
|
||||
int i;
|
||||
|
||||
/* Do nothing if input data is bad. */
|
||||
if (info->sector_count == 0 || info->size == 0 || to < from) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* There is nothing to do if we have no data about the flash
|
||||
* or the protect range and flash range don't overlap.
|
||||
*/
|
||||
if (info->flash_id == FLASH_UNKNOWN ||
|
||||
to < info->start[0] || from > b_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0; i<info->sector_count; ++i) {
|
||||
ulong end; /* last address in current sect */
|
||||
|
||||
end = (i == s_end) ? b_end : info->start[i + 1] - 1;
|
||||
|
||||
/* Update protection if any part of the sector
|
||||
* is in the specified range.
|
||||
*/
|
||||
if (from <= end && to >= info->start[i]) {
|
||||
if (flag & FLAG_PROTECT_CLEAR) {
|
||||
#if defined(CFG_FLASH_PROTECTION)
|
||||
flash_real_protect(info, i, 0);
|
||||
#else
|
||||
info->protect[i] = 0;
|
||||
#endif /* CFG_FLASH_PROTECTION */
|
||||
}
|
||||
else if (flag & FLAG_PROTECT_SET) {
|
||||
#if defined(CFG_FLASH_PROTECTION)
|
||||
flash_real_protect(info, i, 1);
|
||||
#else
|
||||
info->protect[i] = 1;
|
||||
#endif /* CFG_FLASH_PROTECTION */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
flash_info_t *
|
||||
addr2info (ulong addr)
|
||||
{
|
||||
#ifndef CONFIG_SPD823TS
|
||||
flash_info_t *info;
|
||||
int i;
|
||||
|
||||
for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {
|
||||
if (info->flash_id != FLASH_UNKNOWN &&
|
||||
addr >= info->start[0] &&
|
||||
/* WARNING - The '- 1' is needed if the flash
|
||||
* is at the end of the address space, since
|
||||
* info->start[0] + info->size wraps back to 0.
|
||||
* Please don't change this unless you understand this.
|
||||
*/
|
||||
addr <= info->start[0] + info->size - 1) {
|
||||
return (info);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SPD823TS */
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Copy memory to flash.
|
||||
* Make sure all target addresses are within Flash bounds,
|
||||
* and no protected sectors are hit.
|
||||
* Returns:
|
||||
* ERR_OK 0 - OK
|
||||
* ERR_TIMOUT 1 - write timeout
|
||||
* ERR_NOT_ERASED 2 - Flash not erased
|
||||
* ERR_PROTECTED 4 - target range includes protected sectors
|
||||
* ERR_INVAL 8 - target address not in Flash memory
|
||||
* ERR_ALIGN 16 - target address not aligned on boundary
|
||||
* (only some targets require alignment)
|
||||
*/
|
||||
int
|
||||
flash_write (uchar *src, ulong addr, ulong cnt)
|
||||
{
|
||||
#ifdef CONFIG_SPD823TS
|
||||
return (ERR_TIMOUT); /* any other error codes are possible as well */
|
||||
#else
|
||||
int i;
|
||||
ulong end = addr + cnt - 1;
|
||||
flash_info_t *info_first = addr2info (addr);
|
||||
flash_info_t *info_last = addr2info (end );
|
||||
flash_info_t *info;
|
||||
|
||||
if (cnt == 0) {
|
||||
return (ERR_OK);
|
||||
}
|
||||
|
||||
if (!info_first || !info_last) {
|
||||
return (ERR_INVAL);
|
||||
}
|
||||
|
||||
for (info = info_first; info <= info_last; ++info) {
|
||||
ulong b_end = info->start[0] + info->size; /* bank end addr */
|
||||
short s_end = info->sector_count - 1;
|
||||
for (i=0; i<info->sector_count; ++i) {
|
||||
ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
|
||||
|
||||
if ((end >= info->start[i]) && (addr < e_addr) &&
|
||||
(info->protect[i] != 0) ) {
|
||||
return (ERR_PROTECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* finally write data to flash */
|
||||
for (info = info_first; info <= info_last && cnt>0; ++info) {
|
||||
ulong len;
|
||||
|
||||
len = info->start[0] + info->size - addr;
|
||||
if (len > cnt)
|
||||
len = cnt;
|
||||
if ((i = write_buff(info, src, addr, len)) != 0) {
|
||||
return (i);
|
||||
}
|
||||
cnt -= len;
|
||||
addr += len;
|
||||
src += len;
|
||||
}
|
||||
return (ERR_OK);
|
||||
#endif /* CONFIG_SPD823TS */
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void flash_perror (int err)
|
||||
{
|
||||
switch (err) {
|
||||
case ERR_OK:
|
||||
break;
|
||||
case ERR_TIMOUT:
|
||||
puts ("Timeout writing to Flash\n");
|
||||
break;
|
||||
case ERR_NOT_ERASED:
|
||||
puts ("Flash not Erased\n");
|
||||
break;
|
||||
case ERR_PROTECTED:
|
||||
puts ("Can't write to protected Flash sectors\n");
|
||||
break;
|
||||
case ERR_INVAL:
|
||||
puts ("Outside available Flash\n");
|
||||
break;
|
||||
case ERR_ALIGN:
|
||||
puts ("Start and/or end address not on sector boundary\n");
|
||||
break;
|
||||
case ERR_UNKNOWN_FLASH_VENDOR:
|
||||
puts ("Unknown Vendor of Flash\n");
|
||||
break;
|
||||
case ERR_UNKNOWN_FLASH_TYPE:
|
||||
puts ("Unknown Type of Flash\n");
|
||||
break;
|
||||
case ERR_PROG_ERROR:
|
||||
puts ("General Flash Programming Error\n");
|
||||
break;
|
||||
default:
|
||||
printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
#endif /* !CFG_NO_FLASH */
|
|
@ -0,0 +1,734 @@
|
|||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <lists.h>
|
||||
|
||||
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
|
||||
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
|
||||
#define CAT4CHARS(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d)
|
||||
|
||||
/* increase list size by 10% every time it is full */
|
||||
#define kDefaultAllocationPercentIncrease 10
|
||||
|
||||
/* always increase list size by 4 items when it is full */
|
||||
#define kDefaultAllocationminNumItemsIncrease 4
|
||||
|
||||
/*
|
||||
* how many items to expand the list by when it becomes full
|
||||
* = current listSize (in items) + (hiword percent of list size) + loword
|
||||
*/
|
||||
#define NUMITEMSPERALLOC(list) MAX(((*list)->listSize * \
|
||||
((*list)->percentIncrease + 100)) / 100, \
|
||||
(*list)->minNumItemsIncrease )
|
||||
|
||||
#define ITEMPTR(list,item) &(((char *)&(*list)->itemList)[(*(list))->itemSize * (item)])
|
||||
|
||||
#define LIST_SIGNATURE CAT4CHARS('L', 'I', 'S', 'T');
|
||||
|
||||
#define calloc(size,num) malloc(size*num)
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Handle NewHandle (unsigned int numBytes)
|
||||
{
|
||||
void *memPtr;
|
||||
HandleRecord *hanPtr;
|
||||
|
||||
memPtr = calloc (numBytes, 1);
|
||||
hanPtr = (HandleRecord *) calloc (sizeof (HandleRecord), 1);
|
||||
if (hanPtr && (memPtr || numBytes == 0)) {
|
||||
hanPtr->ptr = memPtr;
|
||||
hanPtr->size = numBytes;
|
||||
return (Handle) hanPtr;
|
||||
} else {
|
||||
free (memPtr);
|
||||
free (hanPtr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/********************************************************************/
|
||||
|
||||
void DisposeHandle (Handle handle)
|
||||
{
|
||||
if (handle) {
|
||||
free (*handle);
|
||||
free ((void *) handle);
|
||||
}
|
||||
}
|
||||
/********************************************************************/
|
||||
|
||||
unsigned int GetHandleSize (Handle handle)
|
||||
{
|
||||
return ((HandleRecord *) handle)->size;
|
||||
}
|
||||
/********************************************************************/
|
||||
|
||||
int SetHandleSize (Handle handle, unsigned int newSize)
|
||||
{
|
||||
HandleRecord *hanRecPtr = (HandleRecord *) handle;
|
||||
void *newPtr, *oldPtr;
|
||||
unsigned int oldSize;
|
||||
|
||||
|
||||
oldPtr = hanRecPtr->ptr;
|
||||
oldSize = hanRecPtr->size;
|
||||
|
||||
if (oldSize == newSize)
|
||||
return 1;
|
||||
|
||||
if (oldPtr == NULL) {
|
||||
newPtr = malloc (newSize);
|
||||
} else {
|
||||
newPtr = realloc (oldPtr, newSize);
|
||||
}
|
||||
if (newPtr || (newSize == 0)) {
|
||||
hanRecPtr->ptr = newPtr;
|
||||
hanRecPtr->size = newSize;
|
||||
if (newSize > oldSize)
|
||||
memset ((char *) newPtr + oldSize, 0, newSize - oldSize);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CFG_ALL_LIST_FUNCTIONS
|
||||
|
||||
/* Used to compare list elements by their raw data contents */
|
||||
static int ListMemBlockCmp (void *a, void *b, int size)
|
||||
{
|
||||
return memcmp (a, b, size);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/*
|
||||
* Binary search numElements of size elementSize in array for a match
|
||||
* to the. item. Return the index of the element that matches
|
||||
* (0 - numElements - 1). If no match is found return the -i-1 where
|
||||
* i is the index (0 - numElements) where the item should be placed.
|
||||
* (*theCmp)(a,b) should return <0 if a<b, 0 if a==b, >0 if a>b.
|
||||
*
|
||||
* This function is like the C-Library function bsearch() except that
|
||||
* this function returns the index where the item should be placed if
|
||||
* it is not found.
|
||||
*/
|
||||
int BinSearch ( void *array, int numElements, int elementSize,
|
||||
void *itemPtr, CompareFunction compareFunction)
|
||||
{
|
||||
int low, high, mid, cmp;
|
||||
void *arrayItemPtr;
|
||||
|
||||
for (low = 0, high = numElements - 1, mid = 0, cmp = -1; low <= high;) {
|
||||
mid = (low + high) >> 1;
|
||||
|
||||
arrayItemPtr = (void *) (((char *) array) + (mid * elementSize));
|
||||
cmp = compareFunction
|
||||
? compareFunction (itemPtr, arrayItemPtr)
|
||||
: ListMemBlockCmp (itemPtr, arrayItemPtr, elementSize);
|
||||
if (cmp == 0) {
|
||||
return mid;
|
||||
} else if (cmp < 0) {
|
||||
high = mid - 1;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
if (cmp > 0)
|
||||
mid++;
|
||||
|
||||
return -mid - 1;
|
||||
}
|
||||
|
||||
#endif /* CFG_ALL_LIST_FUNCTIONS */
|
||||
|
||||
/*******************************************************************************/
|
||||
|
||||
/*
|
||||
* If numNewItems == 0 then expand the list by the number of items
|
||||
* indicated by its allocation policy.
|
||||
* If numNewItems > 0 then expand the list by exactly the number of
|
||||
* items indicated.
|
||||
* If numNewItems < 0 then expand the list by the absolute value of
|
||||
* numNewItems plus the number of items indicated by its allocation
|
||||
* policy.
|
||||
* Returns 1 for success, 0 if out of memory
|
||||
*/
|
||||
static int ExpandListSpace (list_t list, int numNewItems)
|
||||
{
|
||||
if (numNewItems == 0) {
|
||||
numNewItems = NUMITEMSPERALLOC (list);
|
||||
} else if (numNewItems < 0) {
|
||||
numNewItems = (-numNewItems) + NUMITEMSPERALLOC (list);
|
||||
}
|
||||
|
||||
if (SetHandleSize ((Handle) list,
|
||||
sizeof (ListStruct) +
|
||||
((*list)->listSize +
|
||||
numNewItems) * (*list)->itemSize)) {
|
||||
(*list)->listSize += numNewItems;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
#ifdef CFG_ALL_LIST_FUNCTIONS
|
||||
|
||||
/*
|
||||
* This function reallocate the list, minus any currently unused
|
||||
* portion of its allotted memory.
|
||||
*/
|
||||
void ListCompact (list_t list)
|
||||
{
|
||||
|
||||
if (!SetHandleSize ((Handle) list,
|
||||
sizeof (ListStruct) +
|
||||
(*list)->numItems * (*list)->itemSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*list)->listSize = (*list)->numItems;
|
||||
}
|
||||
|
||||
#endif /* CFG_ALL_LIST_FUNCTIONS */
|
||||
|
||||
/*******************************/
|
||||
|
||||
list_t ListCreate (int elementSize)
|
||||
{
|
||||
list_t list;
|
||||
|
||||
list = (list_t) (NewHandle (sizeof (ListStruct))); /* create empty list */
|
||||
if (list) {
|
||||
(*list)->signature = LIST_SIGNATURE;
|
||||
(*list)->numItems = 0;
|
||||
(*list)->listSize = 0;
|
||||
(*list)->itemSize = elementSize;
|
||||
(*list)->percentIncrease = kDefaultAllocationPercentIncrease;
|
||||
(*list)->minNumItemsIncrease =
|
||||
kDefaultAllocationminNumItemsIncrease;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
void ListSetAllocationPolicy (list_t list, int minItemsPerAlloc,
|
||||
int percentIncreasePerAlloc)
|
||||
{
|
||||
(*list)->percentIncrease = percentIncreasePerAlloc;
|
||||
(*list)->minNumItemsIncrease = minItemsPerAlloc;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
void ListDispose (list_t list)
|
||||
{
|
||||
DisposeHandle ((Handle) list);
|
||||
}
|
||||
/*******************************/
|
||||
|
||||
#ifdef CFG_ALL_LIST_FUNCTIONS
|
||||
|
||||
void ListDisposePtrList (list_t list)
|
||||
{
|
||||
int index;
|
||||
int numItems;
|
||||
|
||||
if (list) {
|
||||
numItems = ListNumItems (list);
|
||||
|
||||
for (index = 1; index <= numItems; index++)
|
||||
free (*(void **) ListGetPtrToItem (list, index));
|
||||
|
||||
ListDispose (list);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* keeps memory, resets the number of items to 0
|
||||
*/
|
||||
void ListClear (list_t list)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
(*list)->numItems = 0;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* copy is only as large as necessary
|
||||
*/
|
||||
list_t ListCopy (list_t originalList)
|
||||
{
|
||||
list_t tempList = NULL;
|
||||
int numItems;
|
||||
|
||||
if (!originalList)
|
||||
return NULL;
|
||||
|
||||
tempList = ListCreate ((*originalList)->itemSize);
|
||||
if (tempList) {
|
||||
numItems = ListNumItems (originalList);
|
||||
|
||||
if (!SetHandleSize ((Handle) tempList,
|
||||
sizeof (ListStruct) +
|
||||
numItems * (*tempList)->itemSize)) {
|
||||
ListDispose (tempList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*tempList)->numItems = (*originalList)->numItems;
|
||||
(*tempList)->listSize = (*originalList)->numItems;
|
||||
(*tempList)->itemSize = (*originalList)->itemSize;
|
||||
(*tempList)->percentIncrease = (*originalList)->percentIncrease;
|
||||
(*tempList)->minNumItemsIncrease =
|
||||
(*originalList)->minNumItemsIncrease;
|
||||
|
||||
memcpy (ITEMPTR (tempList, 0), ITEMPTR (originalList, 0),
|
||||
numItems * (*tempList)->itemSize);
|
||||
}
|
||||
|
||||
return tempList;
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
/*
|
||||
* list1 = list1 + list2
|
||||
*/
|
||||
int ListAppend (list_t list1, list_t list2)
|
||||
{
|
||||
int numItemsL1, numItemsL2;
|
||||
|
||||
if (!list2)
|
||||
return 1;
|
||||
|
||||
if (!list1)
|
||||
return 0;
|
||||
if ((*list1)->itemSize != (*list2)->itemSize)
|
||||
return 0;
|
||||
|
||||
numItemsL1 = ListNumItems (list1);
|
||||
numItemsL2 = ListNumItems (list2);
|
||||
|
||||
if (numItemsL2 == 0)
|
||||
return 1;
|
||||
|
||||
if (!SetHandleSize ((Handle) list1,
|
||||
sizeof (ListStruct) + (numItemsL1 + numItemsL2) *
|
||||
(*list1)->itemSize)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*list1)->numItems = numItemsL1 + numItemsL2;
|
||||
(*list1)->listSize = numItemsL1 + numItemsL2;
|
||||
|
||||
memmove (ITEMPTR (list1, numItemsL1),
|
||||
ITEMPTR (list2, 0),
|
||||
numItemsL2 * (*list2)->itemSize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* CFG_ALL_LIST_FUNCTIONS */
|
||||
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* returns 1 if the item is inserted, returns 0 if out of memory or
|
||||
* bad arguments were passed.
|
||||
*/
|
||||
int ListInsertItem (list_t list, void *ptrToItem, int itemPosition)
|
||||
{
|
||||
return ListInsertItems (list, ptrToItem, itemPosition, 1);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
int ListInsertItems (list_t list, void *ptrToItems, int firstItemPosition,
|
||||
int numItemsToInsert)
|
||||
{
|
||||
int numItems = (*list)->numItems;
|
||||
|
||||
if (firstItemPosition == numItems + 1)
|
||||
firstItemPosition = LIST_END;
|
||||
else if (firstItemPosition > numItems)
|
||||
return 0;
|
||||
|
||||
if ((*list)->numItems >= (*list)->listSize) {
|
||||
if (!ExpandListSpace (list, -numItemsToInsert))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (firstItemPosition == LIST_START) {
|
||||
if (numItems == 0) {
|
||||
/* special case for empty list */
|
||||
firstItemPosition = LIST_END;
|
||||
} else {
|
||||
firstItemPosition = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstItemPosition == LIST_END) { /* add at the end of the list */
|
||||
if (ptrToItems)
|
||||
memcpy (ITEMPTR (list, numItems), ptrToItems,
|
||||
(*list)->itemSize * numItemsToInsert);
|
||||
else
|
||||
memset (ITEMPTR (list, numItems), 0,
|
||||
(*list)->itemSize * numItemsToInsert);
|
||||
|
||||
(*list)->numItems += numItemsToInsert;
|
||||
} else { /* move part of list up to make room for new item */
|
||||
memmove (ITEMPTR (list, firstItemPosition - 1 + numItemsToInsert),
|
||||
ITEMPTR (list, firstItemPosition - 1),
|
||||
(numItems + 1 - firstItemPosition) * (*list)->itemSize);
|
||||
|
||||
if (ptrToItems)
|
||||
memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems,
|
||||
(*list)->itemSize * numItemsToInsert);
|
||||
else
|
||||
memset (ITEMPTR (list, firstItemPosition - 1), 0,
|
||||
(*list)->itemSize * numItemsToInsert);
|
||||
|
||||
(*list)->numItems += numItemsToInsert;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CFG_ALL_LIST_FUNCTIONS
|
||||
|
||||
/*******************************/
|
||||
|
||||
int ListEqual (list_t list1, list_t list2)
|
||||
{
|
||||
if (list1 == list2)
|
||||
return 1;
|
||||
|
||||
if (list1 == NULL || list2 == NULL)
|
||||
return 0;
|
||||
|
||||
if ((*list1)->itemSize == (*list1)->itemSize) {
|
||||
if ((*list1)->numItems == (*list2)->numItems) {
|
||||
return (memcmp (ITEMPTR (list1, 0), ITEMPTR (list2, 0),
|
||||
(*list1)->itemSize * (*list1)->numItems) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* The item pointed to by ptrToItem is copied over the current item
|
||||
* at itemPosition
|
||||
*/
|
||||
void ListReplaceItem (list_t list, void *ptrToItem, int itemPosition)
|
||||
{
|
||||
ListReplaceItems (list, ptrToItem, itemPosition, 1);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* The item pointed to by ptrToItems is copied over the current item
|
||||
* at itemPosition
|
||||
*/
|
||||
void ListReplaceItems ( list_t list, void *ptrToItems,
|
||||
int firstItemPosition, int numItemsToReplace)
|
||||
{
|
||||
|
||||
if (firstItemPosition == LIST_END)
|
||||
firstItemPosition = (*list)->numItems;
|
||||
else if (firstItemPosition == LIST_START)
|
||||
firstItemPosition = 1;
|
||||
|
||||
memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems,
|
||||
(*list)->itemSize * numItemsToReplace);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
void ListGetItem (list_t list, void *itemDestination, int itemPosition)
|
||||
{
|
||||
ListGetItems (list, itemDestination, itemPosition, 1);
|
||||
}
|
||||
|
||||
#endif /* CFG_ALL_LIST_FUNCTIONS */
|
||||
|
||||
/*******************************/
|
||||
|
||||
#if defined(CFG_ALL_LIST_FUNCTIONS) || defined(CFG_DEVICE_DEREGISTER)
|
||||
|
||||
void ListRemoveItem (list_t list, void *itemDestination, int itemPosition)
|
||||
{
|
||||
ListRemoveItems (list, itemDestination, itemPosition, 1);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
void ListRemoveItems (list_t list, void *itemsDestination,
|
||||
int firstItemPosition, int numItemsToRemove)
|
||||
{
|
||||
int firstItemAfterChunk, numToMove;
|
||||
|
||||
if (firstItemPosition == LIST_START)
|
||||
firstItemPosition = 1;
|
||||
else if (firstItemPosition == LIST_END)
|
||||
firstItemPosition = (*list)->numItems;
|
||||
|
||||
if (itemsDestination != NULL)
|
||||
memcpy (itemsDestination, ITEMPTR (list, firstItemPosition - 1),
|
||||
(*list)->itemSize * numItemsToRemove);
|
||||
|
||||
firstItemAfterChunk = firstItemPosition + numItemsToRemove;
|
||||
numToMove = (*list)->numItems - (firstItemAfterChunk - 1);
|
||||
|
||||
if (numToMove > 0) {
|
||||
/*
|
||||
* move part of list down to cover hole left by removed item
|
||||
*/
|
||||
memmove (ITEMPTR (list, firstItemPosition - 1),
|
||||
ITEMPTR (list, firstItemAfterChunk - 1),
|
||||
(*list)->itemSize * numToMove);
|
||||
}
|
||||
|
||||
(*list)->numItems -= numItemsToRemove;
|
||||
}
|
||||
#endif /* CFG_ALL_LIST_FUNCTIONS || CFG_DEVICE_DEREGISTER */
|
||||
|
||||
/*******************************/
|
||||
|
||||
void ListGetItems (list_t list, void *itemsDestination,
|
||||
int firstItemPosition, int numItemsToGet)
|
||||
{
|
||||
|
||||
if (firstItemPosition == LIST_START)
|
||||
firstItemPosition = 1;
|
||||
else if (firstItemPosition == LIST_END)
|
||||
firstItemPosition = (*list)->numItems;
|
||||
|
||||
memcpy (itemsDestination,
|
||||
ITEMPTR (list, firstItemPosition - 1),
|
||||
(*list)->itemSize * numItemsToGet);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* Returns a pointer to the item at itemPosition. returns null if an
|
||||
* errors occurred.
|
||||
*/
|
||||
void *ListGetPtrToItem (list_t list, int itemPosition)
|
||||
{
|
||||
if (itemPosition == LIST_START)
|
||||
itemPosition = 1;
|
||||
else if (itemPosition == LIST_END)
|
||||
itemPosition = (*list)->numItems;
|
||||
|
||||
return ITEMPTR (list, itemPosition - 1);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* returns a pointer the lists data (abstraction violation for
|
||||
* optimization)
|
||||
*/
|
||||
void *ListGetDataPtr (list_t list)
|
||||
{
|
||||
return &((*list)->itemList[0]);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
#ifdef CFG_ALL_LIST_FUNCTIONS
|
||||
|
||||
int ListApplyToEach (list_t list, int ascending,
|
||||
ListApplicationFunc funcToApply,
|
||||
void *callbackData)
|
||||
{
|
||||
int result = 0, index;
|
||||
|
||||
if (!list || !funcToApply)
|
||||
goto Error;
|
||||
|
||||
if (ascending) {
|
||||
for (index = 1; index <= ListNumItems (list); index++) {
|
||||
result = funcToApply (index,
|
||||
ListGetPtrToItem (list, index),
|
||||
callbackData);
|
||||
if (result < 0)
|
||||
goto Error;
|
||||
}
|
||||
} else {
|
||||
for (index = ListNumItems (list);
|
||||
index > 0 && index <= ListNumItems (list);
|
||||
index--) {
|
||||
result = funcToApply (index,
|
||||
ListGetPtrToItem (list, index),
|
||||
callbackData);
|
||||
if (result < 0)
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
|
||||
Error:
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* CFG_ALL_LIST_FUNCTIONS */
|
||||
|
||||
/********************************/
|
||||
|
||||
int ListGetItemSize (list_t list)
|
||||
{
|
||||
return (*list)->itemSize;
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
int ListNumItems (list_t list)
|
||||
{
|
||||
return (*list)->numItems;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
#ifdef CFG_ALL_LIST_FUNCTIONS
|
||||
|
||||
void ListRemoveDuplicates (list_t list, CompareFunction compareFunction)
|
||||
{
|
||||
int numItems, index, startIndexForFind, duplicatesIndex;
|
||||
|
||||
numItems = ListNumItems (list);
|
||||
|
||||
for (index = 1; index < numItems; index++) {
|
||||
startIndexForFind = index + 1;
|
||||
while (startIndexForFind <= numItems) {
|
||||
duplicatesIndex =
|
||||
ListFindItem (list,
|
||||
ListGetPtrToItem (list, index),
|
||||
startIndexForFind,
|
||||
compareFunction);
|
||||
if (duplicatesIndex > 0) {
|
||||
ListRemoveItem (list, NULL, duplicatesIndex);
|
||||
numItems--;
|
||||
startIndexForFind = duplicatesIndex;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
|
||||
/*******************************/
|
||||
|
||||
int ListFindItem (list_t list, void *ptrToItem, int startingPosition,
|
||||
CompareFunction compareFunction)
|
||||
{
|
||||
int numItems, size, index, cmp;
|
||||
void *listItemPtr;
|
||||
|
||||
if ((numItems = (*list)->numItems) == 0)
|
||||
return 0;
|
||||
|
||||
size = (*list)->itemSize;
|
||||
|
||||
if (startingPosition == LIST_START)
|
||||
startingPosition = 1;
|
||||
else if (startingPosition == LIST_END)
|
||||
startingPosition = numItems;
|
||||
|
||||
for (index = startingPosition; index <= numItems; index++) {
|
||||
listItemPtr = ITEMPTR (list, index - 1);
|
||||
cmp = compareFunction
|
||||
? compareFunction (ptrToItem, listItemPtr)
|
||||
: ListMemBlockCmp (ptrToItem, listItemPtr, size);
|
||||
if (cmp == 0)
|
||||
return index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
int ShortCompare (void *a, void *b)
|
||||
{
|
||||
if (*(short *) a < *(short *) b)
|
||||
return -1;
|
||||
if (*(short *) a > *(short *) b)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
int IntCompare (void *a, void *b)
|
||||
{
|
||||
if (*(int *) a < *(int *) b)
|
||||
return -1;
|
||||
if (*(int *) a > *(int *) b)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
int CStringCompare (void *a, void *b)
|
||||
{
|
||||
return strcmp (*(char **) a, *(char **) b);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
|
||||
int ListBinSearch (list_t list, void *ptrToItem,
|
||||
CompareFunction compareFunction)
|
||||
{
|
||||
int index;
|
||||
|
||||
index = BinSearch (ITEMPTR (list, 0),
|
||||
(int) (*list)->numItems,
|
||||
(int) (*list)->itemSize, ptrToItem,
|
||||
compareFunction);
|
||||
|
||||
if (index >= 0)
|
||||
index++; /* lists start from 1 */
|
||||
else
|
||||
index = 0; /* item not found */
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
* Reserves memory for numItems in the list. If it succeeds then
|
||||
* numItems items can be inserted without possibility of an out of
|
||||
* memory error (useful to simplify error recovery in complex
|
||||
* functions). Returns 1 if success, 0 if out of memory.
|
||||
*/
|
||||
int ListPreAllocate (list_t list, int numItems)
|
||||
{
|
||||
if ((*list)->listSize - (*list)->numItems < numItems) {
|
||||
return ExpandListSpace (list,
|
||||
numItems - ((*list)->listSize -
|
||||
(*list)->numItems));
|
||||
} else {
|
||||
return 1; /* enough items are already pre-allocated */
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CFG_ALL_LIST_FUNCTIONS */
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides a bit-banged interface to the ethernet MII management
|
||||
* channel.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ioports.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
|
||||
#ifdef CONFIG_BITBANGMII
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Utility to send the preamble, address, and register (common to read
|
||||
* and write).
|
||||
*/
|
||||
static void miiphy_pre(char read,
|
||||
unsigned char addr,
|
||||
unsigned char reg)
|
||||
{
|
||||
int j; /* counter */
|
||||
volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
|
||||
|
||||
/*
|
||||
* Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
|
||||
* The IEEE spec says this is a PHY optional requirement. The AMD
|
||||
* 79C874 requires one after power up and one after a MII communications
|
||||
* error. This means that we are doing more preambles than we need,
|
||||
* but it is safer and will be much more robust.
|
||||
*/
|
||||
|
||||
MDIO_ACTIVE;
|
||||
MDIO(1);
|
||||
for(j = 0; j < 32; j++)
|
||||
{
|
||||
MDC(0);
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
}
|
||||
|
||||
/* send the start bit (01) and the read opcode (10) or write (10) */
|
||||
MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY;
|
||||
MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY;
|
||||
MDC(0); MDIO(read); MIIDELAY; MDC(1); MIIDELAY;
|
||||
MDC(0); MDIO(!read); MIIDELAY; MDC(1); MIIDELAY;
|
||||
|
||||
/* send the PHY address */
|
||||
for(j = 0; j < 5; j++)
|
||||
{
|
||||
MDC(0);
|
||||
if((addr & 0x10) == 0)
|
||||
{
|
||||
MDIO(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MDIO(1);
|
||||
}
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
addr <<= 1;
|
||||
}
|
||||
|
||||
/* send the register address */
|
||||
for(j = 0; j < 5; j++)
|
||||
{
|
||||
MDC(0);
|
||||
if((reg & 0x10) == 0)
|
||||
{
|
||||
MDIO(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MDIO(1);
|
||||
}
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
reg <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Read a MII PHY register.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
*/
|
||||
int miiphy_read(unsigned char addr,
|
||||
unsigned char reg,
|
||||
unsigned short *value)
|
||||
{
|
||||
short rdreg; /* register working value */
|
||||
int j; /* counter */
|
||||
volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
|
||||
|
||||
miiphy_pre(1, addr, reg);
|
||||
|
||||
/* tri-state our MDIO I/O pin so we can read */
|
||||
MDC(0);
|
||||
MDIO_TRISTATE;
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
|
||||
/* check the turnaround bit: the PHY should be driving it to zero */
|
||||
if(MDIO_READ != 0)
|
||||
{
|
||||
/* printf("PHY didn't drive TA low\n"); */
|
||||
for(j = 0; j < 32; j++)
|
||||
{
|
||||
MDC(0);
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
MDC(0);
|
||||
MIIDELAY;
|
||||
|
||||
/* read 16 bits of register data, MSB first */
|
||||
rdreg = 0;
|
||||
for(j = 0; j < 16; j++)
|
||||
{
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
rdreg <<= 1;
|
||||
rdreg |= MDIO_READ;
|
||||
MDC(0);
|
||||
MIIDELAY;
|
||||
}
|
||||
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
MDC(0);
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
|
||||
*value = rdreg;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Write a MII PHY register.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
*/
|
||||
int miiphy_write(unsigned char addr,
|
||||
unsigned char reg,
|
||||
unsigned short value)
|
||||
{
|
||||
int j; /* counter */
|
||||
volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
|
||||
|
||||
miiphy_pre(0, addr, reg);
|
||||
|
||||
/* send the turnaround (10) */
|
||||
MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY;
|
||||
MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY;
|
||||
|
||||
/* write 16 bits of register data, MSB first */
|
||||
for(j = 0; j < 16; j++)
|
||||
{
|
||||
MDC(0);
|
||||
if((value & 0x00008000) == 0)
|
||||
{
|
||||
MDIO(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MDIO(1);
|
||||
}
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
value <<= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tri-state the MDIO line.
|
||||
*/
|
||||
MDIO_TRISTATE;
|
||||
MDC(0);
|
||||
MIIDELAY;
|
||||
MDC(1);
|
||||
MIIDELAY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BITBANGMII */
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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 <s_record.h>
|
||||
|
||||
static int hex1_bin (char c);
|
||||
static int hex2_bin (char *s);
|
||||
|
||||
int srec_decode (char *input, int *count, ulong *addr, char *data)
|
||||
{
|
||||
int i;
|
||||
int v; /* conversion buffer */
|
||||
int srec_type; /* S-Record type */
|
||||
unsigned char chksum; /* buffer for checksum */
|
||||
|
||||
chksum = 0;
|
||||
|
||||
/* skip anything before 'S', and the 'S' itself.
|
||||
* Return error if not found
|
||||
*/
|
||||
|
||||
for (; *input; ++input) {
|
||||
if (*input == 'S') { /* skip 'S' */
|
||||
++input;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*input == '\0') { /* no more data? */
|
||||
return (SREC_EMPTY);
|
||||
}
|
||||
|
||||
v = *input++; /* record type */
|
||||
|
||||
if ((*count = hex2_bin(input)) < 0) {
|
||||
return (SREC_E_NOSREC);
|
||||
}
|
||||
|
||||
chksum += *count;
|
||||
input += 2;
|
||||
|
||||
switch (v) { /* record type */
|
||||
|
||||
case '0': /* start record */
|
||||
srec_type = SREC_START; /* 2 byte addr field */
|
||||
*count -= 3; /* - checksum and addr */
|
||||
break;
|
||||
case '1':
|
||||
srec_type = SREC_DATA2; /* 2 byte addr field */
|
||||
*count -= 3; /* - checksum and addr */
|
||||
break;
|
||||
case '2':
|
||||
srec_type = SREC_DATA3; /* 3 byte addr field */
|
||||
*count -= 4; /* - checksum and addr */
|
||||
break;
|
||||
case '3': /* data record with a */
|
||||
srec_type = SREC_DATA4; /* 4 byte addr field */
|
||||
*count -= 5; /* - checksum and addr */
|
||||
break;
|
||||
/*** case '4' ***/
|
||||
case '5': /* count record, addr field contains */
|
||||
srec_type = SREC_COUNT; /* a 2 byte record counter */
|
||||
*count = 0; /* no data */
|
||||
break;
|
||||
/*** case '6' -- not used ***/
|
||||
case '7': /* end record with a */
|
||||
srec_type = SREC_END4; /* 4 byte addr field */
|
||||
*count -= 5; /* - checksum and addr */
|
||||
break;
|
||||
case '8': /* end record with a */
|
||||
srec_type = SREC_END3; /* 3 byte addr field */
|
||||
*count -= 4; /* - checksum and addr */
|
||||
break;
|
||||
case '9': /* end record with a */
|
||||
srec_type = SREC_END2; /* 2 byte addr field */
|
||||
*count -= 3; /* - checksum and addr */
|
||||
break;
|
||||
default:
|
||||
return (SREC_E_BADTYPE);
|
||||
}
|
||||
|
||||
/* read address field */
|
||||
*addr = 0;
|
||||
|
||||
switch (v) {
|
||||
case '3': /* 4 byte addr field */
|
||||
case '7':
|
||||
if ((v = hex2_bin(input)) < 0) {
|
||||
return (SREC_E_NOSREC);
|
||||
}
|
||||
*addr += v;
|
||||
chksum += v;
|
||||
input += 2;
|
||||
/* FALL THRU */
|
||||
case '2': /* 3 byte addr field */
|
||||
case '8':
|
||||
if ((v = hex2_bin(input)) < 0) {
|
||||
return (SREC_E_NOSREC);
|
||||
}
|
||||
*addr <<= 8;
|
||||
*addr += v;
|
||||
chksum += v;
|
||||
input += 2;
|
||||
/* FALL THRU */
|
||||
case '0': /* 2 byte addr field */
|
||||
case '1':
|
||||
case '5':
|
||||
case '9':
|
||||
if ((v = hex2_bin(input)) < 0) {
|
||||
return (SREC_E_NOSREC);
|
||||
}
|
||||
*addr <<= 8;
|
||||
*addr += v;
|
||||
chksum += v;
|
||||
input += 2;
|
||||
|
||||
if ((v = hex2_bin(input)) < 0) {
|
||||
return (SREC_E_NOSREC);
|
||||
}
|
||||
*addr <<= 8;
|
||||
*addr += v;
|
||||
chksum += v;
|
||||
input += 2;
|
||||
|
||||
break;
|
||||
default:
|
||||
return (SREC_E_BADTYPE);
|
||||
}
|
||||
|
||||
/* convert data and calculate checksum */
|
||||
for (i=0; i < *count; ++i) {
|
||||
if ((v = hex2_bin(input)) < 0) {
|
||||
return (SREC_E_NOSREC);
|
||||
}
|
||||
data[i] = v;
|
||||
chksum += v;
|
||||
input += 2;
|
||||
}
|
||||
|
||||
/* read anc check checksum */
|
||||
if ((v = hex2_bin(input)) < 0) {
|
||||
return (SREC_E_NOSREC);
|
||||
}
|
||||
|
||||
if ((unsigned char)v != (unsigned char)~chksum) {
|
||||
return (SREC_E_BADCHKS);
|
||||
}
|
||||
|
||||
return (srec_type);
|
||||
}
|
||||
|
||||
static int hex1_bin (char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return (c - '0');
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return (c + 10 - 'a');
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return (c + 10 - 'A');
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int hex2_bin (char *s)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if ((i = hex1_bin(*s++)) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
if ((j = hex1_bin(*s)) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return ((i<<4) + j);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,734 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Denis Peter, MPL AG Switzerland
|
||||
*
|
||||
* Part of this source has been derived from the Linux USB
|
||||
* project.
|
||||
*
|
||||
* 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 <devices.h>
|
||||
|
||||
#ifdef CONFIG_USB_KEYBOARD
|
||||
|
||||
#include <usb.h>
|
||||
|
||||
#undef USB_KBD_DEBUG
|
||||
/*
|
||||
* if overwrite_console returns 1, the stdin, stderr and stdout
|
||||
* are switched to the serial port, else the settings in the
|
||||
* environment are used
|
||||
*/
|
||||
#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
|
||||
extern int overwrite_console (void);
|
||||
#else
|
||||
int overwrite_console (void)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USB_KBD_DEBUG
|
||||
#define USB_KBD_PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define USB_KBD_PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
|
||||
#define REPEAT_RATE 40/4 /* 40msec -> 25cps */
|
||||
#define REPEAT_DELAY 10 /* 10 x REAPEAT_RATE = 400msec */
|
||||
|
||||
#define NUM_LOCK 0x53
|
||||
#define CAPS_LOCK 0x39
|
||||
#define SCROLL_LOCK 0x47
|
||||
|
||||
|
||||
/* Modifier bits */
|
||||
#define LEFT_CNTR 0
|
||||
#define LEFT_SHIFT 1
|
||||
#define LEFT_ALT 2
|
||||
#define LEFT_GUI 3
|
||||
#define RIGHT_CNTR 4
|
||||
#define RIGHT_SHIFT 5
|
||||
#define RIGHT_ALT 6
|
||||
#define RIGHT_GUI 7
|
||||
|
||||
#define USB_KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
|
||||
|
||||
static volatile char usb_kbd_buffer[USB_KBD_BUFFER_LEN];
|
||||
static volatile int usb_in_pointer = 0;
|
||||
static volatile int usb_out_pointer = 0;
|
||||
|
||||
unsigned char new[8];
|
||||
unsigned char old[8];
|
||||
int repeat_delay;
|
||||
#define DEVNAME "usbkbd"
|
||||
static unsigned char num_lock = 0;
|
||||
static unsigned char caps_lock = 0;
|
||||
static unsigned char scroll_lock = 0;
|
||||
|
||||
static unsigned char leds __attribute__ ((aligned (0x4)));
|
||||
|
||||
static unsigned char usb_kbd_numkey[] = {
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0','\r',0x1b,'\b','\t',' ', '-',
|
||||
'=', '[', ']','\\', '#', ';', '\'', '`', ',', '.', '/'
|
||||
};
|
||||
static unsigned char usb_kbd_numkey_shifted[] = {
|
||||
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')','\r',0x1b,'\b','\t',' ', '_',
|
||||
'+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'
|
||||
};
|
||||
|
||||
/******************************************************************
|
||||
* Queue handling
|
||||
******************************************************************/
|
||||
/* puts character in the queue and sets up the in and out pointer */
|
||||
static void usb_kbd_put_queue(char data)
|
||||
{
|
||||
if((usb_in_pointer+1)==USB_KBD_BUFFER_LEN) {
|
||||
if(usb_out_pointer==0) {
|
||||
return; /* buffer full */
|
||||
} else{
|
||||
usb_in_pointer=0;
|
||||
}
|
||||
} else {
|
||||
if((usb_in_pointer+1)==usb_out_pointer)
|
||||
return; /* buffer full */
|
||||
usb_in_pointer++;
|
||||
}
|
||||
usb_kbd_buffer[usb_in_pointer]=data;
|
||||
return;
|
||||
}
|
||||
|
||||
/* test if a character is in the queue */
|
||||
static int usb_kbd_testc(void)
|
||||
{
|
||||
if(usb_in_pointer==usb_out_pointer)
|
||||
return(0); /* no data */
|
||||
else
|
||||
return(1);
|
||||
}
|
||||
/* gets the character from the queue */
|
||||
static int usb_kbd_getc(void)
|
||||
{
|
||||
char c;
|
||||
while(usb_in_pointer==usb_out_pointer);
|
||||
if((usb_out_pointer+1)==USB_KBD_BUFFER_LEN)
|
||||
usb_out_pointer=0;
|
||||
else
|
||||
usb_out_pointer++;
|
||||
c=usb_kbd_buffer[usb_out_pointer];
|
||||
return (int)c;
|
||||
|
||||
}
|
||||
|
||||
/* forward decleration */
|
||||
static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
|
||||
|
||||
/* search for keyboard and register it if found */
|
||||
int drv_usb_kbd_init(void)
|
||||
{
|
||||
int error,i,index;
|
||||
device_t usb_kbd_dev,*old_dev;
|
||||
struct usb_device *dev;
|
||||
char *stdinname = getenv ("stdin");
|
||||
|
||||
usb_in_pointer=0;
|
||||
usb_out_pointer=0;
|
||||
/* scan all USB Devices */
|
||||
for(i=0;i<USB_MAX_DEVICE;i++) {
|
||||
dev=usb_get_dev_index(i); /* get device */
|
||||
if(dev->devnum!=-1) {
|
||||
if(usb_kbd_probe(dev,0)==1) { /* Ok, we found a keyboard */
|
||||
/* check, if it is already registered */
|
||||
USB_KBD_PRINTF("USB KBD found set up device.\n");
|
||||
for (index=1; index<=ListNumItems(devlist); index++) {
|
||||
old_dev = ListGetPtrToItem(devlist, index);
|
||||
if(strcmp(old_dev->name,DEVNAME)==0) {
|
||||
/* ok, already registered, just return ok */
|
||||
USB_KBD_PRINTF("USB KBD is already registered.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* register the keyboard */
|
||||
USB_KBD_PRINTF("USB KBD register.\n");
|
||||
memset (&usb_kbd_dev, 0, sizeof(device_t));
|
||||
strcpy(usb_kbd_dev.name, DEVNAME);
|
||||
usb_kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
|
||||
usb_kbd_dev.putc = NULL;
|
||||
usb_kbd_dev.puts = NULL;
|
||||
usb_kbd_dev.getc = usb_kbd_getc;
|
||||
usb_kbd_dev.tstc = usb_kbd_testc;
|
||||
error = device_register (&usb_kbd_dev);
|
||||
if(error==0) {
|
||||
/* check if this is the standard input device */
|
||||
if(strcmp(stdinname,DEVNAME)==0) {
|
||||
/* reassign the console */
|
||||
if(overwrite_console()) {
|
||||
return 1;
|
||||
}
|
||||
error=console_assign(stdin,DEVNAME);
|
||||
if(error==0)
|
||||
return 1;
|
||||
else
|
||||
return error;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no USB Keyboard found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* deregistering the keyboard */
|
||||
int usb_kbd_deregister(void)
|
||||
{
|
||||
return device_deregister(DEVNAME);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Low Level drivers
|
||||
*/
|
||||
|
||||
/* set the LEDs. Since this is used in the irq routine, the control job
|
||||
is issued with a timeout of 0. This means, that the job is queued without
|
||||
waiting for job completion */
|
||||
|
||||
static void usb_kbd_setled(struct usb_device *dev)
|
||||
{
|
||||
struct usb_interface_descriptor *iface;
|
||||
iface = &dev->config.if_desc[0];
|
||||
leds=0;
|
||||
if(scroll_lock!=0)
|
||||
leds|=1;
|
||||
leds<<=1;
|
||||
if(caps_lock!=0)
|
||||
leds|=1;
|
||||
leds<<=1;
|
||||
if(num_lock!=0)
|
||||
leds|=1;
|
||||
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0x200, iface->bInterfaceNumber,(void *)&leds, 1, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#define CAPITAL_MASK 0x20
|
||||
/* Translate the scancode in ASCII */
|
||||
static int usb_kbd_translate(unsigned char scancode,unsigned char modifier,int pressed)
|
||||
{
|
||||
unsigned char keycode;
|
||||
|
||||
if(pressed==0) {
|
||||
/* key released */
|
||||
repeat_delay=0;
|
||||
return 0;
|
||||
}
|
||||
if(pressed==2) {
|
||||
repeat_delay++;
|
||||
if(repeat_delay<REPEAT_DELAY)
|
||||
return 0;
|
||||
repeat_delay=REPEAT_DELAY;
|
||||
}
|
||||
keycode=0;
|
||||
if((scancode>3) && (scancode<0x1d)) { /* alpha numeric values */
|
||||
keycode=scancode-4 + 0x61;
|
||||
if(caps_lock)
|
||||
keycode&=~CAPITAL_MASK; /* switch to capital Letters */
|
||||
if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) {
|
||||
if(keycode & CAPITAL_MASK)
|
||||
keycode&=~CAPITAL_MASK; /* switch to capital Letters */
|
||||
else
|
||||
keycode|=CAPITAL_MASK; /* switch to non capital Letters */
|
||||
}
|
||||
}
|
||||
if((scancode>0x1d) && (scancode<0x3A)) {
|
||||
if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) /* shifted */
|
||||
keycode=usb_kbd_numkey_shifted[scancode-0x1e];
|
||||
else /* non shifted */
|
||||
keycode=usb_kbd_numkey[scancode-0x1e];
|
||||
}
|
||||
if(pressed==1) {
|
||||
if(scancode==NUM_LOCK) {
|
||||
num_lock=~num_lock;
|
||||
return 1;
|
||||
}
|
||||
if(scancode==CAPS_LOCK) {
|
||||
caps_lock=~caps_lock;
|
||||
return 1;
|
||||
}
|
||||
if(scancode==SCROLL_LOCK) {
|
||||
scroll_lock=~scroll_lock;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(keycode!=0) {
|
||||
USB_KBD_PRINTF("%c",keycode);
|
||||
usb_kbd_put_queue(keycode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Interrupt service routine */
|
||||
static int usb_kbd_irq(struct usb_device *dev)
|
||||
{
|
||||
int i,res;
|
||||
|
||||
if((dev->irq_status!=0)||(dev->irq_act_len!=8))
|
||||
{
|
||||
USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",dev->irq_status,dev->irq_act_len);
|
||||
return 1;
|
||||
}
|
||||
res=0;
|
||||
for (i = 2; i < 8; i++) {
|
||||
if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8]) {
|
||||
res|=usb_kbd_translate(old[i],new[0],0);
|
||||
}
|
||||
if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8]) {
|
||||
res|=usb_kbd_translate(new[i],new[0],1);
|
||||
}
|
||||
}
|
||||
if((new[2]>3) && (old[2]==new[2])) /* still pressed */
|
||||
res|=usb_kbd_translate(new[2],new[0],2);
|
||||
if(res==1)
|
||||
usb_kbd_setled(dev);
|
||||
memcpy(&old[0],&new[0], 8);
|
||||
return 1; /* install IRQ Handler again */
|
||||
}
|
||||
|
||||
/* probes the USB device dev for keyboard type */
|
||||
static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
|
||||
{
|
||||
struct usb_interface_descriptor *iface;
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
int pipe,maxp;
|
||||
|
||||
if (dev->descriptor.bNumConfigurations != 1) return 0;
|
||||
iface = &dev->config.if_desc[ifnum];
|
||||
|
||||
if (iface->bInterfaceClass != 3) return 0;
|
||||
if (iface->bInterfaceSubClass != 1) return 0;
|
||||
if (iface->bInterfaceProtocol != 1) return 0;
|
||||
if (iface->bNumEndpoints != 1) return 0;
|
||||
|
||||
ep = &iface->ep_desc[0];
|
||||
|
||||
if (!(ep->bEndpointAddress & 0x80)) return 0;
|
||||
if ((ep->bmAttributes & 3) != 3) return 0;
|
||||
USB_KBD_PRINTF("USB KBD found set protocol...\n");
|
||||
/* ok, we found a USB Keyboard, install it */
|
||||
/* usb_kbd_get_hid_desc(dev); */
|
||||
usb_set_protocol(dev, iface->bInterfaceNumber, 0);
|
||||
USB_KBD_PRINTF("USB KBD found set idle...\n");
|
||||
usb_set_idle(dev, iface->bInterfaceNumber, REPEAT_RATE, 0);
|
||||
memset(&new[0], 0, 8);
|
||||
memset(&old[0], 0, 8);
|
||||
repeat_delay=0;
|
||||
pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
|
||||
maxp = usb_maxpacket(dev, pipe);
|
||||
dev->irq_handle=usb_kbd_irq;
|
||||
USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n");
|
||||
usb_submit_int_msg(dev,pipe,&new[0], maxp > 8 ? 8 : maxp,ep->bInterval);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
struct usb_hid_descriptor {
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType; /* 0x21 for HID */
|
||||
unsigned short bcdHID; /* release number */
|
||||
unsigned char bCountryCode;
|
||||
unsigned char bNumDescriptors;
|
||||
unsigned char bReportDescriptorType;
|
||||
unsigned short wDescriptorLength;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* We parse each description item into this structure. Short items data
|
||||
* values are expanded to 32-bit signed int, long items contain a pointer
|
||||
* into the data area.
|
||||
*/
|
||||
|
||||
struct hid_item {
|
||||
unsigned char format;
|
||||
unsigned char size;
|
||||
unsigned char type;
|
||||
unsigned char tag;
|
||||
union {
|
||||
unsigned char u8;
|
||||
char s8;
|
||||
unsigned short u16;
|
||||
short s16;
|
||||
unsigned long u32;
|
||||
long s32;
|
||||
unsigned char *longdata;
|
||||
} data;
|
||||
};
|
||||
|
||||
/*
|
||||
* HID report item format
|
||||
*/
|
||||
|
||||
#define HID_ITEM_FORMAT_SHORT 0
|
||||
#define HID_ITEM_FORMAT_LONG 1
|
||||
|
||||
/*
|
||||
* Special tag indicating long items
|
||||
*/
|
||||
|
||||
#define HID_ITEM_TAG_LONG 15
|
||||
|
||||
|
||||
|
||||
static struct usb_hid_descriptor usb_kbd_hid_desc;
|
||||
|
||||
void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
|
||||
{
|
||||
printf("USB_HID_DESC:\n");
|
||||
printf(" bLenght 0x%x\n",hid->bLength);
|
||||
printf(" bcdHID 0x%x\n",hid->bcdHID);
|
||||
printf(" bCountryCode %d\n",hid->bCountryCode);
|
||||
printf(" bNumDescriptors 0x%x\n",hid->bNumDescriptors);
|
||||
printf(" bReportDescriptorType 0x%x\n",hid->bReportDescriptorType);
|
||||
printf(" wDescriptorLength 0x%x\n",hid->wDescriptorLength);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fetch a report description item from the data stream. We support long
|
||||
* items, though they are not used yet.
|
||||
*/
|
||||
|
||||
static int fetch_item(unsigned char *start,unsigned char *end, struct hid_item *item)
|
||||
{
|
||||
if((end - start) > 0) {
|
||||
unsigned char b = *start++;
|
||||
item->type = (b >> 2) & 3;
|
||||
item->tag = (b >> 4) & 15;
|
||||
if (item->tag == HID_ITEM_TAG_LONG) {
|
||||
item->format = HID_ITEM_FORMAT_LONG;
|
||||
if ((end - start) >= 2) {
|
||||
item->size = *start++;
|
||||
item->tag = *start++;
|
||||
if ((end - start) >= item->size) {
|
||||
item->data.longdata = start;
|
||||
start += item->size;
|
||||
return item->size;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item->format = HID_ITEM_FORMAT_SHORT;
|
||||
item->size = b & 3;
|
||||
switch (item->size) {
|
||||
case 0:
|
||||
return item->size;
|
||||
case 1:
|
||||
if ((end - start) >= 1) {
|
||||
item->data.u8 = *start++;
|
||||
return item->size;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ((end - start) >= 2) {
|
||||
item->data.u16 = swap_16((unsigned short *)start);
|
||||
start+=2;
|
||||
return item->size;
|
||||
}
|
||||
case 3:
|
||||
item->size++;
|
||||
if ((end - start) >= 4) {
|
||||
item->data.u32 = swap_32((unsigned long *)start);
|
||||
start+=4;
|
||||
return item->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* HID report descriptor item type (prefix bit 2,3)
|
||||
*/
|
||||
|
||||
#define HID_ITEM_TYPE_MAIN 0
|
||||
#define HID_ITEM_TYPE_GLOBAL 1
|
||||
#define HID_ITEM_TYPE_LOCAL 2
|
||||
#define HID_ITEM_TYPE_RESERVED 3
|
||||
/*
|
||||
* HID report descriptor main item tags
|
||||
*/
|
||||
|
||||
#define HID_MAIN_ITEM_TAG_INPUT 8
|
||||
#define HID_MAIN_ITEM_TAG_OUTPUT 9
|
||||
#define HID_MAIN_ITEM_TAG_FEATURE 11
|
||||
#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10
|
||||
#define HID_MAIN_ITEM_TAG_END_COLLECTION 12
|
||||
/*
|
||||
* HID report descriptor main item contents
|
||||
*/
|
||||
|
||||
#define HID_MAIN_ITEM_CONSTANT 0x001
|
||||
#define HID_MAIN_ITEM_VARIABLE 0x002
|
||||
#define HID_MAIN_ITEM_RELATIVE 0x004
|
||||
#define HID_MAIN_ITEM_WRAP 0x008
|
||||
#define HID_MAIN_ITEM_NONLINEAR 0x010
|
||||
#define HID_MAIN_ITEM_NO_PREFERRED 0x020
|
||||
#define HID_MAIN_ITEM_NULL_STATE 0x040
|
||||
#define HID_MAIN_ITEM_VOLATILE 0x080
|
||||
#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100
|
||||
|
||||
/*
|
||||
* HID report descriptor collection item types
|
||||
*/
|
||||
|
||||
#define HID_COLLECTION_PHYSICAL 0
|
||||
#define HID_COLLECTION_APPLICATION 1
|
||||
#define HID_COLLECTION_LOGICAL 2
|
||||
/*
|
||||
* HID report descriptor global item tags
|
||||
*/
|
||||
|
||||
#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0
|
||||
#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1
|
||||
#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2
|
||||
#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3
|
||||
#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4
|
||||
#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5
|
||||
#define HID_GLOBAL_ITEM_TAG_UNIT 6
|
||||
#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7
|
||||
#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8
|
||||
#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9
|
||||
#define HID_GLOBAL_ITEM_TAG_PUSH 10
|
||||
#define HID_GLOBAL_ITEM_TAG_POP 11
|
||||
|
||||
/*
|
||||
* HID report descriptor local item tags
|
||||
*/
|
||||
|
||||
#define HID_LOCAL_ITEM_TAG_USAGE 0
|
||||
#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1
|
||||
#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2
|
||||
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3
|
||||
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4
|
||||
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5
|
||||
#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7
|
||||
#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8
|
||||
#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9
|
||||
#define HID_LOCAL_ITEM_TAG_DELIMITER 10
|
||||
|
||||
|
||||
|
||||
static void usb_kbd_show_item(struct hid_item *item)
|
||||
{
|
||||
switch(item->type) {
|
||||
case HID_ITEM_TYPE_MAIN:
|
||||
switch(item->tag) {
|
||||
case HID_MAIN_ITEM_TAG_INPUT:
|
||||
printf("Main Input");
|
||||
break;
|
||||
case HID_MAIN_ITEM_TAG_OUTPUT:
|
||||
printf("Main Output");
|
||||
break;
|
||||
case HID_MAIN_ITEM_TAG_FEATURE:
|
||||
printf("Main Feature");
|
||||
break;
|
||||
case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
|
||||
printf("Main Begin Collection");
|
||||
break;
|
||||
case HID_MAIN_ITEM_TAG_END_COLLECTION:
|
||||
printf("Main End Collection");
|
||||
break;
|
||||
default:
|
||||
printf("Main reserved %d",item->tag);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HID_ITEM_TYPE_GLOBAL:
|
||||
switch(item->tag) {
|
||||
case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
|
||||
printf("- Global Usage Page");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
|
||||
printf("- Global Logical Minimum");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
|
||||
printf("- Global Logical Maximum");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
|
||||
printf("- Global physical Minimum");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
|
||||
printf("- Global physical Maximum");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
|
||||
printf("- Global Unit Exponent");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_UNIT:
|
||||
printf("- Global Unit");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
|
||||
printf("- Global Report Size");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_REPORT_ID:
|
||||
printf("- Global Report ID");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
|
||||
printf("- Global Report Count");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_PUSH:
|
||||
printf("- Global Push");
|
||||
break;
|
||||
case HID_GLOBAL_ITEM_TAG_POP:
|
||||
printf("- Global Pop");
|
||||
break;
|
||||
default:
|
||||
printf("- Global reserved %d",item->tag);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HID_ITEM_TYPE_LOCAL:
|
||||
switch(item->tag) {
|
||||
case HID_LOCAL_ITEM_TAG_USAGE:
|
||||
printf("-- Local Usage");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
|
||||
printf("-- Local Usage Minimum");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
|
||||
printf("-- Local Usage Maximum");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX:
|
||||
printf("-- Local Designator Index");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM:
|
||||
printf("-- Local Designator Minimum");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM:
|
||||
printf("-- Local Designator Maximum");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_STRING_INDEX:
|
||||
printf("-- Local String Index");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_STRING_MINIMUM:
|
||||
printf("-- Local String Minimum");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM:
|
||||
printf("-- Local String Maximum");
|
||||
break;
|
||||
case HID_LOCAL_ITEM_TAG_DELIMITER:
|
||||
printf("-- Local Delimiter");
|
||||
break;
|
||||
default:
|
||||
printf("-- Local reserved %d",item->tag);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("--- reserved %d",item->type);
|
||||
break;
|
||||
}
|
||||
switch(item->size) {
|
||||
case 1:
|
||||
printf(" %d",item->data.u8);
|
||||
break;
|
||||
case 2:
|
||||
printf(" %d",item->data.u16);
|
||||
break;
|
||||
case 4:
|
||||
printf(" %ld",item->data.u32);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int usb_kbd_get_hid_desc(struct usb_device *dev)
|
||||
{
|
||||
unsigned char buffer[256];
|
||||
struct usb_descriptor_header *head;
|
||||
struct usb_config_descriptor *config;
|
||||
int index,len,i;
|
||||
unsigned char *start, *end;
|
||||
struct hid_item item;
|
||||
|
||||
if(usb_get_configuration_no(dev,&buffer[0],0)==-1)
|
||||
return -1;
|
||||
head =(struct usb_descriptor_header *)&buffer[0];
|
||||
if(head->bDescriptorType!=USB_DT_CONFIG) {
|
||||
printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
|
||||
return -1;
|
||||
}
|
||||
index=head->bLength;
|
||||
config=(struct usb_config_descriptor *)&buffer[0];
|
||||
len=swap_16(config->wTotalLength);
|
||||
/* Ok the first entry must be a configuration entry, now process the others */
|
||||
head=(struct usb_descriptor_header *)&buffer[index];
|
||||
while(index+1 < len) {
|
||||
if(head->bDescriptorType==USB_DT_HID) {
|
||||
printf("HID desc found\n");
|
||||
memcpy(&usb_kbd_hid_desc,&buffer[index],buffer[index]);
|
||||
usb_kbd_hid_desc.bcdHID=swap_16(usb_kbd_hid_desc.bcdHID);
|
||||
usb_kbd_hid_desc.wDescriptorLength=swap_16(usb_kbd_hid_desc.wDescriptorLength);
|
||||
usb_kbd_display_hid(&usb_kbd_hid_desc);
|
||||
len=0;
|
||||
break;
|
||||
}
|
||||
index+=head->bLength;
|
||||
head=(struct usb_descriptor_header *)&buffer[index];
|
||||
}
|
||||
if(len>0)
|
||||
return -1;
|
||||
len=usb_kbd_hid_desc.wDescriptorLength;
|
||||
if((index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], len)) < 0) {
|
||||
printf("reading report descriptor failed\n");
|
||||
return -1;
|
||||
}
|
||||
printf(" report descriptor (size %u, read %d)\n", len, index);
|
||||
start=&buffer[0];
|
||||
end=&buffer[len];
|
||||
i=0;
|
||||
do {
|
||||
index=fetch_item(start,end,&item);
|
||||
i+=index;
|
||||
i++;
|
||||
if(index>=0)
|
||||
usb_kbd_show_item(&item);
|
||||
|
||||
start+=index;
|
||||
start++;
|
||||
} while(index>=0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_KEYBOARD */
|
||||
|
||||
/* eof */
|
||||
|
|
@ -0,0 +1,895 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Denis Peter, MPL AG Switzerland
|
||||
*
|
||||
* Most of this source has been derived from the Linux USB
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Note:
|
||||
* Currently only the CBI transport protocoll has been implemented, and it
|
||||
* is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
|
||||
* transport protocoll may work as well.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_USB)
|
||||
#include <usb.h>
|
||||
|
||||
#ifdef CONFIG_USB_STORAGE
|
||||
|
||||
#undef USB_STOR_DEBUG
|
||||
|
||||
#ifdef USB_STOR_DEBUG
|
||||
#define USB_STOR_PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define USB_STOR_PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
#include <scsi.h>
|
||||
/* direction table -- this indicates the direction of the data
|
||||
* transfer for each command code -- a 1 indicates input
|
||||
*/
|
||||
unsigned char us_direction[256/8] = {
|
||||
0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
|
||||
0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
|
||||
|
||||
static unsigned char usb_stor_buf[512];
|
||||
static ccb usb_ccb;
|
||||
|
||||
/*
|
||||
* CBI style
|
||||
*/
|
||||
|
||||
#define US_CBI_ADSC 0
|
||||
|
||||
|
||||
#define USB_MAX_STOR_DEV 5
|
||||
static int usb_max_devs; /* number of highest available usb device */
|
||||
|
||||
static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
|
||||
|
||||
struct us_data;
|
||||
typedef int (*trans_cmnd)(ccb*, struct us_data*);
|
||||
typedef int (*trans_reset)(struct us_data*);
|
||||
|
||||
struct us_data {
|
||||
struct usb_device *pusb_dev; /* this usb_device */
|
||||
unsigned int flags; /* from filter initially */
|
||||
unsigned char ifnum; /* interface number */
|
||||
unsigned char ep_in; /* in endpoint */
|
||||
unsigned char ep_out; /* out ....... */
|
||||
unsigned char ep_int; /* interrupt . */
|
||||
unsigned char subclass; /* as in overview */
|
||||
unsigned char protocol; /* .............. */
|
||||
unsigned char attention_done; /* force attn on first cmd */
|
||||
unsigned short ip_data; /* interrupt data */
|
||||
int action; /* what to do */
|
||||
int ip_wanted; /* needed */
|
||||
int *irq_handle; /* for USB int requests */
|
||||
unsigned int irqpipe; /* pipe for release_irq */
|
||||
unsigned char irqmaxp; /* max packed for irq Pipe */
|
||||
unsigned char irqinterval; /* Intervall for IRQ Pipe */
|
||||
ccb *srb; /* current srb */
|
||||
trans_reset transport_reset; /* reset routine */
|
||||
trans_cmnd transport; /* transport routine */
|
||||
};
|
||||
|
||||
static struct us_data usb_stor[USB_MAX_STOR_DEV];
|
||||
|
||||
|
||||
|
||||
#define USB_STOR_TRANSPORT_GOOD 0
|
||||
#define USB_STOR_TRANSPORT_FAILED -1
|
||||
#define USB_STOR_TRANSPORT_ERROR -2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int usb_stor_get_info(struct usb_device *dev, struct us_data *us, block_dev_desc_t *dev_desc);
|
||||
int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss);
|
||||
unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, unsigned long *buffer);
|
||||
struct usb_device * usb_get_dev_index(int index);
|
||||
void uhci_show_temp_int_td(void);
|
||||
|
||||
block_dev_desc_t *usb_stor_get_dev(int index)
|
||||
{
|
||||
return &usb_dev_desc[index];
|
||||
}
|
||||
|
||||
|
||||
void usb_show_progress(void)
|
||||
{
|
||||
printf(".");
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* (re)-scan the usb and reports device info
|
||||
* to the user if mode = 1
|
||||
* returns current device or -1 if no
|
||||
*/
|
||||
int usb_stor_scan(int mode)
|
||||
{
|
||||
unsigned char i;
|
||||
struct usb_device *dev;
|
||||
|
||||
if(mode==1) {
|
||||
printf("scanning bus for storage devices...\n");
|
||||
}
|
||||
usb_disable_asynch(1); /* asynch transfer not allowed */
|
||||
|
||||
for(i=0;i<USB_MAX_STOR_DEV;i++) {
|
||||
memset(&usb_dev_desc[i],0,sizeof(block_dev_desc_t));
|
||||
usb_dev_desc[i].target=0xff;
|
||||
usb_dev_desc[i].if_type=IF_TYPE_USB;
|
||||
usb_dev_desc[i].dev=i;
|
||||
usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
|
||||
usb_dev_desc[i].block_read=usb_stor_read;
|
||||
}
|
||||
usb_max_devs=0;
|
||||
for(i=0;i<USB_MAX_DEVICE;i++) {
|
||||
dev=usb_get_dev_index(i); /* get device */
|
||||
USB_STOR_PRINTF("i=%d\n",i);
|
||||
if(dev==NULL) {
|
||||
break; /* no more devices avaiable */
|
||||
}
|
||||
if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */
|
||||
/* get info and fill it in */
|
||||
|
||||
if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) {
|
||||
if(mode==1) {
|
||||
printf (" Device %d: ", usb_max_devs);
|
||||
dev_print(&usb_dev_desc[usb_max_devs]);
|
||||
} /* if mode */
|
||||
usb_max_devs++;
|
||||
} /* if get info ok */
|
||||
} /* if storage device */
|
||||
if(usb_max_devs==USB_MAX_STOR_DEV) {
|
||||
printf("max USB Storage Device reached: %d stopping\n",usb_max_devs);
|
||||
break;
|
||||
}
|
||||
} /* for */
|
||||
usb_disable_asynch(0); /* asynch transfer allowed */
|
||||
if(usb_max_devs>0)
|
||||
return 0;
|
||||
else
|
||||
return-1;
|
||||
}
|
||||
|
||||
static int usb_stor_irq(struct usb_device *dev)
|
||||
{
|
||||
struct us_data *us;
|
||||
us=(struct us_data *)dev->privptr;
|
||||
|
||||
if(us->ip_wanted) {
|
||||
us->ip_wanted=0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USB_STOR_DEBUG
|
||||
|
||||
static void usb_show_srb(ccb * pccb)
|
||||
{
|
||||
int i;
|
||||
printf("SRB: len %d datalen 0x%lX\n ",pccb->cmdlen,pccb->datalen);
|
||||
for(i=0;i<12;i++) {
|
||||
printf("%02X ",pccb->cmd[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void display_int_status(unsigned long tmp)
|
||||
{
|
||||
printf("Status: %s %s %s %s %s %s %s\n",
|
||||
(tmp & USB_ST_ACTIVE) ? "Active" : "",
|
||||
(tmp & USB_ST_STALLED) ? "Stalled" : "",
|
||||
(tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
|
||||
(tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
|
||||
(tmp & USB_ST_NAK_REC) ? "NAKed" : "",
|
||||
(tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
|
||||
(tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
|
||||
}
|
||||
#endif
|
||||
/***********************************************************************
|
||||
* Data transfer routines
|
||||
***********************************************************************/
|
||||
|
||||
static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
|
||||
{
|
||||
int max_size;
|
||||
int this_xfer;
|
||||
int result;
|
||||
int partial;
|
||||
int maxtry;
|
||||
int stat;
|
||||
|
||||
/* determine the maximum packet size for these transfers */
|
||||
max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
|
||||
|
||||
/* while we have data left to transfer */
|
||||
while (length) {
|
||||
|
||||
/* calculate how long this will be -- maximum or a remainder */
|
||||
this_xfer = length > max_size ? max_size : length;
|
||||
length -= this_xfer;
|
||||
|
||||
/* setup the retry counter */
|
||||
maxtry = 10;
|
||||
|
||||
/* set up the transfer loop */
|
||||
do {
|
||||
/* transfer the data */
|
||||
USB_STOR_PRINTF("Bulk xfer 0x%x(%d) try #%d\n",
|
||||
(unsigned int)buf, this_xfer, 11 - maxtry);
|
||||
result = usb_bulk_msg(us->pusb_dev, pipe, buf,
|
||||
this_xfer, &partial, USB_CNTL_TIMEOUT*5);
|
||||
USB_STOR_PRINTF("bulk_msg returned %d xferred %d/%d\n",
|
||||
result, partial, this_xfer);
|
||||
if(us->pusb_dev->status!=0) {
|
||||
/* if we stall, we need to clear it before we go on */
|
||||
#ifdef USB_STOR_DEBUG
|
||||
display_int_status(us->pusb_dev->status);
|
||||
#endif
|
||||
if (us->pusb_dev->status & USB_ST_STALLED) {
|
||||
USB_STOR_PRINTF("stalled ->clearing endpoint halt for pipe 0x%x\n", pipe);
|
||||
stat = us->pusb_dev->status;
|
||||
usb_clear_halt(us->pusb_dev, pipe);
|
||||
us->pusb_dev->status=stat;
|
||||
if(this_xfer == partial) {
|
||||
USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n",us->pusb_dev->status);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return result;
|
||||
}
|
||||
if (us->pusb_dev->status & USB_ST_NAK_REC) {
|
||||
USB_STOR_PRINTF("Device NAKed bulk_msg\n");
|
||||
return result;
|
||||
}
|
||||
if(this_xfer == partial) {
|
||||
USB_STOR_PRINTF("bulk transferred with error %d, but data ok\n",us->pusb_dev->status);
|
||||
return 0;
|
||||
}
|
||||
/* if our try counter reaches 0, bail out */
|
||||
USB_STOR_PRINTF("bulk transferred with error %d, data %d\n",us->pusb_dev->status,partial);
|
||||
if (!maxtry--)
|
||||
return result;
|
||||
}
|
||||
/* update to show what data was transferred */
|
||||
this_xfer -= partial;
|
||||
buf += partial;
|
||||
/* continue until this transfer is done */
|
||||
} while ( this_xfer );
|
||||
}
|
||||
|
||||
/* if we get here, we're done and successful */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: this reset function doesn't really reset the port, and it
|
||||
* should. Actually it should probably do what it's doing here, and
|
||||
* reset the port physically
|
||||
*/
|
||||
static int usb_stor_CB_reset(struct us_data *us)
|
||||
{
|
||||
unsigned char cmd[12];
|
||||
int result;
|
||||
|
||||
USB_STOR_PRINTF("CB_reset\n");
|
||||
memset(cmd, 0xFF, sizeof(cmd));
|
||||
cmd[0] = SCSI_SEND_DIAG;
|
||||
cmd[1] = 4;
|
||||
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
|
||||
US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0, us->ifnum, cmd, sizeof(cmd), USB_CNTL_TIMEOUT*5);
|
||||
|
||||
/* long wait for reset */
|
||||
wait_ms(1500);
|
||||
USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status);
|
||||
usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
|
||||
usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
|
||||
|
||||
USB_STOR_PRINTF("CB_reset done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: we also need a CBI_command which sets up the completion
|
||||
* interrupt, and waits for it
|
||||
*/
|
||||
int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
|
||||
{
|
||||
int result;
|
||||
int dir_in,retry;
|
||||
unsigned int pipe;
|
||||
unsigned long status;
|
||||
|
||||
retry=5;
|
||||
dir_in=US_DIRECTION(srb->cmd[0]);
|
||||
|
||||
if(dir_in)
|
||||
pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
|
||||
else
|
||||
pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out);
|
||||
while(retry--) {
|
||||
USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry);
|
||||
#ifdef USB_STOR_DEBUG
|
||||
usb_show_srb(srb);
|
||||
#endif
|
||||
/* let's send the command via the control pipe */
|
||||
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
|
||||
US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0, us->ifnum,
|
||||
srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5);
|
||||
USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status);
|
||||
/* check the return code for the command */
|
||||
if (result < 0) {
|
||||
if(us->pusb_dev->status & USB_ST_STALLED) {
|
||||
status=us->pusb_dev->status;
|
||||
USB_STOR_PRINTF(" stall during command found, clear pipe\n");
|
||||
usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0));
|
||||
us->pusb_dev->status=status;
|
||||
}
|
||||
USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status);
|
||||
return result;
|
||||
}
|
||||
/* transfer the data payload for this command, if one exists*/
|
||||
|
||||
USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen);
|
||||
if (srb->datalen) {
|
||||
result = us_one_transfer(us, pipe, srb->pdata,srb->datalen);
|
||||
USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len);
|
||||
if(!(us->pusb_dev->status & USB_ST_NAK_REC))
|
||||
break;
|
||||
} /* if (srb->datalen) */
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* return result */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
us->ip_wanted=1;
|
||||
submit_int_msg(us->pusb_dev,us->irqpipe,
|
||||
(void *)&us->ip_data,us->irqmaxp ,us->irqinterval);
|
||||
timeout=1000;
|
||||
while(timeout--) {
|
||||
if((volatile int *)us->ip_wanted==0)
|
||||
break;
|
||||
wait_ms(10);
|
||||
}
|
||||
if (us->ip_wanted) {
|
||||
printf(" Did not get interrupt on CBI\n");
|
||||
us->ip_wanted = 0;
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
USB_STOR_PRINTF("Got interrupt data 0x%x, transfered %d status 0x%lX\n", us->ip_data,us->pusb_dev->irq_act_len,us->pusb_dev->irq_status);
|
||||
/* UFI gives us ASC and ASCQ, like a request sense */
|
||||
if (us->subclass == US_SC_UFI) {
|
||||
if (srb->cmd[0] == SCSI_REQ_SENSE ||
|
||||
srb->cmd[0] == SCSI_INQUIRY)
|
||||
return USB_STOR_TRANSPORT_GOOD; /* Good */
|
||||
else
|
||||
if (us->ip_data)
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
else
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
/* otherwise, we interpret the data normally */
|
||||
switch (us->ip_data) {
|
||||
case 0x0001:
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
case 0x0002:
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
default:
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
} /* switch */
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
#define USB_TRANSPORT_UNKNOWN_RETRY 5
|
||||
#define USB_TRANSPORT_NOT_READY_RETRY 10
|
||||
|
||||
int usb_stor_CB_transport(ccb *srb, struct us_data *us)
|
||||
{
|
||||
int result,status;
|
||||
ccb *psrb;
|
||||
ccb reqsrb;
|
||||
int retry,notready;
|
||||
|
||||
psrb=&reqsrb;
|
||||
status=USB_STOR_TRANSPORT_GOOD;
|
||||
retry=0;
|
||||
notready=0;
|
||||
/* issue the command */
|
||||
do_retry:
|
||||
result=usb_stor_CB_comdat(srb,us);
|
||||
USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status);
|
||||
/* if this is an CBI Protocol, get IRQ */
|
||||
if(us->protocol==US_PR_CBI) {
|
||||
status=usb_stor_CBI_get_status(srb,us);
|
||||
/* if the status is error, report it */
|
||||
if(status==USB_STOR_TRANSPORT_ERROR) {
|
||||
USB_STOR_PRINTF(" USB CBI Command Error\n");
|
||||
return status;
|
||||
}
|
||||
srb->sense_buf[12]=(unsigned char)(us->ip_data>>8);
|
||||
srb->sense_buf[13]=(unsigned char)(us->ip_data&0xff);
|
||||
if(!us->ip_data) {
|
||||
/* if the status is good, report it */
|
||||
if(status==USB_STOR_TRANSPORT_GOOD) {
|
||||
USB_STOR_PRINTF(" USB CBI Command Good\n");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* do we have to issue an auto request? */
|
||||
/* HERE we have to check the result */
|
||||
if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
|
||||
USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status);
|
||||
us->transport_reset(us);
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
if((us->protocol==US_PR_CBI) &&
|
||||
((srb->cmd[0]==SCSI_REQ_SENSE) ||
|
||||
(srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */
|
||||
USB_STOR_PRINTF("No auto request and good\n");
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
/* issue an request_sense */
|
||||
memset(&psrb->cmd[0],0,12);
|
||||
psrb->cmd[0]=SCSI_REQ_SENSE;
|
||||
psrb->cmd[1]=srb->lun<<5;
|
||||
psrb->cmd[4]=18;
|
||||
psrb->datalen=18;
|
||||
psrb->pdata=&srb->sense_buf[0];
|
||||
psrb->cmdlen=12;
|
||||
/* issue the command */
|
||||
result=usb_stor_CB_comdat(psrb,us);
|
||||
USB_STOR_PRINTF("auto request returned %d\n",result);
|
||||
/* if this is an CBI Protocol, get IRQ */
|
||||
if(us->protocol==US_PR_CBI) {
|
||||
status=usb_stor_CBI_get_status(psrb,us);
|
||||
}
|
||||
if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) {
|
||||
USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status);
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
|
||||
/* Check the auto request result */
|
||||
if((srb->sense_buf[2]==0) &&
|
||||
(srb->sense_buf[12]==0) &&
|
||||
(srb->sense_buf[13]==0)) /* ok, no sense */
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
/* Check the auto request result */
|
||||
switch(srb->sense_buf[2]) {
|
||||
case 0x01: /* Recovered Error */
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
break;
|
||||
case 0x02: /* Not Ready */
|
||||
if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
|
||||
printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n",
|
||||
srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
else {
|
||||
wait_ms(100);
|
||||
goto do_retry;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
|
||||
printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
|
||||
srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
else
|
||||
goto do_retry;
|
||||
break;
|
||||
}
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int usb_inquiry(ccb *srb,struct us_data *ss)
|
||||
{
|
||||
int retry,i;
|
||||
retry=3;
|
||||
do {
|
||||
memset(&srb->cmd[0],0,12);
|
||||
srb->cmd[0]=SCSI_INQUIRY;
|
||||
srb->cmd[1]=srb->lun<<5;
|
||||
srb->cmd[4]=36;
|
||||
srb->datalen=36;
|
||||
srb->cmdlen=12;
|
||||
i=ss->transport(srb,ss);
|
||||
USB_STOR_PRINTF("inquiry returns %d\n",i);
|
||||
if(i==0)
|
||||
break;
|
||||
}while(retry--);
|
||||
if(!retry) {
|
||||
printf("error in inquiry\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_request_sense(ccb *srb,struct us_data *ss)
|
||||
{
|
||||
char *ptr;
|
||||
return 0;
|
||||
ptr=srb->pdata;
|
||||
memset(&srb->cmd[0],0,12);
|
||||
srb->cmd[0]=SCSI_REQ_SENSE;
|
||||
srb->cmd[1]=srb->lun<<5;
|
||||
srb->cmd[4]=18;
|
||||
srb->datalen=18;
|
||||
srb->pdata=&srb->sense_buf[0];
|
||||
srb->cmdlen=12;
|
||||
ss->transport(srb,ss);
|
||||
USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
|
||||
srb->pdata=ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_test_unit_ready(ccb *srb,struct us_data *ss)
|
||||
{
|
||||
int retries=10;
|
||||
do {
|
||||
memset(&srb->cmd[0],0,12);
|
||||
srb->cmd[0]=SCSI_TST_U_RDY;
|
||||
srb->cmd[1]=srb->lun<<5;
|
||||
srb->datalen=0;
|
||||
srb->cmdlen=12;
|
||||
if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} while(retries--);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int usb_read_capacity(ccb *srb,struct us_data *ss)
|
||||
{
|
||||
int retry;
|
||||
retry=2; /* retries */
|
||||
do {
|
||||
memset(&srb->cmd[0],0,12);
|
||||
srb->cmd[0]=SCSI_RD_CAPAC;
|
||||
srb->cmd[1]=srb->lun<<5;
|
||||
srb->datalen=8;
|
||||
srb->cmdlen=12;
|
||||
if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) {
|
||||
return 0;
|
||||
}
|
||||
}while(retry--);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int usb_read_10(ccb *srb,struct us_data *ss, unsigned long start, unsigned short blocks)
|
||||
{
|
||||
memset(&srb->cmd[0],0,12);
|
||||
srb->cmd[0]=SCSI_READ10;
|
||||
srb->cmd[1]=srb->lun<<5;
|
||||
srb->cmd[2]=((unsigned char) (start>>24))&0xff;
|
||||
srb->cmd[3]=((unsigned char) (start>>16))&0xff;
|
||||
srb->cmd[4]=((unsigned char) (start>>8))&0xff;
|
||||
srb->cmd[5]=((unsigned char) (start))&0xff;
|
||||
srb->cmd[7]=((unsigned char) (blocks>>8))&0xff;
|
||||
srb->cmd[8]=(unsigned char) blocks & 0xff;
|
||||
srb->cmdlen=12;
|
||||
USB_STOR_PRINTF("read10: start %lx blocks %x\n",start,blocks);
|
||||
return ss->transport(srb,ss);
|
||||
}
|
||||
|
||||
|
||||
#define USB_MAX_READ_BLK 20
|
||||
|
||||
unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, unsigned long *buffer)
|
||||
{
|
||||
unsigned long start,blks, buf_addr;
|
||||
unsigned short smallblks;
|
||||
struct usb_device *dev;
|
||||
int retry,i;
|
||||
ccb *srb=&usb_ccb;
|
||||
device&=0xff;
|
||||
/* Setup device
|
||||
*/
|
||||
USB_STOR_PRINTF("\nusb_read: dev %d \n",device);
|
||||
dev=NULL;
|
||||
for(i=0;i<USB_MAX_DEVICE;i++) {
|
||||
dev=usb_get_dev_index(i);
|
||||
if(dev==NULL) {
|
||||
return 0;
|
||||
}
|
||||
if(dev->devnum==usb_dev_desc[device].target)
|
||||
break;
|
||||
}
|
||||
|
||||
usb_disable_asynch(1); /* asynch transfer not allowed */
|
||||
srb->lun=usb_dev_desc[device].lun;
|
||||
buf_addr=(unsigned long)buffer;
|
||||
start=blknr;
|
||||
blks=blkcnt;
|
||||
if(usb_test_unit_ready(srb,(struct us_data *)dev->privptr)) {
|
||||
printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",
|
||||
srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
|
||||
return 0;
|
||||
}
|
||||
USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks, buf_addr);
|
||||
do {
|
||||
retry=2;
|
||||
srb->pdata=(unsigned char *)buf_addr;
|
||||
if(blks>USB_MAX_READ_BLK) {
|
||||
smallblks=USB_MAX_READ_BLK;
|
||||
}
|
||||
else {
|
||||
smallblks=(unsigned short) blks;
|
||||
}
|
||||
retry_it:
|
||||
if(smallblks==USB_MAX_READ_BLK)
|
||||
usb_show_progress();
|
||||
srb->datalen=usb_dev_desc[device].blksz * smallblks;
|
||||
srb->pdata=(unsigned char *)buf_addr;
|
||||
if(usb_read_10(srb,(struct us_data *)dev->privptr, start, smallblks)) {
|
||||
USB_STOR_PRINTF("Read ERROR\n");
|
||||
usb_request_sense(srb,(struct us_data *)dev->privptr);
|
||||
if(retry--)
|
||||
goto retry_it;
|
||||
blkcnt-=blks;
|
||||
break;
|
||||
}
|
||||
start+=smallblks;
|
||||
blks-=smallblks;
|
||||
buf_addr+=srb->datalen;
|
||||
} while(blks!=0);
|
||||
USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
|
||||
usb_disable_asynch(0); /* asynch transfer allowed */
|
||||
if(blkcnt>=USB_MAX_READ_BLK)
|
||||
printf("\n");
|
||||
return(blkcnt);
|
||||
}
|
||||
|
||||
|
||||
/* Probe to see if a new device is actually a Storage device */
|
||||
int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss)
|
||||
{
|
||||
struct usb_interface_descriptor *iface;
|
||||
int i;
|
||||
unsigned int flags = 0;
|
||||
|
||||
int protocol = 0;
|
||||
int subclass = 0;
|
||||
|
||||
|
||||
memset(ss, 0, sizeof(struct us_data));
|
||||
|
||||
/* let's examine the device now */
|
||||
iface = &dev->config.if_desc[ifnum];
|
||||
|
||||
#if 0
|
||||
/* this is the place to patch some storage devices */
|
||||
USB_STOR_PRINTF("iVendor %X iProduct %X\n",dev->descriptor.idVendor,dev->descriptor.idProduct);
|
||||
if ((dev->descriptor.idVendor) == 0x066b && (dev->descriptor.idProduct) == 0x0103) {
|
||||
USB_STOR_PRINTF("patched for E-USB\n");
|
||||
protocol = US_PR_CB;
|
||||
subclass = US_SC_UFI; /* an assumption */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev->descriptor.bDeviceClass != 0 ||
|
||||
iface->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
|
||||
iface->bInterfaceSubClass < US_SC_MIN ||
|
||||
iface->bInterfaceSubClass > US_SC_MAX) {
|
||||
/* if it's not a mass storage, we go no further */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* At this point, we know we've got a live one */
|
||||
USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n");
|
||||
|
||||
/* Initialize the us_data structure with some useful info */
|
||||
ss->flags = flags;
|
||||
ss->ifnum = ifnum;
|
||||
ss->pusb_dev = dev;
|
||||
ss->attention_done = 0;
|
||||
|
||||
/* If the device has subclass and protocol, then use that. Otherwise,
|
||||
* take data from the specific interface.
|
||||
*/
|
||||
if (subclass) {
|
||||
ss->subclass = subclass;
|
||||
ss->protocol = protocol;
|
||||
} else {
|
||||
ss->subclass = iface->bInterfaceSubClass;
|
||||
ss->protocol = iface->bInterfaceProtocol;
|
||||
}
|
||||
|
||||
/* set the handler pointers based on the protocol */
|
||||
USB_STOR_PRINTF("Transport: ");
|
||||
switch (ss->protocol) {
|
||||
case US_PR_CB:
|
||||
USB_STOR_PRINTF("Control/Bulk\n");
|
||||
ss->transport = usb_stor_CB_transport;
|
||||
ss->transport_reset = usb_stor_CB_reset;
|
||||
break;
|
||||
|
||||
case US_PR_CBI:
|
||||
USB_STOR_PRINTF("Control/Bulk/Interrupt\n");
|
||||
ss->transport = usb_stor_CB_transport;
|
||||
ss->transport_reset = usb_stor_CB_reset;
|
||||
break;
|
||||
default:
|
||||
printf("USB Starage Transport unknown / not yet implemented\n");
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are expecting a minimum of 2 endpoints - in and out (bulk).
|
||||
* An optional interrupt is OK (necessary for CBI protocol).
|
||||
* We will ignore any others.
|
||||
*/
|
||||
for (i = 0; i < iface->bNumEndpoints; i++) {
|
||||
/* is it an BULK endpoint? */
|
||||
if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
== USB_ENDPOINT_XFER_BULK) {
|
||||
if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
|
||||
ss->ep_in = iface->ep_desc[i].bEndpointAddress &
|
||||
USB_ENDPOINT_NUMBER_MASK;
|
||||
else
|
||||
ss->ep_out = iface->ep_desc[i].bEndpointAddress &
|
||||
USB_ENDPOINT_NUMBER_MASK;
|
||||
}
|
||||
|
||||
/* is it an interrupt endpoint? */
|
||||
if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
== USB_ENDPOINT_XFER_INT) {
|
||||
ss->ep_int = iface->ep_desc[i].bEndpointAddress &
|
||||
USB_ENDPOINT_NUMBER_MASK;
|
||||
ss->irqinterval = iface->ep_desc[i].bInterval;
|
||||
}
|
||||
}
|
||||
USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n",
|
||||
ss->ep_in, ss->ep_out, ss->ep_int);
|
||||
|
||||
/* Do some basic sanity checks, and bail if we find a problem */
|
||||
if (usb_set_interface(dev, iface->bInterfaceNumber, 0) ||
|
||||
!ss->ep_in || !ss->ep_out ||
|
||||
(ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
|
||||
USB_STOR_PRINTF("Problems with device\n");
|
||||
return 0;
|
||||
}
|
||||
/* set class specific stuff */
|
||||
/* We only handle certain protocols. Currently, this is
|
||||
* the only one.
|
||||
*/
|
||||
if (ss->subclass != US_SC_UFI) {
|
||||
printf("Sorry, protocol %d not yet supported.\n",ss->subclass);
|
||||
return 0;
|
||||
}
|
||||
if(ss->ep_int) /* we had found an interrupt endpoint, prepare irq pipe */
|
||||
{
|
||||
/* set up the IRQ pipe and handler */
|
||||
|
||||
ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
|
||||
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
|
||||
ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
|
||||
dev->irq_handle=usb_stor_irq;
|
||||
dev->privptr=(void *)ss;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t *dev_desc)
|
||||
{
|
||||
unsigned char perq,modi;
|
||||
unsigned long cap[2];
|
||||
unsigned long *capacity,*blksz;
|
||||
ccb *pccb=&usb_ccb;
|
||||
|
||||
ss->transport_reset(ss);
|
||||
pccb->pdata=usb_stor_buf;
|
||||
|
||||
dev_desc->target=dev->devnum;
|
||||
pccb->lun=dev_desc->lun;
|
||||
USB_STOR_PRINTF(" address %d\n",dev_desc->target);
|
||||
|
||||
if(usb_inquiry(pccb,ss))
|
||||
return -1;
|
||||
perq=usb_stor_buf[0];
|
||||
modi=usb_stor_buf[1];
|
||||
if((perq & 0x1f)==0x1f) {
|
||||
return 0; /* skip unknown devices */
|
||||
}
|
||||
if((modi&0x80)==0x80) {/* drive is removable */
|
||||
dev_desc->removable=1;
|
||||
}
|
||||
memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8);
|
||||
memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16);
|
||||
memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4);
|
||||
dev_desc->vendor[8]=0;
|
||||
dev_desc->product[16]=0;
|
||||
dev_desc->revision[4]=0;
|
||||
USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]);
|
||||
if(usb_test_unit_ready(pccb,ss)) {
|
||||
printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]);
|
||||
if(dev_desc->removable==1) {
|
||||
dev_desc->type=perq;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
pccb->pdata=(unsigned char *)&cap[0];
|
||||
memset(pccb->pdata,0,8);
|
||||
if(usb_read_capacity(pccb,ss)!=0) {
|
||||
printf("READ_CAP ERROR\n");
|
||||
cap[0]=2880;
|
||||
cap[1]=0x200;
|
||||
}
|
||||
USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]);
|
||||
#if 0
|
||||
if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */
|
||||
cap[0]>>=16;
|
||||
#endif
|
||||
cap[0]+=1;
|
||||
capacity=&cap[0];
|
||||
blksz=&cap[1];
|
||||
USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz);
|
||||
dev_desc->lba=*capacity;
|
||||
dev_desc->blksz=*blksz;
|
||||
dev_desc->type=perq;
|
||||
USB_STOR_PRINTF(" address %d\n",dev_desc->target);
|
||||
USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
|
||||
|
||||
init_part(dev_desc);
|
||||
|
||||
USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_USB_STORAGE */
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* linux/arch/ppc/kernel/traps.c
|
||||
*
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Modified by Cort Dougan (cort@cs.nmt.edu)
|
||||
* and Paul Mackerras (paulus@cs.anu.edu.au)
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of hardware exceptions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
int (*debugger_exception_handler)(struct pt_regs *) = 0;
|
||||
#endif
|
||||
|
||||
/* Returns 0 if exception not found and fixup otherwise. */
|
||||
extern unsigned long search_exception_table(unsigned long);
|
||||
|
||||
/* THIS NEEDS CHANGING to use the board info structure.
|
||||
*/
|
||||
#define END_OF_MEM 0x02000000
|
||||
|
||||
/*
|
||||
* Trap & Exception support
|
||||
*/
|
||||
|
||||
void
|
||||
print_backtrace(unsigned long *sp)
|
||||
{
|
||||
int cnt = 0;
|
||||
unsigned long i;
|
||||
|
||||
printf("Call backtrace: ");
|
||||
while (sp) {
|
||||
if ((uint)sp > END_OF_MEM)
|
||||
break;
|
||||
|
||||
i = sp[1];
|
||||
if (cnt++ % 7 == 0)
|
||||
printf("\n");
|
||||
printf("%08lX ", i);
|
||||
if (cnt > 32) break;
|
||||
sp = (unsigned long *)*sp;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
show_regs(struct pt_regs * regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
|
||||
" %p TRAP: %04lx DAR: %08lX\n",
|
||||
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
|
||||
printf("MSR: %08lx EE: %01x PR: %01x FP:"
|
||||
" %01x ME: %01x IR/DR: %01x%01x\n",
|
||||
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
|
||||
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
|
||||
regs->msr&MSR_IR ? 1 : 0,
|
||||
regs->msr&MSR_DR ? 1 : 0);
|
||||
|
||||
printf("\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((i % 8) == 0)
|
||||
{
|
||||
printf("GPR%02d: ", i);
|
||||
}
|
||||
|
||||
printf("%08lX ", regs->gpr[i]);
|
||||
if ((i % 8) == 7)
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_exception(int signr, struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
|
||||
}
|
||||
|
||||
void
|
||||
MachineCheckException(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fixup;
|
||||
|
||||
/* Probing PCI using config cycles cause this exception
|
||||
* when a device is not present. Catch it and return to
|
||||
* the PCI exception handler.
|
||||
*/
|
||||
if ((fixup = search_exception_table(regs->nip)) != 0) {
|
||||
regs->nip = fixup;
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("Machine check in kernel mode.\n");
|
||||
printf("Caused by (from msr): ");
|
||||
printf("regs %p ",regs);
|
||||
switch( regs->msr & 0x0000F000)
|
||||
{
|
||||
case (1<<12) :
|
||||
printf("Machine check signal - probably due to mm fault\n"
|
||||
"with mmu off\n");
|
||||
break;
|
||||
case (1<<13) :
|
||||
printf("Transfer error ack signal\n");
|
||||
break;
|
||||
case (1<<14) :
|
||||
printf("Data parity signal\n");
|
||||
break;
|
||||
case (1<<15) :
|
||||
printf("Address parity signal\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown values in msr\n");
|
||||
}
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("machine check");
|
||||
}
|
||||
|
||||
void
|
||||
AlignmentException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Alignment Exception");
|
||||
}
|
||||
|
||||
void
|
||||
ProgramCheckException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Program Check Exception");
|
||||
}
|
||||
|
||||
void
|
||||
SoftEmuException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Software Emulation Exception");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UnknownException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
|
||||
regs->nip, regs->msr, regs->trap);
|
||||
_exception(0, regs);
|
||||
}
|
||||
|
||||
/* Probe an address by reading. If not present, return -1, otherwise
|
||||
* return 0.
|
||||
*/
|
||||
int
|
||||
addr_probe(uint *addr)
|
||||
{
|
||||
#if 0
|
||||
int retval;
|
||||
|
||||
__asm__ __volatile__( \
|
||||
"1: lwz %0,0(%1)\n" \
|
||||
" eieio\n" \
|
||||
" li %0,0\n" \
|
||||
"2:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: li %0,-1\n" \
|
||||
" b 2b\n" \
|
||||
".section __ex_table,\"a\"\n" \
|
||||
" .align 2\n" \
|
||||
" .long 1b,3b\n" \
|
||||
".text" \
|
||||
: "=r" (retval) : "r"(addr));
|
||||
|
||||
return (retval);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,513 @@
|
|||
/**************************************************
|
||||
*
|
||||
* copyright @ motorola, 1999
|
||||
*
|
||||
*************************************************/
|
||||
#include <mpc824x.h>
|
||||
#include <common.h>
|
||||
#include "epic.h"
|
||||
|
||||
|
||||
#define PRINT(format, args...) printf(format , ## args)
|
||||
|
||||
typedef void (*VOIDFUNCPTR) (void); /* ptr to function returning void */
|
||||
struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */
|
||||
{
|
||||
{ EPIC_EX_INT0_VEC_REG, "External Direct/Serial Source 0"},
|
||||
{ EPIC_EX_INT1_VEC_REG, "External Direct/Serial Source 1"},
|
||||
{ EPIC_EX_INT2_VEC_REG, "External Direct/Serial Source 2"},
|
||||
{ EPIC_EX_INT3_VEC_REG, "External Direct/Serial Source 3"},
|
||||
{ EPIC_EX_INT4_VEC_REG, "External Direct/Serial Source 4"},
|
||||
|
||||
{ EPIC_SR_INT5_VEC_REG, "External Serial Source 5"},
|
||||
{ EPIC_SR_INT6_VEC_REG, "External Serial Source 6"},
|
||||
{ EPIC_SR_INT7_VEC_REG, "External Serial Source 7"},
|
||||
{ EPIC_SR_INT8_VEC_REG, "External Serial Source 8"},
|
||||
{ EPIC_SR_INT9_VEC_REG, "External Serial Source 9"},
|
||||
{ EPIC_SR_INT10_VEC_REG, "External Serial Source 10"},
|
||||
{ EPIC_SR_INT11_VEC_REG, "External Serial Source 11"},
|
||||
{ EPIC_SR_INT12_VEC_REG, "External Serial Source 12"},
|
||||
{ EPIC_SR_INT13_VEC_REG, "External Serial Source 13"},
|
||||
{ EPIC_SR_INT14_VEC_REG, "External Serial Source 14"},
|
||||
{ EPIC_SR_INT15_VEC_REG, "External Serial Source 15"},
|
||||
|
||||
{ EPIC_I2C_INT_VEC_REG, "Internal I2C Source"},
|
||||
{ EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"},
|
||||
{ EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"},
|
||||
{ EPIC_MSG_INT_VEC_REG, "Internal Message Source"},
|
||||
};
|
||||
|
||||
VOIDFUNCPTR intVecTbl[MAXVEC]; /* Interrupt vector table */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* epicInit - Initialize the EPIC registers
|
||||
*
|
||||
* This routine resets the Global Configuration Register, thus it:
|
||||
* - Disables all interrupts
|
||||
* - Sets epic registers to reset values
|
||||
* - Sets the value of the Processor Current Task Priority to the
|
||||
* highest priority (0xF).
|
||||
* epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass
|
||||
* Through or 8259 compatible mode).
|
||||
*
|
||||
* If IRQType (input) is Direct IRQs:
|
||||
* - IRQType is written to the SIE bit of the EPIC Interrupt
|
||||
* Configuration register (ICR).
|
||||
* - clkRatio is ignored.
|
||||
* If IRQType is Serial IRQs:
|
||||
* - both IRQType and clkRatio will be written to the ICR register
|
||||
*/
|
||||
|
||||
void epicInit
|
||||
(
|
||||
unsigned int IRQType, /* Direct or Serial */
|
||||
unsigned int clkRatio /* Clk Ratio for Serial IRQs */
|
||||
)
|
||||
{
|
||||
ULONG tmp;
|
||||
|
||||
tmp = sysEUMBBARRead(EPIC_GLOBAL_REG);
|
||||
tmp |= 0xa0000000; /* Set the Global Conf. register */
|
||||
sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp);
|
||||
sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000);
|
||||
tmp = sysEUMBBARRead(EPIC_INT_CONF_REG); /* Read interrupt conf. reg */
|
||||
|
||||
if (IRQType == EPIC_DIRECT_IRQ) /* direct mode */
|
||||
sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff);
|
||||
else /* Serial mode */
|
||||
{
|
||||
tmp = (clkRatio << 28) | 0x08000000; /* Set clock ratio */
|
||||
sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp);
|
||||
}
|
||||
|
||||
while (epicIntAck() != 0xff); /* Clear all pending interrupts */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* epicIntEnable - Enable an interrupt source
|
||||
*
|
||||
* This routine clears the mask bit of an external, an internal or
|
||||
* a Timer register to enable the interrupt.
|
||||
*
|
||||
* RETURNS: None
|
||||
*/
|
||||
void epicIntEnable
|
||||
(
|
||||
int intVec /* Interrupt Vector Number */
|
||||
)
|
||||
{
|
||||
ULONG tmp;
|
||||
ULONG srAddr;
|
||||
|
||||
srAddr = SrcVecTable[intVec].srcAddr; /* Retrieve src Vec/Prio register */
|
||||
tmp = sysEUMBBARRead(srAddr);
|
||||
tmp &= 0x7fffffff; /* Clear the mask bit */
|
||||
sysEUMBBARWrite(srAddr, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* epicIntDisable - Disable an interrupt source
|
||||
*
|
||||
* This routine sets the mask bit of an external, an internal or
|
||||
* a Timer register to disable the interrupt.
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
*/
|
||||
|
||||
void epicIntDisable
|
||||
(
|
||||
int intVec /* Interrupt vector number */
|
||||
)
|
||||
{
|
||||
|
||||
ULONG tmp, srAddr;
|
||||
|
||||
srAddr = SrcVecTable[intVec].srcAddr;
|
||||
tmp = sysEUMBBARRead(srAddr);
|
||||
tmp |= 0x80000000; /* Set the mask bit */
|
||||
sysEUMBBARWrite(srAddr, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* epicIntSourceConfig - Set properties of an interrupt source
|
||||
*
|
||||
* This function sets interrupt properites (Polarity, Sense, Interrupt
|
||||
* Prority, and Interrupt Vector) of an Interrupt Source. The properties
|
||||
* can be set when the current source is not in-request or in-service,
|
||||
* which is determined by the Activity bit. This routine return ERROR
|
||||
* if the the Activity bit is 1 (in-request or in-service).
|
||||
*
|
||||
* This function assumes that the Source Vector/Priority register (input)
|
||||
* is a valid address.
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*/
|
||||
|
||||
int epicIntSourceConfig
|
||||
(
|
||||
int Vect, /* interrupt source vector number */
|
||||
int Polarity, /* interrupt source polarity */
|
||||
int Sense, /* interrupt source Sense */
|
||||
int Prio /* interrupt source priority */
|
||||
)
|
||||
|
||||
{
|
||||
ULONG tmp, newVal;
|
||||
ULONG actBit, srAddr;
|
||||
|
||||
srAddr = SrcVecTable[Vect].srcAddr;
|
||||
tmp = sysEUMBBARRead(srAddr);
|
||||
actBit = (tmp & 40000000) >> 30; /* retrieve activity bit - bit 30 */
|
||||
if (actBit == 1)
|
||||
return ERROR;
|
||||
|
||||
tmp &= 0xff30ff00; /* Erase previously set P,S,Prio,Vector bits */
|
||||
newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect;
|
||||
sysEUMBBARWrite(srAddr, tmp | newVal );
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* epicIntAck - acknowledge an interrupt
|
||||
*
|
||||
* This function reads the Interrupt acknowldge register and return
|
||||
* the vector number of the highest pending interrupt.
|
||||
*
|
||||
* RETURNS: Interrupt Vector number.
|
||||
*/
|
||||
|
||||
unsigned int epicIntAck(void)
|
||||
{
|
||||
return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG ));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* epicEOI - signal an end of interrupt
|
||||
*
|
||||
* This function writes 0x0 to the EOI register to signal end of interrupt.
|
||||
* It is usually called after an interrupt routine is served.
|
||||
*
|
||||
* RETURNS: None
|
||||
*/
|
||||
|
||||
void epicEOI(void)
|
||||
{
|
||||
sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* epicCurTaskPrioSet - sets the priority of the Processor Current Task
|
||||
*
|
||||
* This function should be called after epicInit() to lower the priority
|
||||
* of the processor current task.
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*/
|
||||
|
||||
int epicCurTaskPrioSet
|
||||
(
|
||||
int prioNum /* New priority value */
|
||||
)
|
||||
{
|
||||
|
||||
if ( (prioNum < 0) || (prioNum > 0xF))
|
||||
return ERROR;
|
||||
sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* function: epicIntTaskGet
|
||||
*
|
||||
* description: Get value of processor current interrupt task priority register
|
||||
*
|
||||
* note:
|
||||
***********************************************************************/
|
||||
unsigned char epicIntTaskGet()
|
||||
{
|
||||
/* get the interrupt task priority register */
|
||||
ULONG reg;
|
||||
unsigned char rec;
|
||||
|
||||
reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG );
|
||||
rec = ( reg & 0x0F );
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* function: epicISR
|
||||
*
|
||||
* description: EPIC service routine called by the core exception
|
||||
* at 0x500
|
||||
*
|
||||
* note:
|
||||
**************************************************************/
|
||||
unsigned int epicISR(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************
|
||||
* function: epicModeGet
|
||||
*
|
||||
* description: query EPIC mode, return 0 if pass through mode
|
||||
* return 1 if mixed mode
|
||||
*
|
||||
* note:
|
||||
*************************************************************/
|
||||
unsigned int epicModeGet(void)
|
||||
{
|
||||
ULONG val;
|
||||
|
||||
val = sysEUMBBARRead( EPIC_GLOBAL_REG );
|
||||
return (( val & 0x20000000 ) >> 29);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************
|
||||
* function: epicConfigGet
|
||||
*
|
||||
* description: Get the EPIC interrupt Configuration
|
||||
* return 0 if not error, otherwise return 1
|
||||
*
|
||||
* note:
|
||||
********************************************/
|
||||
void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable)
|
||||
{
|
||||
ULONG val;
|
||||
|
||||
val = sysEUMBBARRead( EPIC_INT_CONF_REG );
|
||||
*clkRatio = ( val & 0x70000000 ) >> 28;
|
||||
*serEnable = ( val & 0x8000000 ) >> 27;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* sysEUMBBARRead - Read a 32-bit EUMBBAR register
|
||||
*
|
||||
* This routine reads the content of a register in the Embedded
|
||||
* Utilities Memory Block, and swaps to big endian before returning
|
||||
* the value.
|
||||
*
|
||||
* RETURNS: The content of the specified EUMBBAR register.
|
||||
*/
|
||||
|
||||
ULONG sysEUMBBARRead
|
||||
(
|
||||
ULONG regNum
|
||||
)
|
||||
{
|
||||
ULONG temp;
|
||||
|
||||
temp = *(ULONG *) (CFG_EUMB_ADDR + regNum);
|
||||
return ( LONGSWAP(temp));
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* sysEUMBBARWrite - Write a 32-bit EUMBBAR register
|
||||
*
|
||||
* This routine swaps the value to little endian then writes it to
|
||||
* a register in the Embedded Utilities Memory Block address space.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void sysEUMBBARWrite
|
||||
(
|
||||
ULONG regNum, /* EUMBBAR register address */
|
||||
ULONG regVal /* Value to be written */
|
||||
)
|
||||
{
|
||||
|
||||
*(ULONG *) (CFG_EUMB_ADDR + regNum) = LONGSWAP(regVal);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* function: epicVendorId
|
||||
*
|
||||
* description: return the EPIC Vendor Identification
|
||||
* register:
|
||||
*
|
||||
* siliccon version, device id, and vendor id
|
||||
*
|
||||
* note:
|
||||
********************************************************/
|
||||
void epicVendorId
|
||||
(
|
||||
unsigned int *step,
|
||||
unsigned int *devId,
|
||||
unsigned int *venId
|
||||
)
|
||||
{
|
||||
ULONG val;
|
||||
val = sysEUMBBARRead( EPIC_VENDOR_ID_REG );
|
||||
*step = ( val & 0x00FF0000 ) >> 16;
|
||||
*devId = ( val & 0x0000FF00 ) >> 8;
|
||||
*venId = ( val & 0x000000FF );
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* function: epicFeatures
|
||||
*
|
||||
* description: return the number of IRQ supported,
|
||||
* number of CPU, and the version of the
|
||||
* OpenEPIC
|
||||
*
|
||||
* note:
|
||||
*************************************************/
|
||||
void epicFeatures
|
||||
(
|
||||
unsigned int *noIRQs,
|
||||
unsigned int *noCPUs,
|
||||
unsigned int *verId
|
||||
)
|
||||
{
|
||||
ULONG val;
|
||||
|
||||
val = sysEUMBBARRead( EPIC_FEATURES_REG );
|
||||
*noIRQs = ( val & 0x07FF0000 ) >> 16;
|
||||
*noCPUs = ( val & 0x00001F00 ) >> 8;
|
||||
*verId = ( val & 0x000000FF );
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* function: epciTmFrequncySet
|
||||
*
|
||||
* description: Set the timer frequency reporting register
|
||||
********************************************************/
|
||||
void epicTmFrequencySet( unsigned int frq )
|
||||
{
|
||||
sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq);
|
||||
}
|
||||
|
||||
/*******************************************************
|
||||
* function: epicTmFrequncyGet
|
||||
*
|
||||
* description: Get the current value of the Timer Frequency
|
||||
* Reporting register
|
||||
*
|
||||
******************************************************/
|
||||
unsigned int epicTmFrequencyGet(void)
|
||||
{
|
||||
return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************
|
||||
* function: epicTmBaseSet
|
||||
*
|
||||
* description: Set the #n global timer base count register
|
||||
* return 0 if no error, otherwise return 1.
|
||||
*
|
||||
* note:
|
||||
****************************************************/
|
||||
unsigned int epicTmBaseSet
|
||||
(
|
||||
ULONG srcAddr, /* Address of the Timer Base register */
|
||||
unsigned int cnt, /* Base count */
|
||||
unsigned int inhibit /* 1 - count inhibit */
|
||||
)
|
||||
{
|
||||
|
||||
unsigned int val = 0x80000000;
|
||||
/* First inhibit counting the timer */
|
||||
sysEUMBBARWrite(srcAddr, val) ;
|
||||
|
||||
/* set the new value */
|
||||
val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31);
|
||||
sysEUMBBARWrite(srcAddr, val) ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* function: epicTmBaseGet
|
||||
*
|
||||
* description: Get the current value of the global timer base count register
|
||||
* return 0 if no error, otherwise return 1.
|
||||
*
|
||||
* note:
|
||||
***********************************************************************/
|
||||
unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val )
|
||||
{
|
||||
*val = sysEUMBBARRead( srcAddr );
|
||||
*val = *val & 0x7fffffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* function: epicTmCountGet
|
||||
*
|
||||
* description: Get the value of a given global timer
|
||||
* current count register
|
||||
* return 0 if no error, otherwise return 1
|
||||
* note:
|
||||
**********************************************************/
|
||||
unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val )
|
||||
{
|
||||
*val = sysEUMBBARRead( srcAddr );
|
||||
*val = *val & 0x7fffffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* function: epicTmInhibit
|
||||
*
|
||||
* description: Stop counting of a given global timer
|
||||
* return 0 if no error, otherwise return 1
|
||||
*
|
||||
* note:
|
||||
***********************************************************/
|
||||
unsigned int epicTmInhibit( unsigned int srcAddr )
|
||||
{
|
||||
ULONG val;
|
||||
|
||||
val = sysEUMBBARRead( srcAddr );
|
||||
val |= 0x80000000;
|
||||
sysEUMBBARWrite( srcAddr, val );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* function: epicTmEnable
|
||||
*
|
||||
* description: Enable counting of a given global timer
|
||||
* return 0 if no error, otherwise return 1
|
||||
*
|
||||
* note:
|
||||
*****************************************************************/
|
||||
unsigned int epicTmEnable( ULONG srcAddr )
|
||||
{
|
||||
ULONG val;
|
||||
|
||||
val = sysEUMBBARRead( srcAddr );
|
||||
val &= 0x7fffffff;
|
||||
sysEUMBBARWrite( srcAddr, val );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void epicSourcePrint(int Vect)
|
||||
{
|
||||
ULONG srcVal;
|
||||
|
||||
srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr);
|
||||
PRINT("%s\n", SrcVecTable[Vect].srcName);
|
||||
PRINT("Address = 0x%lx\n", SrcVecTable[Vect].srcAddr);
|
||||
PRINT("Vector = %ld\n", (srcVal & 0x000000FF) );
|
||||
PRINT("Mask = %ld\n", srcVal >> 31);
|
||||
PRINT("Activitiy = %ld\n", (srcVal & 40000000) >> 30);
|
||||
PRINT("Polarity = %ld\n", (srcVal & 0x00800000) >> 23);
|
||||
PRINT("Sense = %ld\n", (srcVal & 0x00400000) >> 22);
|
||||
PRINT("Priority = %ld\n", (srcVal & 0x000F0000) >> 16);
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* linux/arch/ppc/kernel/traps.c
|
||||
*
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Modified by Cort Dougan (cort@cs.nmt.edu)
|
||||
* and Paul Mackerras (paulus@cs.anu.edu.au)
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of hardware exceptions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/* Returns 0 if exception not found and fixup otherwise. */
|
||||
extern unsigned long search_exception_table(unsigned long);
|
||||
|
||||
/* THIS NEEDS CHANGING to use the board info structure.
|
||||
*/
|
||||
#define END_OF_MEM 0x00400000
|
||||
|
||||
/*
|
||||
* Trap & Exception support
|
||||
*/
|
||||
|
||||
void
|
||||
print_backtrace(unsigned long *sp)
|
||||
{
|
||||
int cnt = 0;
|
||||
unsigned long i;
|
||||
|
||||
printf("Call backtrace: ");
|
||||
while (sp) {
|
||||
if ((uint)sp > END_OF_MEM)
|
||||
break;
|
||||
|
||||
i = sp[1];
|
||||
if (cnt++ % 7 == 0)
|
||||
printf("\n");
|
||||
printf("%08lX ", i);
|
||||
if (cnt > 32) break;
|
||||
sp = (unsigned long *)*sp;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs * regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
|
||||
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
|
||||
printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
|
||||
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
|
||||
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
|
||||
regs->msr&MSR_IR ? 1 : 0,
|
||||
regs->msr&MSR_DR ? 1 : 0);
|
||||
|
||||
printf("\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((i % 8) == 0)
|
||||
{
|
||||
printf("GPR%02d: ", i);
|
||||
}
|
||||
|
||||
printf("%08lX ", regs->gpr[i]);
|
||||
if ((i % 8) == 7)
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_exception(int signr, struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
|
||||
}
|
||||
|
||||
void
|
||||
MachineCheckException(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fixup;
|
||||
|
||||
/* Probing PCI using config cycles cause this exception
|
||||
* when a device is not present. Catch it and return to
|
||||
* the PCI exception handler.
|
||||
*/
|
||||
if ((fixup = search_exception_table(regs->nip)) != 0) {
|
||||
regs->nip = fixup;
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Machine check in kernel mode.\n");
|
||||
printf("Caused by (from msr): ");
|
||||
printf("regs %p ",regs);
|
||||
switch( regs->msr & 0x0000F000)
|
||||
{
|
||||
case (1<<12) :
|
||||
printf("Machine check signal - probably due to mm fault\n"
|
||||
"with mmu off\n");
|
||||
break;
|
||||
case (1<<13) :
|
||||
printf("Transfer error ack signal\n");
|
||||
break;
|
||||
case (1<<14) :
|
||||
printf("Data parity signal\n");
|
||||
break;
|
||||
case (1<<15) :
|
||||
printf("Address parity signal\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown values in msr\n");
|
||||
}
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("machine check");
|
||||
}
|
||||
|
||||
void
|
||||
AlignmentException(struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Alignment Exception");
|
||||
}
|
||||
|
||||
void
|
||||
ProgramCheckException(struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Program Check Exception");
|
||||
}
|
||||
|
||||
void
|
||||
SoftEmuException(struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Software Emulation Exception");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UnknownException(struct pt_regs *regs)
|
||||
{
|
||||
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
|
||||
regs->nip, regs->msr, regs->trap);
|
||||
_exception(0, regs);
|
||||
}
|
||||
|
||||
/* Probe an address by reading. If not present, return -1, otherwise
|
||||
* return 0.
|
||||
*/
|
||||
int
|
||||
addr_probe(uint *addr)
|
||||
{
|
||||
#if 0
|
||||
int retval;
|
||||
|
||||
__asm__ __volatile__( \
|
||||
"1: lwz %0,0(%1)\n" \
|
||||
" eieio\n" \
|
||||
" li %0,0\n" \
|
||||
"2:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: li %0,-1\n" \
|
||||
" b 2b\n" \
|
||||
".section __ex_table,\"a\"\n" \
|
||||
" .align 2\n" \
|
||||
" .long 1b,3b\n" \
|
||||
".text" \
|
||||
: "=r" (retval) : "r"(addr));
|
||||
|
||||
return (retval);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* MPC8260 FCC Fast Ethernet
|
||||
*
|
||||
* Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
|
||||
*
|
||||
* (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.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
|
||||
*/
|
||||
|
||||
/*
|
||||
* MPC8260 FCC Fast Ethernet
|
||||
* Basic ET HW initialization and packet RX/TX routines
|
||||
*
|
||||
* This code will not perform the IO port configuration. This should be
|
||||
* done in the iop_conf_t structure specific for the board.
|
||||
*
|
||||
* TODO:
|
||||
* add a PHY driver to do the negotiation
|
||||
* reflect negotiation results in FPSMR
|
||||
* look for ways to configure the board specific stuff elsewhere, eg.
|
||||
* config_xxx.h or the board directory
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/cpm_8260.h>
|
||||
#include <mpc8260.h>
|
||||
#include <net.h>
|
||||
#include <command.h>
|
||||
#include <config.h>
|
||||
|
||||
#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET)
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#if (CONFIG_ETHER_INDEX == 1)
|
||||
|
||||
#define PROFF_ENET PROFF_FCC1
|
||||
#define CPM_CR_ENET_SBLOCK CPM_CR_FCC1_SBLOCK
|
||||
#define CPM_CR_ENET_SBLOCK CPM_CR_FCC1_SBLOCK
|
||||
#define CPM_CR_ENET_PAGE CPM_CR_FCC1_PAGE
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#elif (CONFIG_ETHER_INDEX == 2)
|
||||
|
||||
#define PROFF_ENET PROFF_FCC2
|
||||
#define CPM_CR_ENET_SBLOCK CPM_CR_FCC2_SBLOCK
|
||||
#define CPM_CR_ENET_PAGE CPM_CR_FCC2_PAGE
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#elif (CONFIG_ETHER_INDEX == 3)
|
||||
|
||||
#define PROFF_ENET PROFF_FCC3
|
||||
#define CPM_CR_ENET_SBLOCK CPM_CR_FCC3_SBLOCK
|
||||
#define CPM_CR_ENET_PAGE CPM_CR_FCC3_PAGE
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
#else
|
||||
#error "FCC Ethernet not correctly defined"
|
||||
#endif
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
/* Maximum input DMA size. Must be a should(?) be a multiple of 4. */
|
||||
#define PKT_MAXDMA_SIZE 1520
|
||||
|
||||
/* The FCC stores dest/src/type, data, and checksum for receive packets. */
|
||||
#define PKT_MAXBUF_SIZE 1518
|
||||
#define PKT_MINBUF_SIZE 64
|
||||
|
||||
/* Maximum input buffer size. Must be a multiple of 32. */
|
||||
#define PKT_MAXBLR_SIZE 1536
|
||||
|
||||
#define TOUT_LOOP 1000000
|
||||
|
||||
#define TX_BUF_CNT 2
|
||||
#ifdef __GNUC__
|
||||
static char txbuf[TX_BUF_CNT][PKT_MAXBLR_SIZE] __attribute__ ((aligned(8)));
|
||||
#else
|
||||
#error "txbuf must be 64-bit aligned"
|
||||
#endif
|
||||
|
||||
static uint rxIdx; /* index of the current RX buffer */
|
||||
static uint txIdx; /* index of the current TX buffer */
|
||||
|
||||
/*
|
||||
* FCC Ethernet Tx and Rx buffer descriptors.
|
||||
* Provide for Double Buffering
|
||||
* Note: PKTBUFSRX is defined in net.h
|
||||
*/
|
||||
|
||||
typedef volatile struct rtxbd {
|
||||
cbd_t rxbd[PKTBUFSRX];
|
||||
cbd_t txbd[TX_BUF_CNT];
|
||||
} RTXBD;
|
||||
|
||||
/* Good news: the FCC supports external BDs! */
|
||||
#ifdef __GNUC__
|
||||
static RTXBD rtx __attribute__ ((aligned(8)));
|
||||
#else
|
||||
#error "rtx must be 64-bit aligned"
|
||||
#endif
|
||||
|
||||
int eth_send(volatile void *packet, int length)
|
||||
{
|
||||
int i;
|
||||
int result = 0;
|
||||
|
||||
if (length <= 0) {
|
||||
printf("fec: bad packet size: %d\n", length);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf("fec: tx buffer not ready\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rtx.txbd[txIdx].cbd_bufaddr = (uint)packet;
|
||||
rtx.txbd[txIdx].cbd_datlen = length;
|
||||
rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
|
||||
BD_ENET_TX_WRAP);
|
||||
|
||||
for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf("fec: tx error\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ET_DEBUG
|
||||
printf("cycles: %d status: %04x\n", i, rtx.txbd[txIdx].cbd_sc);
|
||||
#endif
|
||||
|
||||
/* return only status bits */
|
||||
result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
int eth_rx(void)
|
||||
{
|
||||
int length;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
|
||||
length = -1;
|
||||
break; /* nothing received - leave for() loop */
|
||||
}
|
||||
length = rtx.rxbd[rxIdx].cbd_datlen;
|
||||
|
||||
if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) {
|
||||
printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
|
||||
}
|
||||
else {
|
||||
/* Pass the packet up to the protocol layers. */
|
||||
NetReceive(NetRxPackets[rxIdx], length - 4);
|
||||
}
|
||||
|
||||
|
||||
/* Give the buffer back to the FCC. */
|
||||
rtx.rxbd[rxIdx].cbd_datlen = 0;
|
||||
|
||||
/* wrap around buffer index when necessary */
|
||||
if ((rxIdx + 1) >= PKTBUFSRX) {
|
||||
rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
|
||||
rxIdx = 0;
|
||||
}
|
||||
else {
|
||||
rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
|
||||
rxIdx++;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
int eth_init(bd_t *bis)
|
||||
{
|
||||
int i;
|
||||
volatile immap_t *immr = (immap_t *)CFG_IMMR;
|
||||
volatile cpm8260_t *cp = &(immr->im_cpm);
|
||||
fcc_enet_t *pram_ptr;
|
||||
unsigned long mem_addr;
|
||||
|
||||
#if 0
|
||||
mii_discover_phy();
|
||||
#endif
|
||||
|
||||
/* 28.9 - (1-2): ioports have been set up already */
|
||||
|
||||
/* 28.9 - (3): connect FCC's tx and rx clocks */
|
||||
immr->im_cpmux.cmx_uar = 0;
|
||||
immr->im_cpmux.cmx_fcr = (immr->im_cpmux.cmx_fcr & ~CFG_CMXFCR_MASK) |
|
||||
CFG_CMXFCR_VALUE;
|
||||
|
||||
/* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
|
||||
immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr =
|
||||
FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
|
||||
|
||||
/* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet */
|
||||
immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC;
|
||||
|
||||
/* 28.9 - (6): FDSR: Ethernet Syn */
|
||||
immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fdsr = 0xD555;
|
||||
|
||||
/* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
|
||||
rxIdx = 0;
|
||||
txIdx = 0;
|
||||
|
||||
/* Setup Receiver Buffer Descriptors */
|
||||
for (i = 0; i < PKTBUFSRX; i++)
|
||||
{
|
||||
rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
|
||||
rtx.rxbd[i].cbd_datlen = 0;
|
||||
rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
|
||||
}
|
||||
rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
|
||||
|
||||
/* Setup Ethernet Transmitter Buffer Descriptors */
|
||||
for (i = 0; i < TX_BUF_CNT; i++)
|
||||
{
|
||||
rtx.txbd[i].cbd_sc = (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
|
||||
rtx.txbd[i].cbd_datlen = 0;
|
||||
rtx.txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
|
||||
}
|
||||
rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
|
||||
|
||||
/* 28.9 - (7): initialise parameter ram */
|
||||
pram_ptr = (fcc_enet_t *)&(immr->im_dprambase[PROFF_ENET]);
|
||||
|
||||
/* clear whole structure to make sure all reserved fields are zero */
|
||||
memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
|
||||
|
||||
/*
|
||||
* common Parameter RAM area
|
||||
*
|
||||
* Allocate space in the reserved FCC area of DPRAM for the
|
||||
* internal buffers. No one uses this space (yet), so we
|
||||
* can do this. Later, we will add resource management for
|
||||
* this area.
|
||||
*/
|
||||
mem_addr = CPM_FCC_SPECIAL_BASE + ((CONFIG_ETHER_INDEX-1) * 64);
|
||||
pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
|
||||
pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
|
||||
/*
|
||||
* Set maximum bytes per receive buffer.
|
||||
* It must be a multiple of 32.
|
||||
*/
|
||||
pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
|
||||
pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
|
||||
CFG_CPMFCR_RAMTYPE) << 24;
|
||||
pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
|
||||
pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
|
||||
CFG_CPMFCR_RAMTYPE) << 24;
|
||||
pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
|
||||
|
||||
/* protocol-specific area */
|
||||
pram_ptr->fen_cmask = 0xdebb20e3; /* CRC mask */
|
||||
pram_ptr->fen_cpres = 0xffffffff; /* CRC preset */
|
||||
pram_ptr->fen_retlim = 15; /* Retry limit threshold */
|
||||
pram_ptr->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
|
||||
/*
|
||||
* Set Ethernet station address.
|
||||
*
|
||||
* This is supplied in the board information structure, so we
|
||||
* copy that into the controller.
|
||||
* So, far we have only been given one Ethernet address. We make
|
||||
* it unique by setting a few bits in the upper byte of the
|
||||
* non-static part of the address.
|
||||
*/
|
||||
#define ea bis->bi_enetaddr
|
||||
pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
|
||||
pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
|
||||
pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
|
||||
#undef ea
|
||||
pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
|
||||
/* pad pointer. use tiptr since we don't need a specific padding char */
|
||||
pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
|
||||
pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */
|
||||
pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */
|
||||
pram_ptr->fen_rfthr = 1;
|
||||
pram_ptr->fen_rfcnt = 1;
|
||||
#if 0
|
||||
printf("pram_ptr->fen_genfcc.fcc_rbase %08lx\n",
|
||||
pram_ptr->fen_genfcc.fcc_rbase);
|
||||
printf("pram_ptr->fen_genfcc.fcc_tbase %08lx\n",
|
||||
pram_ptr->fen_genfcc.fcc_tbase);
|
||||
#endif
|
||||
|
||||
/* 28.9 - (8): clear out events in FCCE */
|
||||
immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fcce = ~0x0;
|
||||
|
||||
/* 28.9 - (9): FCCM: mask all events */
|
||||
immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fccm = 0;
|
||||
|
||||
/* 28.9 - (10-12): we don't use ethernet interrupts */
|
||||
|
||||
/* 28.9 - (13)
|
||||
*
|
||||
* Let's re-initialize the channel now. We have to do it later
|
||||
* than the manual describes because we have just now finished
|
||||
* the BD initialization.
|
||||
*/
|
||||
cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET_PAGE,
|
||||
CPM_CR_ENET_SBLOCK,
|
||||
0x0c,
|
||||
CPM_CR_INIT_TRX) | CPM_CR_FLG;
|
||||
do {
|
||||
__asm__ __volatile__ ("eieio");
|
||||
} while (cp->cp_cpcr & CPM_CR_FLG);
|
||||
|
||||
/* 28.9 - (14): enable tx/rx in gfmr */
|
||||
immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void eth_halt(void)
|
||||
{
|
||||
volatile immap_t *immr = (immap_t *)CFG_IMMR;
|
||||
|
||||
/* write GFMR: disable tx/rx */
|
||||
immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr &=
|
||||
~(FCC_GFMR_ENT | FCC_GFMR_ENR);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET */
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* linux/arch/ppc/kernel/traps.c
|
||||
*
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Modified by Cort Dougan (cort@cs.nmt.edu)
|
||||
* and Paul Mackerras (paulus@cs.anu.edu.au)
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of hardware exceptions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
int (*debugger_exception_handler)(struct pt_regs *) = 0;
|
||||
#endif
|
||||
|
||||
/* Returns 0 if exception not found and fixup otherwise. */
|
||||
extern unsigned long search_exception_table(unsigned long);
|
||||
|
||||
/* THIS NEEDS CHANGING to use the board info structure.
|
||||
*/
|
||||
#define END_OF_MEM 0x02000000
|
||||
|
||||
/*
|
||||
* Trap & Exception support
|
||||
*/
|
||||
|
||||
void
|
||||
print_backtrace(unsigned long *sp)
|
||||
{
|
||||
int cnt = 0;
|
||||
unsigned long i;
|
||||
|
||||
printf("Call backtrace: ");
|
||||
while (sp) {
|
||||
if ((uint)sp > END_OF_MEM)
|
||||
break;
|
||||
|
||||
i = sp[1];
|
||||
if (cnt++ % 7 == 0)
|
||||
printf("\n");
|
||||
printf("%08lX ", i);
|
||||
if (cnt > 32) break;
|
||||
sp = (unsigned long *)*sp;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs * regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
|
||||
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
|
||||
printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
|
||||
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
|
||||
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
|
||||
regs->msr&MSR_IR ? 1 : 0,
|
||||
regs->msr&MSR_DR ? 1 : 0);
|
||||
|
||||
printf("\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((i % 8) == 0)
|
||||
{
|
||||
printf("GPR%02d: ", i);
|
||||
}
|
||||
|
||||
printf("%08lX ", regs->gpr[i]);
|
||||
if ((i % 8) == 7)
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_exception(int signr, struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
|
||||
}
|
||||
|
||||
void
|
||||
MachineCheckException(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fixup;
|
||||
|
||||
/* Probing PCI using config cycles cause this exception
|
||||
* when a device is not present. Catch it and return to
|
||||
* the PCI exception handler.
|
||||
*/
|
||||
if ((fixup = search_exception_table(regs->nip)) != 0) {
|
||||
regs->nip = fixup;
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("Machine check in kernel mode.\n");
|
||||
printf("Caused by (from msr): ");
|
||||
printf("regs %p ",regs);
|
||||
switch( regs->msr & 0x0000F000)
|
||||
{
|
||||
case (1<<12) :
|
||||
printf("Machine check signal - probably due to mm fault\n"
|
||||
"with mmu off\n");
|
||||
break;
|
||||
case (1<<13) :
|
||||
printf("Transfer error ack signal\n");
|
||||
break;
|
||||
case (1<<14) :
|
||||
printf("Data parity signal\n");
|
||||
break;
|
||||
case (1<<15) :
|
||||
printf("Address parity signal\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown values in msr\n");
|
||||
}
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("machine check");
|
||||
}
|
||||
|
||||
void
|
||||
AlignmentException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Alignment Exception");
|
||||
}
|
||||
|
||||
void
|
||||
ProgramCheckException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Program Check Exception");
|
||||
}
|
||||
|
||||
void
|
||||
SoftEmuException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Software Emulation Exception");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UnknownException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
|
||||
regs->nip, regs->msr, regs->trap);
|
||||
_exception(0, regs);
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
extern void do_bedbug_breakpoint(struct pt_regs *);
|
||||
#endif
|
||||
|
||||
void
|
||||
DebugException(struct pt_regs *regs)
|
||||
{
|
||||
|
||||
printf("Debugger trap at @ %lx\n", regs->nip );
|
||||
show_regs(regs);
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
do_bedbug_breakpoint( regs );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Probe an address by reading. If not present, return -1, otherwise
|
||||
* return 0.
|
||||
*/
|
||||
int
|
||||
addr_probe(uint *addr)
|
||||
{
|
||||
#if 0
|
||||
int retval;
|
||||
|
||||
__asm__ __volatile__( \
|
||||
"1: lwz %0,0(%1)\n" \
|
||||
" eieio\n" \
|
||||
" li %0,0\n" \
|
||||
"2:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: li %0,-1\n" \
|
||||
" b 2b\n" \
|
||||
".section __ex_table,\"a\"\n" \
|
||||
" .align 2\n" \
|
||||
" .long 1b,3b\n" \
|
||||
".text" \
|
||||
: "=r" (retval) : "r"(addr));
|
||||
|
||||
return (retval);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* linux/arch/ppc/kernel/traps.c
|
||||
*
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Modified by Cort Dougan (cort@cs.nmt.edu)
|
||||
* and Paul Mackerras (paulus@cs.anu.edu.au)
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of hardware exceptions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
int (*debugger_exception_handler)(struct pt_regs *) = 0;
|
||||
#endif
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
extern void do_bedbug_breakpoint(struct pt_regs *);
|
||||
#endif
|
||||
|
||||
/* Returns 0 if exception not found and fixup otherwise. */
|
||||
extern unsigned long search_exception_table(unsigned long);
|
||||
|
||||
/* THIS NEEDS CHANGING to use the board info structure.
|
||||
*/
|
||||
#define END_OF_MEM 0x02000000
|
||||
|
||||
/*
|
||||
* Trap & Exception support
|
||||
*/
|
||||
|
||||
void
|
||||
print_backtrace(unsigned long *sp)
|
||||
{
|
||||
int cnt = 0;
|
||||
unsigned long i;
|
||||
|
||||
printf("Call backtrace: ");
|
||||
while (sp) {
|
||||
if ((uint)sp > END_OF_MEM)
|
||||
break;
|
||||
|
||||
i = sp[1];
|
||||
if (cnt++ % 7 == 0)
|
||||
printf("\n");
|
||||
printf("%08lX ", i);
|
||||
if (cnt > 32) break;
|
||||
sp = (unsigned long *)*sp;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs * regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
|
||||
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
|
||||
printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
|
||||
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
|
||||
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
|
||||
regs->msr&MSR_IR ? 1 : 0,
|
||||
regs->msr&MSR_DR ? 1 : 0);
|
||||
|
||||
printf("\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((i % 8) == 0)
|
||||
{
|
||||
printf("GPR%02d: ", i);
|
||||
}
|
||||
|
||||
printf("%08lX ", regs->gpr[i]);
|
||||
if ((i % 8) == 7)
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_exception(int signr, struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
|
||||
}
|
||||
|
||||
void
|
||||
MachineCheckException(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fixup;
|
||||
|
||||
/* Probing PCI using config cycles cause this exception
|
||||
* when a device is not present. Catch it and return to
|
||||
* the PCI exception handler.
|
||||
*/
|
||||
if ((fixup = search_exception_table(regs->nip)) != 0) {
|
||||
regs->nip = fixup;
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("Machine check in kernel mode.\n");
|
||||
printf("Caused by (from msr): ");
|
||||
printf("regs %p ",regs);
|
||||
switch( regs->msr & 0x0000F000)
|
||||
{
|
||||
case (1<<12) :
|
||||
printf("Machine check signal - probably due to mm fault\n"
|
||||
"with mmu off\n");
|
||||
break;
|
||||
case (1<<13) :
|
||||
printf("Transfer error ack signal\n");
|
||||
break;
|
||||
case (1<<14) :
|
||||
printf("Data parity signal\n");
|
||||
break;
|
||||
case (1<<15) :
|
||||
printf("Address parity signal\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown values in msr\n");
|
||||
}
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("machine check");
|
||||
}
|
||||
|
||||
void
|
||||
AlignmentException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Alignment Exception");
|
||||
}
|
||||
|
||||
void
|
||||
ProgramCheckException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Program Check Exception");
|
||||
}
|
||||
|
||||
void
|
||||
SoftEmuException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Software Emulation Exception");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UnknownException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
|
||||
regs->nip, regs->msr, regs->trap);
|
||||
_exception(0, regs);
|
||||
}
|
||||
|
||||
void
|
||||
DebugException(struct pt_regs *regs)
|
||||
{
|
||||
printf("Debugger trap at @ %lx\n", regs->nip );
|
||||
show_regs(regs);
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
do_bedbug_breakpoint( regs );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Probe an address by reading. If not present, return -1, otherwise
|
||||
* return 0.
|
||||
*/
|
||||
int
|
||||
addr_probe(uint *addr)
|
||||
{
|
||||
#if 0
|
||||
int retval;
|
||||
|
||||
__asm__ __volatile__( \
|
||||
"1: lwz %0,0(%1)\n" \
|
||||
" eieio\n" \
|
||||
" li %0,0\n" \
|
||||
"2:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: li %0,-1\n" \
|
||||
" b 2b\n" \
|
||||
".section __ex_table,\"a\"\n" \
|
||||
" .align 2\n" \
|
||||
" .long 1b,3b\n" \
|
||||
".text" \
|
||||
: "=r" (retval) : "r"(addr));
|
||||
|
||||
return (retval);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#include <common.h>
|
||||
#include <commproc.h>
|
||||
|
||||
#if defined(CFG_I2C_UCODE_PATCH) || defined(CFG_SPI_UCODE_PATCH)
|
||||
|
||||
static void UcodeCopy (volatile cpm8xx_t *cpm);
|
||||
|
||||
void cpm_load_patch (volatile immap_t *immr)
|
||||
{
|
||||
immr->im_cpm.cp_rccr &= ~0x0003; /* Disable microcode program area */
|
||||
|
||||
UcodeCopy ((cpm8xx_t *)&immr->im_cpm); /* Copy ucode patch to DPRAM */
|
||||
#ifdef CFG_SPI_UCODE_PATCH
|
||||
{
|
||||
volatile spi_t *spi = (spi_t *) & immr->im_cpm.cp_dparam[PROFF_SPI];
|
||||
/* Activate the microcode per the instructions in the microcode manual */
|
||||
/* NOTE: We're only relocating the SPI parameters (not I2C). */
|
||||
immr->im_cpm.cp_cpmcr1 = 0x802a; /* Write Trap register 1 value */
|
||||
immr->im_cpm.cp_cpmcr2 = 0x8028; /* Write Trap register 2 value */
|
||||
spi->spi_rpbase = CFG_SPI_DPMEM_OFFSET; /* Where to relocte SPI params */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CFG_I2C_UCODE_PATCH
|
||||
{
|
||||
volatile iic_t *iip = (iic_t *) & immr->im_cpm.cp_dparam[PROFF_IIC];
|
||||
/* Activate the microcode per the instructions in the microcode manual */
|
||||
/* NOTE: We're only relocating the I2C parameters (not SPI). */
|
||||
immr->im_cpm.cp_cpmcr3 = 0x802e; /* Write Trap register 3 value */
|
||||
immr->im_cpm.cp_cpmcr4 = 0x802c; /* Write Trap register 4 value */
|
||||
iip->iic_rpbase = CFG_I2C_DPMEM_OFFSET; /* Where to relocte I2C params */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable DPRAM microcode to execute from the first 512 bytes
|
||||
* and a 256 byte extension of DPRAM.
|
||||
*/
|
||||
immr->im_cpm.cp_rccr |= 0x0001;
|
||||
}
|
||||
|
||||
static ulong patch_2000[] = {
|
||||
0x7FFFEFD9, 0x3FFD0000, 0x7FFB49F7, 0x7FF90000,
|
||||
0x5FEFADF7, 0x5F88ADF7, 0x5FEFAFF7, 0x5F88AFF7,
|
||||
0x3A9CFBC8, 0x77CAE1BB, 0xF4DE7FAD, 0xABAE9330,
|
||||
0x4E08FDCF, 0x6E0FAFF8, 0x7CCF76CF, 0xFDAFF9CF,
|
||||
0xABF88DC8, 0xAB5879F7, 0xB0927383, 0xDFD079F7,
|
||||
0xB090E6BB, 0xE5BBE74F, 0xB3FA6F0F, 0x6FFB76CE,
|
||||
0xEE0CF9CF, 0x2BFBEFEF, 0xCFEEF9CF, 0x76CEAD23,
|
||||
0x90B3DF99, 0x7FDDD0C1, 0x4BF847FD, 0x7CCF76CE,
|
||||
0xCFEF77CA, 0x7EAF7FAD, 0x7DFDF0B7, 0xEF7A7FCA,
|
||||
0x77CAFBC8, 0x6079E722, 0xFBC85FFF, 0xDFFF5FB3,
|
||||
0xFFFBFBC8, 0xF3C894A5, 0xE7C9EDF9, 0x7F9A7FAD,
|
||||
0x5F36AFE8, 0x5F5BFFDF, 0xDF95CB9E, 0xAF7D5FC3,
|
||||
0xAFED8C1B, 0x5FC3AFDD, 0x5FC5DF99, 0x7EFDB0B3,
|
||||
0x5FB3FFFE, 0xABAE5FB3, 0xFFFE5FD0, 0x600BE6BB,
|
||||
0x600B5FD0, 0xDFC827FB, 0xEFDF5FCA, 0xCFDE3A9C,
|
||||
0xE7C9EDF9, 0xF3C87F9E, 0x54CA7FED, 0x2D3A3637,
|
||||
0x756F7E9A, 0xF1CE37EF, 0x2E677FEE, 0x10EBADF8,
|
||||
0xEFDECFEA, 0xE52F7D9F, 0xE12BF1CE, 0x5F647E9A,
|
||||
0x4DF8CFEA, 0x5F717D9B, 0xEFEECFEA, 0x5F73E522,
|
||||
0xEFDE5F73, 0xCFDA0B61, 0x7385DF61, 0xE7C9EDF9,
|
||||
0x7E9A30D5, 0x1458BFFF, 0xF3C85FFF, 0xDFFFA7F8,
|
||||
0x5F5BBFFE, 0x7F7D10D0, 0x144D5F33, 0xBFFFAF78,
|
||||
0x5F5BBFFD, 0xA7F85F33, 0xBFFE77FD, 0x30BD4E08,
|
||||
0xFDCFE5FF, 0x6E0FAFF8, 0x7EEF7E9F, 0xFDEFF1CF,
|
||||
0x5F17ABF8, 0x0D5B5F5B, 0xFFEF79F7, 0x309EAFDD,
|
||||
0x5F3147F8, 0x5F31AFED, 0x7FDD50AF, 0x497847FD,
|
||||
0x7F9E7FED, 0x7DFD70A9, 0xEF7E7ECE, 0x6BA07F9E,
|
||||
0x2D227EFD, 0x30DB5F5B, 0xFFFD5F5B, 0xFFEF5F5B,
|
||||
0xFFDF0C9C, 0xAFED0A9A, 0xAFDD0C37, 0x5F37AFBD,
|
||||
0x7FBDB081, 0x5F8147F8,
|
||||
};
|
||||
|
||||
static ulong patch_2F00[] = {
|
||||
0x3E303430, 0x34343737, 0xABBF9B99, 0x4B4FBDBD,
|
||||
0x59949334, 0x9FFF37FB, 0x9B177DD9, 0x936956BB,
|
||||
0xFBDD697B, 0xDD2FD113, 0x1DB9F7BB, 0x36313963,
|
||||
0x79373369, 0x3193137F, 0x7331737A, 0xF7BB9B99,
|
||||
0x9BB19795, 0x77FDFD3D, 0x573B773F, 0x737933F7,
|
||||
0xB991D115, 0x31699315, 0x31531694, 0xBF4FBDBD,
|
||||
0x35931497, 0x35376956, 0xBD697B9D, 0x96931313,
|
||||
0x19797937, 0x69350000,
|
||||
};
|
||||
|
||||
static void UcodeCopy (volatile cpm8xx_t *cpm)
|
||||
{
|
||||
vu_long *p;
|
||||
int i;
|
||||
|
||||
p = (vu_long *)&(cpm->cp_dpmem[0x0000]);
|
||||
for (i=0; i < sizeof(patch_2000)/4; ++i) {
|
||||
p[i] = patch_2000[i];
|
||||
}
|
||||
|
||||
p = (vu_long *)&(cpm->cp_dpmem[0x0F00]);
|
||||
for (i=0; i < sizeof(patch_2F00)/4; ++i) {
|
||||
p[i] = patch_2F00[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CFG_I2C_UCODE_PATCH, CFG_SPI_UCODE_PATCH */
|
|
@ -0,0 +1,182 @@
|
|||
/*-----------------------------------------------------------------------------+
|
||||
|
|
||||
| This source code has been made available to you by IBM on an AS-IS
|
||||
| basis. Anyone receiving this source is licensed under IBM
|
||||
| copyrights to use it in any way he or she deems fit, including
|
||||
| copying it, modifying it, compiling it, and redistributing it either
|
||||
| with or without modifications. No license under IBM patents or
|
||||
| patent applications is to be implied by the copyright license.
|
||||
|
|
||||
| Any user of this software should understand that IBM cannot provide
|
||||
| technical support for this software and will not be responsible for
|
||||
| any consequences resulting from the use of this software.
|
||||
|
|
||||
| Any person who transfers this source code or any derivative work
|
||||
| must include the IBM copyright notice, this paragraph, and the
|
||||
| preceding two paragraphs in the transferred software.
|
||||
|
|
||||
| COPYRIGHT I B M CORPORATION 1995
|
||||
| LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
|
||||
+-----------------------------------------------------------------------------*/
|
||||
/*-----------------------------------------------------------------------------+
|
||||
|
|
||||
| File Name: miiphy.c
|
||||
|
|
||||
| Function: This module has utilities for accessing the MII PHY through
|
||||
| the EMAC3 macro.
|
||||
|
|
||||
| Author: Mark Wisner
|
||||
|
|
||||
| Change Activity-
|
||||
|
|
||||
| Date Description of Change BY
|
||||
| --------- --------------------- ---
|
||||
| 05-May-99 Created MKW
|
||||
| 01-Jul-99 Changed clock setting of sta_reg from 66Mhz to 50Mhz to
|
||||
| better match OPB speed. Also modified delay times. JWB
|
||||
| 29-Jul-99 Added Full duplex support MKW
|
||||
| 24-Aug-99 Removed printf from dp83843_duplex() JWB
|
||||
| 19-Jul-00 Ported to esd cpci405 sr
|
||||
|
|
||||
+-----------------------------------------------------------------------------*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <commproc.h>
|
||||
#include <405gp_enet.h>
|
||||
#include <405_mal.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_440)
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
/* Dump out to the screen PHY regs */
|
||||
/***********************************************************/
|
||||
|
||||
void miiphy_dump (unsigned char addr)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned short data;
|
||||
|
||||
|
||||
for (i = 0; i < 0x1A; i++) {
|
||||
if (miiphy_read (addr, i, &data)) {
|
||||
printf ("read error for reg %lx\n", i);
|
||||
return;
|
||||
}
|
||||
printf ("Phy reg %lx ==> %4x\n", i, data);
|
||||
|
||||
/* jump to the next set of regs */
|
||||
if (i == 0x07)
|
||||
i = 0x0f;
|
||||
|
||||
} /* end for loop */
|
||||
} /* end dump */
|
||||
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
/* read a phy reg and return the value with a rc */
|
||||
/***********************************************************/
|
||||
|
||||
int miiphy_read (unsigned char addr, unsigned char reg,
|
||||
unsigned short *value)
|
||||
{
|
||||
unsigned long sta_reg; /* STA scratch area */
|
||||
unsigned long i;
|
||||
|
||||
/* see if it is ready for 1000 nsec */
|
||||
i = 0;
|
||||
|
||||
/* see if it is ready for sec */
|
||||
while ((in32 (EMAC_STACR) & EMAC_STACR_OC) == 0) {
|
||||
udelay (7);
|
||||
if (i > 5) {
|
||||
printf ("read err 1\n");
|
||||
return -1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
sta_reg = reg; /* reg address */
|
||||
/* set clock (50Mhz) and read flags */
|
||||
sta_reg = (sta_reg | EMAC_STACR_READ) & ~EMAC_STACR_CLK_100MHZ;
|
||||
sta_reg = sta_reg | (addr << 5); /* Phy address */
|
||||
|
||||
out32 (EMAC_STACR, sta_reg);
|
||||
#if 0 /* test-only */
|
||||
printf ("a2: write: EMAC_STACR=0x%0x\n", sta_reg); /* test-only */
|
||||
#endif
|
||||
|
||||
sta_reg = in32 (EMAC_STACR);
|
||||
i = 0;
|
||||
while ((sta_reg & EMAC_STACR_OC) == 0) {
|
||||
udelay (7);
|
||||
if (i > 5) {
|
||||
printf ("read err 2\n");
|
||||
return -1;
|
||||
}
|
||||
i++;
|
||||
sta_reg = in32 (EMAC_STACR);
|
||||
}
|
||||
if ((sta_reg & EMAC_STACR_PHYE) != 0) {
|
||||
printf ("read err 3\n");
|
||||
printf ("a2: read: EMAC_STACR=0x%0lx, i=%d\n",
|
||||
sta_reg, (int) i); /* test-only */
|
||||
return -1;
|
||||
}
|
||||
|
||||
*value = *(short *) (&sta_reg);
|
||||
return 0;
|
||||
|
||||
|
||||
} /* phy_read */
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
/* write a phy reg and return the value with a rc */
|
||||
/***********************************************************/
|
||||
|
||||
int miiphy_write (unsigned char addr, unsigned char reg,
|
||||
unsigned short value)
|
||||
{
|
||||
unsigned long sta_reg; /* STA scratch area */
|
||||
unsigned long i;
|
||||
|
||||
/* see if it is ready for 1000 nsec */
|
||||
i = 0;
|
||||
|
||||
while ((in32 (EMAC_STACR) & EMAC_STACR_OC) == 0) {
|
||||
if (i > 5)
|
||||
return -1;
|
||||
udelay (7);
|
||||
i++;
|
||||
}
|
||||
sta_reg = 0;
|
||||
sta_reg = reg; /* reg address */
|
||||
/* set clock (50Mhz) and read flags */
|
||||
sta_reg = (sta_reg | EMAC_STACR_WRITE) & ~EMAC_STACR_CLK_100MHZ;
|
||||
sta_reg = sta_reg | ((unsigned long) addr << 5); /* Phy address */
|
||||
memcpy (&sta_reg, &value, 2); /* put in data */
|
||||
|
||||
out32 (EMAC_STACR, sta_reg);
|
||||
|
||||
/* wait for completion */
|
||||
i = 0;
|
||||
sta_reg = in32 (EMAC_STACR);
|
||||
while ((sta_reg & EMAC_STACR_OC) == 0) {
|
||||
udelay (7);
|
||||
if (i > 5)
|
||||
return -1;
|
||||
i++;
|
||||
sta_reg = in32 (EMAC_STACR);
|
||||
}
|
||||
|
||||
if ((sta_reg & EMAC_STACR_PHYE) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
} /* phy_read */
|
||||
|
||||
#endif /* CONFIG_405GP */
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* linux/arch/ppc/kernel/traps.c
|
||||
*
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Modified by Cort Dougan (cort@cs.nmt.edu)
|
||||
* and Paul Mackerras (paulus@cs.anu.edu.au)
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of hardware exceptions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
int (*debugger_exception_handler)(struct pt_regs *) = 0;
|
||||
#endif
|
||||
|
||||
/* Returns 0 if exception not found and fixup otherwise. */
|
||||
extern unsigned long search_exception_table(unsigned long);
|
||||
|
||||
/* THIS NEEDS CHANGING to use the board info structure.
|
||||
*/
|
||||
#define END_OF_MEM 0x00400000
|
||||
|
||||
|
||||
static __inline__ void set_tsr(unsigned long val)
|
||||
{
|
||||
#if defined(CONFIG_440)
|
||||
asm volatile("mtspr 0x150, %0" : : "r" (val));
|
||||
#else
|
||||
asm volatile("mttsr %0" : : "r" (val));
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline__ unsigned long get_esr(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
|
||||
#else
|
||||
asm volatile("mfesr %0" : "=r" (val) :);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
#define ESR_MCI 0x80000000
|
||||
#define ESR_PIL 0x08000000
|
||||
#define ESR_PPR 0x04000000
|
||||
#define ESR_PTR 0x02000000
|
||||
#define ESR_DST 0x00800000
|
||||
#define ESR_DIZ 0x00400000
|
||||
#define ESR_U0F 0x00008000
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
extern void do_bedbug_breakpoint(struct pt_regs *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Trap & Exception support
|
||||
*/
|
||||
|
||||
void
|
||||
print_backtrace(unsigned long *sp)
|
||||
{
|
||||
int cnt = 0;
|
||||
unsigned long i;
|
||||
|
||||
printf("Call backtrace: ");
|
||||
while (sp) {
|
||||
if ((uint)sp > END_OF_MEM)
|
||||
break;
|
||||
|
||||
i = sp[1];
|
||||
if (cnt++ % 7 == 0)
|
||||
printf("\n");
|
||||
printf("%08lX ", i);
|
||||
if (cnt > 32) break;
|
||||
sp = (unsigned long *)*sp;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs * regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
|
||||
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
|
||||
printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
|
||||
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
|
||||
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
|
||||
regs->msr&MSR_IR ? 1 : 0,
|
||||
regs->msr&MSR_DR ? 1 : 0);
|
||||
|
||||
printf("\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((i % 8) == 0)
|
||||
{
|
||||
printf("GPR%02d: ", i);
|
||||
}
|
||||
|
||||
printf("%08lX ", regs->gpr[i]);
|
||||
if ((i % 8) == 7)
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_exception(int signr, struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
|
||||
}
|
||||
|
||||
void
|
||||
MachineCheckException(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fixup;
|
||||
|
||||
/* Probing PCI using config cycles cause this exception
|
||||
* when a device is not present. Catch it and return to
|
||||
* the PCI exception handler.
|
||||
*/
|
||||
if ((fixup = search_exception_table(regs->nip)) != 0) {
|
||||
regs->nip = fixup;
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("Machine check in kernel mode.\n");
|
||||
printf("Caused by (from msr): ");
|
||||
printf("regs %p ",regs);
|
||||
switch( regs->msr & 0x0000F000)
|
||||
{
|
||||
case (1<<12) :
|
||||
printf("Machine check signal - probably due to mm fault\n"
|
||||
"with mmu off\n");
|
||||
break;
|
||||
case (1<<13) :
|
||||
printf("Transfer error ack signal\n");
|
||||
break;
|
||||
case (1<<14) :
|
||||
printf("Data parity signal\n");
|
||||
break;
|
||||
case (1<<15) :
|
||||
printf("Address parity signal\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown values in msr\n");
|
||||
}
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("machine check");
|
||||
}
|
||||
|
||||
void
|
||||
AlignmentException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Alignment Exception");
|
||||
}
|
||||
|
||||
void
|
||||
ProgramCheckException(struct pt_regs *regs)
|
||||
{
|
||||
long esr_val;
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
show_regs(regs);
|
||||
|
||||
esr_val = get_esr();
|
||||
if( esr_val & ESR_PIL )
|
||||
printf( "** Illegal Instruction **\n" );
|
||||
else if( esr_val & ESR_PPR )
|
||||
printf( "** Privileged Instruction **\n" );
|
||||
else if( esr_val & ESR_PTR )
|
||||
printf( "** Trap Instruction **\n" );
|
||||
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Program Check Exception");
|
||||
}
|
||||
|
||||
void
|
||||
PITException(struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* Reset PIT interrupt
|
||||
*/
|
||||
set_tsr(0x08000000);
|
||||
|
||||
/*
|
||||
* Call timer_interrupt routine in interrupts.c
|
||||
*/
|
||||
timer_interrupt(NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UnknownException(struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
|
||||
regs->nip, regs->msr, regs->trap);
|
||||
_exception(0, regs);
|
||||
}
|
||||
|
||||
void
|
||||
DebugException(struct pt_regs *regs)
|
||||
{
|
||||
printf("Debugger trap at @ %lx\n", regs->nip );
|
||||
show_regs(regs);
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
do_bedbug_breakpoint( regs );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Probe an address by reading. If not present, return -1, otherwise
|
||||
* return 0.
|
||||
*/
|
||||
int
|
||||
addr_probe(uint *addr)
|
||||
{
|
||||
#if 0
|
||||
int retval;
|
||||
|
||||
__asm__ __volatile__( \
|
||||
"1: lwz %0,0(%1)\n" \
|
||||
" eieio\n" \
|
||||
" li %0,0\n" \
|
||||
"2:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: li %0,-1\n" \
|
||||
" b 2b\n" \
|
||||
".section __ex_table,\"a\"\n" \
|
||||
" .align 2\n" \
|
||||
" .long 1b,3b\n" \
|
||||
".text" \
|
||||
: "=r" (retval) : "r"(addr));
|
||||
|
||||
return (retval);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* (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 <command.h>
|
||||
#include <ide.h>
|
||||
#include <cmd_disk.h>
|
||||
|
||||
#undef PART_DEBUG
|
||||
|
||||
#ifdef PART_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* reports device info to the user
|
||||
*/
|
||||
void dev_print (block_dev_desc_t *dev_desc)
|
||||
{
|
||||
ulong lba512; /* number of blocks if 512bytes block size */
|
||||
|
||||
if (dev_desc->type==DEV_TYPE_UNKNOWN) {
|
||||
puts ("not available\n");
|
||||
return;
|
||||
}
|
||||
if (dev_desc->if_type==IF_TYPE_SCSI) {
|
||||
printf ("(%d:%d) ", dev_desc->target,dev_desc->lun);
|
||||
}
|
||||
if (dev_desc->if_type==IF_TYPE_IDE) {
|
||||
printf ("Model: %s Firm: %s Ser#: %s\n",
|
||||
dev_desc->vendor,
|
||||
dev_desc->revision,
|
||||
dev_desc->product);
|
||||
} else {
|
||||
printf ("Vendor: %s Prod.: %s Rev: %s\n",
|
||||
dev_desc->vendor,
|
||||
dev_desc->product,
|
||||
dev_desc->revision);
|
||||
}
|
||||
puts (" Type: ");
|
||||
if (dev_desc->removable)
|
||||
puts ("Removable ");
|
||||
switch (dev_desc->type & 0x1F) {
|
||||
case DEV_TYPE_HARDDISK: puts ("Hard Disk");
|
||||
break;
|
||||
case DEV_TYPE_CDROM: puts ("CD ROM");
|
||||
break;
|
||||
case DEV_TYPE_OPDISK: puts ("Optical Device");
|
||||
break;
|
||||
case DEV_TYPE_TAPE: puts ("Tape");
|
||||
break;
|
||||
default: printf ("# %02X #", dev_desc->type & 0x1F);
|
||||
break;
|
||||
}
|
||||
puts ("\n");
|
||||
if ((dev_desc->lba * dev_desc->blksz)>0L) {
|
||||
ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
|
||||
|
||||
lba512 = (dev_desc->lba * (dev_desc->blksz/512));
|
||||
|
||||
mb = (10 * lba512) / 2048; /* 2048 = (1024 * 1024) / 512 MB */
|
||||
/* round to 1 digit */
|
||||
mb_quot = mb / 10;
|
||||
mb_rem = mb - (10 * mb_quot);
|
||||
|
||||
gb = mb / 1024;
|
||||
gb_quot = gb / 10;
|
||||
gb_rem = gb - (10 * gb_quot);
|
||||
|
||||
printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n",
|
||||
mb_quot, mb_rem,
|
||||
gb_quot, gb_rem,
|
||||
dev_desc->lba,
|
||||
dev_desc->blksz);
|
||||
} else {
|
||||
puts (" Capacity: not available\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(CONFIG_MAC_PARTITION) || \
|
||||
defined(CONFIG_DOS_PARTITION) || \
|
||||
defined(CONFIG_ISO_PARTITION)
|
||||
|
||||
void init_part (block_dev_desc_t * dev_desc)
|
||||
{
|
||||
#ifdef CONFIG_ISO_PARTITION
|
||||
if (test_part_iso(dev_desc) == 0) {
|
||||
dev_desc->part_type = PART_TYPE_ISO;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MAC_PARTITION
|
||||
if (test_part_mac(dev_desc) == 0) {
|
||||
dev_desc->part_type = PART_TYPE_MAC;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DOS_PARTITION
|
||||
if (test_part_dos(dev_desc) == 0) {
|
||||
dev_desc->part_type = PART_TYPE_DOS;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int get_partition_info (block_dev_desc_t *dev_desc, int part, disk_partition_t *info)
|
||||
{
|
||||
switch (dev_desc->part_type) {
|
||||
#ifdef CONFIG_MAC_PARTITION
|
||||
case PART_TYPE_MAC:
|
||||
if (get_partition_info_mac(dev_desc,part,info) == 0) {
|
||||
PRINTF ("## Valid MAC partition found ##\n");
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DOS_PARTITION
|
||||
case PART_TYPE_DOS:
|
||||
if (get_partition_info_dos(dev_desc,part,info) == 0) {
|
||||
PRINTF ("## Valid DOS partition found ##\n");
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ISO_PARTITION
|
||||
case PART_TYPE_ISO:
|
||||
if (get_partition_info_iso(dev_desc,part,info) == 0) {
|
||||
PRINTF ("## Valid ISO boot partition found ##\n");
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
|
||||
{
|
||||
puts ("\nPartition Map for ");
|
||||
switch (dev_desc->if_type) {
|
||||
case IF_TYPE_IDE: puts ("IDE");
|
||||
break;
|
||||
case IF_TYPE_SCSI: puts ("SCSI");
|
||||
break;
|
||||
case IF_TYPE_ATAPI: puts ("ATAPI");
|
||||
break;
|
||||
case IF_TYPE_USB: puts ("USB");
|
||||
break;
|
||||
case IF_TYPE_DOC: puts ("DOC");
|
||||
break;
|
||||
default: puts ("UNKNOWN");
|
||||
break;
|
||||
}
|
||||
printf (" device %d -- Partition Type: %s\n\n",
|
||||
dev_desc->dev, type);
|
||||
}
|
||||
|
||||
void print_part (block_dev_desc_t * dev_desc)
|
||||
{
|
||||
|
||||
switch (dev_desc->part_type) {
|
||||
#ifdef CONFIG_MAC_PARTITION
|
||||
case PART_TYPE_MAC:
|
||||
PRINTF ("## Testing for valid MAC partition ##\n");
|
||||
print_part_header ("MAC", dev_desc);
|
||||
print_part_mac (dev_desc);
|
||||
return;
|
||||
#endif
|
||||
#ifdef CONFIG_DOS_PARTITION
|
||||
case PART_TYPE_DOS:
|
||||
PRINTF ("## Testing for valid DOS partition ##\n");
|
||||
print_part_header ("DOS", dev_desc);
|
||||
print_part_dos (dev_desc);
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ISO_PARTITION
|
||||
case PART_TYPE_ISO:
|
||||
PRINTF ("## Testing for valid ISO Boot partition ##\n");
|
||||
print_part_header ("ISO", dev_desc);
|
||||
print_part_iso (dev_desc);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
puts ("## Unknown partition table\n");
|
||||
}
|
||||
|
||||
|
||||
#else /* neither MAC nor DOS nor ISO partition configured */
|
||||
# error neither CONFIG_MAC_PARTITION nor CONFIG_DOS_PARTITION nor CONFIG_ISO_PARTITION configured!
|
||||
#endif
|
||||
|
||||
#endif /* (CONFIG_COMMANDS & CFG_CMD_IDE) || CONFIG_COMMANDS & CFG_CMD_SCSI) */
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Support for indirect PCI bridges.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <pci.h>
|
||||
|
||||
#define cfg_read(val, addr, type, op) *val = op((type)(addr))
|
||||
#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
|
||||
|
||||
#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
|
||||
static int \
|
||||
indirect_##rw##_config_##size(struct pci_controller *hose, \
|
||||
pci_dev_t dev, int offset, type val) \
|
||||
{ \
|
||||
out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
|
||||
cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \
|
||||
static int \
|
||||
indirect_##rw##_config_##size(struct pci_controller *hose, \
|
||||
pci_dev_t dev, int offset, type val) \
|
||||
{ \
|
||||
unsigned int msr = mfmsr(); \
|
||||
mtmsr(msr & ~(MSR_EE | MSR_CE)); \
|
||||
out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
|
||||
cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
|
||||
out_le32(hose->cfg_addr, 0x00000000); \
|
||||
mtmsr(msr); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
|
||||
INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
|
||||
INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
|
||||
#ifdef CONFIG_405GP
|
||||
INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3)
|
||||
INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2)
|
||||
INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0)
|
||||
#else
|
||||
INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
|
||||
INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
|
||||
INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
|
||||
#endif
|
||||
|
||||
void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
|
||||
{
|
||||
pci_set_ops(hose,
|
||||
indirect_read_config_byte,
|
||||
indirect_read_config_word,
|
||||
indirect_read_config_dword,
|
||||
indirect_write_config_byte,
|
||||
indirect_write_config_word,
|
||||
indirect_write_config_dword);
|
||||
|
||||
hose->cfg_addr = (unsigned int *) cfg_addr;
|
||||
hose->cfg_data = (unsigned char *) cfg_data;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright 1998-2001 by Donald Becker.
|
||||
* This software may be used and distributed according to the terms of
|
||||
* the GNU General Public License (GPL), incorporated herein by reference.
|
||||
* Contact the author for use under other terms.
|
||||
*
|
||||
* This program must be compiled with "-O"!
|
||||
* See the bottom of this file for the suggested compile-command.
|
||||
*
|
||||
* The author may be reached as becker@scyld.com, or C/O
|
||||
* Scyld Computing Corporation
|
||||
* 410 Severn Ave., Suite 210
|
||||
* Annapolis MD 21403
|
||||
*
|
||||
* Common-sense licensing statement: Using any portion of this program in
|
||||
* your own program means that you must give credit to the original author
|
||||
* and release the resulting code under the GPL.
|
||||
*/
|
||||
|
||||
#define _PPC_STRING_H_ /* avoid unnecessary str/mem functions */
|
||||
#define _LINUX_STRING_H_ /* avoid unnecessary str/mem functions */
|
||||
|
||||
#include <common.h>
|
||||
#include <syscall.h>
|
||||
|
||||
static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr);
|
||||
|
||||
int eepro100_eeprom(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
unsigned char hwaddr1[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x05 };
|
||||
unsigned char hwaddr2[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x06 };
|
||||
|
||||
#if defined(CONFIG_OXC)
|
||||
ret |= reset_eeprom(0x80000000, hwaddr1);
|
||||
ret |= reset_eeprom(0x81000000, hwaddr2);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Default EEPROM for i82559 */
|
||||
static unsigned short default_eeprom[64] = {
|
||||
0x0100, 0x0302, 0x0504, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0x40c0, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
|
||||
};
|
||||
|
||||
static unsigned short eeprom[256];
|
||||
|
||||
static int eeprom_size = 64;
|
||||
static int eeprom_addr_size = 6;
|
||||
|
||||
static int debug = 0;
|
||||
|
||||
static inline unsigned short swap16(unsigned short x)
|
||||
{
|
||||
return (((x & 0xff) << 8) | ((x & 0xff00) >> 8));
|
||||
}
|
||||
|
||||
static inline void outw(short data, long addr)
|
||||
{
|
||||
*(volatile short *)(addr) = swap16(data);
|
||||
}
|
||||
|
||||
static inline short inw(long addr)
|
||||
{
|
||||
return swap16(*(volatile short *)(addr));
|
||||
}
|
||||
|
||||
static inline void *memcpy(void *dst, const void *src, unsigned int len)
|
||||
{
|
||||
void * ret = dst;
|
||||
while (len-- > 0) *((char *)dst)++ = *((char *)src)++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The EEPROM commands include the alway-set leading bit. */
|
||||
#define EE_WRITE_CMD (5)
|
||||
#define EE_READ_CMD (6)
|
||||
#define EE_ERASE_CMD (7)
|
||||
|
||||
/* Serial EEPROM section. */
|
||||
#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
|
||||
#define EE_CS 0x02 /* EEPROM chip select. */
|
||||
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
|
||||
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
|
||||
#define EE_ENB (0x4800 | EE_CS)
|
||||
#define EE_WRITE_0 0x4802
|
||||
#define EE_WRITE_1 0x4806
|
||||
#define EE_OFFSET 14
|
||||
|
||||
/* Delay between EEPROM clock transitions. */
|
||||
#define eeprom_delay(ee_addr) inw(ee_addr)
|
||||
|
||||
/* Wait for the EEPROM to finish the previous operation. */
|
||||
static int eeprom_busy_poll(long ee_ioaddr)
|
||||
{
|
||||
int i;
|
||||
outw(EE_ENB, ee_ioaddr);
|
||||
for (i = 0; i < 10000; i++) /* Typical 2000 ticks */
|
||||
if (inw(ee_ioaddr) & EE_DATA_READ)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* This executes a generic EEPROM command, typically a write or write enable.
|
||||
It returns the data output from the EEPROM, and thus may also be used for
|
||||
reads. */
|
||||
static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
|
||||
{
|
||||
unsigned retval = 0;
|
||||
long ee_addr = ioaddr + EE_OFFSET;
|
||||
|
||||
if (debug > 1)
|
||||
mon_printf(" EEPROM op 0x%x: ", cmd);
|
||||
|
||||
outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
|
||||
|
||||
/* Shift the command bits out. */
|
||||
do {
|
||||
short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
|
||||
outw(dataval, ee_addr);
|
||||
eeprom_delay(ee_addr);
|
||||
if (debug > 2)
|
||||
mon_printf("%X", inw(ee_addr) & 15);
|
||||
outw(dataval | EE_SHIFT_CLK, ee_addr);
|
||||
eeprom_delay(ee_addr);
|
||||
retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
|
||||
} while (--cmd_len >= 0);
|
||||
#if 0
|
||||
outw(EE_ENB, ee_addr);
|
||||
#endif
|
||||
/* Terminate the EEPROM access. */
|
||||
outw(EE_ENB & ~EE_CS, ee_addr);
|
||||
if (debug > 1)
|
||||
mon_printf(" EEPROM result is 0x%5.5x.\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int read_eeprom(long ioaddr, int location, int addr_len)
|
||||
{
|
||||
return do_eeprom_cmd(ioaddr, ((EE_READ_CMD << addr_len) | location)
|
||||
<< 16 , 3 + addr_len + 16) & 0xffff;
|
||||
}
|
||||
|
||||
static void write_eeprom(long ioaddr, int index, int value, int addr_len)
|
||||
{
|
||||
long ee_ioaddr = ioaddr + EE_OFFSET;
|
||||
int i;
|
||||
|
||||
/* Poll for previous op finished. */
|
||||
eeprom_busy_poll(ee_ioaddr); /* Typical 0 ticks */
|
||||
/* Enable programming modes. */
|
||||
do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len);
|
||||
/* Do the actual write. */
|
||||
do_eeprom_cmd(ioaddr,
|
||||
(((EE_WRITE_CMD<<addr_len) | index)<<16) | (value & 0xffff),
|
||||
3 + addr_len + 16);
|
||||
/* Poll for write finished. */
|
||||
i = eeprom_busy_poll(ee_ioaddr); /* Typical 2000 ticks */
|
||||
if (debug)
|
||||
mon_printf(" Write finished after %d ticks.\n", i);
|
||||
/* Disable programming. This command is not instantaneous, so we check
|
||||
for busy before the next op. */
|
||||
do_eeprom_cmd(ioaddr, (0x40 << (addr_len-4)), 3 + addr_len);
|
||||
eeprom_busy_poll(ee_ioaddr);
|
||||
}
|
||||
|
||||
static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr)
|
||||
{
|
||||
unsigned short checksum = 0;
|
||||
int size_test;
|
||||
int i;
|
||||
|
||||
mon_printf("Resetting i82559 EEPROM @ 0x%08x ... ", ioaddr);
|
||||
|
||||
size_test = do_eeprom_cmd(ioaddr, (EE_READ_CMD << 8) << 16, 27);
|
||||
eeprom_addr_size = (size_test & 0xffe0000) == 0xffe0000 ? 8 : 6;
|
||||
eeprom_size = 1 << eeprom_addr_size;
|
||||
|
||||
memcpy(eeprom, default_eeprom, sizeof default_eeprom);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
eeprom[i] = (hwaddr[i*2+1]<<8) + hwaddr[i*2];
|
||||
|
||||
/* Recalculate the checksum. */
|
||||
for (i = 0; i < eeprom_size - 1; i++)
|
||||
checksum += eeprom[i];
|
||||
eeprom[i] = 0xBABA - checksum;
|
||||
|
||||
for (i = 0; i < eeprom_size; i++)
|
||||
write_eeprom(ioaddr, i, eeprom[i], eeprom_addr_size);
|
||||
|
||||
for (i = 0; i < eeprom_size; i++)
|
||||
if (read_eeprom(ioaddr, i, eeprom_addr_size) != eeprom[i]) {
|
||||
mon_printf("failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mon_printf("done\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* (C) Copyright 2000
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _PCMCIA_H
|
||||
#define _PCMCIA_H
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
|
||||
/*
|
||||
* Allow configuration to select PCMCIA slot,
|
||||
* or try to generate a useful default
|
||||
*/
|
||||
#if ( CONFIG_COMMANDS & CFG_CMD_PCMCIA) || \
|
||||
((CONFIG_COMMANDS & CFG_CMD_IDE) && \
|
||||
(defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) ) )
|
||||
|
||||
#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
|
||||
|
||||
/* The RPX series use SLOT_B */
|
||||
#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
|
||||
# define CONFIG_PCMCIA_SLOT_B
|
||||
#elif defined(CONFIG_ADS) /* The ADS board use SLOT_A */
|
||||
# define CONFIG_PCMCIA_SLOT_A
|
||||
#elif defined(CONFIG_FADS) /* The FADS series are a mess */
|
||||
# if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821)
|
||||
# define CONFIG_PCMCIA_SLOT_A
|
||||
# else
|
||||
# define CONFIG_PCMCIA_SLOT_B
|
||||
# endif
|
||||
#elif defined(CONFIG_TQM8xxL)
|
||||
# define CONFIG_PCMCIA_SLOT_B /* The TQM8xxL use SLOT_B */
|
||||
#elif defined(CONFIG_SPD823TS) /* The SPD8xx use SLOT_B */
|
||||
# define CONFIG_PCMCIA_SLOT_B
|
||||
#elif defined(CONFIG_IVMS8) || defined(CONFIG_IVML24) /* The IVM* use SLOT_A */
|
||||
# define CONFIG_PCMCIA_SLOT_A
|
||||
#elif defined(CONFIG_LWMON) /* The LWMON use SLOT_B */
|
||||
# define CONFIG_PCMCIA_SLOT_B
|
||||
#elif defined(CONFIG_ICU862) /* The ICU862 use SLOT_B */
|
||||
# define CONFIG_PCMCIA_SLOT_B
|
||||
#elif defined(CONFIG_C2MON) /* The C2MON use SLOT_B */
|
||||
# define CONFIG_PCMCIA_SLOT_B
|
||||
#elif defined(CONFIG_R360MPI) /* The R360MPI use SLOT_B */
|
||||
# define CONFIG_PCMCIA_SLOT_B
|
||||
#else
|
||||
# error "PCMCIA Slot not configured"
|
||||
#endif
|
||||
|
||||
#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
|
||||
|
||||
/* Make sure exactly one slot is defined - we support only one for now */
|
||||
#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
|
||||
#error Neither CONFIG_PCMCIA_SLOT_A nor CONFIG_PCMCIA_SLOT_B configured
|
||||
#endif
|
||||
#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
|
||||
#error Both CONFIG_PCMCIA_SLOT_A and CONFIG_PCMCIA_SLOT_B configured
|
||||
#endif
|
||||
|
||||
#define PCMCIA_SOCKETS_NO 1
|
||||
#define PCMCIA_MEM_WIN_NO 4
|
||||
#define PCMCIA_IO_WIN_NO 2
|
||||
|
||||
/* define _slot_ to be able to optimize macros */
|
||||
#ifdef CONFIG_PCMCIA_SLOT_A
|
||||
# define _slot_ 0
|
||||
# define PCMCIA_SLOT_MSG "slot A"
|
||||
# define PCMCIA_SLOT_x PCMCIA_PSLOT_A
|
||||
#else
|
||||
# define _slot_ 1
|
||||
# define PCMCIA_SLOT_MSG "slot B"
|
||||
# define PCMCIA_SLOT_x PCMCIA_PSLOT_B
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The TQM850L hardware has two pins swapped! Grrrrgh!
|
||||
*/
|
||||
#ifdef CONFIG_TQM850L
|
||||
#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXOE
|
||||
#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXRESET
|
||||
#else
|
||||
#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXRESET
|
||||
#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXOE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This structure is used to address each window in the PCMCIA controller.
|
||||
*
|
||||
* Keep in mind that we assume that pcmcia_win_t[n+1] is mapped directly
|
||||
* after pcmcia_win_t[n]...
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
ulong br;
|
||||
ulong or;
|
||||
} pcmcia_win_t;
|
||||
|
||||
/*
|
||||
* Definitions for PCMCIA control registers to operate in IDE mode
|
||||
*
|
||||
* All timing related setup (PCMCIA_SHT, PCMCIA_SST, PCMCIA_SL)
|
||||
* to be done later (depending on CPU clock)
|
||||
*/
|
||||
|
||||
/* Window 0:
|
||||
* Base: 0xFE100000 CS1
|
||||
* Port Size: 2 Bytes
|
||||
* Port Size: 16 Bit
|
||||
* Common Memory Space
|
||||
*/
|
||||
|
||||
#define CFG_PCMCIA_PBR0 0xFE100000
|
||||
#define CFG_PCMCIA_POR0 ( PCMCIA_BSIZE_2 \
|
||||
| PCMCIA_PPS_16 \
|
||||
| PCMCIA_PRS_MEM \
|
||||
| PCMCIA_SLOT_x \
|
||||
| PCMCIA_PV \
|
||||
)
|
||||
|
||||
/* Window 1:
|
||||
* Base: 0xFE100080 CS1
|
||||
* Port Size: 8 Bytes
|
||||
* Port Size: 8 Bit
|
||||
* Common Memory Space
|
||||
*/
|
||||
|
||||
#define CFG_PCMCIA_PBR1 0xFE100080
|
||||
#define CFG_PCMCIA_POR1 ( PCMCIA_BSIZE_8 \
|
||||
| PCMCIA_PPS_8 \
|
||||
| PCMCIA_PRS_MEM \
|
||||
| PCMCIA_SLOT_x \
|
||||
| PCMCIA_PV \
|
||||
)
|
||||
|
||||
/* Window 2:
|
||||
* Base: 0xFE100100 CS2
|
||||
* Port Size: 8 Bytes
|
||||
* Port Size: 8 Bit
|
||||
* Common Memory Space
|
||||
*/
|
||||
|
||||
#define CFG_PCMCIA_PBR2 0xFE100100
|
||||
#define CFG_PCMCIA_POR2 ( PCMCIA_BSIZE_8 \
|
||||
| PCMCIA_PPS_8 \
|
||||
| PCMCIA_PRS_MEM \
|
||||
| PCMCIA_SLOT_x \
|
||||
| PCMCIA_PV \
|
||||
)
|
||||
|
||||
/* Window 3:
|
||||
* not used
|
||||
*/
|
||||
#define CFG_PCMCIA_PBR3 0
|
||||
#define CFG_PCMCIA_POR3 0
|
||||
|
||||
/* Window 4:
|
||||
* Base: 0xFE100C00 CS1
|
||||
* Port Size: 2 Bytes
|
||||
* Port Size: 16 Bit
|
||||
* Common Memory Space
|
||||
*/
|
||||
|
||||
#define CFG_PCMCIA_PBR4 0xFE100C00
|
||||
#define CFG_PCMCIA_POR4 ( PCMCIA_BSIZE_2 \
|
||||
| PCMCIA_PPS_16 \
|
||||
| PCMCIA_PRS_MEM \
|
||||
| PCMCIA_SLOT_x \
|
||||
| PCMCIA_PV \
|
||||
)
|
||||
|
||||
/* Window 5:
|
||||
* Base: 0xFE100C80 CS1
|
||||
* Port Size: 8 Bytes
|
||||
* Port Size: 8 Bit
|
||||
* Common Memory Space
|
||||
*/
|
||||
|
||||
#define CFG_PCMCIA_PBR5 0xFE100C80
|
||||
#define CFG_PCMCIA_POR5 ( PCMCIA_BSIZE_8 \
|
||||
| PCMCIA_PPS_8 \
|
||||
| PCMCIA_PRS_MEM \
|
||||
| PCMCIA_SLOT_x \
|
||||
| PCMCIA_PV \
|
||||
)
|
||||
|
||||
/* Window 6:
|
||||
* Base: 0xFE100D00 CS2
|
||||
* Port Size: 8 Bytes
|
||||
* Port Size: 8 Bit
|
||||
* Common Memory Space
|
||||
*/
|
||||
|
||||
#define CFG_PCMCIA_PBR6 0xFE100D00
|
||||
#define CFG_PCMCIA_POR6 ( PCMCIA_BSIZE_8 \
|
||||
| PCMCIA_PPS_8 \
|
||||
| PCMCIA_PRS_MEM \
|
||||
| PCMCIA_SLOT_x \
|
||||
| PCMCIA_PV \
|
||||
)
|
||||
|
||||
/* Window 7:
|
||||
* not used
|
||||
*/
|
||||
#define CFG_PCMCIA_PBR7 0
|
||||
#define CFG_PCMCIA_POR7 0
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*
|
||||
* CIS Tupel codes
|
||||
*/
|
||||
#define CISTPL_NULL 0x00
|
||||
#define CISTPL_DEVICE 0x01
|
||||
#define CISTPL_LONGLINK_CB 0x02
|
||||
#define CISTPL_INDIRECT 0x03
|
||||
#define CISTPL_CONFIG_CB 0x04
|
||||
#define CISTPL_CFTABLE_ENTRY_CB 0x05
|
||||
#define CISTPL_LONGLINK_MFC 0x06
|
||||
#define CISTPL_BAR 0x07
|
||||
#define CISTPL_PWR_MGMNT 0x08
|
||||
#define CISTPL_EXTDEVICE 0x09
|
||||
#define CISTPL_CHECKSUM 0x10
|
||||
#define CISTPL_LONGLINK_A 0x11
|
||||
#define CISTPL_LONGLINK_C 0x12
|
||||
#define CISTPL_LINKTARGET 0x13
|
||||
#define CISTPL_NO_LINK 0x14
|
||||
#define CISTPL_VERS_1 0x15
|
||||
#define CISTPL_ALTSTR 0x16
|
||||
#define CISTPL_DEVICE_A 0x17
|
||||
#define CISTPL_JEDEC_C 0x18
|
||||
#define CISTPL_JEDEC_A 0x19
|
||||
#define CISTPL_CONFIG 0x1a
|
||||
#define CISTPL_CFTABLE_ENTRY 0x1b
|
||||
#define CISTPL_DEVICE_OC 0x1c
|
||||
#define CISTPL_DEVICE_OA 0x1d
|
||||
#define CISTPL_DEVICE_GEO 0x1e
|
||||
#define CISTPL_DEVICE_GEO_A 0x1f
|
||||
#define CISTPL_MANFID 0x20
|
||||
#define CISTPL_FUNCID 0x21
|
||||
#define CISTPL_FUNCE 0x22
|
||||
#define CISTPL_SWIL 0x23
|
||||
#define CISTPL_END 0xff
|
||||
|
||||
/*
|
||||
* CIS Function ID codes
|
||||
*/
|
||||
#define CISTPL_FUNCID_MULTI 0x00
|
||||
#define CISTPL_FUNCID_MEMORY 0x01
|
||||
#define CISTPL_FUNCID_SERIAL 0x02
|
||||
#define CISTPL_FUNCID_PARALLEL 0x03
|
||||
#define CISTPL_FUNCID_FIXED 0x04
|
||||
#define CISTPL_FUNCID_VIDEO 0x05
|
||||
#define CISTPL_FUNCID_NETWORK 0x06
|
||||
#define CISTPL_FUNCID_AIMS 0x07
|
||||
#define CISTPL_FUNCID_SCSI 0x08
|
||||
|
||||
/*
|
||||
* Fixed Disk FUNCE codes
|
||||
*/
|
||||
#define CISTPL_IDE_INTERFACE 0x01
|
||||
|
||||
#define CISTPL_FUNCE_IDE_IFACE 0x01
|
||||
#define CISTPL_FUNCE_IDE_MASTER 0x02
|
||||
#define CISTPL_FUNCE_IDE_SLAVE 0x03
|
||||
|
||||
/* First feature byte */
|
||||
#define CISTPL_IDE_SILICON 0x04
|
||||
#define CISTPL_IDE_UNIQUE 0x08
|
||||
#define CISTPL_IDE_DUAL 0x10
|
||||
|
||||
/* Second feature byte */
|
||||
#define CISTPL_IDE_HAS_SLEEP 0x01
|
||||
#define CISTPL_IDE_HAS_STANDBY 0x02
|
||||
#define CISTPL_IDE_HAS_IDLE 0x04
|
||||
#define CISTPL_IDE_LOW_POWER 0x08
|
||||
#define CISTPL_IDE_REG_INHIBIT 0x10
|
||||
#define CISTPL_IDE_HAS_INDEX 0x20
|
||||
#define CISTPL_IDE_IOIS16 0x40
|
||||
|
||||
#endif /* CFG_CMD_PCMCIA || CFG_CMD_IDE && (CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT) */
|
||||
|
||||
#endif /* _PCMCIA_H */
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef __MON_SYS_CALL_H__
|
||||
#define __MON_SYS_CALL_H__
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/* These are declarations of system calls available in C code */
|
||||
int mon_getc(void);
|
||||
int mon_tstc(void);
|
||||
void mon_putc(const char);
|
||||
void mon_puts(const char*);
|
||||
void mon_printf(const char* fmt, ...);
|
||||
void mon_install_hdlr(int, interrupt_handler_t*, void*);
|
||||
void mon_free_hdlr(int);
|
||||
void *mon_malloc(size_t);
|
||||
void mon_free(void*);
|
||||
|
||||
#endif /* ifndef __ASSEMBLY__ */
|
||||
|
||||
#define NR_SYSCALLS 9 /* number of syscalls */
|
||||
|
||||
/*
|
||||
* Make sure these functions are in the same order as they
|
||||
* appear in the "examples/syscall.S" file !!!
|
||||
*/
|
||||
#define SYSCALL_GETC 0
|
||||
#define SYSCALL_TSTC 1
|
||||
#define SYSCALL_PUTC 2
|
||||
#define SYSCALL_PUTS 3
|
||||
#define SYSCALL_PRINTF 4
|
||||
#define SYSCALL_INSTALL_HDLR 5
|
||||
#define SYSCALL_FREE_HDLR 6
|
||||
#define SYSCALL_MALLOC 7
|
||||
#define SYSCALL_FREE 8
|
||||
|
||||
#endif
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* This file is derived from crc32.c from the zlib-1.1.3 distribution
|
||||
* by Jean-loup Gailly and Mark Adler.
|
||||
*/
|
||||
|
||||
/* crc32.c -- compute the CRC-32 of a data stream
|
||||
* Copyright (C) 1995-1998 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#ifndef USE_HOSTCC /* Shut down "ANSI does not permit..." warnings */
|
||||
#include <common.h> /* to get command definitions like CFG_CMD_JFFS2 */
|
||||
#endif
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
#define local static
|
||||
#define ZEXPORT /* empty */
|
||||
unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
|
||||
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
|
||||
local int crc_table_empty = 1;
|
||||
local uLongf crc_table[256];
|
||||
local void make_crc_table OF((void));
|
||||
|
||||
/*
|
||||
Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
|
||||
x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
|
||||
|
||||
Polynomials over GF(2) are represented in binary, one bit per coefficient,
|
||||
with the lowest powers in the most significant bit. Then adding polynomials
|
||||
is just exclusive-or, and multiplying a polynomial by x is a right shift by
|
||||
one. If we call the above polynomial p, and represent a byte as the
|
||||
polynomial q, also with the lowest power in the most significant bit (so the
|
||||
byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
|
||||
where a mod b means the remainder after dividing a by b.
|
||||
|
||||
This calculation is done using the shift-register method of multiplying and
|
||||
taking the remainder. The register is initialized to zero, and for each
|
||||
incoming bit, x^32 is added mod p to the register if the bit is a one (where
|
||||
x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
|
||||
x (which is shifting right by one and adding x^32 mod p if the bit shifted
|
||||
out is a one). We start with the highest power (least significant bit) of
|
||||
q and repeat for all eight bits of q.
|
||||
|
||||
The table is simply the CRC of all possible eight bit values. This is all
|
||||
the information needed to generate CRC's on data a byte at a time for all
|
||||
combinations of CRC register values and incoming bytes.
|
||||
*/
|
||||
local void make_crc_table()
|
||||
{
|
||||
uLong c;
|
||||
int n, k;
|
||||
uLong poly; /* polynomial exclusive-or pattern */
|
||||
/* terms of polynomial defining this crc (except x^32): */
|
||||
static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
|
||||
|
||||
/* make exclusive-or pattern from polynomial (0xedb88320L) */
|
||||
poly = 0L;
|
||||
for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
|
||||
poly |= 1L << (31 - p[n]);
|
||||
|
||||
for (n = 0; n < 256; n++)
|
||||
{
|
||||
c = (uLong)n;
|
||||
for (k = 0; k < 8; k++)
|
||||
c = c & 1 ? poly ^ (c >> 1) : c >> 1;
|
||||
crc_table[n] = c;
|
||||
}
|
||||
crc_table_empty = 0;
|
||||
}
|
||||
#else
|
||||
/* ========================================================================
|
||||
* Table of CRC-32's of all single-byte values (made by make_crc_table)
|
||||
*/
|
||||
local const uLongf crc_table[256] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* =========================================================================
|
||||
* This function can be used by asm versions of crc32()
|
||||
*/
|
||||
const uLongf * ZEXPORT get_crc_table()
|
||||
{
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
if (crc_table_empty) make_crc_table();
|
||||
#endif
|
||||
return (const uLongf *)crc_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
|
||||
#define DO2(buf) DO1(buf); DO1(buf);
|
||||
#define DO4(buf) DO2(buf); DO2(buf);
|
||||
#define DO8(buf) DO4(buf); DO4(buf);
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT crc32(crc, buf, len)
|
||||
uLong crc;
|
||||
const Bytef *buf;
|
||||
uInt len;
|
||||
{
|
||||
if (buf == Z_NULL) return 0L;
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
if (crc_table_empty)
|
||||
make_crc_table();
|
||||
#endif
|
||||
crc = crc ^ 0xffffffffL;
|
||||
while (len >= 8)
|
||||
{
|
||||
DO8(buf);
|
||||
len -= 8;
|
||||
}
|
||||
if (len) do {
|
||||
DO1(buf);
|
||||
} while (--len);
|
||||
return crc ^ 0xffffffffL;
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
|
||||
|
||||
/* No ones complement version. JFFS2 (and other things ?)
|
||||
* don't use ones compliment in their CRC calculations.
|
||||
*/
|
||||
uLong ZEXPORT crc32_no_comp(uLong crc, const Bytef *buf, uInt len)
|
||||
{
|
||||
if (buf == Z_NULL) return 0L;
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
if (crc_table_empty)
|
||||
make_crc_table();
|
||||
#endif
|
||||
while (len >= 8)
|
||||
{
|
||||
DO8(buf);
|
||||
len -= 8;
|
||||
}
|
||||
if (len) do {
|
||||
DO1(buf);
|
||||
} while (--len);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_JFFS2 */
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
|
||||
*
|
||||
* 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 <asm/processor.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
int write_bat (ppc_bat_t bat, unsigned long upper, unsigned long lower)
|
||||
{
|
||||
switch (bat) {
|
||||
case IBAT0:
|
||||
mtspr (IBAT0L, lower);
|
||||
mtspr (IBAT0U, upper);
|
||||
break;
|
||||
|
||||
case IBAT1:
|
||||
mtspr (IBAT1L, lower);
|
||||
mtspr (IBAT1U, upper);
|
||||
break;
|
||||
|
||||
case IBAT2:
|
||||
mtspr (IBAT2L, lower);
|
||||
mtspr (IBAT2U, upper);
|
||||
break;
|
||||
|
||||
case IBAT3:
|
||||
mtspr (IBAT3L, lower);
|
||||
mtspr (IBAT3U, upper);
|
||||
break;
|
||||
|
||||
case DBAT0:
|
||||
mtspr (DBAT0L, lower);
|
||||
mtspr (DBAT0U, upper);
|
||||
break;
|
||||
|
||||
case DBAT1:
|
||||
mtspr (DBAT1L, lower);
|
||||
mtspr (DBAT1U, upper);
|
||||
break;
|
||||
|
||||
case DBAT2:
|
||||
mtspr (DBAT2L, lower);
|
||||
mtspr (DBAT2U, upper);
|
||||
break;
|
||||
|
||||
case DBAT3:
|
||||
mtspr (DBAT3L, lower);
|
||||
mtspr (DBAT3U, upper);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int read_bat (ppc_bat_t bat, unsigned long *upper, unsigned long *lower)
|
||||
{
|
||||
unsigned long register u;
|
||||
unsigned long register l;
|
||||
|
||||
switch (bat) {
|
||||
case IBAT0:
|
||||
l = mfspr (IBAT0L);
|
||||
u = mfspr (IBAT0U);
|
||||
break;
|
||||
|
||||
case IBAT1:
|
||||
l = mfspr (IBAT1L);
|
||||
u = mfspr (IBAT1U);
|
||||
break;
|
||||
|
||||
case IBAT2:
|
||||
l = mfspr (IBAT2L);
|
||||
u = mfspr (IBAT2U);
|
||||
break;
|
||||
|
||||
case IBAT3:
|
||||
l = mfspr (IBAT3L);
|
||||
u = mfspr (IBAT3U);
|
||||
break;
|
||||
|
||||
case DBAT0:
|
||||
l = mfspr (DBAT0L);
|
||||
u = mfspr (DBAT0U);
|
||||
break;
|
||||
|
||||
case DBAT1:
|
||||
l = mfspr (DBAT1L);
|
||||
u = mfspr (DBAT1U);
|
||||
break;
|
||||
|
||||
case DBAT2:
|
||||
l = mfspr (DBAT2L);
|
||||
u = mfspr (DBAT2U);
|
||||
break;
|
||||
|
||||
case DBAT3:
|
||||
l = mfspr (DBAT3L);
|
||||
u = mfspr (DBAT3U);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*upper = u;
|
||||
*lower = l;
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* 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>
|
||||
|
||||
void flush_cache (ulong start_addr, ulong size)
|
||||
{
|
||||
ulong addr, end_addr = start_addr + size;
|
||||
|
||||
if (CFG_CACHELINE_SIZE) {
|
||||
addr = start_addr & (CFG_CACHELINE_SIZE - 1);
|
||||
for (addr = start_addr;
|
||||
addr < end_addr;
|
||||
addr += CFG_CACHELINE_SIZE) {
|
||||
asm ("dcbst 0,%0": :"r" (addr));
|
||||
}
|
||||
asm ("sync"); /* Wait for all dcbst to complete on bus */
|
||||
|
||||
for (addr = start_addr;
|
||||
addr < end_addr;
|
||||
addr += CFG_CACHELINE_SIZE) {
|
||||
asm ("icbi 0,%0": :"r" (addr));
|
||||
}
|
||||
}
|
||||
asm ("sync"); /* Always flush prefetch queue in any case */
|
||||
asm ("isync");
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* 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 <command.h>
|
||||
#include <net.h>
|
||||
#include "bootp.h"
|
||||
#include "rarp.h"
|
||||
#include "tftp.h"
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_NET)
|
||||
|
||||
#define TIMEOUT 5 /* Seconds before trying BOOTP again */
|
||||
#ifndef CONFIG_NET_RETRY_COUNT
|
||||
# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
|
||||
#else
|
||||
# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
|
||||
#endif
|
||||
|
||||
|
||||
int RarpTry;
|
||||
|
||||
/*
|
||||
* Handle a RARP received packet.
|
||||
*/
|
||||
static void
|
||||
RarpHandler(uchar * dummi0, unsigned dummi1, unsigned dummi2, unsigned dummi3)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Got good RARP\n");
|
||||
#endif
|
||||
TftpStart ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Timeout on BOOTP request.
|
||||
*/
|
||||
static void
|
||||
RarpTimeout(void)
|
||||
{
|
||||
if (RarpTry >= TIMEOUT_COUNT) {
|
||||
puts ("\nRetry count exceeded; starting again\n");
|
||||
NetStartAgain ();
|
||||
} else {
|
||||
NetSetTimeout (TIMEOUT * CFG_HZ, RarpTimeout);
|
||||
RarpRequest ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RarpRequest (void)
|
||||
{
|
||||
int i;
|
||||
volatile uchar *pkt;
|
||||
ARP_t * rarp;
|
||||
|
||||
printf("RARP broadcast %d\n", ++RarpTry);
|
||||
pkt = NetTxPacket;
|
||||
|
||||
NetSetEther(pkt, NetBcastAddr, PROT_RARP);
|
||||
pkt += ETHER_HDR_SIZE;
|
||||
|
||||
rarp = (ARP_t *)pkt;
|
||||
|
||||
rarp->ar_hrd = ARP_ETHER;
|
||||
rarp->ar_pro = PROT_IP;
|
||||
rarp->ar_hln = 6;
|
||||
rarp->ar_pln = 4;
|
||||
rarp->ar_op = RARPOP_REQUEST;
|
||||
memcpy (&rarp->ar_data[0], NetOurEther, 6); /* source ET addr */
|
||||
memcpy (&rarp->ar_data[6], &NetOurIP, 4); /* source IP addr */
|
||||
memcpy (&rarp->ar_data[10], NetOurEther, 6); /* dest ET addr = source ET addr ??*/
|
||||
/* dest. IP addr set to broadcast */
|
||||
for (i = 0; i <= 3; i++) {
|
||||
rarp->ar_data[16 + i] = 0xff;
|
||||
}
|
||||
|
||||
NetSendPacket(NetTxPacket, ETHER_HDR_SIZE + ARP_HDR_SIZE);
|
||||
|
||||
NetSetTimeout(TIMEOUT * CFG_HZ, RarpTimeout);
|
||||
NetSetHandler(RarpHandler);
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_NET */
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* (C) Copyright 2002 SIXNET, dge@sixnetio.com.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Date & Time support for DS1306 RTC using software SPI
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#if defined(CONFIG_RTC_DS1306) && (CONFIG_COMMANDS & CFG_CMD_DATE)
|
||||
|
||||
static unsigned int bin2bcd(unsigned int n);
|
||||
static unsigned char bcd2bin(unsigned char c);
|
||||
static void soft_spi_send(unsigned char n);
|
||||
static unsigned char soft_spi_read(void);
|
||||
static void init_spi(void);
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Definitions
|
||||
*/
|
||||
|
||||
#define PB_SPISCK 0x00000002 /* PB 30 */
|
||||
#define PB_SPIMOSI 0x00000004 /* PB 29 */
|
||||
#define PB_SPIMISO 0x00000008 /* PB 28 */
|
||||
#define PB_SPI_CE 0x00010000 /* PB 15 */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* read clock time from DS1306 and return it in *tmp */
|
||||
void rtc_get(struct rtc_time *tmp)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
unsigned char spi_byte; /* Data Byte */
|
||||
|
||||
init_spi(); /* set port B for software SPI */
|
||||
|
||||
/* Now we can enable the DS1306 RTC */
|
||||
immap->im_cpm.cp_pbdat |= PB_SPI_CE;
|
||||
udelay(10);
|
||||
|
||||
/* Shift out the address (0) of the time in the Clock Chip */
|
||||
soft_spi_send(0);
|
||||
|
||||
/* Put the clock readings into the rtc_time structure */
|
||||
tmp->tm_sec = bcd2bin(soft_spi_read()); /* Read seconds */
|
||||
tmp->tm_min = bcd2bin(soft_spi_read()); /* Read minutes */
|
||||
|
||||
/* Hours are trickier */
|
||||
spi_byte = soft_spi_read(); /* Read Hours into temporary value */
|
||||
if (spi_byte & 0x40) {
|
||||
/* 12 hour mode bit is set (time is in 1-12 format) */
|
||||
if (spi_byte & 0x20) {
|
||||
/* since PM we add 11 to get 0-23 for hours */
|
||||
tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) + 11;
|
||||
}
|
||||
else {
|
||||
/* since AM we subtract 1 to get 0-23 for hours */
|
||||
tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Otherwise, 0-23 hour format */
|
||||
tmp->tm_hour = (bcd2bin(spi_byte & 0x3F));
|
||||
}
|
||||
|
||||
soft_spi_read(); /* Read and discard Day of week */
|
||||
tmp->tm_mday = bcd2bin(soft_spi_read()); /* Read Day of the Month */
|
||||
tmp->tm_mon = bcd2bin(soft_spi_read()); /* Read Month */
|
||||
|
||||
/* Read Year and convert to this century */
|
||||
tmp->tm_year = bcd2bin(soft_spi_read()) + 2000;
|
||||
|
||||
/* Now we can disable the DS1306 RTC */
|
||||
immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
|
||||
udelay(10);
|
||||
|
||||
GregorianDay(tmp); /* Determine the day of week */
|
||||
|
||||
debug("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);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* set clock time in DS1306 RTC and in MPC8xx RTC */
|
||||
void rtc_set(struct rtc_time *tmp)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
|
||||
init_spi(); /* set port B for software SPI */
|
||||
|
||||
/* Now we can enable the DS1306 RTC */
|
||||
immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
|
||||
udelay(10);
|
||||
|
||||
/* First disable write protect in the clock chip control register */
|
||||
soft_spi_send(0x8F); /* send address of the control register */
|
||||
soft_spi_send(0x00); /* send control register contents */
|
||||
|
||||
/* Now disable the DS1306 to terminate the write */
|
||||
immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;
|
||||
udelay(10);
|
||||
|
||||
/* Now enable the DS1306 to initiate a new write */
|
||||
immap->im_cpm.cp_pbdat |= PB_SPI_CE;
|
||||
udelay(10);
|
||||
|
||||
/* Next, send the address of the clock time write registers */
|
||||
soft_spi_send(0x80); /* send address of the first time register */
|
||||
|
||||
/* Use Burst Mode to send all of the time data to the clock */
|
||||
bin2bcd(tmp->tm_sec);
|
||||
soft_spi_send(bin2bcd(tmp->tm_sec)); /* Send Seconds */
|
||||
soft_spi_send(bin2bcd(tmp->tm_min)); /* Send Minutes */
|
||||
soft_spi_send(bin2bcd(tmp->tm_hour)); /* Send Hour */
|
||||
soft_spi_send(bin2bcd(tmp->tm_wday)); /* Send Day of the Week */
|
||||
soft_spi_send(bin2bcd(tmp->tm_mday)); /* Send Day of Month */
|
||||
soft_spi_send(bin2bcd(tmp->tm_mon)); /* Send Month */
|
||||
soft_spi_send(bin2bcd(tmp->tm_year - 2000)); /* Send Year */
|
||||
|
||||
/* Now we can disable the Clock chip to terminate the burst write */
|
||||
immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
|
||||
udelay(10);
|
||||
|
||||
/* Now we can enable the Clock chip to initiate a new write */
|
||||
immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
|
||||
udelay(10);
|
||||
|
||||
/* First we Enable write protect in the clock chip control register */
|
||||
soft_spi_send(0x8F); /* send address of the control register */
|
||||
soft_spi_send(0x40); /* send out Control Register contents */
|
||||
|
||||
/* Now disable the DS1306 */
|
||||
immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
|
||||
udelay(10);
|
||||
|
||||
/* Set standard MPC8xx clock to the same time so Linux will
|
||||
* see the time even if it doesn't have a DS1306 clock driver.
|
||||
* This helps with experimenting with standard kernels.
|
||||
*/
|
||||
{
|
||||
ulong tim;
|
||||
|
||||
tim = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
|
||||
immap->im_sitk.sitk_rtck = KAPWR_KEY;
|
||||
immap->im_sit.sit_rtc = tim;
|
||||
}
|
||||
|
||||
debug("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);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void rtc_reset(void)
|
||||
{
|
||||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static unsigned char bcd2bin(unsigned char n)
|
||||
{
|
||||
return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static unsigned int bin2bcd(unsigned int n)
|
||||
{
|
||||
return (((n / 10) << 4) | (n % 10));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Initialize Port B for software SPI */
|
||||
static void init_spi(void) {
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
|
||||
/* Force output pins to begin at logic 0 */
|
||||
immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
|
||||
|
||||
/* Set these 3 signals as outputs */
|
||||
immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK);
|
||||
|
||||
immap->im_cpm.cp_pbdir &= ~PB_SPIMISO; /* Make MISO pin an input */
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
|
||||
static void soft_spi_send(unsigned char n)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
unsigned char bitpos; /* bit position to receive */
|
||||
unsigned char i; /* Loop Control */
|
||||
|
||||
/* bit position to send, start with most significant bit */
|
||||
bitpos = 0x80;
|
||||
|
||||
/* Send 8 bits to software SPI */
|
||||
for (i = 0; i < 8; i++) { /* Loop for 8 bits */
|
||||
immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
|
||||
|
||||
if (n & bitpos)
|
||||
immap->im_cpm.cp_pbdat |= PB_SPIMOSI; /* Set MOSI to 1 */
|
||||
else
|
||||
immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI; /* Set MOSI to 0 */
|
||||
udelay(10);
|
||||
|
||||
immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
|
||||
udelay(10);
|
||||
|
||||
bitpos >>= 1; /* Shift for next bit position */
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
|
||||
static unsigned char soft_spi_read(void)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR;
|
||||
|
||||
unsigned char spi_byte = 0; /* Return value, assume success */
|
||||
unsigned char bitpos; /* bit position to receive */
|
||||
unsigned char i; /* Loop Control */
|
||||
|
||||
/* bit position to receive, start with most significant bit */
|
||||
bitpos = 0x80;
|
||||
|
||||
/* Read 8 bits here */
|
||||
for (i = 0; i < 8; i++) { /* Do 8 bits in loop */
|
||||
immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
|
||||
udelay(10);
|
||||
if (immap->im_cpm.cp_pbdat & PB_SPIMISO) /* Get a bit of data */
|
||||
spi_byte |= bitpos; /* Set data accordingly */
|
||||
immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
|
||||
udelay(10);
|
||||
bitpos >>= 1; /* Shift for next bit position */
|
||||
}
|
||||
|
||||
return spi_byte; /* Return the byte read */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Andrew May, Viasat Inc, amay@viasat.com
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* M41T11 Serial Access Timekeeper(R) SRAM
|
||||
* can you believe a trademark on that?
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <rtc.h>
|
||||
#include <i2c.h>
|
||||
|
||||
/*
|
||||
I Don't have an example config file but this
|
||||
is what should be done.
|
||||
|
||||
#define CONFIG_RTC_M41T11 1
|
||||
#define CFG_I2C_RTC_ADDR 0x68
|
||||
#if 0
|
||||
#define CFG_M41T11_EXT_CENTURY_DATA
|
||||
#else
|
||||
#define CFG_M41T11_BASE_YEAR 2000
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_RTC_M41T11) && defined(CFG_I2C_RTC_ADDR) && (CONFIG_COMMANDS & CFG_CMD_DATE)
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
static unsigned bcd2bin (uchar n)
|
||||
{
|
||||
return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
|
||||
}
|
||||
|
||||
static unsigned char bin2bcd (unsigned int n)
|
||||
{
|
||||
return (((n / 10) << 4) | (n % 10));
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
these are simple defines for the chip local to here so they aren't too
|
||||
verbose
|
||||
DAY/DATE aren't nice but that is how they are on the data sheet
|
||||
*/
|
||||
#define RTC_SEC_ADDR 0x0
|
||||
#define RTC_MIN_ADDR 0x1
|
||||
#define RTC_HOUR_ADDR 0x2
|
||||
#define RTC_DAY_ADDR 0x3
|
||||
#define RTC_DATE_ADDR 0x4
|
||||
#define RTC_MONTH_ADDR 0x5
|
||||
#define RTC_YEARS_ADDR 0x6
|
||||
|
||||
#define RTC_REG_CNT 7
|
||||
|
||||
#define RTC_CONTROL_ADDR 0x7
|
||||
|
||||
|
||||
#ifndef CFG_M41T11_EXT_CENTURY_DATA
|
||||
|
||||
#define REG_CNT (RTC_REG_CNT+1)
|
||||
|
||||
/*
|
||||
you only get 00-99 for the year we will asume you
|
||||
want from the year 2000 if you don't set the config
|
||||
*/
|
||||
#ifndef CFG_M41T11_BASE_YEAR
|
||||
#define CFG_M41T11_BASE_YEAR 2000
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* we will store extra year info in byte 9*/
|
||||
#define M41T11_YEAR_DATA 0x8
|
||||
#define M41T11_YEAR_SIZE 1
|
||||
#define REG_CNT (RTC_REG_CNT+1+M41T11_YEAR_SIZE)
|
||||
#endif
|
||||
|
||||
#define M41T11_STORAGE_SZ (64-REG_CNT)
|
||||
|
||||
void rtc_get (struct rtc_time *tmp)
|
||||
{
|
||||
uchar data[RTC_REG_CNT];
|
||||
|
||||
i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
|
||||
|
||||
if( data[RTC_SEC_ADDR] & 0x80 ){
|
||||
printf( "m41t11 RTC Clock stopped!!!\n" );
|
||||
}
|
||||
tmp->tm_sec = bcd2bin (data[RTC_SEC_ADDR] & 0x7F);
|
||||
tmp->tm_min = bcd2bin (data[RTC_MIN_ADDR] & 0x7F);
|
||||
tmp->tm_hour = bcd2bin (data[RTC_HOUR_ADDR] & 0x3F);
|
||||
tmp->tm_mday = bcd2bin (data[RTC_DATE_ADDR] & 0x3F);
|
||||
tmp->tm_mon = bcd2bin (data[RTC_MONTH_ADDR]& 0x1F);
|
||||
#ifndef CFG_M41T11_EXT_CENTURY_DATA
|
||||
tmp->tm_year = CFG_M41T11_BASE_YEAR
|
||||
+ bcd2bin(data[RTC_YEARS_ADDR])
|
||||
+ ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0);
|
||||
#else
|
||||
{
|
||||
unsigned char cent;
|
||||
i2c_read(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE);
|
||||
if( !(data[RTC_HOUR_ADDR] & 0x80) ){
|
||||
printf( "m41t11 RTC: cann't keep track of years without CEB set\n" );
|
||||
}
|
||||
if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){
|
||||
/*century flip store off new year*/
|
||||
cent += 1;
|
||||
i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE);
|
||||
}
|
||||
tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]);
|
||||
}
|
||||
#endif
|
||||
tmp->tm_wday = bcd2bin (data[RTC_DAY_ADDR] & 0x07);
|
||||
tmp->tm_yday = 0;
|
||||
tmp->tm_isdst= 0;
|
||||
|
||||
debug ( "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);
|
||||
}
|
||||
|
||||
void rtc_set (struct rtc_time *tmp)
|
||||
{
|
||||
uchar data[RTC_REG_CNT];
|
||||
|
||||
debug ( "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);
|
||||
|
||||
data[RTC_SEC_ADDR] = bin2bcd(tmp->tm_sec) & 0x7F;/*just in case*/
|
||||
data[RTC_MIN_ADDR] = bin2bcd(tmp->tm_min);
|
||||
data[RTC_HOUR_ADDR] = bin2bcd(tmp->tm_hour) & 0x3F;/*handle cent stuff later*/
|
||||
data[RTC_DATE_ADDR] = bin2bcd(tmp->tm_mday) & 0x3F;
|
||||
data[RTC_MONTH_ADDR] = bin2bcd(tmp->tm_mon);
|
||||
data[RTC_DAY_ADDR] = bin2bcd(tmp->tm_wday) & 0x07;
|
||||
|
||||
data[RTC_HOUR_ADDR] |= 0x80;/*we will always use CEB*/
|
||||
|
||||
data[RTC_YEARS_ADDR] = bin2bcd(tmp->tm_year%100);/*same thing either way*/
|
||||
#ifndef CFG_M41T11_EXT_CENTURY_DATA
|
||||
if( ((tmp->tm_year - CFG_M41T11_BASE_YEAR) > 200) ||
|
||||
(tmp->tm_year < CFG_M41T11_BASE_YEAR) ){
|
||||
printf( "m41t11 RTC setting year out of range!!need recompile\n" );
|
||||
}
|
||||
data[RTC_HOUR_ADDR] |= (tmp->tm_year - CFG_M41T11_BASE_YEAR) > 100 ? 0x40 : 0;
|
||||
#else
|
||||
{
|
||||
unsigned char cent;
|
||||
cent = tmp->tm_year ? tmp->tm_year / 100 : 0;
|
||||
data[RTC_HOUR_ADDR] |= (cent & 0x1) ? 0x40 : 0;
|
||||
i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE);
|
||||
}
|
||||
#endif
|
||||
i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
|
||||
}
|
||||
|
||||
void rtc_reset (void)
|
||||
{
|
||||
unsigned char val;
|
||||
/* clear all control & status registers */
|
||||
i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1);
|
||||
val = val & 0x7F;/*make sure we are running*/
|
||||
i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT);
|
||||
|
||||
i2c_read(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
|
||||
val = val & 0x3F;/*turn off freq test keep calibration*/
|
||||
i2c_write(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
|
||||
}
|
||||
|
||||
int rtc_store(int addr, unsigned char* data, int size)
|
||||
{
|
||||
/*don't let things wrap onto the time on a write*/
|
||||
if( (addr+size) >= M41T11_STORAGE_SZ )
|
||||
return 1;
|
||||
return i2c_write( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
|
||||
}
|
||||
|
||||
int rtc_recall(int addr, unsigned char* data, int size)
|
||||
{
|
||||
return i2c_read( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RTC_M41T11 && CFG_I2C_RTC_ADDR && CFG_CMD_DATE */
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Date & Time support for ST Electronics M48T35Ax RTC
|
||||
*/
|
||||
|
||||
/*#define DEBUG */
|
||||
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <rtc.h>
|
||||
#include <config.h>
|
||||
|
||||
#if defined(CONFIG_RTC_M48T35A) && (CONFIG_COMMANDS & CFG_CMD_DATE)
|
||||
|
||||
static uchar rtc_read (uchar reg);
|
||||
static void rtc_write (uchar reg, uchar val);
|
||||
static uchar bin2bcd (unsigned int n);
|
||||
static unsigned bcd2bin(uchar c);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void rtc_get (struct rtc_time *tmp)
|
||||
{
|
||||
uchar sec, min, hour, cent_day, date, month, year;
|
||||
uchar ccr; /* Clock control register */
|
||||
|
||||
/* Lock RTC for read using clock control register */
|
||||
ccr = rtc_read(0);
|
||||
ccr = ccr | 0x40;
|
||||
rtc_write(0, ccr);
|
||||
|
||||
sec = rtc_read (0x1);
|
||||
min = rtc_read (0x2);
|
||||
hour = rtc_read (0x3);
|
||||
cent_day= rtc_read (0x4);
|
||||
date = rtc_read (0x5);
|
||||
month = rtc_read (0x6);
|
||||
year = rtc_read (0x7);
|
||||
|
||||
/* UNLock RTC */
|
||||
ccr = rtc_read(0);
|
||||
ccr = ccr & 0xBF;
|
||||
rtc_write(0, ccr);
|
||||
|
||||
debug ( "Get RTC year: %02x month: %02x date: %02x cent_day: %02x "
|
||||
"hr: %02x min: %02x sec: %02x\n",
|
||||
year, month, date, cent_day,
|
||||
hour, min, sec );
|
||||
|
||||
tmp->tm_sec = bcd2bin (sec & 0x7F);
|
||||
tmp->tm_min = bcd2bin (min & 0x7F);
|
||||
tmp->tm_hour = bcd2bin (hour & 0x3F);
|
||||
tmp->tm_mday = bcd2bin (date & 0x3F);
|
||||
tmp->tm_mon = bcd2bin (month & 0x1F);
|
||||
tmp->tm_year = bcd2bin (year) + ((cent_day & 0x10) ? 2000 : 1900);
|
||||
tmp->tm_wday = bcd2bin (cent_day & 0x07);
|
||||
tmp->tm_yday = 0;
|
||||
tmp->tm_isdst= 0;
|
||||
|
||||
debug ( "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);
|
||||
}
|
||||
|
||||
void rtc_set (struct rtc_time *tmp)
|
||||
{
|
||||
uchar ccr; /* Clock control register */
|
||||
uchar century;
|
||||
|
||||
debug ( "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);
|
||||
|
||||
/* Lock RTC for write using clock control register */
|
||||
ccr = rtc_read(0);
|
||||
ccr = ccr | 0x80;
|
||||
rtc_write(0, ccr);
|
||||
|
||||
rtc_write (0x07, bin2bcd(tmp->tm_year % 100));
|
||||
rtc_write (0x06, bin2bcd(tmp->tm_mon));
|
||||
rtc_write (0x05, bin2bcd(tmp->tm_mday));
|
||||
|
||||
century = ((tmp->tm_year >= 2000) ? 0x10 : 0) | 0x20;
|
||||
rtc_write (0x04, bin2bcd(tmp->tm_wday) | century);
|
||||
|
||||
rtc_write (0x03, bin2bcd(tmp->tm_hour));
|
||||
rtc_write (0x02, bin2bcd(tmp->tm_min ));
|
||||
rtc_write (0x01, bin2bcd(tmp->tm_sec ));
|
||||
|
||||
/* UNLock RTC */
|
||||
ccr = rtc_read(0);
|
||||
ccr = ccr & 0x7F;
|
||||
rtc_write(0, ccr);
|
||||
}
|
||||
|
||||
void rtc_reset (void)
|
||||
{
|
||||
uchar val;
|
||||
|
||||
/* Clear all clock control registers */
|
||||
rtc_write (0x0, 0x80); /* No Read Lock or calibration */
|
||||
|
||||
/* Clear stop bit */
|
||||
val = rtc_read (0x1);
|
||||
val &= 0x7f;
|
||||
rtc_write(0x1, val);
|
||||
|
||||
/* Enable century / disable frequency test */
|
||||
val = rtc_read (0x4);
|
||||
val = (val & 0xBF) | 0x20;
|
||||
rtc_write(0x4, val);
|
||||
|
||||
/* Clear write lock */
|
||||
rtc_write(0x0, 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static uchar rtc_read (uchar reg)
|
||||
{
|
||||
uchar val;
|
||||
val = *(unsigned char *)
|
||||
((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void rtc_write (uchar reg, uchar val)
|
||||
{
|
||||
*(unsigned char *)
|
||||
((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg) = val;
|
||||
}
|
||||
|
||||
static unsigned bcd2bin (uchar n)
|
||||
{
|
||||
return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
|
||||
}
|
||||
|
||||
static unsigned char bin2bcd (unsigned int n)
|
||||
{
|
||||
return (((n / 10) << 4) | (n % 10));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RTC_M48T35A && CFG_CMD_DATE */
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Denis Peter MPL AG Switzerland. d.peter@mpl.ch
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Date & Time support for the MC146818 (PIXX4) RTC
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#if defined(CONFIG_RTC_MC146818) && (CONFIG_COMMANDS & CFG_CMD_DATE)
|
||||
|
||||
static uchar rtc_read (uchar reg);
|
||||
static void rtc_write (uchar reg, uchar val);
|
||||
static uchar bin2bcd (unsigned int n);
|
||||
static unsigned bcd2bin(uchar c);
|
||||
|
||||
#define RTC_PORT_MC146818 CFG_ISA_IO_BASE_ADDRESS + 0x70
|
||||
#define RTC_SECONDS 0x00
|
||||
#define RTC_SECONDS_ALARM 0x01
|
||||
#define RTC_MINUTES 0x02
|
||||
#define RTC_MINUTES_ALARM 0x03
|
||||
#define RTC_HOURS 0x04
|
||||
#define RTC_HOURS_ALARM 0x05
|
||||
#define RTC_DAY_OF_WEEK 0x06
|
||||
#define RTC_DATE_OF_MONTH 0x07
|
||||
#define RTC_MONTH 0x08
|
||||
#define RTC_YEAR 0x09
|
||||
#define RTC_CONFIG_A 0x0A
|
||||
#define RTC_CONFIG_B 0x0B
|
||||
#define RTC_CONFIG_C 0x0C
|
||||
#define RTC_CONFIG_D 0x0D
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void rtc_get (struct rtc_time *tmp)
|
||||
{
|
||||
uchar sec, min, hour, mday, wday, mon, year;
|
||||
/* here check if rtc can be accessed */
|
||||
while((rtc_read(RTC_CONFIG_A)&0x80)==0x80);
|
||||
sec = rtc_read (RTC_SECONDS);
|
||||
min = rtc_read (RTC_MINUTES);
|
||||
hour = rtc_read (RTC_HOURS);
|
||||
mday = rtc_read (RTC_DATE_OF_MONTH);
|
||||
wday = rtc_read (RTC_DAY_OF_WEEK);
|
||||
mon = rtc_read (RTC_MONTH);
|
||||
year = rtc_read (RTC_YEAR);
|
||||
#ifdef RTC_DEBUG
|
||||
printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
|
||||
"hr: %02x min: %02x sec: %02x\n",
|
||||
year, mon_cent, mday, wday,
|
||||
hour, min, sec );
|
||||
printf ( "Alarms: month: %02x hour: %02x min: %02x sec: %02x\n",
|
||||
rtc_read (RTC_CONFIG_D) & 0x3F,
|
||||
rtc_read (RTC_HOURS_ALARM),
|
||||
rtc_read (RTC_MINUTES_ALARM),
|
||||
rtc_read (RTC_SECONDS_ALARM) );
|
||||
#endif
|
||||
tmp->tm_sec = bcd2bin (sec & 0x7F);
|
||||
tmp->tm_min = bcd2bin (min & 0x7F);
|
||||
tmp->tm_hour = bcd2bin (hour & 0x3F);
|
||||
tmp->tm_mday = bcd2bin (mday & 0x3F);
|
||||
tmp->tm_mon = bcd2bin (mon & 0x1F);
|
||||
tmp->tm_year = bcd2bin (year);
|
||||
tmp->tm_wday = bcd2bin (wday & 0x07);
|
||||
if(tmp->tm_year<70)
|
||||
tmp->tm_year+=2000;
|
||||
else
|
||||
tmp->tm_year+=1900;
|
||||
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)
|
||||
{
|
||||
#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
|
||||
rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
|
||||
|
||||
rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100));
|
||||
rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon));
|
||||
|
||||
rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday));
|
||||
rtc_write (RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday));
|
||||
rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour));
|
||||
rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min ));
|
||||
rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec ));
|
||||
rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
|
||||
|
||||
}
|
||||
|
||||
void rtc_reset (void)
|
||||
{
|
||||
rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
|
||||
rtc_write(RTC_CONFIG_A,0x20); /* Normal OP */
|
||||
rtc_write(RTC_CONFIG_B,0x00);
|
||||
rtc_write(RTC_CONFIG_B,0x00);
|
||||
rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef CFG_RTC_REG_BASE_ADDR
|
||||
/*
|
||||
* use direct memory access
|
||||
*/
|
||||
static uchar rtc_read (uchar reg)
|
||||
{
|
||||
return(in8(CFG_RTC_REG_BASE_ADDR+reg));
|
||||
}
|
||||
|
||||
static void rtc_write (uchar reg, uchar val)
|
||||
{
|
||||
out8(CFG_RTC_REG_BASE_ADDR+reg, val);
|
||||
}
|
||||
#else
|
||||
static uchar rtc_read (uchar reg)
|
||||
{
|
||||
out8(RTC_PORT_MC146818,reg);
|
||||
return(in8(RTC_PORT_MC146818+1));
|
||||
}
|
||||
|
||||
static void rtc_write (uchar reg, uchar val)
|
||||
{
|
||||
out8(RTC_PORT_MC146818,reg);
|
||||
out8(RTC_PORT_MC146818+1,val);
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned bcd2bin (uchar n)
|
||||
{
|
||||
return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
|
||||
}
|
||||
|
||||
static unsigned char bin2bcd (unsigned int n)
|
||||
{
|
||||
return (((n / 10) << 4) | (n % 10));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RTC_MC146818 && CFG_CMD_DATE */
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* (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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Date & Time support for internal RTC of MPC8xx
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#if defined(CONFIG_RTC_MPC8xx) && (CONFIG_COMMANDS & CFG_CMD_DATE)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void rtc_get (struct rtc_time *tmp)
|
||||
{
|
||||
volatile immap_t *immr = (immap_t *)CFG_IMMR;
|
||||
ulong tim;
|
||||
|
||||
tim = immr->im_sit.sit_rtc;
|
||||
|
||||
to_tm (tim, tmp);
|
||||
|
||||
debug ( "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);
|
||||
}
|
||||
|
||||
void rtc_set (struct rtc_time *tmp)
|
||||
{
|
||||
volatile immap_t *immr = (immap_t *)CFG_IMMR;
|
||||
ulong tim;
|
||||
|
||||
debug ( "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);
|
||||
|
||||
tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
|
||||
immr->im_sitk.sitk_rtck = KAPWR_KEY;
|
||||
immr->im_sit.sit_rtc = tim;
|
||||
}
|
||||
|
||||
void rtc_reset (void)
|
||||
{
|
||||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif /* CONFIG_RTC_MPC8xx && CFG_CMD_DATE */
|
Loading…
Reference in New Issue