?? epcs.c
字號:
/* * (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);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -