Add support for Nios-II EPCS Controller core. * Patch by Scott McNutt, 20 Oct 2004: Nios-II cleanups: - Add sysid command (Nios-II only). - Locate default exception trampoline at proper offset. - Implement I/O routines (readb, writeb, etc) - Implement do_bootm_linuxmaster
parent
8f0b7cbe80
commit
0c1c117cf1
@ -0,0 +1,711 @@ |
||||
/*
|
||||
* (C) Copyright 2004, Psyent Corporation <www.psyent.com> |
||||
* Scott McNutt <smcnutt@psyent.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> |
||||
|
||||
#if defined(CFG_NIOS_EPCSBASE) |
||||
#include <command.h> |
||||
#include <nios2.h> |
||||
#include <nios2-io.h> |
||||
#include <nios2-epcs.h> |
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/ |
||||
#define SHORT_HELP\ |
||||
"epcs - read/write Cyclone EPCS configuration device.\n" |
||||
|
||||
#define LONG_HELP\ |
||||
"\n"\
|
||||
"epcs erase start [end]\n"\
|
||||
" - erase sector start or sectors start through end.\n"\
|
||||
"epcs info\n"\
|
||||
" - display EPCS device information.\n"\
|
||||
"epcs protect on | off\n"\
|
||||
" - turn device protection on or off.\n"\
|
||||
"epcs read addr offset count\n"\
|
||||
" - read count bytes from offset to addr.\n"\
|
||||
"epcs write addr offset count\n"\
|
||||
" - write count bytes to offset from addr.\n"\
|
||||
"epcs verify addr offset count\n"\
|
||||
" - verify count bytes at offset from addr.\n" |
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/ |
||||
/* Operation codes for serial configuration devices
|
||||
*/ |
||||
#define EPCS_WRITE_ENA 0x06 /* Write enable */ |
||||
#define EPCS_WRITE_DIS 0x04 /* Write disable */ |
||||
#define EPCS_READ_STAT 0x05 /* Read status */ |
||||
#define EPCS_READ_BYTES 0x03 /* Read bytes */ |
||||
#define EPCS_READ_ID 0xab /* Read silicon id */ |
||||
#define EPCS_WRITE_STAT 0x01 /* Write status */ |
||||
#define EPCS_WRITE_BYTES 0x02 /* Write bytes */ |
||||
#define EPCS_ERASE_BULK 0xc7 /* Erase entire device */ |
||||
#define EPCS_ERASE_SECT 0xd8 /* Erase sector */ |
||||
|
||||
/* Device status register bits
|
||||
*/ |
||||
#define EPCS_STATUS_WIP (1<<0) /* Write in progress */ |
||||
#define EPCS_STATUS_WEL (1<<1) /* Write enable latch */ |
||||
|
||||
/* Misc
|
||||
*/ |
||||
#define EPCS_TIMEOUT 100 /* 100 msec timeout */ |
||||
|
||||
static nios_spi_t *epcs = |
||||
(nios_spi_t *)CACHE_BYPASS(CFG_NIOS_EPCSBASE); |
||||
|
||||
/***********************************************************************
|
||||
* Device access |
||||
***********************************************************************/ |
||||
static int epcs_cs (int assert) |
||||
{ |
||||
ulong start; |
||||
|
||||
if (assert) { |
||||
epcs->control |= NIOS_SPI_SSO; |
||||
} else { |
||||
/* Let all bits shift out */ |
||||
start = get_timer (0); |
||||
while ((epcs->status & NIOS_SPI_TMT) == 0) |
||||
if (get_timer (start) > EPCS_TIMEOUT) |
||||
return (-1); |
||||
epcs->control &= ~NIOS_SPI_SSO; |
||||
} |
||||
return (0); |
||||
} |
||||
|
||||
static int epcs_tx (unsigned char c) |
||||
{ |
||||
ulong start; |
||||
|
||||
start = get_timer (0); |
||||
while ((epcs->status & NIOS_SPI_TRDY) == 0) |
||||
if (get_timer (start) > EPCS_TIMEOUT) |
||||
return (-1); |
||||
epcs->txdata = c; |
||||
return (0); |
||||
} |
||||
|
||||
static int epcs_rx (void) |
||||
{ |
||||
ulong start; |
||||
|
||||
start = get_timer (0); |
||||
while ((epcs->status & NIOS_SPI_RRDY) == 0) |
||||
if (get_timer (start) > EPCS_TIMEOUT) |
||||
return (-1); |
||||
return (epcs->rxdata); |
||||
} |
||||
|
||||
static unsigned char bitrev[] = { |
||||
0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, |
||||
0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f |
||||
}; |
||||
|
||||
static unsigned char epcs_bitrev (unsigned char c) |
||||
{ |
||||
unsigned char val; |
||||
|
||||
val = bitrev[c>>4]; |
||||
val |= bitrev[c & 0x0f]<<4; |
||||
return (val); |
||||
} |
||||
|
||||
static void epcs_rcv (unsigned char *dst, int len) |
||||
{ |
||||
while (len--) { |
||||
epcs_tx (0); |
||||
*dst++ = epcs_rx (); |
||||
} |
||||
} |
||||
|
||||
static void epcs_rrcv (unsigned char *dst, int len) |
||||
{ |
||||
while (len--) { |
||||
epcs_tx (0); |
||||
*dst++ = epcs_bitrev (epcs_rx ()); |
||||
} |
||||
} |
||||
|
||||
static void epcs_snd (unsigned char *src, int len) |
||||
{ |
||||
while (len--) { |
||||
epcs_tx (*src++); |
||||
epcs_rx (); |
||||
} |
||||
} |
||||
|
||||
static void epcs_rsnd (unsigned char *src, int len) |
||||
{ |
||||
while (len--) { |
||||
epcs_tx (epcs_bitrev (*src++)); |
||||
epcs_rx (); |
||||
} |
||||
} |
||||
|
||||
static void epcs_wr_enable (void) |
||||
{ |
||||
epcs_cs (1); |
||||
epcs_tx (EPCS_WRITE_ENA); |
||||
epcs_rx (); |
||||
epcs_cs (0); |
||||
} |
||||
|
||||
static unsigned char epcs_status_rd (void) |
||||
{ |
||||
unsigned char status; |
||||
|
||||
epcs_cs (1); |
||||
epcs_tx (EPCS_READ_STAT); |
||||
epcs_rx (); |
||||
epcs_tx (0); |
||||
status = epcs_rx (); |
||||
epcs_cs (0); |
||||
return (status); |
||||
} |
||||
|
||||
static void epcs_status_wr (unsigned char status) |
||||
{ |
||||
epcs_wr_enable (); |
||||
epcs_cs (1); |
||||
epcs_tx (EPCS_WRITE_STAT); |
||||
epcs_rx (); |
||||
epcs_tx (status); |
||||
epcs_rx (); |
||||
epcs_cs (0); |
||||
return; |
||||
} |
||||
|
||||
/***********************************************************************
|
||||
* Device information |
||||
***********************************************************************/ |
||||
|
||||
static struct epcs_devinfo_t devinfo[] = { |
||||
{ "EPCS1 ", 0x10, 17, 4, 15, 8, 0x0c }, |
||||
{ "EPCS4 ", 0x12, 19, 8, 16, 8, 0x1c }, |
||||
{ 0, 0, 0, 0, 0, 0 } |
||||
}; |
||||
|
||||
epcs_devinfo_t *epcs_dev_find (void) |
||||
{ |
||||
unsigned char buf[4]; |
||||
unsigned char id; |
||||
int i; |
||||
struct epcs_devinfo_t *dev = NULL; |
||||
|
||||
/* Read silicon id requires 3 "dummy bytes" before it's put
|
||||
* on the wire. |
||||
*/ |
||||
buf[0] = EPCS_READ_ID; |
||||
buf[1] = 0; |
||||
buf[2] = 0; |
||||
buf[3] = 0; |
||||
|
||||
epcs_cs (1); |
||||
epcs_snd (buf,4); |
||||
epcs_rcv (buf,1); |
||||
if (epcs_cs (0) == -1) |
||||
return (NULL); |
||||
id = buf[0]; |
||||
|
||||
/* Find the info struct */ |
||||
i = 0; |
||||
while (devinfo[i].name) { |
||||
if (id == devinfo[i].id) { |
||||
dev = &devinfo[i]; |
||||
break; |
||||
} |
||||
i++; |
||||
} |
||||
|
||||
return (dev); |
||||
} |
||||
|
||||
/***********************************************************************
|
||||
* Misc Utilities |
||||
***********************************************************************/ |
||||
int epcs_cfgsz (void) |
||||
{ |
||||
int sz = 0; |
||||
unsigned char buf[128]; |
||||
unsigned char *p; |
||||
struct epcs_devinfo_t *dev = epcs_dev_find (); |
||||
|
||||
if (!dev) |
||||
return (-1); |
||||
|
||||
/* Read in the first 128 bytes of the device */ |
||||
buf[0] = EPCS_READ_BYTES; |
||||
buf[1] = 0; |
||||
buf[2] = 0; |
||||
buf[3] = 0; |
||||
|
||||
epcs_cs (1); |
||||
epcs_snd (buf,4); |
||||
epcs_rrcv (buf, sizeof(buf)); |
||||
epcs_cs (0); |
||||
|
||||
/* Search for the starting 0x6a which is followed by the
|
||||
* 4-byte 'register' and 4-byte bit-count. |
||||
*/ |
||||
p = buf; |
||||
while (p < buf + sizeof(buf)-8) { |
||||
if ( *p == 0x6a ) { |
||||
/* Point to bit count and extract */ |
||||
p += 5; |
||||
sz = *p++; |
||||
sz |= *p++ << 8; |
||||
sz |= *p++ << 16; |
||||
sz |= *p++ << 24; |
||||
/* Convert to byte count */ |
||||
sz += 7; |
||||
sz >>= 3; |
||||
} else if (*p == 0xff) { |
||||
/* 0xff is ok ... just skip */ |
||||
p++; |
||||
continue; |
||||
} else { |
||||
/* Not 0xff or 0x6a ... something's not
|
||||
* right ... report 'unknown' (sz=0). |
||||
*/ |
||||
break; |
||||
} |
||||
} |
||||
return (sz); |
||||
} |
||||
|
||||
int epcs_erase (unsigned start, unsigned end) |
||||
{ |
||||
unsigned off, sectsz; |
||||
unsigned char buf[4]; |
||||
struct epcs_devinfo_t *dev = epcs_dev_find (); |
||||
|
||||
if (!dev || (start>end)) |
||||
return (-1); |
||||
|
||||
/* Erase the requested sectors. An address is required
|
||||
* that lies within the requested sector -- we'll just |
||||
* use the first address in the sector. |
||||
*/ |
||||
printf ("epcs erasing sector %d ", start); |
||||
if (start != end) |
||||
printf ("to %d ", end); |
||||
sectsz = (1 << dev->sz_sect); |
||||
while (start <= end) { |
||||
off = start * sectsz; |
||||
start++; |
||||
|
||||
buf[0] = EPCS_ERASE_SECT; |
||||
buf[1] = off >> 16; |
||||
buf[2] = off >> 8; |
||||
buf[3] = off; |
||||
|
||||
epcs_wr_enable (); |
||||
epcs_cs (1); |
||||
epcs_snd (buf,4); |
||||
epcs_cs (0); |
||||
|
||||
printf ("."); /* Some user feedback */ |
||||
|
||||
/* Wait for erase to complete */ |
||||
while (epcs_status_rd() & EPCS_STATUS_WIP) |
||||
; |
||||
} |
||||
printf (" done.\n"); |
||||
return (0); |
||||
} |
||||
|
||||
int epcs_read (ulong addr, ulong off, ulong cnt) |
||||
{ |
||||
unsigned char buf[4]; |
||||
struct epcs_devinfo_t *dev = epcs_dev_find (); |
||||
|
||||
if (!dev) |
||||
return (-1); |
||||
|
||||
buf[0] = EPCS_READ_BYTES; |
||||
buf[1] = off >> 16; |
||||
buf[2] = off >> 8; |
||||
buf[3] = off; |
||||
|
||||
epcs_cs (1); |
||||
epcs_snd (buf,4); |
||||
epcs_rrcv ((unsigned char *)addr, cnt); |
||||
epcs_cs (0); |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
int epcs_write (ulong addr, ulong off, ulong cnt) |
||||
{ |
||||
ulong wrcnt; |
||||
unsigned pgsz; |
||||
unsigned char buf[4]; |
||||
struct epcs_devinfo_t *dev = epcs_dev_find (); |
||||
|
||||
if (!dev) |
||||
return (-1); |
||||
|
||||
pgsz = (1<<dev->sz_page); |
||||
while (cnt) { |
||||
if (off % pgsz) |
||||
wrcnt = pgsz - (off % pgsz); |
||||
else |
||||
wrcnt = pgsz; |
||||
wrcnt = (wrcnt > cnt) ? cnt : wrcnt; |
||||
|
||||
buf[0] = EPCS_WRITE_BYTES; |
||||
buf[1] = off >> 16; |
||||
buf[2] = off >> 8; |
||||
buf[3] = off; |
||||
|
||||
epcs_wr_enable (); |
||||
epcs_cs (1); |
||||
epcs_snd (buf,4); |
||||
epcs_rsnd ((unsigned char *)addr, wrcnt); |
||||
epcs_cs (0); |
||||
|
||||
/* Wait for write to complete */ |
||||
while (epcs_status_rd() & EPCS_STATUS_WIP) |
||||
; |
||||
|
||||
cnt -= wrcnt; |
||||
off += wrcnt; |
||||
addr += wrcnt; |
||||
} |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
int epcs_verify (ulong addr, ulong off, ulong cnt, ulong *err) |
||||
{ |
||||
ulong rdcnt; |
||||
unsigned char buf[256]; |
||||
unsigned char *start,*end; |
||||
int i; |
||||
|
||||
start = end = (unsigned char *)addr; |
||||
while (cnt) { |
||||
rdcnt = (cnt>sizeof(buf)) ? sizeof(buf) : cnt; |
||||
epcs_read ((ulong)buf, off, rdcnt); |
||||
for (i=0; i<rdcnt; i++) { |
||||
if (*end != buf[i]) { |
||||
*err = end - start; |
||||
return(-1); |
||||
} |
||||
end++; |
||||
} |
||||
cnt -= rdcnt; |
||||
off += rdcnt; |
||||
} |
||||
return (0); |
||||
} |
||||
|
||||
static int epcs_sect_erased (int sect, unsigned *offset, |
||||
struct epcs_devinfo_t *dev) |
||||
{ |
||||
unsigned char buf[128]; |
||||
unsigned off, end; |
||||
unsigned sectsz; |
||||
int i; |
||||
|
||||
sectsz = (1 << dev->sz_sect); |
||||
off = sectsz * sect; |
||||
end = off + sectsz; |
||||
|
||||
while (off < end) { |
||||
epcs_read ((ulong)buf, off, sizeof(buf)); |
||||
for (i=0; i < sizeof(buf); i++) { |
||||
if (buf[i] != 0xff) { |
||||
*offset = off + i; |
||||
return (0); |
||||
} |
||||
} |
||||
off += sizeof(buf); |
||||
} |
||||
return (1); |
||||
} |
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Commands |
||||
***********************************************************************/ |
||||
static |
||||
void do_epcs_info (struct epcs_devinfo_t *dev, int argc, char *argv[]) |
||||
{ |
||||
int i; |
||||
unsigned char stat; |
||||
unsigned tmp; |
||||
int erased; |
||||
|
||||
/* Basic device info */ |
||||
printf ("%s: %d kbytes (%d sectors x %d kbytes," |
||||
" %d bytes/page)\n", |
||||
dev->name, 1 << (dev->size-10), |
||||
dev->num_sects, 1 << (dev->sz_sect-10), |
||||
1 << dev->sz_page ); |
||||
|
||||
/* Status -- for now protection is all-or-nothing */ |
||||
stat = epcs_status_rd(); |
||||
printf ("status: 0x%02x (WIP:%d, WEL:%d, PROT:%s)\n", |
||||
stat, |
||||
(stat & EPCS_STATUS_WIP) ? 1 : 0, |
||||
(stat & EPCS_STATUS_WEL) ? 1 : 0, |
||||
(stat & dev->prot_mask) ? "on" : "off" ); |
||||
|
||||
/* Configuration */ |
||||
tmp = epcs_cfgsz (); |
||||
if (tmp) { |
||||
printf ("config: 0x%06x (%d) bytes\n", tmp, tmp ); |
||||
} else { |
||||
printf ("config: unknown\n" ); |
||||
} |
||||
|
||||
/* Sector info */ |
||||
for (i=0; i<dev->num_sects; i++) { |
||||
erased = epcs_sect_erased (i, &tmp, dev); |
||||
printf (" %d: %06x ", |
||||
i, i*(1<<dev->sz_sect) ); |
||||
if (erased) |
||||
printf ("erased\n"); |
||||
else |
||||
printf ("data @ 0x%06x\n", tmp); |
||||
} |
||||
|
||||
return; |
||||
} |
||||
|
||||
static |
||||
void do_epcs_erase (struct epcs_devinfo_t *dev, int argc, char *argv[]) |
||||
{ |
||||
unsigned start,end; |
||||
|
||||
if ((argc < 3) || (argc > 4)) { |
||||
printf ("USAGE: epcs erase sect [end]\n"); |
||||
return; |
||||
} |
||||
if ((epcs_status_rd() & dev->prot_mask) != 0) { |
||||
printf ( "epcs: device protected.\n"); |
||||
return; |
||||
} |
||||
|
||||
start = simple_strtoul (argv[2], NULL, 10); |
||||
if (argc > 3) |
||||
end = simple_strtoul (argv[3], NULL, 10); |
||||
else |
||||
end = start; |
||||
if ((start >= dev->num_sects) || (start > end)) { |
||||
printf ("epcs: invalid sector range: [%d:%d]\n", |
||||
start, end ); |
||||
return; |
||||
} |
||||
|
||||
epcs_erase (start, end); |
||||
|
||||
return; |
||||
} |
||||
|
||||
static |
||||
void do_epcs_protect (struct epcs_devinfo_t *dev, int argc, char *argv[]) |
||||
{ |
||||
unsigned char stat; |
||||
|
||||
/* For now protection is all-or-nothing to keep things
|
||||
* simple. The protection bits don't map in a linear |
||||
* fashion ... and we would rather protect the bottom |
||||
* of the device since it contains the config data and |
||||
* leave the top unprotected for app use. But unfortunately |
||||
* protection works from top-to-bottom so it does |
||||
* really help very much from a software app point-of-view. |
||||
*/ |
||||
if (argc < 3) { |
||||
printf ("USAGE: epcs protect on | off\n"); |
||||
return; |
||||
} |
||||
if (!dev) |
||||
return; |
||||
|
||||
/* Protection on/off is just a matter of setting/clearing
|
||||
* all protection bits in the status register. |
||||
*/ |
||||
stat = epcs_status_rd (); |
||||
if (strcmp ("on", argv[2]) == 0) { |
||||
stat |= dev->prot_mask; |
||||
} else if (strcmp ("off", argv[2]) == 0 ) { |
||||
stat &= ~dev->prot_mask; |
||||
} else { |
||||
printf ("epcs: unknown protection: %s\n", argv[2]); |
||||
return; |
||||
} |
||||
epcs_status_wr (stat); |
||||
return; |
||||
} |
||||
|
||||
static |
||||
void do_epcs_read (struct epcs_devinfo_t *dev, int argc, char *argv[]) |
||||
{ |
||||
ulong addr,off,cnt; |
||||
ulong sz; |
||||
|
||||
if (argc < 5) { |
||||
printf ("USAGE: epcs read addr offset count\n"); |
||||
return; |
||||
} |
||||
|
||||
sz = 1 << dev->size; |
||||
addr = simple_strtoul (argv[2], NULL, 16); |
||||
off = simple_strtoul (argv[3], NULL, 16); |
||||
cnt = simple_strtoul (argv[4], NULL, 16); |
||||
if (off > sz) { |
||||
printf ("offset is greater than device size" |
||||
"... aborting.\n"); |
||||
return; |
||||
} |
||||
if ((off + cnt) > sz) { |
||||
printf ("request exceeds device size" |
||||
"... truncating.\n"); |
||||
cnt = sz - off; |
||||
} |
||||
printf ("epcs: read %08lx <- %06lx (0x%lx bytes)\n", |
||||
addr, off, cnt); |
||||
epcs_read (addr, off, cnt); |
||||
|
||||
return; |
||||
} |
||||
|
||||
static |
||||
void do_epcs_write (struct epcs_devinfo_t *dev, int argc, char *argv[]) |
||||
{ |
||||
ulong addr,off,cnt; |
||||
ulong sz; |
||||
ulong err; |
||||
|
||||
if (argc < 5) { |
||||
printf ("USAGE: epcs write addr offset count\n"); |
||||
return; |
||||
} |
||||
if ((epcs_status_rd() & dev->prot_mask) != 0) { |
||||
printf ( "epcs: device protected.\n"); |
||||
return; |
||||
} |
||||
|
||||
sz = 1 << dev->size; |
||||
addr = simple_strtoul (argv[2], NULL, 16); |
||||
off = simple_strtoul (argv[3], NULL, 16); |
||||
cnt = simple_strtoul (argv[4], NULL, 16); |
||||
if (off > sz) { |
||||
printf ("offset is greater than device size" |
||||
"... aborting.\n"); |
||||
return; |
||||
} |
||||
if ((off + cnt) > sz) { |
||||
printf ("request exceeds device size" |
||||
"... truncating.\n"); |
||||
cnt = sz - off; |
||||
} |
||||
printf ("epcs: write %08lx -> %06lx (0x%lx bytes)\n", |
||||
addr, off, cnt); |
||||
epcs_write (addr, off, cnt); |
||||
if (epcs_verify (addr, off, cnt, &err) != 0) |
||||
printf ("epcs: write error at offset %06lx\n", err); |
||||
|
||||
return; |
||||
} |
||||
|
||||
static |
||||
void do_epcs_verify (struct epcs_devinfo_t *dev, int argc, char *argv[]) |
||||
{ |
||||
ulong addr,off,cnt; |
||||
ulong sz; |
||||
ulong err; |
||||
|
||||
if (argc < 5) { |
||||
printf ("USAGE: epcs verify addr offset count\n"); |
||||
return; |
||||
} |
||||
|
||||
sz = 1 << dev->size; |
||||
addr = simple_strtoul (argv[2], NULL, 16); |
||||
off = simple_strtoul (argv[3], NULL, 16); |
||||
cnt = simple_strtoul (argv[4], NULL, 16); |
||||
if (off > sz) { |
||||
printf ("offset is greater than device size" |
||||
"... aborting.\n"); |
||||
return; |
||||
} |
||||
if ((off + cnt) > sz) { |
||||
printf ("request exceeds device size" |
||||
"... truncating.\n"); |
||||
cnt = sz - off; |
||||
} |
||||
printf ("epcs: verify %08lx -> %06lx (0x%lx bytes)\n", |
||||
addr, off, cnt); |
||||
if (epcs_verify (addr, off, cnt, &err) != 0) |
||||
printf ("epcs: verify error at offset %06lx\n", err); |
||||
|
||||
return; |
||||
} |
||||
|
||||
/*-----------------------------------------------------------------------*/ |
||||
int do_epcs (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
||||
{ |
||||
int len; |
||||
struct epcs_devinfo_t *dev = epcs_dev_find (); |
||||
|
||||
if (!dev) { |
||||
printf ("epcs: device not found.\n"); |
||||
return (-1); |
||||
} |
||||
|
||||
if (argc < 2) { |
||||
do_epcs_info (dev, argc, argv); |
||||
return (0); |
||||
} |
||||
|
||||
len = strlen (argv[1]); |
||||
if (strncmp ("info", argv[1], len) == 0) { |
||||
do_epcs_info (dev, argc, argv); |
||||
} else if (strncmp ("erase", argv[1], len) == 0) { |
||||
do_epcs_erase (dev, argc, argv); |
||||
} else if (strncmp ("protect", argv[1], len) == 0) { |
||||
do_epcs_protect (dev, argc, argv); |
||||
} else if (strncmp ("read", argv[1], len) == 0) { |
||||
do_epcs_read (dev, argc, argv); |
||||
} else if (strncmp ("write", argv[1], len) == 0) { |
||||
do_epcs_write (dev, argc, argv); |
||||
} else if (strncmp ("verify", argv[1], len) == 0) { |
||||
do_epcs_verify (dev, argc, argv); |
||||
} else { |
||||
printf ("epcs: unknown operation: %s\n", argv[1]); |
||||
} |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
/*-----------------------------------------------------------------------*/ |
||||
|
||||
|
||||
U_BOOT_CMD( epcs, 5, 0, do_epcs, SHORT_HELP, LONG_HELP ); |
||||
|
||||
#endif /* CONFIG_NIOS_EPCS */ |
@ -0,0 +1,57 @@ |
||||
/*
|
||||
* (C) Copyright 2004, Psyent Corporation <www.psyent.com> |
||||
* Scott McNutt <smcnutt@psyent.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> |
||||
|
||||
#if defined (CFG_NIOS_SYSID_BASE) |
||||
|
||||
#include <command.h> |
||||
#include <nios2.h> |
||||
#include <nios2-io.h> |
||||
#include <linux/time.h> |
||||
|
||||
void display_sysid (void) |
||||
{ |
||||
struct nios_sysid_t *sysid = |
||||
(struct nios_sysid_t *)CACHE_BYPASS(CFG_NIOS_SYSID_BASE); |
||||
struct tm t; |
||||
char asc[32]; |
||||
|
||||
localtime_r ((time_t *)&sysid->timestamp, &t); |
||||
asctime_r (&t, asc); |
||||
printf ("SYSID : %08x, %s", sysid->id, asc); |
||||
|
||||
} |
||||
|
||||
int do_sysid (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
||||
{ |
||||
display_sysid (); |
||||
return (0); |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
sysid, 1, 1, do_sysid, |
||||
"sysid - display Nios-II system id\n\n", |
||||
"\n - display Nios-II system id\n" |
||||
); |
||||
#endif /* CFG_NIOS_SYSID_BASE */ |
@ -0,0 +1,71 @@ |
||||
/*
|
||||
* (C) Copyright 2004, Psyent Corporation <www.psyent.com> |
||||
* Scott McNutt <smcnutt@psyent.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 |
||||
*/ |
||||
|
||||
/*************************************************************************
|
||||
* Altera Nios-II EPCS Controller Core interfaces |
||||
************************************************************************/ |
||||
|
||||
#ifndef __NIOS2_EPCS_H__ |
||||
#define __NIOS2_EPCS_H__ |
||||
|
||||
typedef struct epcs_devinfo_t { |
||||
const char *name; /* Device name */ |
||||
unsigned char id; /* Device silicon id */ |
||||
unsigned char size; /* Total size log2(bytes)*/ |
||||
unsigned char num_sects; /* Number of sectors */ |
||||
unsigned char sz_sect; /* Sector size log2(bytes) */ |
||||
unsigned char sz_page; /* Page size log2(bytes) */ |
||||
unsigned char prot_mask; /* Protection mask */ |
||||
}epcs_devinfo_t; |
||||
|
||||
/* Returns the devinfo struct if EPCS device is found;
|
||||
* NULL otherwise. |
||||
*/ |
||||
extern epcs_devinfo_t *epcs_dev_find (void); |
||||
|
||||
/* Returns the number of bytes used by config data.
|
||||
* Negative on error. |
||||
*/ |
||||
extern int epcs_cfgsz (void); |
||||
|
||||
/* Erase sectors 'start' to 'end' - return zero on success
|
||||
*/ |
||||
extern int epcs_erase (unsigned start, unsigned end); |
||||
|
||||
/* Read 'cnt' bytes from device offset 'off' into buf at 'addr'
|
||||
* Zero return on success |
||||
*/ |
||||
extern int epcs_read (ulong addr, ulong off, ulong cnt); |
||||
|
||||
/* Write 'cnt' bytes to device offset 'off' from buf at 'addr'.
|
||||
* Zero return on success |
||||
*/ |
||||
extern int epcs_write (ulong addr, ulong off, ulong cnt); |
||||
|
||||
/* Verify 'cnt' bytes at device offset 'off' comparing with buf
|
||||
* at 'addr'. On failure, write first invalid offset to *err. |
||||
* Zero return on success |
||||
*/ |
||||
extern int epcs_verify (ulong addr, ulong off, ulong cnt, ulong *err); |
||||
|
||||
#endif /* __NIOS2_EPCS_H__ */ |
Loading…
Reference in new issue