📄 asmi.c.svn-base
字号:
/* * (C) Copyright 2003, 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(CONFIG_NIOS_ASMI)#include <command.h>#include <nios-io.h>#if !defined(CFG_NIOS_ASMIBASE)#error "*** CFG_NIOS_ASMIBASE not defined ***"#endif/*-----------------------------------------------------------------------*/#define SHORT_HELP\ "asmi - read/write Cyclone ASMI configuration device.\n"#define LONG_HELP\ "\n"\ "asmi erase start [end]\n"\ " - erase sector start or sectors start through end.\n"\ "asmi info\n"\ " - display ASMI device information.\n"\ "asmi protect on | off\n"\ " - turn device protection on or off.\n"\ "asmi read addr offset count\n"\ " - read count bytes from offset to addr.\n"\ "asmi write addr offset count\n"\ " - write count bytes to offset from addr.\n"\ "asmi verify addr offset count\n"\ " - verify count bytes at offset from addr.\n"/*-----------------------------------------------------------------------*//* Operation codes for serial configuration devices */#define ASMI_WRITE_ENA 0x06 /* Write enable */#define ASMI_WRITE_DIS 0x04 /* Write disable */#define ASMI_READ_STAT 0x05 /* Read status */#define ASMI_READ_BYTES 0x03 /* Read bytes */#define ASMI_READ_ID 0xab /* Read silicon id */#define ASMI_WRITE_STAT 0x01 /* Write status */#define ASMI_WRITE_BYTES 0x02 /* Write bytes */#define ASMI_ERASE_BULK 0xc7 /* Erase entire device */#define ASMI_ERASE_SECT 0xd8 /* Erase sector *//* Device status register bits */#define ASMI_STATUS_WIP (1<<0) /* Write in progress */#define ASMI_STATUS_WEL (1<<1) /* Write enable latch */static nios_asmi_t *asmi = (nios_asmi_t *)CFG_NIOS_ASMIBASE;/*********************************************************************** * Device access ***********************************************************************/static void asmi_cs (int assert){ if (assert) { asmi->control |= NIOS_ASMI_SSO; } else { /* Let all bits shift out */ while ((asmi->status & NIOS_ASMI_TMT) == 0) ; asmi->control &= ~NIOS_ASMI_SSO; }}static void asmi_tx (unsigned char c){ while ((asmi->status & NIOS_ASMI_TRDY) == 0) ; asmi->txdata = c;}static int asmi_rx (void){ while ((asmi->status & NIOS_ASMI_RRDY) == 0) ; return (asmi->rxdata);}static unsigned char bitrev[] = { 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f};static unsigned char asmi_bitrev( unsigned char c ){ unsigned char val; val = bitrev[c>>4]; val |= bitrev[c & 0x0f]<<4; return (val);}static void asmi_rcv (unsigned char *dst, int len){ while (len--) { asmi_tx (0); *dst++ = asmi_rx (); }}static void asmi_rrcv (unsigned char *dst, int len){ while (len--) { asmi_tx (0); *dst++ = asmi_bitrev (asmi_rx ()); }}static void asmi_snd (unsigned char *src, int len){ while (len--) { asmi_tx (*src++); asmi_rx (); }}static void asmi_rsnd (unsigned char *src, int len){ while (len--) { asmi_tx (asmi_bitrev (*src++)); asmi_rx (); }}static void asmi_wr_enable (void){ asmi_cs (1); asmi_tx (ASMI_WRITE_ENA); asmi_rx (); asmi_cs (0);}static unsigned char asmi_status_rd (void){ unsigned char status; asmi_cs (1); asmi_tx (ASMI_READ_STAT); asmi_rx (); asmi_tx (0); status = asmi_rx (); asmi_cs (0); return (status);}static void asmi_status_wr (unsigned char status){ asmi_wr_enable (); asmi_cs (1); asmi_tx (ASMI_WRITE_STAT); asmi_rx (); asmi_tx (status); asmi_rx (); asmi_cs (0); return;}/*********************************************************************** * Device information ***********************************************************************/typedef struct asmi_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 */}asmi_devinfo_t;static struct asmi_devinfo_t devinfo[] = { { "EPCS1 ", 0x10, 17, 4, 15, 8, 0x0c }, { "EPCS4 ", 0x12, 19, 8, 16, 8, 0x1c }, { 0, 0, 0, 0, 0, 0 }};static asmi_devinfo_t *asmi_dev_find (void){ unsigned char buf[4]; unsigned char id; int i; struct asmi_devinfo_t *dev = NULL; /* Read silicon id requires 3 "dummy bytes" before it's put * on the wire. */ buf[0] = ASMI_READ_ID; buf[1] = 0; buf[2] = 0; buf[3] = 0; asmi_cs (1); asmi_snd (buf,4); asmi_rcv (buf,1); asmi_cs (0); 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 ***********************************************************************/static unsigned asmi_cfgsz (void){ unsigned sz = 0; unsigned char buf[128]; unsigned char *p; /* Read in the first 128 bytes of the device */ buf[0] = ASMI_READ_BYTES; buf[1] = 0; buf[2] = 0; buf[3] = 0; asmi_cs (1); asmi_snd (buf,4); asmi_rrcv (buf, sizeof(buf)); asmi_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);}static int asmi_erase (unsigned start, unsigned end){ unsigned off, sectsz; unsigned char buf[4]; struct asmi_devinfo_t *dev = asmi_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 ("asmi 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] = ASMI_ERASE_SECT; buf[1] = off >> 16; buf[2] = off >> 8; buf[3] = off; asmi_wr_enable (); asmi_cs (1); asmi_snd (buf,4); asmi_cs (0); printf ("."); /* Some user feedback */ /* Wait for erase to complete */ while (asmi_status_rd() & ASMI_STATUS_WIP) ; } printf (" done.\n"); return (0);}static int asmi_read (ulong addr, ulong off, ulong cnt){ unsigned char buf[4]; buf[0] = ASMI_READ_BYTES; buf[1] = off >> 16; buf[2] = off >> 8; buf[3] = off; asmi_cs (1); asmi_snd (buf,4); asmi_rrcv ((unsigned char *)addr, cnt); asmi_cs (0); return (0);}staticint asmi_write (ulong addr, ulong off, ulong cnt){ ulong wrcnt; unsigned pgsz; unsigned char buf[4]; struct asmi_devinfo_t *dev = asmi_dev_find ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -