summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/shared/flash/intelFlash.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/shared/flash/intelFlash.c')
-rw-r--r--bsps/powerpc/shared/flash/intelFlash.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/bsps/powerpc/shared/flash/intelFlash.c b/bsps/powerpc/shared/flash/intelFlash.c
new file mode 100644
index 0000000000..0d2fa92f31
--- /dev/null
+++ b/bsps/powerpc/shared/flash/intelFlash.c
@@ -0,0 +1,464 @@
+/*
+ * Trivial driver for 16-bit intel flash present on the
+ * MVME5500/MVME6100 boards.
+ *
+ * For recognized devices, look for 'intelDevs'.
+ *
+ * This driver currently only supports stride=4 and 16-bit
+ * mode (width=2).
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+#ifdef TESTING
+
+#define TIMEOUT_US 100000
+#define rtems_task_wake_after(t) sleep(t)
+#define CLOCKRATE_GET(p) (*(p)=1)
+
+#else
+
+#include <rtems.h>
+#define TIMEOUT_US 1000
+#define CLOCKRATE_GET(p) *p = rtems_clock_get_ticks_per_second()
+
+#endif
+
+#define ERASE_TIMEOUT_S 2
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <bsp/flashPgmPvt.h>
+
+#define DEBUG 0
+#undef DEBUG
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#define NumberOf(arr) (sizeof(arr)/sizeof(arr[0]))
+
+/* This driver assumes two 16-bit devices in parallel */
+
+/********* Register Definitions ****************/
+
+/* command codes */
+#define F_CMD_RD_ARR 0xffffffff /* back to 'normal' read mode */
+#define F_CMD_RD_ID 0x90909090 /* read from ID space */
+#define F_CMD_RD_STA 0x70707070 /* read status register */
+#define F_CMD_WR_STA 0x50505050 /* clear status register */
+#define F_CMD_WR_BUF 0xe8e8e8e8 /* write to buffer */
+#define F_CMD_WR_WRD 0x40404040 /* write word */
+#define F_CMD_WR_ERA 0x20202020 /* block erase */
+#define F_CMD_WR_LCK 0x60606060 /* lock bit (1st cycle) */
+#define F_CMD_WR_CMD 0xd0d0d0d0 /* commit erase */
+#define F_CMD_WR_LCK_SET 0x01010101 /* lock block commit */
+
+/* Status codes (F_CMD_RD_STA result) */
+#define STA_RDY (1<<7) /* ready */
+#define STA_ES (1<<6) /* erase suspend */
+#define STA_EE (1<<5) /* erase error */
+#define STA_PE (1<<4) /* program error */
+#define STA_VE (1<<3) /* VPEN < min */
+#define STA_PS (1<<2) /* program susp. */
+#define STA_LE (1<<1) /* block locked */
+#define STA_EFP (1<<0) /* buf. EFP stat.*/
+
+/* Any error */
+#define STA_ERROR (STA_EE|STA_PE|STA_VE|STA_LE)
+
+/* TODO: Code using RDYRDY assumes flash is 16-bit wide :-( */
+#define STA_RDYRDY 0x00800080 /* ready status on both devices */
+
+/********* Forward Declarations ****************/
+
+STATIC int
+flash_get_id_intel(struct bankdesc *, uint32_t, uint32_t *, uint32_t *);
+
+STATIC void
+flash_unlock_block_intel(struct bankdesc *, uint32_t);
+
+STATIC void
+flash_lock_block_intel(struct bankdesc *, uint32_t);
+
+STATIC int
+flash_erase_block_intel(struct bankdesc *, uint32_t);
+
+STATIC uint32_t
+flash_check_ready_intel(struct bankdesc *, uint32_t);
+
+STATIC void
+flash_print_stat_intel(struct bankdesc *, uint32_t, int);
+
+STATIC void
+flash_array_mode_intel(struct bankdesc *, uint32_t);
+
+STATIC uint32_t
+flash_write_line_intel(struct bankdesc *, uint32_t, const char *, uint32_t);
+
+/********* Global Variables ********************/
+
+static struct flash_bank_ops intelOps = {
+ get_id : flash_get_id_intel,
+ unlock_block: flash_unlock_block_intel,
+ lock_block : flash_lock_block_intel,
+ erase_block : flash_erase_block_intel,
+ check_ready : flash_check_ready_intel,
+ print_stat : flash_print_stat_intel,
+ array_mode : flash_array_mode_intel,
+ write_line : flash_write_line_intel,
+};
+
+static struct devdesc intelDevs[] = {
+ { 0x8801, "K3 64Mb", 8*1024*1024, 0x40, 0x20000 },
+ { 0x8802, "K3 128Mb", 16*1024*1024, 0x40, 0x20000 },
+ { 0x8803, "K3 256Mb", 32*1024*1024, 0x40, 0x20000 },
+ { 0x8805, "K18 64Mb", 8*1024*1024, 0x40, 0x20000 },
+ { 0x8806, "K18 128Mb", 16*1024*1024, 0x40, 0x20000 },
+ { 0x8807, "K18 256Mb", 32*1024*1024, 0x40, 0x20000 },
+ { 0x0016, "J3 32Mb", 4*1024*1024, 0x20, 0x20000 },
+ { 0x0017, "J3 64Mb", 8*1024*1024, 0x20, 0x20000 },
+ { 0x0018, "J3 128Mb", 16*1024*1024, 0x20, 0x20000 },
+ { 0x001d, "J3 256Mb", 32*1024*1024, 0x20, 0x20000 },
+ { 0, 0, 0, 0}
+};
+
+struct vendesc BSP_flash_vendor_intel[] =
+{
+ { 0x89, "Intel", intelDevs, &intelOps },
+ { 0, 0}
+};
+
+/********* Helper Subroutines ******************/
+
+/* Basic low-level access routine for writing a command to the
+ * internal state machine.
+ *
+ * Flash is slow, so who cares if these access routines
+ * are not extremely efficient...
+ */
+STATIC uint32_t
+BSP_flashReadRaw(uint32_t cmd, uint32_t addr)
+{
+#if DEBUG > 4
+ printf("Writing CMD *0x%08"PRIx32" = 0x%08"PRIx32"\n", addr, cmd);
+#endif
+#ifdef TESTING
+ return STA_RDYRDY;
+#else
+ if ( cmd & 0xffff0000 ) {
+ /* 32-bit access */
+ addr &= ~(sizeof(uint32_t)-1);
+ *(A32)addr = cmd;
+ return *(A32)addr;
+ } else if ( cmd & 0xffffff00 ) {
+ /* 16-bit access */
+ addr &= ~(sizeof(uint16_t)-1);
+ *(A16)addr = cmd;
+ return *(A16)addr;
+ } else {
+ *(A8)addr = cmd;
+ return *(A8)addr;
+ }
+#endif
+}
+
+STATIC void
+BSP_flashWriteRaw(uint32_t val, uint32_t addr)
+{
+#ifdef TESTING
+ printf("Writing CNT *0x%08"PRIx32" = 0x%08"PRIx32"\n", addr, val);
+#else
+/* TODO implicitly assumes FLASH_WIDTH = 2, FLASH_NDEVS = 2 */
+ /* 32-bit access */
+ addr &= ~(sizeof(uint32_t)-1);
+ *(A32)addr = val;
+#endif
+}
+
+STATIC uint32_t
+flash_pend(struct bankdesc *b, uint32_t a, uint32_t timeout_us)
+{
+uint32_t then, now, sta;
+
+ then = BSP_flashBspOps.read_us_timer();
+
+ do {
+ sta = BSP_flashReadRaw(F_CMD_RD_STA, a);
+ now = BSP_flashBspOps.read_us_timer();
+ if ( now-then > timeout_us ) {
+ /* timeout */
+ sta = -1;
+ break;
+ }
+ } while ( STA_RDYRDY != (STA_RDYRDY & sta) );
+
+ /* switch back to normal mode */
+ flash_array_mode_intel(b, a);
+
+ return STA_RDYRDY == sta ? 0 : sta;
+}
+
+
+/********* Access Methods **********************/
+
+STATIC void
+flash_array_mode_intel(struct bankdesc *b, uint32_t a)
+{
+ BSP_flashReadRaw(F_CMD_RD_ARR, a);
+}
+
+/* Dump status bits (F_CMD_RD_STA results); 'verbose' prints non-error bits, too */
+STATIC void
+flash_print_stat_intel(struct bankdesc *b, uint32_t sta, int verbose)
+{
+int ch;
+ if ( sta & STA_ERROR ) {
+ ch = ':';
+ fprintf(stderr,"Errors found");
+ if ( STA_EE & sta ) {
+ fprintf(stderr,"%c ERASE",ch);
+ ch = ',';
+ }
+ if ( STA_PE & sta ) {
+ fprintf(stderr,"%c PROGRAM",ch);
+ ch = ',';
+ }
+ if ( STA_VE & sta ) {
+ fprintf(stderr,"%c VPEN TOO LOW",ch);
+ ch = ',';
+ }
+ if ( STA_LE & sta ) {
+ fprintf(stderr,"%c BLOCK LOCKED",ch);
+ ch = ',';
+ }
+ fprintf(stderr,"\n");
+ }
+ if ( verbose ) {
+ fprintf(stderr,"%sREADY\n",STA_RDY & sta ? "" : "NOT ");
+ }
+}
+
+
+/* Query the status of the device and assert it's readiness
+ * leave off in array-reading mode.
+ *
+ * RETURNS: 0 on success, error status (result of status query) on error.
+ *
+ * NOTES: - error message is printed to stderr.
+ * - device switched back to array mode on exit.
+ * - 'addr' must be 32-bit aligned.
+ */
+STATIC uint32_t
+flash_check_ready_intel(struct bankdesc *b, uint32_t addr)
+{
+uint32_t sta;
+
+ (void)BSP_flashReadRaw(F_CMD_WR_STA, addr);
+ if ( STA_RDYRDY != (STA_RDYRDY & (sta=BSP_flashReadRaw(F_CMD_RD_STA, addr))) ) {
+ fprintf(stderr,"Flash not ready (@0x%08"PRIx32")\n", addr);
+ flash_print_stat_intel(b, sta, 0);
+ } else {
+ sta = 0;
+ }
+ /* switch back to normal mode */
+ flash_array_mode_intel(b, addr);
+ return sta;
+}
+
+/* Erase single block holding 'addr'ess
+ *
+ * RETURNS: zero on error, device status on failure.
+ *
+ * NOTES: - device switched back to array mode on exit.
+ * - 'addr' must be 32-bit aligned.
+ */
+STATIC int
+flash_erase_block_intel(struct bankdesc *b, uint32_t addr)
+{
+uint32_t sta;
+int i;
+rtems_interval p;
+
+ if ( (sta = flash_check_ready_intel(b, addr)) )
+ return sta;
+
+ (void)BSP_flashReadRaw(F_CMD_WR_ERA, addr);
+ (void)BSP_flashReadRaw(F_CMD_WR_CMD, addr);
+
+ CLOCKRATE_GET( &p );
+ i = p * ERASE_TIMEOUT_S;
+
+ while ( STA_RDYRDY != (STA_RDYRDY & (sta = BSP_flashReadRaw(F_CMD_RD_STA, addr))) && --i > 0 ) {
+ rtems_task_wake_after(1);
+ }
+ /* switch back to 'normal' mode */
+ (void)flash_array_mode_intel(b, addr);
+ if ( 0 == i ) {
+ fprintf(stderr,"Flash erase block: timeout\n");
+ return -1;
+ }
+
+ /* Verify */
+ for ( i = 0; i<b->fblksz; i++ ) {
+ if ( (char)0xff != ((char*)addr)[i] ) {
+ fprintf(stderr,"ERROR: Erase verification failed at %p\n",
+ ((char*)addr) + i);
+ return -1;
+ }
+ }
+ return STA_RDYRDY == sta ? 0 : sta;
+}
+
+/* Unlock block holding 'addr'ess
+ *
+ * NOTES: - device switched back to array mode on exit.
+ * - 'addr' must be 32-bit aligned.
+ */
+
+STATIC void
+flash_unlock_block_intel(struct bankdesc *b, uint32_t addr)
+{
+#ifdef DEBUG
+ printf("Unlocking block 0x%08"PRIx32"\n", addr);
+#endif
+ (void)BSP_flashReadRaw(F_CMD_WR_LCK, addr);
+ (void)BSP_flashReadRaw(F_CMD_WR_CMD, addr);
+ flash_pend(b, addr, TIMEOUT_US);
+}
+
+/* Lock block holding 'addr'ess
+ *
+ * NOTES: - device switched back to array mode on exit.
+ * - 'addr' must be 32-bit aligned.
+ */
+
+STATIC void
+flash_lock_block_intel(struct bankdesc *b, uint32_t addr)
+{
+#ifdef DEBUG
+ printf("Locking block 0x%08"PRIx32"\n", addr);
+#endif
+ (void)BSP_flashReadRaw(F_CMD_WR_LCK, addr);
+ (void)BSP_flashReadRaw(F_CMD_WR_LCK_SET, addr);
+ flash_pend(b, addr, TIMEOUT_US);
+}
+
+STATIC uint32_t
+flash_write_line_intel(struct bankdesc *b, uint32_t a, const char *s, uint32_t N)
+{
+uint32_t sta, Nspla, nxt, j;
+union {
+ uint32_t u;
+ char c[sizeof(uint32_t)];
+} buf;
+
+ /* address block */
+ if ( STA_RDYRDY != (sta = BSP_flashReadRaw(F_CMD_WR_BUF, a)) ) {
+ return sta;
+ }
+
+ /* count per device */
+ N /= FLASH_STRIDE(b);
+
+ /* splat out */
+ Nspla = (N<<8) | N;
+ Nspla = (Nspla<<16) | Nspla;
+ BSP_flashWriteRaw(Nspla - 0x01010101, a);
+
+ /* fill buffer */
+ for (nxt = a; N>0; N--) {
+#if defined(TESTING) || (DEBUG > 4)
+ printf("Writing DAT *0x%08"PRIx32" = 0x%08"PRIx32"\n", nxt, *(const uint32_t*)s);
+#endif
+ /* deal with misaligned sources */
+ for ( j=0; j<sizeof(buf.u); j++ ) {
+ buf.c[j] = *s++;
+ }
+ *(A32)nxt = buf.u;
+ nxt += FLASH_STRIDE(b);
+ }
+
+ BSP_flashReadRaw(F_CMD_WR_CMD, a);
+
+ sta = flash_pend(b, a, TIMEOUT_US);
+
+ return sta;
+}
+
+/* Query device for basic information verifying that we talk
+ * to a 'known'/'supported' device.
+ *
+ * NOTES: - device switched back to array mode on exit.
+ * - 'addr' must be 32-bit aligned.
+ */
+
+STATIC int
+flash_get_id_intel(struct bankdesc *b, uint32_t addr, uint32_t *pVendorId, uint32_t *pDeviceId)
+{
+uint16_t v,d;
+
+ if ( 4 != FLASH_STRIDE(b) ) {
+ fprintf(stderr,"intel flash programmer: Strides other than 4 not implemented yet\n");
+ return -1;
+ }
+
+ /* Try to read ID */
+ v = BSP_flashReadRaw(F_CMD_RD_ID, addr);
+ d = BSP_flashReadRaw(F_CMD_RD_ID, addr + FLASH_STRIDE(b));
+
+ /* switch to array mode */
+ flash_array_mode_intel(b, addr);
+
+ *pVendorId = v;
+ *pDeviceId = d;
+
+ return 0;
+}