1 /*
2  * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
3  * Scott McNutt <smcnutt@psyent.com>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 #include <common.h>
25 
26 #if defined(CONFIG_SYS_NIOS_EPCSBASE)
27 #include <command.h>
28 #include <asm/io.h>
29 #include <nios2-io.h>
30 #include <nios2-epcs.h>
31 
32 
33 /*-----------------------------------------------------------------------*/
34 #define SHORT_HELP\
35 	"epcs    - read/write Cyclone EPCS configuration device.\n"
36 
37 #define LONG_HELP\
38 	"\n"\
39 	"epcs erase start [end]\n"\
40 	"    - erase sector start or sectors start through end.\n"\
41 	"epcs info\n"\
42 	"    - display EPCS device information.\n"\
43 	"epcs protect on | off\n"\
44 	"    - turn device protection on or off.\n"\
45 	"epcs read addr offset count\n"\
46 	"    - read count bytes from offset to addr.\n"\
47 	"epcs write addr offset count\n"\
48 	"    - write count bytes to offset from addr.\n"\
49 	"epcs verify addr offset count\n"\
50 	"    - verify count bytes at offset from addr."
51 
52 
53 /*-----------------------------------------------------------------------*/
54 /* Operation codes for serial configuration devices
55  */
56 #define EPCS_WRITE_ENA		0x06	/* Write enable */
57 #define EPCS_WRITE_DIS		0x04	/* Write disable */
58 #define EPCS_READ_STAT		0x05	/* Read status */
59 #define EPCS_READ_BYTES		0x03	/* Read bytes */
60 #define EPCS_READ_ID		0xab	/* Read silicon id */
61 #define EPCS_WRITE_STAT		0x01	/* Write status */
62 #define EPCS_WRITE_BYTES	0x02	/* Write bytes */
63 #define EPCS_ERASE_BULK		0xc7	/* Erase entire device */
64 #define EPCS_ERASE_SECT		0xd8	/* Erase sector */
65 
66 /* Device status register bits
67  */
68 #define EPCS_STATUS_WIP		(1<<0)	/* Write in progress */
69 #define EPCS_STATUS_WEL		(1<<1)	/* Write enable latch */
70 
71 /* Misc
72  */
73 #define EPCS_TIMEOUT		100	/* 100 msec timeout */
74 
75 static nios_spi_t *epcs = (nios_spi_t *)CONFIG_SYS_NIOS_EPCSBASE;
76 
77 /***********************************************************************
78  * Device access
79  ***********************************************************************/
epcs_cs(int assert)80 static int epcs_cs (int assert)
81 {
82 	ulong start;
83 	unsigned tmp;
84 
85 
86 	if (assert) {
87 		tmp = readl (&epcs->control);
88 		writel (tmp | NIOS_SPI_SSO, &epcs->control);
89 	} else {
90 		/* Let all bits shift out */
91 		start = get_timer (0);
92 		while ((readl (&epcs->status) & NIOS_SPI_TMT) == 0)
93 			if (get_timer (start) > EPCS_TIMEOUT)
94 				return (-1);
95 		tmp = readl (&epcs->control);
96 		writel (tmp & ~NIOS_SPI_SSO, &epcs->control);
97 	}
98 	return (0);
99 }
100 
epcs_tx(unsigned char c)101 static int epcs_tx (unsigned char c)
102 {
103 	ulong start;
104 
105 	start = get_timer (0);
106 	while ((readl (&epcs->status) & NIOS_SPI_TRDY) == 0)
107 		if (get_timer (start) > EPCS_TIMEOUT)
108 			return (-1);
109 	writel (c, &epcs->txdata);
110 	return (0);
111 }
112 
epcs_rx(void)113 static int epcs_rx (void)
114 {
115 	ulong start;
116 
117 	start = get_timer (0);
118 	while ((readl (&epcs->status) & NIOS_SPI_RRDY) == 0)
119 		if (get_timer (start) > EPCS_TIMEOUT)
120 			return (-1);
121 	return (readl (&epcs->rxdata));
122 }
123 
124 static unsigned char bitrev[] = {
125 	0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
126 	0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f
127 };
128 
epcs_bitrev(unsigned char c)129 static unsigned char epcs_bitrev (unsigned char c)
130 {
131 	unsigned char val;
132 
133 	val  = bitrev[c>>4];
134 	val |= bitrev[c & 0x0f]<<4;
135 	return (val);
136 }
137 
epcs_rcv(unsigned char * dst,int len)138 static void epcs_rcv (unsigned char *dst, int len)
139 {
140 	while (len--) {
141 		epcs_tx (0);
142 		*dst++ = epcs_rx ();
143 	}
144 }
145 
epcs_rrcv(unsigned char * dst,int len)146 static void epcs_rrcv (unsigned char *dst, int len)
147 {
148 	while (len--) {
149 		epcs_tx (0);
150 		*dst++ = epcs_bitrev (epcs_rx ());
151 	}
152 }
153 
epcs_snd(unsigned char * src,int len)154 static void epcs_snd (unsigned char *src, int len)
155 {
156 	while (len--) {
157 		epcs_tx (*src++);
158 		epcs_rx ();
159 	}
160 }
161 
epcs_rsnd(unsigned char * src,int len)162 static void epcs_rsnd (unsigned char *src, int len)
163 {
164 	while (len--) {
165 		epcs_tx (epcs_bitrev (*src++));
166 		epcs_rx ();
167 	}
168 }
169 
epcs_wr_enable(void)170 static void epcs_wr_enable (void)
171 {
172 	epcs_cs (1);
173 	epcs_tx (EPCS_WRITE_ENA);
174 	epcs_rx ();
175 	epcs_cs (0);
176 }
177 
epcs_status_rd(void)178 static unsigned char epcs_status_rd (void)
179 {
180 	unsigned char status;
181 
182 	epcs_cs (1);
183 	epcs_tx (EPCS_READ_STAT);
184 	epcs_rx ();
185 	epcs_tx (0);
186 	status = epcs_rx ();
187 	epcs_cs (0);
188 	return (status);
189 }
190 
epcs_status_wr(unsigned char status)191 static void epcs_status_wr (unsigned char status)
192 {
193 	epcs_wr_enable ();
194 	epcs_cs (1);
195 	epcs_tx (EPCS_WRITE_STAT);
196 	epcs_rx ();
197 	epcs_tx (status);
198 	epcs_rx ();
199 	epcs_cs (0);
200 	return;
201 }
202 
203 /***********************************************************************
204  * Device information
205  ***********************************************************************/
206 
207 static struct epcs_devinfo_t devinfo[] = {
208 	{ "EPCS1 ", 0x10, 17, 4, 15, 8, 0x0c },
209 	{ "EPCS4 ", 0x12, 19, 8, 16, 8, 0x1c },
210 	{ "EPCS16", 0x14, 21, 32, 16, 8, 0x1c },
211 	{ "EPCS64", 0x16, 23,128, 16, 8, 0x1c },
212 	{ 0, 0, 0, 0, 0, 0 }
213 };
214 
epcs_reset(void)215 int epcs_reset (void)
216 {
217 	/* When booting from an epcs controller, the epcs bootrom
218 	 * code may leave the slave select in an asserted state.
219 	 * This causes two problems: (1) The initial epcs access
220 	 * will fail -- not a big deal, and (2) a software reset
221 	 * will cause the bootrom code to hang since it does not
222 	 * ensure the select is negated prior to first access -- a
223 	 * big deal. Here we just negate chip select and everything
224 	 * gets better :-)
225 	 */
226 	epcs_cs (0); /* Negate chip select */
227 	return (0);
228 }
229 
epcs_dev_find(void)230 epcs_devinfo_t *epcs_dev_find (void)
231 {
232 	unsigned char buf[4];
233 	unsigned char id;
234 	int i;
235 	struct epcs_devinfo_t *dev = NULL;
236 
237 	/* Read silicon id requires 3 "dummy bytes" before it's put
238 	 * on the wire.
239 	 */
240 	buf[0] = EPCS_READ_ID;
241 	buf[1] = 0;
242 	buf[2] = 0;
243 	buf[3] = 0;
244 
245 	epcs_cs (1);
246 	epcs_snd (buf,4);
247 	epcs_rcv (buf,1);
248 	if (epcs_cs (0) == -1)
249 		return (NULL);
250 	id = buf[0];
251 
252 	/* Find the info struct */
253 	i = 0;
254 	while (devinfo[i].name) {
255 		if (id == devinfo[i].id) {
256 			dev = &devinfo[i];
257 			break;
258 		}
259 		i++;
260 	}
261 
262 	return (dev);
263 }
264 
265 /***********************************************************************
266  * Misc Utilities
267  ***********************************************************************/
epcs_cfgsz(void)268 int epcs_cfgsz (void)
269 {
270 	int sz = 0;
271 	unsigned char buf[128];
272 	unsigned char *p;
273 	struct epcs_devinfo_t *dev = epcs_dev_find ();
274 
275 	if (!dev)
276 		return (-1);
277 
278 	/* Read in the first 128 bytes of the device */
279 	buf[0] = EPCS_READ_BYTES;
280 	buf[1] = 0;
281 	buf[2] = 0;
282 	buf[3] = 0;
283 
284 	epcs_cs (1);
285 	epcs_snd (buf,4);
286 	epcs_rrcv (buf, sizeof(buf));
287 	epcs_cs (0);
288 
289 	/* Search for the starting 0x6a which is followed by the
290 	 * 4-byte 'register' and 4-byte bit-count.
291 	 */
292 	p = buf;
293 	while (p < buf + sizeof(buf)-8) {
294 		if ( *p == 0x6a ) {
295 			/* Point to bit count and extract */
296 			p += 5;
297 			sz = *p++;
298 			sz |= *p++ << 8;
299 			sz |= *p++ << 16;
300 			sz |= *p++ << 24;
301 			/* Convert to byte count */
302 			sz += 7;
303 			sz >>= 3;
304 		} else if (*p == 0xff) {
305 			/* 0xff is ok ... just skip */
306 			p++;
307 			continue;
308 		} else {
309 			/* Not 0xff or 0x6a ... something's not
310 			 * right ... report 'unknown' (sz=0).
311 			 */
312 			break;
313 		}
314 	}
315 	return (sz);
316 }
317 
epcs_erase(unsigned start,unsigned end)318 int epcs_erase (unsigned start, unsigned end)
319 {
320 	unsigned off, sectsz;
321 	unsigned char buf[4];
322 	struct epcs_devinfo_t *dev = epcs_dev_find ();
323 
324 	if (!dev || (start>end))
325 		return (-1);
326 
327 	/* Erase the requested sectors. An address is required
328 	 * that lies within the requested sector -- we'll just
329 	 * use the first address in the sector.
330 	 */
331 	printf ("epcs erasing sector %d ", start);
332 	if (start != end)
333 		printf ("to %d ", end);
334 	sectsz = (1 << dev->sz_sect);
335 	while (start <= end) {
336 		off = start * sectsz;
337 		start++;
338 
339 		buf[0] = EPCS_ERASE_SECT;
340 		buf[1] = off >> 16;
341 		buf[2] = off >> 8;
342 		buf[3] = off;
343 
344 		epcs_wr_enable ();
345 		epcs_cs (1);
346 		epcs_snd (buf,4);
347 		epcs_cs (0);
348 
349 		printf ("."); /* Some user feedback */
350 
351 		/* Wait for erase to complete */
352 		while (epcs_status_rd() & EPCS_STATUS_WIP)
353 			;
354 	}
355 	printf (" done.\n");
356 	return (0);
357 }
358 
epcs_read(ulong addr,ulong off,ulong cnt)359 int epcs_read (ulong addr, ulong off, ulong cnt)
360 {
361 	unsigned char buf[4];
362 	struct epcs_devinfo_t *dev = epcs_dev_find ();
363 
364 	if (!dev)
365 		return (-1);
366 
367 	buf[0] = EPCS_READ_BYTES;
368 	buf[1] = off >> 16;
369 	buf[2] = off >> 8;
370 	buf[3] = off;
371 
372 	epcs_cs (1);
373 	epcs_snd (buf,4);
374 	epcs_rrcv ((unsigned char *)addr, cnt);
375 	epcs_cs (0);
376 
377 	return (0);
378 }
379 
epcs_write(ulong addr,ulong off,ulong cnt)380 int epcs_write (ulong addr, ulong off, ulong cnt)
381 {
382 	ulong wrcnt;
383 	unsigned pgsz;
384 	unsigned char buf[4];
385 	struct epcs_devinfo_t *dev = epcs_dev_find ();
386 
387 	if (!dev)
388 		return (-1);
389 
390 	pgsz = (1<<dev->sz_page);
391 	while (cnt) {
392 		if (off % pgsz)
393 			wrcnt = pgsz - (off % pgsz);
394 		else
395 			wrcnt = pgsz;
396 		wrcnt = (wrcnt > cnt) ? cnt : wrcnt;
397 
398 		buf[0] = EPCS_WRITE_BYTES;
399 		buf[1] = off >> 16;
400 		buf[2] = off >> 8;
401 		buf[3] = off;
402 
403 		epcs_wr_enable ();
404 		epcs_cs (1);
405 		epcs_snd (buf,4);
406 		epcs_rsnd ((unsigned char *)addr, wrcnt);
407 		epcs_cs (0);
408 
409 		/* Wait for write to complete */
410 		while (epcs_status_rd() & EPCS_STATUS_WIP)
411 			;
412 
413 		cnt -= wrcnt;
414 		off += wrcnt;
415 		addr += wrcnt;
416 	}
417 
418 	return (0);
419 }
420 
epcs_verify(ulong addr,ulong off,ulong cnt,ulong * err)421 int epcs_verify (ulong addr, ulong off, ulong cnt, ulong *err)
422 {
423 	ulong rdcnt;
424 	unsigned char buf[256];
425 	unsigned char *start,*end;
426 	int i;
427 
428 	start = end = (unsigned char *)addr;
429 	while (cnt) {
430 		rdcnt = (cnt>sizeof(buf)) ? sizeof(buf) : cnt;
431 		epcs_read ((ulong)buf, off, rdcnt);
432 		for (i=0; i<rdcnt; i++) {
433 			if (*end != buf[i]) {
434 				*err = end - start;
435 				return(-1);
436 			}
437 			end++;
438 		}
439 		cnt -= rdcnt;
440 		off += rdcnt;
441 	}
442 	return (0);
443 }
444 
epcs_sect_erased(int sect,unsigned * offset,struct epcs_devinfo_t * dev)445 static int epcs_sect_erased (int sect, unsigned *offset,
446 		struct epcs_devinfo_t *dev)
447 {
448 	unsigned char buf[128];
449 	unsigned off, end;
450 	unsigned sectsz;
451 	int i;
452 
453 	sectsz = (1 << dev->sz_sect);
454 	off = sectsz * sect;
455 	end = off + sectsz;
456 
457 	while (off < end) {
458 		epcs_read ((ulong)buf, off, sizeof(buf));
459 		for (i=0; i < sizeof(buf); i++) {
460 			if (buf[i] != 0xff) {
461 				*offset = off + i;
462 				return (0);
463 			}
464 		}
465 		off += sizeof(buf);
466 	}
467 	return (1);
468 }
469 
470 
471 /***********************************************************************
472  * Commands
473  ***********************************************************************/
474 static
do_epcs_info(struct epcs_devinfo_t * dev,int argc,char * argv[])475 void do_epcs_info (struct epcs_devinfo_t *dev, int argc, char *argv[])
476 {
477 	int i;
478 	unsigned char stat;
479 	unsigned tmp;
480 	int erased;
481 
482 	/* Basic device info */
483 	printf ("%s: %d kbytes (%d sectors x %d kbytes,"
484 		" %d bytes/page)\n",
485 		dev->name, 1 << (dev->size-10),
486 		dev->num_sects, 1 << (dev->sz_sect-10),
487 		1 << dev->sz_page );
488 
489 	/* Status -- for now protection is all-or-nothing */
490 	stat = epcs_status_rd();
491 	printf ("status: 0x%02x (WIP:%d, WEL:%d, PROT:%s)\n",
492 		stat,
493 		(stat & EPCS_STATUS_WIP) ? 1 : 0,
494 	        (stat & EPCS_STATUS_WEL) ? 1 : 0,
495 		(stat & dev->prot_mask) ? "on" : "off" );
496 
497 	/* Configuration  */
498 	tmp = epcs_cfgsz ();
499 	if (tmp) {
500 		printf ("config: 0x%06x (%d) bytes\n", tmp, tmp );
501 	} else {
502 		printf ("config: unknown\n" );
503 	}
504 
505 	/* Sector info */
506 	for (i=0; (i < dev->num_sects) && (argc > 1); i++) {
507 		erased = epcs_sect_erased (i, &tmp, dev);
508 		if ((i & 0x03) == 0) printf ("\n");
509 		printf ("%4d: %07x ",
510 			i, i*(1<<dev->sz_sect) );
511 		if (erased)
512 			printf ("E ");
513 		else
514 			printf ("  ");
515 	}
516 	printf ("\n");
517 
518 	return;
519 }
520 
521 static
do_epcs_erase(struct epcs_devinfo_t * dev,int argc,char * argv[])522 void do_epcs_erase (struct epcs_devinfo_t *dev, int argc, char *argv[])
523 {
524 	unsigned start,end;
525 
526 	if ((argc < 3) || (argc > 4)) {
527 		printf ("USAGE: epcs erase sect [end]\n");
528 		return;
529 	}
530 	if ((epcs_status_rd() & dev->prot_mask) != 0) {
531 		printf ( "epcs: device protected.\n");
532 		return;
533 	}
534 
535 	start = simple_strtoul (argv[2], NULL, 10);
536 	if (argc > 3)
537 		end = simple_strtoul (argv[3], NULL, 10);
538 	else
539 		end = start;
540 	if ((start >= dev->num_sects) || (start > end)) {
541 		printf ("epcs: invalid sector range: [%d:%d]\n",
542 			start, end );
543 		return;
544 	}
545 
546 	epcs_erase (start, end);
547 
548 	return;
549 }
550 
551 static
do_epcs_protect(struct epcs_devinfo_t * dev,int argc,char * argv[])552 void do_epcs_protect (struct epcs_devinfo_t *dev, int argc, char *argv[])
553 {
554 	unsigned char stat;
555 
556 	/* For now protection is all-or-nothing to keep things
557 	 * simple. The protection bits don't map in a linear
558 	 * fashion ... and we would rather protect the bottom
559 	 * of the device since it contains the config data and
560 	 * leave the top unprotected for app use. But unfortunately
561 	 * protection works from top-to-bottom so it does
562 	 * really help very much from a software app point-of-view.
563 	 */
564 	if (argc < 3) {
565 		printf ("USAGE: epcs protect on | off\n");
566 		return;
567 	}
568 	if (!dev)
569 		return;
570 
571 	/* Protection on/off is just a matter of setting/clearing
572 	 * all protection bits in the status register.
573 	 */
574 	stat = epcs_status_rd ();
575 	if (strcmp ("on", argv[2]) == 0) {
576 		stat |= dev->prot_mask;
577 	} else if (strcmp ("off", argv[2]) == 0 ) {
578 		stat &= ~dev->prot_mask;
579 	} else {
580 		printf ("epcs: unknown protection: %s\n", argv[2]);
581 		return;
582 	}
583 	epcs_status_wr (stat);
584 	return;
585 }
586 
587 static
do_epcs_read(struct epcs_devinfo_t * dev,int argc,char * argv[])588 void do_epcs_read (struct epcs_devinfo_t *dev, int argc, char *argv[])
589 {
590 	ulong addr,off,cnt;
591 	ulong sz;
592 
593 	if (argc < 5) {
594 		printf ("USAGE: epcs read addr offset count\n");
595 		return;
596 	}
597 
598 	sz = 1 << dev->size;
599 	addr = simple_strtoul (argv[2], NULL, 16);
600 	off  = simple_strtoul (argv[3], NULL, 16);
601 	cnt  = simple_strtoul (argv[4], NULL, 16);
602 	if (off > sz) {
603 		printf ("offset is greater than device size"
604 			"... aborting.\n");
605 		return;
606 	}
607 	if ((off + cnt) > sz) {
608 		printf ("request exceeds device size"
609 			"... truncating.\n");
610 		cnt = sz - off;
611 	}
612 	printf ("epcs: read %08lx <- %06lx (0x%lx bytes)\n",
613 			addr, off, cnt);
614 	epcs_read (addr, off, cnt);
615 
616 	return;
617 }
618 
619 static
do_epcs_write(struct epcs_devinfo_t * dev,int argc,char * argv[])620 void do_epcs_write (struct epcs_devinfo_t *dev, int argc, char *argv[])
621 {
622 	ulong addr,off,cnt;
623 	ulong sz;
624 	ulong err;
625 
626 	if (argc < 5) {
627 		printf ("USAGE: epcs write addr offset count\n");
628 		return;
629 	}
630 	if ((epcs_status_rd() & dev->prot_mask) != 0) {
631 		printf ( "epcs: device protected.\n");
632 		return;
633 	}
634 
635 	sz = 1 << dev->size;
636 	addr = simple_strtoul (argv[2], NULL, 16);
637 	off  = simple_strtoul (argv[3], NULL, 16);
638 	cnt  = simple_strtoul (argv[4], NULL, 16);
639 	if (off > sz) {
640 		printf ("offset is greater than device size"
641 			"... aborting.\n");
642 		return;
643 	}
644 	if ((off + cnt) > sz) {
645 		printf ("request exceeds device size"
646 			"... truncating.\n");
647 		cnt = sz - off;
648 	}
649 	printf ("epcs: write %08lx -> %06lx (0x%lx bytes)\n",
650 			addr, off, cnt);
651 	epcs_write (addr, off, cnt);
652 	if (epcs_verify (addr, off, cnt, &err) != 0)
653 		printf ("epcs: write error at offset %06lx\n", err);
654 
655 	return;
656 }
657 
658 static
do_epcs_verify(struct epcs_devinfo_t * dev,int argc,char * argv[])659 void do_epcs_verify (struct epcs_devinfo_t *dev, int argc, char *argv[])
660 {
661 	ulong addr,off,cnt;
662 	ulong sz;
663 	ulong err;
664 
665 	if (argc < 5) {
666 		printf ("USAGE: epcs verify addr offset count\n");
667 		return;
668 	}
669 
670 	sz = 1 << dev->size;
671 	addr = simple_strtoul (argv[2], NULL, 16);
672 	off  = simple_strtoul (argv[3], NULL, 16);
673 	cnt  = simple_strtoul (argv[4], NULL, 16);
674 	if (off > sz) {
675 		printf ("offset is greater than device size"
676 			"... aborting.\n");
677 		return;
678 	}
679 	if ((off + cnt) > sz) {
680 		printf ("request exceeds device size"
681 			"... truncating.\n");
682 		cnt = sz - off;
683 	}
684 	printf ("epcs: verify %08lx -> %06lx (0x%lx bytes)\n",
685 			addr, off, cnt);
686 	if (epcs_verify (addr, off, cnt, &err) != 0)
687 		printf ("epcs: verify error at offset %06lx\n", err);
688 
689 	return;
690 }
691 
692 /*-----------------------------------------------------------------------*/
do_epcs(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])693 int do_epcs (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
694 {
695 	int len;
696 	struct epcs_devinfo_t *dev = epcs_dev_find ();
697 
698 	if (!dev) {
699 		printf ("epcs: device not found.\n");
700 		return (-1);
701 	}
702 
703 	if (argc < 2) {
704 		do_epcs_info (dev, argc, argv);
705 		return (0);
706 	}
707 
708 	len = strlen (argv[1]);
709 	if (strncmp ("info", argv[1], len) == 0) {
710 		do_epcs_info (dev, argc, argv);
711 	} else if (strncmp ("erase", argv[1], len) == 0) {
712 		do_epcs_erase (dev, argc, argv);
713 	} else if (strncmp ("protect", argv[1], len) == 0) {
714 		do_epcs_protect (dev, argc, argv);
715 	} else if (strncmp ("read", argv[1], len) == 0) {
716 		do_epcs_read (dev, argc, argv);
717 	} else if (strncmp ("write", argv[1], len) == 0) {
718 		do_epcs_write (dev, argc, argv);
719 	} else if (strncmp ("verify", argv[1], len) == 0) {
720 		do_epcs_verify (dev, argc, argv);
721 	} else {
722 		printf ("epcs: unknown operation: %s\n", argv[1]);
723 	}
724 
725 	return (0);
726 }
727 
728 /*-----------------------------------------------------------------------*/
729 
730 
731 U_BOOT_CMD( epcs, 5, 0, do_epcs, SHORT_HELP, LONG_HELP );
732 
733 #endif /* CONFIG_NIOS_EPCS */
734