249 lines
8.9 KiB
C
249 lines
8.9 KiB
C
|
/***********************************************************************
|
||
|
* Copyright(C) 2011, NXP Semiconductor
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Software that is described herein is for illustrative purposes only
|
||
|
* which provides customers with programming information regarding the
|
||
|
* products. This software is supplied "AS IS" without any warranties.
|
||
|
* NXP Semiconductors assumes no responsibility or liability for the
|
||
|
* use of the software, conveys no license or title under any patent,
|
||
|
* copyright, or mask work right to the product. NXP Semiconductors
|
||
|
* reserves the right to make changes in the software without
|
||
|
* notification. NXP Semiconductors also make no representation or
|
||
|
* warranty that such application will be suitable for the specified
|
||
|
* use without further testing or modification.
|
||
|
**********************************************************************/
|
||
|
|
||
|
#ifndef SPIFI_ROM_API_H
|
||
|
#define SPIFI_ROM_API_H
|
||
|
|
||
|
#include <stdint.h>
|
||
|
/* define the symbol TESTING in the environment if test output desired */
|
||
|
|
||
|
/* maintain LONGEST_PROT >= the length (in bytes) of the largest
|
||
|
protection block of any serial flash that this driver handles */
|
||
|
#define LONGEST_PROT 68
|
||
|
|
||
|
typedef uint8_t uc;
|
||
|
|
||
|
#ifndef NULL
|
||
|
#define NULL ((void *)0)
|
||
|
#endif
|
||
|
|
||
|
/* protection/sector descriptors */
|
||
|
typedef struct {
|
||
|
uint32_t base;
|
||
|
uc flags;
|
||
|
int8_t log2;
|
||
|
uint16_t rept;
|
||
|
} protEnt;
|
||
|
/* bits in the flags byte */
|
||
|
enum {RWPROT=1};
|
||
|
|
||
|
/* overall data structure includes # sectors, length of protection reg,
|
||
|
array of descriptors
|
||
|
typedef struct {
|
||
|
uint16_t sectors;
|
||
|
uint16_t protBytes;
|
||
|
protEnt *entries;
|
||
|
} protDesc; */
|
||
|
|
||
|
typedef union {
|
||
|
uint16_t hw;
|
||
|
uc byte[2];
|
||
|
}stat_t;
|
||
|
/* the object that init returns, and other routines use as an operand */
|
||
|
typedef struct {
|
||
|
uint32_t base, regbase, devSize, memSize;
|
||
|
uc mfger, devType, devID, busy;
|
||
|
stat_t stat;
|
||
|
uint16_t reserved;
|
||
|
uint16_t set_prot, write_prot;
|
||
|
uint32_t mem_cmd, prog_cmd;
|
||
|
uint16_t sectors, protBytes;
|
||
|
uint32_t opts, errCheck;
|
||
|
uc erase_shifts[4], erase_ops[4];
|
||
|
protEnt *protEnts;
|
||
|
char prot[LONGEST_PROT];
|
||
|
} SPIFIobj;
|
||
|
|
||
|
/* operands of program and erase */
|
||
|
typedef struct {
|
||
|
char *dest;
|
||
|
uint32_t length;
|
||
|
char *scratch;
|
||
|
int32_t protect;
|
||
|
uint32_t options;
|
||
|
} SPIFIopers;
|
||
|
|
||
|
/* instruction classes for wait_busy */
|
||
|
typedef enum {stat_inst, block_erase, prog_inst, chip_erase} inst_type;
|
||
|
|
||
|
/* bits in options operands (MODE3, RCVCLK, and FULLCLK
|
||
|
have the same relationship as in the Control register) */
|
||
|
#define S_MODE3 1
|
||
|
#define S_MODE0 0
|
||
|
#define S_MINIMAL 2
|
||
|
#define S_MAXIMAL 0
|
||
|
#define S_FORCE_ERASE 4
|
||
|
#define S_ERASE_NOT_REQD 8
|
||
|
#define S_CALLER_ERASE 8
|
||
|
#define S_ERASE_AS_REQD 0
|
||
|
#define S_VERIFY_PROG 0x10
|
||
|
#define S_VERIFY_ERASE 0x20
|
||
|
#define S_NO_VERIFY 0
|
||
|
#define S_RCVCLK 0x80
|
||
|
#define S_INTCLK 0
|
||
|
#define S_FULLCLK 0x40
|
||
|
#define S_HALFCLK 0
|
||
|
#define S_DUAL 0x100
|
||
|
#define S_CALLER_PROT 0x200
|
||
|
#define S_DRIVER_PROT 0
|
||
|
|
||
|
/* the following values in the first post-address memory command byte work
|
||
|
for all known quad devices that support "no opcode" operation */
|
||
|
#define NO_OPCODE_FOLLOWS 0xA5
|
||
|
#define OPCODE_FOLLOWS 0xFF
|
||
|
|
||
|
/* basic SPI commands for serial flash */
|
||
|
#define BASE_READ_CMD (CMD_RD<<OPCODE_SHIFT|4<<FRAMEFORM_SHIFT|UNL_DATA)
|
||
|
#define FAST_READ_CMD (CMD_READ_FAST<<OPCODE_SHIFT|4<<FRAMEFORM_SHIFT|1<<INTLEN_SHIFT|UNL_DATA)
|
||
|
#define BASE_PROG_CMD (CMD_PROG<<OPCODE_SHIFT|4<<FRAMEFORM_SHIFT|DOUT)
|
||
|
|
||
|
/* the length of a standard program command is 256 on all devices */
|
||
|
#define PROG_SIZE 256
|
||
|
|
||
|
/* options in obj->opts (mostly for setMulti) */
|
||
|
/* used by Winbond: send 0xA3 command so hardware can read faster */
|
||
|
#define OPT_SEND_A3 1
|
||
|
/* used by SST: send 0x38 command to enable quad and allow full command set */
|
||
|
#define OPT_SEND_38 2
|
||
|
/* used by Winbond and others: read status reg 2, check it,
|
||
|
if necessary write it back with Quad Enable set */
|
||
|
#define OPT_35_OR02_01 4
|
||
|
/* used by Atmel: read Configuration register, if necessary set Quad Enable */
|
||
|
#define OPT_3F_OR80_3E 8
|
||
|
/* used by Numonyx to set all-quad mode: only for parts that include RSTQIO */
|
||
|
#define OPT_65_CLR_C0_61 0x10
|
||
|
/* used by Numonyx: send 0x81 command to write Volatile Configuration Register
|
||
|
to set # dummy bytes and allow XIP mode */
|
||
|
#define OPT_81 0x20
|
||
|
/* set for devices without full device erase command (Numonyx type 0x40) */
|
||
|
#define OPT_NO_DEV_ERASE 0x40
|
||
|
/* used by Macronix: status reg 2 includes selection between write-protect
|
||
|
in status reg and command-based */
|
||
|
#define OPT_WPSEL 0x80
|
||
|
/* set when protection data has been read into the SPIFI object */
|
||
|
#define OPT_PROT_READ 0x100
|
||
|
/* set if device needs 4-byte address (and maybe 0x4B command = use 4-byte address) */
|
||
|
#define OPT_4BAD 0x200
|
||
|
/* set if setMulti should set the Dual bit in Control reg */
|
||
|
#define OPT_DUAL 0x400
|
||
|
/* send "# dummy bits" in C0 command to Winbond */
|
||
|
#define OPT_C0 0x800
|
||
|
/* set QE for Chingis */
|
||
|
#define OPT_05_OR40_01 0x1000
|
||
|
/* write status does not go busy */
|
||
|
#define OPT_01_NO_BUSY 0x2000
|
||
|
/* protection mode bits moved from protMode byte to opts Fri May 13 2011 */
|
||
|
#define OPT_PROT_STAT 0x4000
|
||
|
#define OPT_PROT_REG 0x8000
|
||
|
#define OPT_PROT_CMD3 0x10000
|
||
|
#define OPT_PROT_CMDE 0x20000
|
||
|
#define OPT_PROT_MASK 0x3C000
|
||
|
|
||
|
#define OPT_ALL_QUAD 0x40000
|
||
|
|
||
|
#ifndef OMIT_ROM_TABLE
|
||
|
/* interface to ROM API */
|
||
|
typedef struct {
|
||
|
int32_t (*spifi_init) (SPIFIobj *obj, uint32_t csHigh, uint32_t options,
|
||
|
uint32_t mhz);
|
||
|
int32_t (*spifi_program) (SPIFIobj *obj, char *source, SPIFIopers *opers);
|
||
|
int32_t (*spifi_erase) (SPIFIobj *obj, SPIFIopers *opers);
|
||
|
/* mode switching */
|
||
|
void (*cancel_mem_mode)(SPIFIobj *obj);
|
||
|
void (*set_mem_mode) (SPIFIobj *obj);
|
||
|
|
||
|
/* mid level functions */
|
||
|
int32_t (*checkAd) (SPIFIobj *obj, SPIFIopers *opers);
|
||
|
int32_t (*setProt) (SPIFIobj *obj, SPIFIopers *opers, char *change,
|
||
|
char *saveProt);
|
||
|
int32_t (*check_block) (SPIFIobj *obj, char *source, SPIFIopers *opers,
|
||
|
uint32_t check_program);
|
||
|
int32_t (*send_erase_cmd) (SPIFIobj *obj, uint8_t op, uint32_t addr);
|
||
|
uint32_t (*ck_erase) (SPIFIobj *obj, uint32_t *addr, uint32_t length);
|
||
|
int32_t (*prog_block) (SPIFIobj *obj, char *source, SPIFIopers *opers,
|
||
|
uint32_t *left_in_page);
|
||
|
uint32_t (*ck_prog) (SPIFIobj *obj, char *source, char *dest, uint32_t length);
|
||
|
|
||
|
/* low level functions */
|
||
|
void(*setSize) (SPIFIobj *obj, int32_t value);
|
||
|
int32_t (*setDev) (SPIFIobj *obj, uint32_t opts, uint32_t mem_cmd,
|
||
|
uint32_t prog_cmd);
|
||
|
uint32_t (*cmd) (uc op, uc addrLen, uc intLen, uint16_t len);
|
||
|
uint32_t (*readAd) (SPIFIobj *obj, uint32_t cmd, uint32_t addr);
|
||
|
void (*send04) (SPIFIobj *obj, uc op, uc len, uint32_t value);
|
||
|
void (*wren_sendAd) (SPIFIobj *obj, uint32_t cmd, uint32_t addr, uint32_t value);
|
||
|
int32_t (*write_stat) (SPIFIobj *obj, uc len, uint16_t value);
|
||
|
int32_t (*wait_busy) (SPIFIobj *obj, uc prog_or_erase);
|
||
|
} SPIFI_RTNS;
|
||
|
|
||
|
#define define_spifi_romPtr(name) const SPIFI_RTNS *name=*((SPIFI_RTNS **)SPIFI_ROM_PTR)
|
||
|
#endif /* OMIT_ROM_TABLE */
|
||
|
|
||
|
#ifdef USE_SPIFI_LIB
|
||
|
extern SPIFI_RTNS spifi_table;
|
||
|
#endif /* USE_SPIFI_LIB */
|
||
|
|
||
|
/* example of using this interface:
|
||
|
#include "spifi_rom_api.h"
|
||
|
#define CSHIGH 4
|
||
|
#define SPIFI_MHZ 80
|
||
|
#define source_data_ad (char *)1234
|
||
|
|
||
|
int32_t rc;
|
||
|
SPIFIopers opers;
|
||
|
|
||
|
define_spifi_romPtr(spifi);
|
||
|
SPIFIobj *obj = malloc(sizeof(SPIFIobj));
|
||
|
if (!obj) { can't allocate memory }
|
||
|
|
||
|
rc = spifi->spifi_init (obj, CSHIGH, S_FULLCLK+S_RCVCLK, SPIFI_MHZ);
|
||
|
if (rc) { investigate init error rc }
|
||
|
printf ("the serial flash contains %d bytes\n", obj->devSize);
|
||
|
|
||
|
opers.dest = where_to_program;
|
||
|
opers.length = how_many_bytes;
|
||
|
opers.scratch = NULL; // unprogrammed data is not saved/restored
|
||
|
opers.protect = -1; // save & restore protection
|
||
|
opers.options = S_VERIFY_PROG;
|
||
|
|
||
|
rc = spifi->spifi_program (obj, source_data_ad, &opers);
|
||
|
if (rc) { investigate program error rc }
|
||
|
*/
|
||
|
|
||
|
/* these are for normal users, including boot code */
|
||
|
int32_t spifi_init (SPIFIobj *obj, uint32_t csHigh, uint32_t options, uint32_t mhz);
|
||
|
int32_t spifi_program (SPIFIobj *obj, char *source, SPIFIopers *opers);
|
||
|
int32_t spifi_erase (SPIFIobj *obj, SPIFIopers *opers);
|
||
|
|
||
|
/* these are used by the manufacturer-specific init functions */
|
||
|
void setSize (SPIFIobj *obj, int32_t value);
|
||
|
int32_t setDev (SPIFIobj *obj, uint32_t opts, uint32_t mem_cmd, uint32_t prog_cmd);
|
||
|
uint32_t read04(SPIFIobj *obj, uc op, uc len);
|
||
|
int32_t write_stat (SPIFIobj *obj, uc len, uint16_t value);
|
||
|
void setProtEnts(SPIFIobj *obj, const protEnt *p, uint32_t protTabLen);
|
||
|
|
||
|
/* needs to be defined for each platform */
|
||
|
void pullMISO(int high);
|
||
|
|
||
|
#ifdef TESTING
|
||
|
/* used by testing code */
|
||
|
unsigned short getProtBytes (SPIFIobj *obj, unsigned short *sectors);
|
||
|
/* predeclare a debug routine */
|
||
|
void wait_sample (volatile unsigned *addr, unsigned mask, unsigned value);
|
||
|
#endif
|
||
|
|
||
|
#endif /* SPIFI_ROM_API_H */
|