Initial revision

This commit is contained in:
wdenk 2002-08-17 09:36:01 +00:00
parent cf356ef708
commit affae2bff8
89 changed files with 34073 additions and 0 deletions

570
board/c2mon/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

50
board/cogent/dipsw.c Normal file
View file

@ -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");
}

648
board/cogent/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

486
board/cu824/flash.c Normal file
View file

@ -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));
}

453
board/eltec/mhpc/flash.c Normal file
View file

@ -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);
}

396
board/ep8260/flash.c Normal file
View file

@ -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);
}

108
board/ep8260/mii_phy.c Normal file
View file

@ -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;
}
}

113
board/esd/adciop/flash.c Normal file
View file

@ -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);
}

646
board/esd/common/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

160
board/esd/cpci405/flash.c Normal file
View file

@ -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);
}

View file

@ -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;
}
/* ------------------------------------------------------------------------- */

View file

@ -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);
}

123
board/esd/du405/flash.c Normal file
View file

@ -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);
}

156
board/esd/ocrtc/flash.c Normal file
View file

@ -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);
}

101
board/esd/pci405/flash.c Normal file
View file

@ -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);
}

1096
board/esteem192e/flash.c Normal file

File diff suppressed because it is too large Load diff

744
board/etx094/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

315
board/evb64260/i2c.c Normal file
View file

@ -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;
}

View file

@ -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;
}

624
board/fads/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

42
board/fads/lamp.c Normal file
View file

@ -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);
}
}

470
board/genietv/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

335
board/gth/ee_access.c Normal file
View file

@ -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);
}

649
board/gth/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

460
board/hermes/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

597
board/hymod/eeprom.c Normal file
View file

@ -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;
}
}

745
board/hymod/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

617
board/icu862/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

456
board/ip860/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

598
board/ivm/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

625
board/lantec/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

408
board/mbx8xx/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

196
board/mbx8xx/vpd.c Normal file
View file

@ -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;
}

78
board/mousse/flash.h Normal file
View file

@ -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 */

508
board/mpc8260ads/flash.c Normal file
View file

@ -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;
}

860
board/mpl/common/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

469
board/mpl/common/isa.c Normal file
View file

@ -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;
}

655
board/mpl/common/kbd.c Normal file
View file

@ -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 */

1152
board/mpl/common/usb_uhci.c Normal file

File diff suppressed because it is too large Load diff

513
board/musenki/flash.c Normal file
View file

@ -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;
}
/*-----------------------------------------------------------------------
*/

465
board/nx823/flash.c Normal file
View file

@ -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);
}

573
board/pcippc2/flash.c Normal file
View file

@ -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");
}

49
board/pcippc2/pcippc2.h Normal file
View file

@ -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

View file

@ -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();
}

434
board/rpxsuper/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

108
board/rpxsuper/mii_phy.c Normal file
View file

@ -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;
}
}

402
board/rsdproto/flash.c Normal file
View file

@ -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;
}

553
board/siemens/CCM/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

653
board/siemens/IAD210/atm.c Normal file
View file

@ -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();
}

View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

488
board/siemens/SCM/flash.c Normal file
View file

@ -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);
}

700
board/siemens/pcu_e/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

746
board/sixnet/flash.c Normal file
View file

@ -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

57
board/spd8xx/flash.c Normal file
View file

@ -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;
}
/*-----------------------------------------------------------------------
*/

488
board/tqm8260/flash.c Normal file
View file

@ -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);
}

90
board/w7o/fsboot.c Normal file
View file

@ -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;
}

48
board/w7o/watchdog.c Normal file
View file

@ -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 */

637
board/westel/amx860/flash.c Normal file
View file

@ -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);
}
/*-----------------------------------------------------------------------
*/

519
common/docecc.c Normal file
View file

@ -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(&reg[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) */

219
common/flash.c Normal file
View file

@ -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 */

734
common/lists.c Normal file
View file

@ -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 */

231
common/miiphybb.c Normal file
View file

@ -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 */

195
common/s_record.c Normal file
View file

@ -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);
}

1066
common/usb.c Normal file

File diff suppressed because it is too large Load diff

734
common/usb_kbd.c Normal file
View file

@ -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 */

895
common/usb_storage.c Normal file
View file

@ -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 */

234
cpu/74xx_7xx/traps.c Normal file
View file

@ -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;
}

View file

@ -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);
}

205
cpu/mpc824x/traps.c Normal file
View file

@ -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;
}

347
cpu/mpc8260/ether_fcc.c Normal file
View file

@ -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 */

246
cpu/mpc8260/traps.c Normal file
View file

@ -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;
}

245
cpu/mpc8xx/traps.c Normal file
View file

@ -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;
}

102
cpu/mpc8xx/upatch.c Normal file
View file

@ -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 */

182
cpu/ppc4xx/miiphy.c Normal file
View file

@ -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 */

291
cpu/ppc4xx/traps.c Normal file
View file

@ -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;
}

227
disk/part.c Normal file
View file

@ -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) */

74
drivers/pci_indirect.c Normal file
View file

@ -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

210
examples/eepro100_eeprom.c Normal file
View file

@ -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;
}

301
include/pcmcia.h Normal file
View file

@ -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 */

37
include/syscall.h Normal file
View file

@ -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

199
lib_generic/crc32.c Normal file
View file

@ -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 */

133
lib_ppc/bat_rw.c Normal file
View file

@ -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);
}

47
lib_ppc/cache.c Normal file
View file

@ -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");
}

106
net/rarp.c Normal file
View file

@ -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 */

274
rtc/ds1306.c Normal file
View file

@ -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

202
rtc/m41t11.c Normal file
View file

@ -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, &cent, 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, &cent, 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, &cent, 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 */

166
rtc/m48t35ax.c Normal file
View file

@ -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 */

172
rtc/mc146818.c Normal file
View file

@ -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 */

75
rtc/mpc8xx.c Normal file
View file

@ -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 */