2014-03-20 13:20:33 +04:00
/*
* st_spi_fsm . c - ST Fast Sequence Mode ( FSM ) Serial Flash Controller
*
* Author : Angus Clark < angus . clark @ st . com >
*
2014-03-20 15:11:45 +04:00
* Copyright ( C ) 2010 - 2014 STMicroelectronics Limited
2014-03-20 13:20:33 +04:00
*
* JEDEC probe based on drivers / mtd / devices / m25p80 . c
*
* This code is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
2014-03-20 13:20:46 +04:00
# include <linux/regmap.h>
2014-03-20 13:20:33 +04:00
# include <linux/platform_device.h>
2014-03-20 13:20:46 +04:00
# include <linux/mfd/syscon.h>
2014-03-20 13:20:33 +04:00
# include <linux/mtd/mtd.h>
2014-03-20 13:21:07 +04:00
# include <linux/mtd/partitions.h>
2014-03-20 13:20:33 +04:00
# include <linux/sched.h>
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/of.h>
2014-03-20 13:20:39 +04:00
# include "serial_flash_cmds.h"
2014-03-20 13:20:34 +04:00
/*
* FSM SPI Controller Registers
*/
# define SPI_CLOCKDIV 0x0010
# define SPI_MODESELECT 0x0018
# define SPI_CONFIGDATA 0x0020
# define SPI_STA_MODE_CHANGE 0x0028
# define SPI_FAST_SEQ_TRANSFER_SIZE 0x0100
# define SPI_FAST_SEQ_ADD1 0x0104
# define SPI_FAST_SEQ_ADD2 0x0108
# define SPI_FAST_SEQ_ADD_CFG 0x010c
# define SPI_FAST_SEQ_OPC1 0x0110
# define SPI_FAST_SEQ_OPC2 0x0114
# define SPI_FAST_SEQ_OPC3 0x0118
# define SPI_FAST_SEQ_OPC4 0x011c
# define SPI_FAST_SEQ_OPC5 0x0120
# define SPI_MODE_BITS 0x0124
# define SPI_DUMMY_BITS 0x0128
# define SPI_FAST_SEQ_FLASH_STA_DATA 0x012c
# define SPI_FAST_SEQ_1 0x0130
# define SPI_FAST_SEQ_2 0x0134
# define SPI_FAST_SEQ_3 0x0138
# define SPI_FAST_SEQ_4 0x013c
# define SPI_FAST_SEQ_CFG 0x0140
# define SPI_FAST_SEQ_STA 0x0144
# define SPI_QUAD_BOOT_SEQ_INIT_1 0x0148
# define SPI_QUAD_BOOT_SEQ_INIT_2 0x014c
# define SPI_QUAD_BOOT_READ_SEQ_1 0x0150
# define SPI_QUAD_BOOT_READ_SEQ_2 0x0154
# define SPI_PROGRAM_ERASE_TIME 0x0158
# define SPI_MULT_PAGE_REPEAT_SEQ_1 0x015c
# define SPI_MULT_PAGE_REPEAT_SEQ_2 0x0160
# define SPI_STATUS_WR_TIME_REG 0x0164
# define SPI_FAST_SEQ_DATA_REG 0x0300
/*
* Register : SPI_MODESELECT
*/
# define SPI_MODESELECT_CONTIG 0x01
# define SPI_MODESELECT_FASTREAD 0x02
# define SPI_MODESELECT_DUALIO 0x04
# define SPI_MODESELECT_FSM 0x08
# define SPI_MODESELECT_QUADBOOT 0x10
/*
* Register : SPI_CONFIGDATA
*/
# define SPI_CFG_DEVICE_ST 0x1
# define SPI_CFG_DEVICE_ATMEL 0x4
# define SPI_CFG_MIN_CS_HIGH(x) (((x) & 0xfff) << 4)
# define SPI_CFG_CS_SETUPHOLD(x) (((x) & 0xff) << 16)
# define SPI_CFG_DATA_HOLD(x) (((x) & 0xff) << 24)
2014-03-20 13:20:35 +04:00
# define SPI_CFG_DEFAULT_MIN_CS_HIGH SPI_CFG_MIN_CS_HIGH(0x0AA)
# define SPI_CFG_DEFAULT_CS_SETUPHOLD SPI_CFG_CS_SETUPHOLD(0xA0)
# define SPI_CFG_DEFAULT_DATA_HOLD SPI_CFG_DATA_HOLD(0x00)
2014-03-20 13:20:34 +04:00
/*
* Register : SPI_FAST_SEQ_TRANSFER_SIZE
*/
# define TRANSFER_SIZE(x) ((x) * 8)
/*
* Register : SPI_FAST_SEQ_ADD_CFG
*/
# define ADR_CFG_CYCLES_ADD1(x) ((x) << 0)
# define ADR_CFG_PADS_1_ADD1 (0x0 << 6)
# define ADR_CFG_PADS_2_ADD1 (0x1 << 6)
# define ADR_CFG_PADS_4_ADD1 (0x3 << 6)
# define ADR_CFG_CSDEASSERT_ADD1 (1 << 8)
# define ADR_CFG_CYCLES_ADD2(x) ((x) << (0+16))
# define ADR_CFG_PADS_1_ADD2 (0x0 << (6+16))
# define ADR_CFG_PADS_2_ADD2 (0x1 << (6+16))
# define ADR_CFG_PADS_4_ADD2 (0x3 << (6+16))
# define ADR_CFG_CSDEASSERT_ADD2 (1 << (8+16))
/*
* Register : SPI_FAST_SEQ_n
*/
# define SEQ_OPC_OPCODE(x) ((x) << 0)
# define SEQ_OPC_CYCLES(x) ((x) << 8)
# define SEQ_OPC_PADS_1 (0x0 << 14)
# define SEQ_OPC_PADS_2 (0x1 << 14)
# define SEQ_OPC_PADS_4 (0x3 << 14)
# define SEQ_OPC_CSDEASSERT (1 << 16)
/*
* Register : SPI_FAST_SEQ_CFG
*/
# define SEQ_CFG_STARTSEQ (1 << 0)
# define SEQ_CFG_SWRESET (1 << 5)
# define SEQ_CFG_CSDEASSERT (1 << 6)
# define SEQ_CFG_READNOTWRITE (1 << 7)
# define SEQ_CFG_ERASE (1 << 8)
# define SEQ_CFG_PADS_1 (0x0 << 16)
# define SEQ_CFG_PADS_2 (0x1 << 16)
# define SEQ_CFG_PADS_4 (0x3 << 16)
/*
* Register : SPI_MODE_BITS
*/
# define MODE_DATA(x) (x & 0xff)
# define MODE_CYCLES(x) ((x & 0x3f) << 16)
# define MODE_PADS_1 (0x0 << 22)
# define MODE_PADS_2 (0x1 << 22)
# define MODE_PADS_4 (0x3 << 22)
# define DUMMY_CSDEASSERT (1 << 24)
/*
* Register : SPI_DUMMY_BITS
*/
# define DUMMY_CYCLES(x) ((x & 0x3f) << 16)
# define DUMMY_PADS_1 (0x0 << 22)
# define DUMMY_PADS_2 (0x1 << 22)
# define DUMMY_PADS_4 (0x3 << 22)
# define DUMMY_CSDEASSERT (1 << 24)
/*
* Register : SPI_FAST_SEQ_FLASH_STA_DATA
*/
# define STA_DATA_BYTE1(x) ((x & 0xff) << 0)
# define STA_DATA_BYTE2(x) ((x & 0xff) << 8)
# define STA_PADS_1 (0x0 << 16)
# define STA_PADS_2 (0x1 << 16)
# define STA_PADS_4 (0x3 << 16)
# define STA_CSDEASSERT (0x1 << 20)
# define STA_RDNOTWR (0x1 << 21)
/*
* FSM SPI Instruction Opcodes
*/
# define STFSM_OPC_CMD 0x1
# define STFSM_OPC_ADD 0x2
# define STFSM_OPC_STA 0x3
# define STFSM_OPC_MODE 0x4
# define STFSM_OPC_DUMMY 0x5
# define STFSM_OPC_DATA 0x6
# define STFSM_OPC_WAIT 0x7
# define STFSM_OPC_JUMP 0x8
# define STFSM_OPC_GOTO 0x9
# define STFSM_OPC_STOP 0xF
/*
* FSM SPI Instructions ( = = opcode + operand ) .
*/
# define STFSM_INSTR(cmd, op) ((cmd) | ((op) << 4))
# define STFSM_INST_CMD1 STFSM_INSTR(STFSM_OPC_CMD, 1)
# define STFSM_INST_CMD2 STFSM_INSTR(STFSM_OPC_CMD, 2)
# define STFSM_INST_CMD3 STFSM_INSTR(STFSM_OPC_CMD, 3)
# define STFSM_INST_CMD4 STFSM_INSTR(STFSM_OPC_CMD, 4)
# define STFSM_INST_CMD5 STFSM_INSTR(STFSM_OPC_CMD, 5)
# define STFSM_INST_ADD1 STFSM_INSTR(STFSM_OPC_ADD, 1)
# define STFSM_INST_ADD2 STFSM_INSTR(STFSM_OPC_ADD, 2)
# define STFSM_INST_DATA_WRITE STFSM_INSTR(STFSM_OPC_DATA, 1)
# define STFSM_INST_DATA_READ STFSM_INSTR(STFSM_OPC_DATA, 2)
# define STFSM_INST_STA_RD1 STFSM_INSTR(STFSM_OPC_STA, 0x1)
# define STFSM_INST_STA_WR1 STFSM_INSTR(STFSM_OPC_STA, 0x1)
# define STFSM_INST_STA_RD2 STFSM_INSTR(STFSM_OPC_STA, 0x2)
# define STFSM_INST_STA_WR1_2 STFSM_INSTR(STFSM_OPC_STA, 0x3)
# define STFSM_INST_MODE STFSM_INSTR(STFSM_OPC_MODE, 0)
# define STFSM_INST_DUMMY STFSM_INSTR(STFSM_OPC_DUMMY, 0)
# define STFSM_INST_WAIT STFSM_INSTR(STFSM_OPC_WAIT, 0)
# define STFSM_INST_STOP STFSM_INSTR(STFSM_OPC_STOP, 0)
2014-03-20 13:20:35 +04:00
# define STFSM_DEFAULT_EMI_FREQ 100000000UL /* 100 MHz */
# define STFSM_DEFAULT_WR_TIME (STFSM_DEFAULT_EMI_FREQ * (15 / 1000)) /* 15ms */
# define STFSM_FLASH_SAFE_FREQ 10000000UL /* 10 MHz */
2014-03-20 13:20:36 +04:00
# define STFSM_MAX_WAIT_SEQ_MS 1000 /* FSM execution time */
2014-03-20 13:20:54 +04:00
/* Flash Commands */
# define FLASH_CMD_WREN 0x06
# define FLASH_CMD_WRDI 0x04
# define FLASH_CMD_RDID 0x9f
# define FLASH_CMD_RDSR 0x05
# define FLASH_CMD_RDSR2 0x35
# define FLASH_CMD_WRSR 0x01
# define FLASH_CMD_SE_4K 0x20
# define FLASH_CMD_SE_32K 0x52
# define FLASH_CMD_SE 0xd8
# define FLASH_CMD_CHIPERASE 0xc7
# define FLASH_CMD_WRVCR 0x81
# define FLASH_CMD_RDVCR 0x85
# define FLASH_CMD_READ 0x03 /* READ */
# define FLASH_CMD_READ_FAST 0x0b /* FAST READ */
# define FLASH_CMD_READ_1_1_2 0x3b /* DUAL OUTPUT READ */
# define FLASH_CMD_READ_1_2_2 0xbb /* DUAL I/O READ */
# define FLASH_CMD_READ_1_1_4 0x6b /* QUAD OUTPUT READ */
# define FLASH_CMD_READ_1_4_4 0xeb /* QUAD I/O READ */
# define FLASH_CMD_WRITE 0x02 /* PAGE PROGRAM */
# define FLASH_CMD_WRITE_1_1_2 0xa2 /* DUAL INPUT PROGRAM */
# define FLASH_CMD_WRITE_1_2_2 0xd2 /* DUAL INPUT EXT PROGRAM */
# define FLASH_CMD_WRITE_1_1_4 0x32 /* QUAD INPUT PROGRAM */
# define FLASH_CMD_WRITE_1_4_4 0x12 /* QUAD INPUT EXT PROGRAM */
# define FLASH_CMD_EN4B_ADDR 0xb7 /* Enter 4-byte address mode */
# define FLASH_CMD_EX4B_ADDR 0xe9 /* Exit 4-byte address mode */
/* READ commands with 32-bit addressing (N25Q256 and S25FLxxxS) */
# define FLASH_CMD_READ4 0x13
# define FLASH_CMD_READ4_FAST 0x0c
# define FLASH_CMD_READ4_1_1_2 0x3c
# define FLASH_CMD_READ4_1_2_2 0xbc
# define FLASH_CMD_READ4_1_1_4 0x6c
# define FLASH_CMD_READ4_1_4_4 0xec
2014-03-20 13:21:04 +04:00
/* S25FLxxxS commands */
# define S25FL_CMD_WRITE4_1_1_4 0x34
# define S25FL_CMD_SE4 0xdc
# define S25FL_CMD_CLSR 0x30
# define S25FL_CMD_DYBWR 0xe1
# define S25FL_CMD_DYBRD 0xe0
# define S25FL_CMD_WRITE4 0x12 / * Note, opcode clashes with
* ' FLASH_CMD_WRITE_1_4_4 '
* as found on N25Qxxx devices ! */
2014-03-20 13:20:59 +04:00
/* Status register */
# define FLASH_STATUS_BUSY 0x01
# define FLASH_STATUS_WEL 0x02
# define FLASH_STATUS_BP0 0x04
# define FLASH_STATUS_BP1 0x08
# define FLASH_STATUS_BP2 0x10
# define FLASH_STATUS_SRWP0 0x80
# define FLASH_STATUS_TIMEOUT 0xff
2014-03-20 13:21:04 +04:00
/* S25FL Error Flags */
# define S25FL_STATUS_E_ERR 0x20
# define S25FL_STATUS_P_ERR 0x40
2014-03-20 13:20:59 +04:00
2014-03-20 13:20:57 +04:00
# define FLASH_PAGESIZE 256 /* In Bytes */
# define FLASH_PAGESIZE_32 (FLASH_PAGESIZE / 4) /* In uint32_t */
2014-03-20 13:20:59 +04:00
# define FLASH_MAX_BUSY_WAIT (300 * HZ) /* Maximum 'CHIPERASE' time */
2014-03-20 13:20:57 +04:00
2014-03-20 13:20:54 +04:00
/*
* Flags to tweak operation of default read / write / erase routines
*/
# define CFG_READ_TOGGLE_32BIT_ADDR 0x00000001
# define CFG_WRITE_TOGGLE_32BIT_ADDR 0x00000002
# define CFG_WRITE_EX_32BIT_ADDR_DELAY 0x00000004
# define CFG_ERASESEC_TOGGLE_32BIT_ADDR 0x00000008
# define CFG_S25FL_CHECK_ERROR_FLAGS 0x00000010
2014-03-20 13:21:06 +04:00
struct stfsm_seq {
uint32_t data_size ;
uint32_t addr1 ;
uint32_t addr2 ;
uint32_t addr_cfg ;
uint32_t seq_opc [ 5 ] ;
uint32_t mode ;
uint32_t dummy ;
uint32_t status ;
uint8_t seq [ 16 ] ;
uint32_t seq_cfg ;
} __packed __aligned ( 4 ) ;
2014-03-20 13:20:33 +04:00
struct stfsm {
struct device * dev ;
void __iomem * base ;
struct resource * region ;
struct mtd_info mtd ;
struct mutex lock ;
2014-03-20 13:20:41 +04:00
struct flash_info * info ;
2014-03-20 13:20:35 +04:00
2014-03-20 13:20:54 +04:00
uint32_t configuration ;
2014-03-20 13:20:35 +04:00
uint32_t fifo_dir_delay ;
2014-03-20 13:20:46 +04:00
bool booted_from_spi ;
2014-03-20 13:20:50 +04:00
bool reset_signal ;
bool reset_por ;
2014-03-20 13:20:33 +04:00
2014-03-20 13:21:06 +04:00
struct stfsm_seq stfsm_seq_read ;
struct stfsm_seq stfsm_seq_write ;
struct stfsm_seq stfsm_seq_en_32bit_addr ;
} ;
2014-03-20 13:20:36 +04:00
2014-03-20 13:20:42 +04:00
/* Parameters to configure a READ or WRITE FSM sequence */
struct seq_rw_config {
uint32_t flags ; /* flags to support config */
uint8_t cmd ; /* FLASH command */
int write ; /* Write Sequence */
uint8_t addr_pads ; /* No. of addr pads (MODE & DUMMY) */
uint8_t data_pads ; /* No. of data pads */
uint8_t mode_data ; /* MODE data */
uint8_t mode_cycles ; /* No. of MODE cycles */
uint8_t dummy_cycles ; /* No. of DUMMY cycles */
} ;
2014-03-20 13:20:40 +04:00
/* SPI Flash Device Table */
struct flash_info {
char * name ;
/*
* JEDEC id zero means " no ID " ( most older chips ) ; otherwise it has
* a high byte of zero plus three data bytes : the manufacturer id ,
* then a two byte device id .
*/
u32 jedec_id ;
u16 ext_id ;
/*
* The size listed here is what works with FLASH_CMD_SE , which isn ' t
* necessarily called a " sector " by the vendor .
*/
unsigned sector_size ;
u16 n_sectors ;
u32 flags ;
/*
* Note , where FAST_READ is supported , freq_max specifies the
* FAST_READ frequency , not the READ frequency .
*/
u32 max_freq ;
int ( * config ) ( struct stfsm * ) ;
} ;
2014-03-20 13:20:55 +04:00
static int stfsm_n25q_config ( struct stfsm * fsm ) ;
2014-03-20 13:21:03 +04:00
static int stfsm_mx25_config ( struct stfsm * fsm ) ;
2014-03-20 13:21:04 +04:00
static int stfsm_s25fl_config ( struct stfsm * fsm ) ;
2014-03-20 13:21:05 +04:00
static int stfsm_w25q_config ( struct stfsm * fsm ) ;
2014-03-20 13:20:55 +04:00
2014-03-20 13:20:40 +04:00
static struct flash_info flash_types [ ] = {
/*
* ST Microelectronics / Numonyx - -
* ( newer production versions may have feature updates
* ( eg faster operating frequency )
*/
# define M25P_FLAG (FLASH_FLAG_READ_WRITE | FLASH_FLAG_READ_FAST)
{ " m25p40 " , 0x202013 , 0 , 64 * 1024 , 8 , M25P_FLAG , 25 , NULL } ,
{ " m25p80 " , 0x202014 , 0 , 64 * 1024 , 16 , M25P_FLAG , 25 , NULL } ,
{ " m25p16 " , 0x202015 , 0 , 64 * 1024 , 32 , M25P_FLAG , 25 , NULL } ,
{ " m25p32 " , 0x202016 , 0 , 64 * 1024 , 64 , M25P_FLAG , 50 , NULL } ,
{ " m25p64 " , 0x202017 , 0 , 64 * 1024 , 128 , M25P_FLAG , 50 , NULL } ,
{ " m25p128 " , 0x202018 , 0 , 256 * 1024 , 64 , M25P_FLAG , 50 , NULL } ,
# define M25PX_FLAG (FLASH_FLAG_READ_WRITE | \
FLASH_FLAG_READ_FAST | \
FLASH_FLAG_READ_1_1_2 | \
FLASH_FLAG_WRITE_1_1_2 )
{ " m25px32 " , 0x207116 , 0 , 64 * 1024 , 64 , M25PX_FLAG , 75 , NULL } ,
{ " m25px64 " , 0x207117 , 0 , 64 * 1024 , 128 , M25PX_FLAG , 75 , NULL } ,
# define MX25_FLAG (FLASH_FLAG_READ_WRITE | \
FLASH_FLAG_READ_FAST | \
FLASH_FLAG_READ_1_1_2 | \
FLASH_FLAG_READ_1_2_2 | \
FLASH_FLAG_READ_1_1_4 | \
FLASH_FLAG_READ_1_4_4 | \
FLASH_FLAG_SE_4K | \
FLASH_FLAG_SE_32K )
{ " mx25l25635e " , 0xc22019 , 0 , 64 * 1024 , 512 ,
2014-03-20 13:21:03 +04:00
( MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET ) , 70 ,
stfsm_mx25_config } ,
2014-03-26 20:39:15 +04:00
{ " mx25l25655e " , 0xc22619 , 0 , 64 * 1024 , 512 ,
( MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET ) , 70 ,
stfsm_mx25_config } ,
2014-03-20 13:20:40 +04:00
# define N25Q_FLAG (FLASH_FLAG_READ_WRITE | \
FLASH_FLAG_READ_FAST | \
FLASH_FLAG_READ_1_1_2 | \
FLASH_FLAG_READ_1_2_2 | \
FLASH_FLAG_READ_1_1_4 | \
FLASH_FLAG_READ_1_4_4 | \
FLASH_FLAG_WRITE_1_1_2 | \
FLASH_FLAG_WRITE_1_2_2 | \
FLASH_FLAG_WRITE_1_1_4 | \
FLASH_FLAG_WRITE_1_4_4 )
2014-03-20 13:20:55 +04:00
{ " n25q128 " , 0x20ba18 , 0 , 64 * 1024 , 256 , N25Q_FLAG , 108 ,
stfsm_n25q_config } ,
2014-03-20 13:20:40 +04:00
{ " n25q256 " , 0x20ba19 , 0 , 64 * 1024 , 512 ,
2014-03-20 13:20:55 +04:00
N25Q_FLAG | FLASH_FLAG_32BIT_ADDR , 108 , stfsm_n25q_config } ,
2014-03-20 13:20:40 +04:00
/*
* Spansion S25FLxxxP
* - 256 KiB and 64 KiB sector variants ( identified by ext . JEDEC )
*/
# define S25FLXXXP_FLAG (FLASH_FLAG_READ_WRITE | \
FLASH_FLAG_READ_1_1_2 | \
FLASH_FLAG_READ_1_2_2 | \
FLASH_FLAG_READ_1_1_4 | \
FLASH_FLAG_READ_1_4_4 | \
FLASH_FLAG_WRITE_1_1_4 | \
FLASH_FLAG_READ_FAST )
{ " s25fl129p0 " , 0x012018 , 0x4d00 , 256 * 1024 , 64 , S25FLXXXP_FLAG , 80 ,
2014-03-20 13:21:04 +04:00
stfsm_s25fl_config } ,
2014-03-20 13:20:40 +04:00
{ " s25fl129p1 " , 0x012018 , 0x4d01 , 64 * 1024 , 256 , S25FLXXXP_FLAG , 80 ,
2014-03-20 13:21:04 +04:00
stfsm_s25fl_config } ,
2014-03-20 13:20:40 +04:00
/*
* Spansion S25FLxxxS
* - 256 KiB and 64 KiB sector variants ( identified by ext . JEDEC )
* - RESET # signal supported by die but not bristled out on all
* package types . The package type is a function of board design ,
* so this information is captured in the board ' s flags .
* - Supports ' DYB ' sector protection . Depending on variant , sectors
* may default to locked state on power - on .
*/
# define S25FLXXXS_FLAG (S25FLXXXP_FLAG | \
FLASH_FLAG_RESET | \
FLASH_FLAG_DYB_LOCKING )
{ " s25fl128s0 " , 0x012018 , 0x0300 , 256 * 1024 , 64 , S25FLXXXS_FLAG , 80 ,
2014-03-20 13:21:04 +04:00
stfsm_s25fl_config } ,
2014-03-20 13:20:40 +04:00
{ " s25fl128s1 " , 0x012018 , 0x0301 , 64 * 1024 , 256 , S25FLXXXS_FLAG , 80 ,
2014-03-20 13:21:04 +04:00
stfsm_s25fl_config } ,
2014-03-20 13:20:40 +04:00
{ " s25fl256s0 " , 0x010219 , 0x4d00 , 256 * 1024 , 128 ,
2014-03-20 13:21:04 +04:00
S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR , 80 , stfsm_s25fl_config } ,
2014-03-20 13:20:40 +04:00
{ " s25fl256s1 " , 0x010219 , 0x4d01 , 64 * 1024 , 512 ,
2014-03-20 13:21:04 +04:00
S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR , 80 , stfsm_s25fl_config } ,
2014-03-20 13:20:40 +04:00
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
# define W25X_FLAG (FLASH_FLAG_READ_WRITE | \
FLASH_FLAG_READ_FAST | \
FLASH_FLAG_READ_1_1_2 | \
FLASH_FLAG_WRITE_1_1_2 )
{ " w25x40 " , 0xef3013 , 0 , 64 * 1024 , 8 , W25X_FLAG , 75 , NULL } ,
{ " w25x80 " , 0xef3014 , 0 , 64 * 1024 , 16 , W25X_FLAG , 75 , NULL } ,
{ " w25x16 " , 0xef3015 , 0 , 64 * 1024 , 32 , W25X_FLAG , 75 , NULL } ,
{ " w25x32 " , 0xef3016 , 0 , 64 * 1024 , 64 , W25X_FLAG , 75 , NULL } ,
{ " w25x64 " , 0xef3017 , 0 , 64 * 1024 , 128 , W25X_FLAG , 75 , NULL } ,
/* Winbond -- w25q "blocks" are 64K, "sectors" are 4KiB */
# define W25Q_FLAG (FLASH_FLAG_READ_WRITE | \
FLASH_FLAG_READ_FAST | \
FLASH_FLAG_READ_1_1_2 | \
FLASH_FLAG_READ_1_2_2 | \
FLASH_FLAG_READ_1_1_4 | \
FLASH_FLAG_READ_1_4_4 | \
FLASH_FLAG_WRITE_1_1_4 )
2014-03-20 13:21:05 +04:00
{ " w25q80 " , 0xef4014 , 0 , 64 * 1024 , 16 , W25Q_FLAG , 80 ,
stfsm_w25q_config } ,
{ " w25q16 " , 0xef4015 , 0 , 64 * 1024 , 32 , W25Q_FLAG , 80 ,
stfsm_w25q_config } ,
{ " w25q32 " , 0xef4016 , 0 , 64 * 1024 , 64 , W25Q_FLAG , 80 ,
stfsm_w25q_config } ,
{ " w25q64 " , 0xef4017 , 0 , 64 * 1024 , 128 , W25Q_FLAG , 80 ,
stfsm_w25q_config } ,
2014-03-20 13:20:40 +04:00
/* Sentinel */
{ NULL , 0x000000 , 0 , 0 , 0 , 0 , 0 , NULL } ,
} ;
2014-03-20 13:20:53 +04:00
/*
* FSM message sequence configurations :
*
* All configs are presented in order of preference
*/
/* Default READ configurations, in order of preference */
static struct seq_rw_config default_read_configs [ ] = {
{ FLASH_FLAG_READ_1_4_4 , FLASH_CMD_READ_1_4_4 , 0 , 4 , 4 , 0x00 , 2 , 4 } ,
{ FLASH_FLAG_READ_1_1_4 , FLASH_CMD_READ_1_1_4 , 0 , 1 , 4 , 0x00 , 4 , 0 } ,
{ FLASH_FLAG_READ_1_2_2 , FLASH_CMD_READ_1_2_2 , 0 , 2 , 2 , 0x00 , 4 , 0 } ,
{ FLASH_FLAG_READ_1_1_2 , FLASH_CMD_READ_1_1_2 , 0 , 1 , 2 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_FAST , FLASH_CMD_READ_FAST , 0 , 1 , 1 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_WRITE , FLASH_CMD_READ , 0 , 1 , 1 , 0x00 , 0 , 0 } ,
{ 0x00 , 0 , 0 , 0 , 0 , 0x00 , 0 , 0 } ,
} ;
/* Default WRITE configurations */
static struct seq_rw_config default_write_configs [ ] = {
{ FLASH_FLAG_WRITE_1_4_4 , FLASH_CMD_WRITE_1_4_4 , 1 , 4 , 4 , 0x00 , 0 , 0 } ,
{ FLASH_FLAG_WRITE_1_1_4 , FLASH_CMD_WRITE_1_1_4 , 1 , 1 , 4 , 0x00 , 0 , 0 } ,
{ FLASH_FLAG_WRITE_1_2_2 , FLASH_CMD_WRITE_1_2_2 , 1 , 2 , 2 , 0x00 , 0 , 0 } ,
{ FLASH_FLAG_WRITE_1_1_2 , FLASH_CMD_WRITE_1_1_2 , 1 , 1 , 2 , 0x00 , 0 , 0 } ,
{ FLASH_FLAG_READ_WRITE , FLASH_CMD_WRITE , 1 , 1 , 1 , 0x00 , 0 , 0 } ,
{ 0x00 , 0 , 0 , 0 , 0 , 0x00 , 0 , 0 } ,
} ;
2014-03-20 13:20:54 +04:00
/*
* [ N25Qxxx ] Configuration
*/
# define N25Q_VCR_DUMMY_CYCLES(x) (((x) & 0xf) << 4)
# define N25Q_VCR_XIP_DISABLED ((uint8_t)0x1 << 3)
# define N25Q_VCR_WRAP_CONT 0x3
/* N25Q 3-byte Address READ configurations
* - ' FAST ' variants configured for 8 dummy cycles .
*
* Note , the number of dummy cycles used for ' FAST ' READ operations is
* configurable and would normally be tuned according to the READ command and
* operating frequency . However , this applies universally to all ' FAST ' READ
* commands , including those used by the SPIBoot controller , and remains in
* force until the device is power - cycled . Since the SPIBoot controller is
* hard - wired to use 8 dummy cycles , we must configure the device to also use 8
* cycles .
*/
static struct seq_rw_config n25q_read3_configs [ ] = {
{ FLASH_FLAG_READ_1_4_4 , FLASH_CMD_READ_1_4_4 , 0 , 4 , 4 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_1_1_4 , FLASH_CMD_READ_1_1_4 , 0 , 1 , 4 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_1_2_2 , FLASH_CMD_READ_1_2_2 , 0 , 2 , 2 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_1_1_2 , FLASH_CMD_READ_1_1_2 , 0 , 1 , 2 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_FAST , FLASH_CMD_READ_FAST , 0 , 1 , 1 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_WRITE , FLASH_CMD_READ , 0 , 1 , 1 , 0x00 , 0 , 0 } ,
{ 0x00 , 0 , 0 , 0 , 0 , 0x00 , 0 , 0 } ,
} ;
/* N25Q 4-byte Address READ configurations
* - use special 4 - byte address READ commands ( reduces overheads , and
* reduces risk of hitting watchdog reset issues ) .
* - ' FAST ' variants configured for 8 dummy cycles ( see note above . )
*/
static struct seq_rw_config n25q_read4_configs [ ] = {
{ FLASH_FLAG_READ_1_4_4 , FLASH_CMD_READ4_1_4_4 , 0 , 4 , 4 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_1_1_4 , FLASH_CMD_READ4_1_1_4 , 0 , 1 , 4 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_1_2_2 , FLASH_CMD_READ4_1_2_2 , 0 , 2 , 2 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_1_1_2 , FLASH_CMD_READ4_1_1_2 , 0 , 1 , 2 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_FAST , FLASH_CMD_READ4_FAST , 0 , 1 , 1 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_WRITE , FLASH_CMD_READ4 , 0 , 1 , 1 , 0x00 , 0 , 0 } ,
{ 0x00 , 0 , 0 , 0 , 0 , 0x00 , 0 , 0 } ,
} ;
2014-03-20 13:21:03 +04:00
/*
* [ MX25xxx ] Configuration
*/
# define MX25_STATUS_QE (0x1 << 6)
static int stfsm_mx25_en_32bit_addr_seq ( struct stfsm_seq * seq )
{
seq - > seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_EN4B_ADDR ) |
SEQ_OPC_CSDEASSERT ) ;
seq - > seq [ 0 ] = STFSM_INST_CMD1 ;
seq - > seq [ 1 ] = STFSM_INST_WAIT ;
seq - > seq [ 2 ] = STFSM_INST_STOP ;
seq - > seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_ERASE |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ;
return 0 ;
}
2014-03-20 13:21:04 +04:00
/*
* [ S25FLxxx ] Configuration
*/
# define STFSM_S25FL_CONFIG_QE (0x1 << 1)
/*
* S25FLxxxS devices provide three ways of supporting 32 - bit addressing : Bank
* Register , Extended Address Modes , and a 32 - bit address command set . The
* 32 - bit address command set is used here , since it avoids any problems with
* entering a state that is incompatible with the SPIBoot Controller .
*/
static struct seq_rw_config stfsm_s25fl_read4_configs [ ] = {
{ FLASH_FLAG_READ_1_4_4 , FLASH_CMD_READ4_1_4_4 , 0 , 4 , 4 , 0x00 , 2 , 4 } ,
{ FLASH_FLAG_READ_1_1_4 , FLASH_CMD_READ4_1_1_4 , 0 , 1 , 4 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_1_2_2 , FLASH_CMD_READ4_1_2_2 , 0 , 2 , 2 , 0x00 , 4 , 0 } ,
{ FLASH_FLAG_READ_1_1_2 , FLASH_CMD_READ4_1_1_2 , 0 , 1 , 2 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_FAST , FLASH_CMD_READ4_FAST , 0 , 1 , 1 , 0x00 , 0 , 8 } ,
{ FLASH_FLAG_READ_WRITE , FLASH_CMD_READ4 , 0 , 1 , 1 , 0x00 , 0 , 0 } ,
{ 0x00 , 0 , 0 , 0 , 0 , 0x00 , 0 , 0 } ,
} ;
static struct seq_rw_config stfsm_s25fl_write4_configs [ ] = {
{ FLASH_FLAG_WRITE_1_1_4 , S25FL_CMD_WRITE4_1_1_4 , 1 , 1 , 4 , 0x00 , 0 , 0 } ,
{ FLASH_FLAG_READ_WRITE , S25FL_CMD_WRITE4 , 1 , 1 , 1 , 0x00 , 0 , 0 } ,
{ 0x00 , 0 , 0 , 0 , 0 , 0x00 , 0 , 0 } ,
} ;
2014-03-20 13:21:05 +04:00
/*
* [ W25Qxxx ] Configuration
*/
# define W25Q_STATUS_QE (0x1 << 9)
2014-03-20 13:20:38 +04:00
static struct stfsm_seq stfsm_seq_read_jedec = {
. data_size = TRANSFER_SIZE ( 8 ) ,
. seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_RDID ) ) ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_DATA_READ ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
2014-03-20 13:20:59 +04:00
static struct stfsm_seq stfsm_seq_read_status_fifo = {
. data_size = TRANSFER_SIZE ( 4 ) ,
. seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_RDSR ) ) ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_DATA_READ ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
2014-03-20 13:20:47 +04:00
static struct stfsm_seq stfsm_seq_erase_sector = {
/* 'addr_cfg' configured during initialisation */
. seq_opc = {
( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WREN ) | SEQ_OPC_CSDEASSERT ) ,
( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_SE ) ) ,
} ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_CMD2 ,
STFSM_INST_ADD1 ,
STFSM_INST_ADD2 ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
2014-03-20 13:21:00 +04:00
static struct stfsm_seq stfsm_seq_erase_chip = {
. seq_opc = {
( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WREN ) | SEQ_OPC_CSDEASSERT ) ,
( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_CHIPERASE ) | SEQ_OPC_CSDEASSERT ) ,
} ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_CMD2 ,
STFSM_INST_WAIT ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_ERASE |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
2014-03-20 13:21:02 +04:00
static struct stfsm_seq stfsm_seq_write_status = {
. seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WREN ) | SEQ_OPC_CSDEASSERT ) ,
. seq_opc [ 1 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WRSR ) ) ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_CMD2 ,
STFSM_INST_STA_WR1 ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
2014-03-20 13:20:52 +04:00
static struct stfsm_seq stfsm_seq_wrvcr = {
. seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WREN ) | SEQ_OPC_CSDEASSERT ) ,
. seq_opc [ 1 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WRVCR ) ) ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_CMD2 ,
STFSM_INST_STA_WR1 ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
2014-03-20 13:20:48 +04:00
static int stfsm_n25q_en_32bit_addr_seq ( struct stfsm_seq * seq )
{
seq - > seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_EN4B_ADDR ) ) ;
seq - > seq_opc [ 1 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WREN ) |
SEQ_OPC_CSDEASSERT ) ;
seq - > seq [ 0 ] = STFSM_INST_CMD2 ;
seq - > seq [ 1 ] = STFSM_INST_CMD1 ;
seq - > seq [ 2 ] = STFSM_INST_WAIT ;
seq - > seq [ 3 ] = STFSM_INST_STOP ;
seq - > seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_ERASE |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ;
return 0 ;
}
2014-03-20 13:20:36 +04:00
static inline int stfsm_is_idle ( struct stfsm * fsm )
{
return readl ( fsm - > base + SPI_FAST_SEQ_STA ) & 0x10 ;
}
2014-03-20 13:20:35 +04:00
static inline uint32_t stfsm_fifo_available ( struct stfsm * fsm )
{
return ( readl ( fsm - > base + SPI_FAST_SEQ_STA ) > > 5 ) & 0x7f ;
}
static void stfsm_clear_fifo ( struct stfsm * fsm )
{
uint32_t avail ;
for ( ; ; ) {
avail = stfsm_fifo_available ( fsm ) ;
if ( ! avail )
break ;
while ( avail ) {
readl ( fsm - > base + SPI_FAST_SEQ_DATA_REG ) ;
avail - - ;
}
}
}
2014-03-20 13:20:36 +04:00
static inline void stfsm_load_seq ( struct stfsm * fsm ,
const struct stfsm_seq * seq )
{
void __iomem * dst = fsm - > base + SPI_FAST_SEQ_TRANSFER_SIZE ;
const uint32_t * src = ( const uint32_t * ) seq ;
int words = sizeof ( * seq ) / sizeof ( * src ) ;
BUG_ON ( ! stfsm_is_idle ( fsm ) ) ;
while ( words - - ) {
writel ( * src , dst ) ;
src + + ;
dst + = 4 ;
}
}
static void stfsm_wait_seq ( struct stfsm * fsm )
{
unsigned long deadline ;
int timeout = 0 ;
deadline = jiffies + msecs_to_jiffies ( STFSM_MAX_WAIT_SEQ_MS ) ;
while ( ! timeout ) {
if ( time_after_eq ( jiffies , deadline ) )
timeout = 1 ;
if ( stfsm_is_idle ( fsm ) )
return ;
cond_resched ( ) ;
}
dev_err ( fsm - > dev , " timeout on sequence completion \n " ) ;
}
2014-03-20 15:11:43 +04:00
static void stfsm_read_fifo ( struct stfsm * fsm , uint32_t * buf , uint32_t size )
2014-03-20 13:20:37 +04:00
{
uint32_t remaining = size > > 2 ;
uint32_t avail ;
uint32_t words ;
dev_dbg ( fsm - > dev , " Reading %d bytes from FIFO \n " , size ) ;
BUG_ON ( ( ( ( uint32_t ) buf ) & 0x3 ) | | ( size & 0x3 ) ) ;
while ( remaining ) {
for ( ; ; ) {
avail = stfsm_fifo_available ( fsm ) ;
if ( avail )
break ;
udelay ( 1 ) ;
}
words = min ( avail , remaining ) ;
remaining - = words ;
readsl ( fsm - > base + SPI_FAST_SEQ_DATA_REG , buf , words ) ;
buf + = words ;
}
}
2014-03-20 15:11:43 +04:00
static int stfsm_write_fifo ( struct stfsm * fsm , const uint32_t * buf ,
uint32_t size )
2014-03-20 13:20:58 +04:00
{
uint32_t words = size > > 2 ;
dev_dbg ( fsm - > dev , " writing %d bytes to FIFO \n " , size ) ;
BUG_ON ( ( ( ( uint32_t ) buf ) & 0x3 ) | | ( size & 0x3 ) ) ;
writesl ( fsm - > base + SPI_FAST_SEQ_DATA_REG , buf , words ) ;
return size ;
}
2014-03-20 13:20:51 +04:00
static int stfsm_enter_32bit_addr ( struct stfsm * fsm , int enter )
{
2014-03-20 13:21:06 +04:00
struct stfsm_seq * seq = & fsm - > stfsm_seq_en_32bit_addr ;
2014-03-20 13:20:51 +04:00
uint32_t cmd = enter ? FLASH_CMD_EN4B_ADDR : FLASH_CMD_EX4B_ADDR ;
seq - > seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( cmd ) |
SEQ_OPC_CSDEASSERT ) ;
stfsm_load_seq ( fsm , seq ) ;
stfsm_wait_seq ( fsm ) ;
return 0 ;
}
2014-03-20 13:20:59 +04:00
static uint8_t stfsm_wait_busy ( struct stfsm * fsm )
{
struct stfsm_seq * seq = & stfsm_seq_read_status_fifo ;
unsigned long deadline ;
uint32_t status ;
int timeout = 0 ;
/* Use RDRS1 */
seq - > seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_RDSR ) ) ;
/* Load read_status sequence */
stfsm_load_seq ( fsm , seq ) ;
/*
* Repeat until busy bit is deasserted , or timeout , or error ( S25FLxxxS )
*/
deadline = jiffies + FLASH_MAX_BUSY_WAIT ;
while ( ! timeout ) {
if ( time_after_eq ( jiffies , deadline ) )
timeout = 1 ;
stfsm_wait_seq ( fsm ) ;
stfsm_read_fifo ( fsm , & status , 4 ) ;
if ( ( status & FLASH_STATUS_BUSY ) = = 0 )
return 0 ;
if ( ( fsm - > configuration & CFG_S25FL_CHECK_ERROR_FLAGS ) & &
( ( status & S25FL_STATUS_P_ERR ) | |
( status & S25FL_STATUS_E_ERR ) ) )
return ( uint8_t ) ( status & 0xff ) ;
if ( ! timeout )
/* Restart */
writel ( seq - > seq_cfg , fsm - > base + SPI_FAST_SEQ_CFG ) ;
2014-03-20 15:11:46 +04:00
cond_resched ( ) ;
2014-03-20 13:20:59 +04:00
}
dev_err ( fsm - > dev , " timeout on wait_busy \n " ) ;
return FLASH_STATUS_TIMEOUT ;
}
2014-03-20 13:21:01 +04:00
static int stfsm_read_status ( struct stfsm * fsm , uint8_t cmd ,
uint8_t * status )
{
struct stfsm_seq * seq = & stfsm_seq_read_status_fifo ;
uint32_t tmp ;
dev_dbg ( fsm - > dev , " reading STA[%s] \n " ,
( cmd = = FLASH_CMD_RDSR ) ? " 1 " : " 2 " ) ;
seq - > seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( cmd ) ) ,
stfsm_load_seq ( fsm , seq ) ;
stfsm_read_fifo ( fsm , & tmp , 4 ) ;
* status = ( uint8_t ) ( tmp > > 24 ) ;
stfsm_wait_seq ( fsm ) ;
return 0 ;
}
2014-03-20 13:21:02 +04:00
static int stfsm_write_status ( struct stfsm * fsm , uint16_t status ,
int sta_bytes )
{
struct stfsm_seq * seq = & stfsm_seq_write_status ;
dev_dbg ( fsm - > dev , " writing STA[%s] 0x%04x \n " ,
( sta_bytes = = 1 ) ? " 1 " : " 1+2 " , status ) ;
seq - > status = ( uint32_t ) status | STA_PADS_1 | STA_CSDEASSERT ;
seq - > seq [ 2 ] = ( sta_bytes = = 1 ) ?
STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2 ;
stfsm_load_seq ( fsm , seq ) ;
stfsm_wait_seq ( fsm ) ;
return 0 ;
} ;
2014-03-20 13:20:52 +04:00
static int stfsm_wrvcr ( struct stfsm * fsm , uint8_t data )
{
struct stfsm_seq * seq = & stfsm_seq_wrvcr ;
dev_dbg ( fsm - > dev , " writing VCR 0x%02x \n " , data ) ;
seq - > status = ( STA_DATA_BYTE1 ( data ) | STA_PADS_1 | STA_CSDEASSERT ) ;
stfsm_load_seq ( fsm , seq ) ;
stfsm_wait_seq ( fsm ) ;
return 0 ;
}
2014-03-20 13:20:50 +04:00
/*
* SoC reset on ' boot - from - spi ' systems
*
* Certain modes of operation cause the Flash device to enter a particular state
* for a period of time ( e . g . ' Erase Sector ' , ' Quad Enable ' , and ' Enter 32 - bit
* Addr ' commands ) . On boot - from - spi systems , it is important to consider what
* happens if a warm reset occurs during this period . The SPIBoot controller
* assumes that Flash device is in its default reset state , 24 - bit address mode ,
* and ready to accept commands . This can be achieved using some form of
* on - board logic / controller to force a device POR in response to a SoC - level
* reset or by making use of the device reset signal if available ( limited
* number of devices only ) .
*
* Failure to take such precautions can cause problems following a warm reset .
* For some operations ( e . g . ERASE ) , there is little that can be done . For
* other modes of operation ( e . g . 32 - bit addressing ) , options are often
* available that can help minimise the window in which a reset could cause a
* problem .
*
*/
static bool stfsm_can_handle_soc_reset ( struct stfsm * fsm )
{
/* Reset signal is available on the board and supported by the device */
if ( fsm - > reset_signal & & fsm - > info - > flags & FLASH_FLAG_RESET )
return true ;
/* Board-level logic forces a power-on-reset */
if ( fsm - > reset_por )
return true ;
/* Reset is not properly handled and may result in failure to reboot */
return false ;
}
2014-03-20 13:20:47 +04:00
/* Configure 'addr_cfg' according to addressing mode */
static void stfsm_prepare_erasesec_seq ( struct stfsm * fsm ,
struct stfsm_seq * seq )
{
int addr1_cycles = fsm - > info - > flags & FLASH_FLAG_32BIT_ADDR ? 16 : 8 ;
seq - > addr_cfg = ( ADR_CFG_CYCLES_ADD1 ( addr1_cycles ) |
ADR_CFG_PADS_1_ADD1 |
ADR_CFG_CYCLES_ADD2 ( 16 ) |
ADR_CFG_PADS_1_ADD2 |
ADR_CFG_CSDEASSERT_ADD2 ) ;
}
2014-03-20 13:20:42 +04:00
/* Search for preferred configuration based on available flags */
static struct seq_rw_config *
stfsm_search_seq_rw_configs ( struct stfsm * fsm ,
struct seq_rw_config cfgs [ ] )
{
struct seq_rw_config * config ;
int flags = fsm - > info - > flags ;
for ( config = cfgs ; config - > cmd ! = 0 ; config + + )
if ( ( config - > flags & flags ) = = config - > flags )
return config ;
return NULL ;
}
2014-03-20 13:20:44 +04:00
/* Prepare a READ/WRITE sequence according to configuration parameters */
static void stfsm_prepare_rw_seq ( struct stfsm * fsm ,
struct stfsm_seq * seq ,
struct seq_rw_config * cfg )
{
int addr1_cycles , addr2_cycles ;
int i = 0 ;
memset ( seq , 0 , sizeof ( * seq ) ) ;
/* Add READ/WRITE OPC */
seq - > seq_opc [ i + + ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( cfg - > cmd ) ) ;
/* Add WREN OPC for a WRITE sequence */
if ( cfg - > write )
seq - > seq_opc [ i + + ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WREN ) |
SEQ_OPC_CSDEASSERT ) ;
/* Address configuration (24 or 32-bit addresses) */
addr1_cycles = ( fsm - > info - > flags & FLASH_FLAG_32BIT_ADDR ) ? 16 : 8 ;
addr1_cycles / = cfg - > addr_pads ;
addr2_cycles = 16 / cfg - > addr_pads ;
seq - > addr_cfg = ( ( addr1_cycles & 0x3f ) < < 0 | /* ADD1 cycles */
( cfg - > addr_pads - 1 ) < < 6 | /* ADD1 pads */
( addr2_cycles & 0x3f ) < < 16 | /* ADD2 cycles */
( ( cfg - > addr_pads - 1 ) < < 22 ) ) ; /* ADD2 pads */
/* Data/Sequence configuration */
seq - > seq_cfg = ( ( cfg - > data_pads - 1 ) < < 16 |
SEQ_CFG_STARTSEQ |
SEQ_CFG_CSDEASSERT ) ;
if ( ! cfg - > write )
seq - > seq_cfg | = SEQ_CFG_READNOTWRITE ;
/* Mode configuration (no. of pads taken from addr cfg) */
seq - > mode = ( ( cfg - > mode_data & 0xff ) < < 0 | /* data */
( cfg - > mode_cycles & 0x3f ) < < 16 | /* cycles */
( cfg - > addr_pads - 1 ) < < 22 ) ; /* pads */
/* Dummy configuration (no. of pads taken from addr cfg) */
seq - > dummy = ( ( cfg - > dummy_cycles & 0x3f ) < < 16 | /* cycles */
( cfg - > addr_pads - 1 ) < < 22 ) ; /* pads */
/* Instruction sequence */
i = 0 ;
if ( cfg - > write )
seq - > seq [ i + + ] = STFSM_INST_CMD2 ;
seq - > seq [ i + + ] = STFSM_INST_CMD1 ;
seq - > seq [ i + + ] = STFSM_INST_ADD1 ;
seq - > seq [ i + + ] = STFSM_INST_ADD2 ;
if ( cfg - > mode_cycles )
seq - > seq [ i + + ] = STFSM_INST_MODE ;
if ( cfg - > dummy_cycles )
seq - > seq [ i + + ] = STFSM_INST_DUMMY ;
seq - > seq [ i + + ] =
cfg - > write ? STFSM_INST_DATA_WRITE : STFSM_INST_DATA_READ ;
seq - > seq [ i + + ] = STFSM_INST_STOP ;
}
2014-03-20 13:20:49 +04:00
static int stfsm_search_prepare_rw_seq ( struct stfsm * fsm ,
struct stfsm_seq * seq ,
struct seq_rw_config * cfgs )
{
struct seq_rw_config * config ;
config = stfsm_search_seq_rw_configs ( fsm , cfgs ) ;
if ( ! config ) {
dev_err ( fsm - > dev , " failed to find suitable config \n " ) ;
return - EINVAL ;
}
stfsm_prepare_rw_seq ( fsm , seq , config ) ;
return 0 ;
}
2014-03-20 13:20:56 +04:00
/* Prepare a READ/WRITE/ERASE 'default' sequences */
static int stfsm_prepare_rwe_seqs_default ( struct stfsm * fsm )
{
uint32_t flags = fsm - > info - > flags ;
int ret ;
/* Configure 'READ' sequence */
2014-03-20 13:21:06 +04:00
ret = stfsm_search_prepare_rw_seq ( fsm , & fsm - > stfsm_seq_read ,
2014-03-20 13:20:56 +04:00
default_read_configs ) ;
if ( ret ) {
dev_err ( fsm - > dev ,
" failed to prep READ sequence with flags [0x%08x] \n " ,
flags ) ;
return ret ;
}
/* Configure 'WRITE' sequence */
2014-03-20 13:21:06 +04:00
ret = stfsm_search_prepare_rw_seq ( fsm , & fsm - > stfsm_seq_write ,
2014-03-20 13:20:56 +04:00
default_write_configs ) ;
if ( ret ) {
dev_err ( fsm - > dev ,
" failed to prep WRITE sequence with flags [0x%08x] \n " ,
flags ) ;
return ret ;
}
/* Configure 'ERASE_SECTOR' sequence */
stfsm_prepare_erasesec_seq ( fsm , & stfsm_seq_erase_sector ) ;
return 0 ;
}
2014-03-20 13:21:03 +04:00
static int stfsm_mx25_config ( struct stfsm * fsm )
{
uint32_t flags = fsm - > info - > flags ;
uint32_t data_pads ;
uint8_t sta ;
int ret ;
bool soc_reset ;
/*
* Use default READ / WRITE sequences
*/
ret = stfsm_prepare_rwe_seqs_default ( fsm ) ;
if ( ret )
return ret ;
/*
* Configure 32 - bit Address Support
*/
if ( flags & FLASH_FLAG_32BIT_ADDR ) {
/* Configure 'enter_32bitaddr' FSM sequence */
2014-03-20 13:21:06 +04:00
stfsm_mx25_en_32bit_addr_seq ( & fsm - > stfsm_seq_en_32bit_addr ) ;
2014-03-20 13:21:03 +04:00
soc_reset = stfsm_can_handle_soc_reset ( fsm ) ;
if ( soc_reset | | ! fsm - > booted_from_spi ) {
/* If we can handle SoC resets, we enable 32-bit address
* mode pervasively */
stfsm_enter_32bit_addr ( fsm , 1 ) ;
} else {
/* Else, enable/disable 32-bit addressing before/after
* each operation */
fsm - > configuration = ( CFG_READ_TOGGLE_32BIT_ADDR |
CFG_WRITE_TOGGLE_32BIT_ADDR |
CFG_ERASESEC_TOGGLE_32BIT_ADDR ) ;
/* It seems a small delay is required after exiting
* 32 - bit mode following a write operation . The issue
* is under investigation .
*/
fsm - > configuration | = CFG_WRITE_EX_32BIT_ADDR_DELAY ;
}
}
/* For QUAD mode, set 'QE' STATUS bit */
2014-03-20 13:21:06 +04:00
data_pads = ( ( fsm - > stfsm_seq_read . seq_cfg > > 16 ) & 0x3 ) + 1 ;
2014-03-20 13:21:03 +04:00
if ( data_pads = = 4 ) {
stfsm_read_status ( fsm , FLASH_CMD_RDSR , & sta ) ;
sta | = MX25_STATUS_QE ;
stfsm_write_status ( fsm , sta , 1 ) ;
}
return 0 ;
}
2014-03-20 13:20:55 +04:00
static int stfsm_n25q_config ( struct stfsm * fsm )
{
uint32_t flags = fsm - > info - > flags ;
uint8_t vcr ;
int ret = 0 ;
bool soc_reset ;
/* Configure 'READ' sequence */
if ( flags & FLASH_FLAG_32BIT_ADDR )
2014-03-20 13:21:06 +04:00
ret = stfsm_search_prepare_rw_seq ( fsm , & fsm - > stfsm_seq_read ,
2014-03-20 13:20:55 +04:00
n25q_read4_configs ) ;
else
2014-03-20 13:21:06 +04:00
ret = stfsm_search_prepare_rw_seq ( fsm , & fsm - > stfsm_seq_read ,
2014-03-20 13:20:55 +04:00
n25q_read3_configs ) ;
if ( ret ) {
dev_err ( fsm - > dev ,
" failed to prepare READ sequence with flags [0x%08x] \n " ,
flags ) ;
return ret ;
}
/* Configure 'WRITE' sequence (default configs) */
2014-03-20 13:21:06 +04:00
ret = stfsm_search_prepare_rw_seq ( fsm , & fsm - > stfsm_seq_write ,
2014-03-20 13:20:55 +04:00
default_write_configs ) ;
if ( ret ) {
dev_err ( fsm - > dev ,
" preparing WRITE sequence using flags [0x%08x] failed \n " ,
flags ) ;
return ret ;
}
/* * Configure 'ERASE_SECTOR' sequence */
stfsm_prepare_erasesec_seq ( fsm , & stfsm_seq_erase_sector ) ;
/* Configure 32-bit address support */
if ( flags & FLASH_FLAG_32BIT_ADDR ) {
2014-03-20 13:21:06 +04:00
stfsm_n25q_en_32bit_addr_seq ( & fsm - > stfsm_seq_en_32bit_addr ) ;
2014-03-20 13:20:55 +04:00
soc_reset = stfsm_can_handle_soc_reset ( fsm ) ;
if ( soc_reset | | ! fsm - > booted_from_spi ) {
/*
* If we can handle SoC resets , we enable 32 - bit
* address mode pervasively
*/
stfsm_enter_32bit_addr ( fsm , 1 ) ;
} else {
/*
* If not , enable / disable for WRITE and ERASE
* operations ( READ uses special commands )
*/
fsm - > configuration = ( CFG_WRITE_TOGGLE_32BIT_ADDR |
CFG_ERASESEC_TOGGLE_32BIT_ADDR ) ;
}
}
/*
* Configure device to use 8 dummy cycles
*/
vcr = ( N25Q_VCR_DUMMY_CYCLES ( 8 ) | N25Q_VCR_XIP_DISABLED |
N25Q_VCR_WRAP_CONT ) ;
stfsm_wrvcr ( fsm , vcr ) ;
return 0 ;
}
2014-03-20 13:21:04 +04:00
static void stfsm_s25fl_prepare_erasesec_seq_32 ( struct stfsm_seq * seq )
{
seq - > seq_opc [ 1 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( S25FL_CMD_SE4 ) ) ;
seq - > addr_cfg = ( ADR_CFG_CYCLES_ADD1 ( 16 ) |
ADR_CFG_PADS_1_ADD1 |
ADR_CFG_CYCLES_ADD2 ( 16 ) |
ADR_CFG_PADS_1_ADD2 |
ADR_CFG_CSDEASSERT_ADD2 ) ;
}
static void stfsm_s25fl_read_dyb ( struct stfsm * fsm , uint32_t offs , uint8_t * dby )
{
uint32_t tmp ;
struct stfsm_seq seq = {
. data_size = TRANSFER_SIZE ( 4 ) ,
. seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( S25FL_CMD_DYBRD ) ) ,
. addr_cfg = ( ADR_CFG_CYCLES_ADD1 ( 16 ) |
ADR_CFG_PADS_1_ADD1 |
ADR_CFG_CYCLES_ADD2 ( 16 ) |
ADR_CFG_PADS_1_ADD2 ) ,
. addr1 = ( offs > > 16 ) & 0xffff ,
. addr2 = offs & 0xffff ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_ADD1 ,
STFSM_INST_ADD2 ,
STFSM_INST_DATA_READ ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
stfsm_load_seq ( fsm , & seq ) ;
stfsm_read_fifo ( fsm , & tmp , 4 ) ;
* dby = ( uint8_t ) ( tmp > > 24 ) ;
stfsm_wait_seq ( fsm ) ;
}
static void stfsm_s25fl_write_dyb ( struct stfsm * fsm , uint32_t offs , uint8_t dby )
{
struct stfsm_seq seq = {
. seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WREN ) |
SEQ_OPC_CSDEASSERT ) ,
. seq_opc [ 1 ] = ( SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( S25FL_CMD_DYBWR ) ) ,
. addr_cfg = ( ADR_CFG_CYCLES_ADD1 ( 16 ) |
ADR_CFG_PADS_1_ADD1 |
ADR_CFG_CYCLES_ADD2 ( 16 ) |
ADR_CFG_PADS_1_ADD2 ) ,
. status = ( uint32_t ) dby | STA_PADS_1 | STA_CSDEASSERT ,
. addr1 = ( offs > > 16 ) & 0xffff ,
. addr2 = offs & 0xffff ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_CMD2 ,
STFSM_INST_ADD1 ,
STFSM_INST_ADD2 ,
STFSM_INST_STA_WR1 ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
stfsm_load_seq ( fsm , & seq ) ;
stfsm_wait_seq ( fsm ) ;
stfsm_wait_busy ( fsm ) ;
}
static int stfsm_s25fl_clear_status_reg ( struct stfsm * fsm )
{
struct stfsm_seq seq = {
. seq_opc [ 0 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( S25FL_CMD_CLSR ) |
SEQ_OPC_CSDEASSERT ) ,
. seq_opc [ 1 ] = ( SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES ( 8 ) |
SEQ_OPC_OPCODE ( FLASH_CMD_WRDI ) |
SEQ_OPC_CSDEASSERT ) ,
. seq = {
STFSM_INST_CMD1 ,
STFSM_INST_CMD2 ,
STFSM_INST_WAIT ,
STFSM_INST_STOP ,
} ,
. seq_cfg = ( SEQ_CFG_PADS_1 |
SEQ_CFG_ERASE |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ ) ,
} ;
stfsm_load_seq ( fsm , & seq ) ;
stfsm_wait_seq ( fsm ) ;
return 0 ;
}
static int stfsm_s25fl_config ( struct stfsm * fsm )
{
struct flash_info * info = fsm - > info ;
uint32_t flags = info - > flags ;
uint32_t data_pads ;
uint32_t offs ;
uint16_t sta_wr ;
uint8_t sr1 , cr1 , dyb ;
int ret ;
if ( flags & FLASH_FLAG_32BIT_ADDR ) {
/*
* Prepare Read / Write / Erase sequences according to S25FLxxx
* 32 - bit address command set
*/
2014-03-20 13:21:06 +04:00
ret = stfsm_search_prepare_rw_seq ( fsm , & fsm - > stfsm_seq_read ,
2014-03-20 13:21:04 +04:00
stfsm_s25fl_read4_configs ) ;
if ( ret )
return ret ;
2014-03-20 13:21:06 +04:00
ret = stfsm_search_prepare_rw_seq ( fsm , & fsm - > stfsm_seq_write ,
2014-03-20 13:21:04 +04:00
stfsm_s25fl_write4_configs ) ;
if ( ret )
return ret ;
stfsm_s25fl_prepare_erasesec_seq_32 ( & stfsm_seq_erase_sector ) ;
} else {
/* Use default configurations for 24-bit addressing */
ret = stfsm_prepare_rwe_seqs_default ( fsm ) ;
if ( ret )
return ret ;
}
/*
* For devices that support ' DYB ' sector locking , check lock status and
* unlock sectors if necessary ( some variants power - on with sectors
* locked by default )
*/
if ( flags & FLASH_FLAG_DYB_LOCKING ) {
offs = 0 ;
for ( offs = 0 ; offs < info - > sector_size * info - > n_sectors ; ) {
stfsm_s25fl_read_dyb ( fsm , offs , & dyb ) ;
if ( dyb = = 0x00 )
stfsm_s25fl_write_dyb ( fsm , offs , 0xff ) ;
/* Handle bottom/top 4KiB parameter sectors */
if ( ( offs < info - > sector_size * 2 ) | |
( offs > = ( info - > sector_size - info - > n_sectors * 4 ) ) )
offs + = 0x1000 ;
else
offs + = 0x10000 ;
}
}
/* Check status of 'QE' bit */
2014-03-20 13:21:06 +04:00
data_pads = ( ( fsm - > stfsm_seq_read . seq_cfg > > 16 ) & 0x3 ) + 1 ;
2014-03-20 13:21:04 +04:00
stfsm_read_status ( fsm , FLASH_CMD_RDSR2 , & cr1 ) ;
if ( data_pads = = 4 ) {
if ( ! ( cr1 & STFSM_S25FL_CONFIG_QE ) ) {
/* Set 'QE' */
cr1 | = STFSM_S25FL_CONFIG_QE ;
stfsm_read_status ( fsm , FLASH_CMD_RDSR , & sr1 ) ;
sta_wr = ( ( uint16_t ) cr1 < < 8 ) | sr1 ;
stfsm_write_status ( fsm , sta_wr , 2 ) ;
stfsm_wait_busy ( fsm ) ;
}
} else {
if ( ( cr1 & STFSM_S25FL_CONFIG_QE ) ) {
/* Clear 'QE' */
cr1 & = ~ STFSM_S25FL_CONFIG_QE ;
stfsm_read_status ( fsm , FLASH_CMD_RDSR , & sr1 ) ;
sta_wr = ( ( uint16_t ) cr1 < < 8 ) | sr1 ;
stfsm_write_status ( fsm , sta_wr , 2 ) ;
stfsm_wait_busy ( fsm ) ;
}
}
/*
* S25FLxxx devices support Program and Error error flags .
* Configure driver to check flags and clear if necessary .
*/
fsm - > configuration | = CFG_S25FL_CHECK_ERROR_FLAGS ;
return 0 ;
}
2014-03-20 13:21:05 +04:00
static int stfsm_w25q_config ( struct stfsm * fsm )
{
uint32_t data_pads ;
uint16_t sta_wr ;
uint8_t sta1 , sta2 ;
int ret ;
ret = stfsm_prepare_rwe_seqs_default ( fsm ) ;
if ( ret )
return ret ;
/* If using QUAD mode, set QE STATUS bit */
2014-03-20 13:21:06 +04:00
data_pads = ( ( fsm - > stfsm_seq_read . seq_cfg > > 16 ) & 0x3 ) + 1 ;
2014-03-20 13:21:05 +04:00
if ( data_pads = = 4 ) {
stfsm_read_status ( fsm , FLASH_CMD_RDSR , & sta1 ) ;
stfsm_read_status ( fsm , FLASH_CMD_RDSR2 , & sta2 ) ;
sta_wr = ( ( uint16_t ) sta2 < < 8 ) | sta1 ;
sta_wr | = W25Q_STATUS_QE ;
stfsm_write_status ( fsm , sta_wr , 2 ) ;
stfsm_wait_busy ( fsm ) ;
}
return 0 ;
}
2014-03-20 13:20:57 +04:00
static int stfsm_read ( struct stfsm * fsm , uint8_t * buf , uint32_t size ,
uint32_t offset )
{
2014-03-20 13:21:06 +04:00
struct stfsm_seq * seq = & fsm - > stfsm_seq_read ;
2014-03-20 13:20:57 +04:00
uint32_t data_pads ;
uint32_t read_mask ;
uint32_t size_ub ;
uint32_t size_lb ;
uint32_t size_mop ;
uint32_t tmp [ 4 ] ;
uint32_t page_buf [ FLASH_PAGESIZE_32 ] ;
uint8_t * p ;
dev_dbg ( fsm - > dev , " reading %d bytes from 0x%08x \n " , size , offset ) ;
/* Enter 32-bit address mode, if required */
if ( fsm - > configuration & CFG_READ_TOGGLE_32BIT_ADDR )
stfsm_enter_32bit_addr ( fsm , 1 ) ;
/* Must read in multiples of 32 cycles (or 32*pads/8 Bytes) */
data_pads = ( ( seq - > seq_cfg > > 16 ) & 0x3 ) + 1 ;
read_mask = ( data_pads < < 2 ) - 1 ;
/* Handle non-aligned buf */
p = ( ( uint32_t ) buf & 0x3 ) ? ( uint8_t * ) page_buf : buf ;
/* Handle non-aligned size */
size_ub = ( size + read_mask ) & ~ read_mask ;
size_lb = size & ~ read_mask ;
size_mop = size & read_mask ;
seq - > data_size = TRANSFER_SIZE ( size_ub ) ;
seq - > addr1 = ( offset > > 16 ) & 0xffff ;
seq - > addr2 = offset & 0xffff ;
stfsm_load_seq ( fsm , seq ) ;
if ( size_lb )
stfsm_read_fifo ( fsm , ( uint32_t * ) p , size_lb ) ;
if ( size_mop ) {
stfsm_read_fifo ( fsm , tmp , read_mask + 1 ) ;
memcpy ( p + size_lb , & tmp , size_mop ) ;
}
/* Handle non-aligned buf */
if ( ( uint32_t ) buf & 0x3 )
memcpy ( buf , page_buf , size ) ;
/* Wait for sequence to finish */
stfsm_wait_seq ( fsm ) ;
stfsm_clear_fifo ( fsm ) ;
/* Exit 32-bit address mode, if required */
if ( fsm - > configuration & CFG_READ_TOGGLE_32BIT_ADDR )
stfsm_enter_32bit_addr ( fsm , 0 ) ;
return 0 ;
}
2014-03-20 15:11:43 +04:00
static int stfsm_write ( struct stfsm * fsm , const uint8_t * buf ,
uint32_t size , uint32_t offset )
2014-03-20 13:20:59 +04:00
{
2014-03-20 13:21:06 +04:00
struct stfsm_seq * seq = & fsm - > stfsm_seq_write ;
2014-03-20 13:20:59 +04:00
uint32_t data_pads ;
uint32_t write_mask ;
uint32_t size_ub ;
uint32_t size_lb ;
uint32_t size_mop ;
uint32_t tmp [ 4 ] ;
uint32_t page_buf [ FLASH_PAGESIZE_32 ] ;
uint8_t * t = ( uint8_t * ) & tmp ;
const uint8_t * p ;
int ret ;
int i ;
dev_dbg ( fsm - > dev , " writing %d bytes to 0x%08x \n " , size , offset ) ;
/* Enter 32-bit address mode, if required */
if ( fsm - > configuration & CFG_WRITE_TOGGLE_32BIT_ADDR )
stfsm_enter_32bit_addr ( fsm , 1 ) ;
/* Must write in multiples of 32 cycles (or 32*pads/8 bytes) */
data_pads = ( ( seq - > seq_cfg > > 16 ) & 0x3 ) + 1 ;
write_mask = ( data_pads < < 2 ) - 1 ;
/* Handle non-aligned buf */
if ( ( uint32_t ) buf & 0x3 ) {
memcpy ( page_buf , buf , size ) ;
p = ( uint8_t * ) page_buf ;
} else {
p = buf ;
}
/* Handle non-aligned size */
size_ub = ( size + write_mask ) & ~ write_mask ;
size_lb = size & ~ write_mask ;
size_mop = size & write_mask ;
seq - > data_size = TRANSFER_SIZE ( size_ub ) ;
seq - > addr1 = ( offset > > 16 ) & 0xffff ;
seq - > addr2 = offset & 0xffff ;
/* Need to set FIFO to write mode, before writing data to FIFO (see
* GNBvb79594 )
*/
writel ( 0x00040000 , fsm - > base + SPI_FAST_SEQ_CFG ) ;
/*
* Before writing data to the FIFO , apply a small delay to allow a
* potential change of FIFO direction to complete .
*/
if ( fsm - > fifo_dir_delay = = 0 )
readl ( fsm - > base + SPI_FAST_SEQ_CFG ) ;
else
udelay ( fsm - > fifo_dir_delay ) ;
/* Write data to FIFO, before starting sequence (see GNBvd79593) */
if ( size_lb ) {
stfsm_write_fifo ( fsm , ( uint32_t * ) p , size_lb ) ;
p + = size_lb ;
}
/* Handle non-aligned size */
if ( size_mop ) {
memset ( t , 0xff , write_mask + 1 ) ; /* fill with 0xff's */
for ( i = 0 ; i < size_mop ; i + + )
t [ i ] = * p + + ;
stfsm_write_fifo ( fsm , tmp , write_mask + 1 ) ;
}
/* Start sequence */
stfsm_load_seq ( fsm , seq ) ;
/* Wait for sequence to finish */
stfsm_wait_seq ( fsm ) ;
/* Wait for completion */
ret = stfsm_wait_busy ( fsm ) ;
2014-03-20 13:21:04 +04:00
if ( ret & & fsm - > configuration & CFG_S25FL_CHECK_ERROR_FLAGS )
stfsm_s25fl_clear_status_reg ( fsm ) ;
2014-03-20 13:20:59 +04:00
/* Exit 32-bit address mode, if required */
if ( fsm - > configuration & CFG_WRITE_TOGGLE_32BIT_ADDR ) {
stfsm_enter_32bit_addr ( fsm , 0 ) ;
if ( fsm - > configuration & CFG_WRITE_EX_32BIT_ADDR_DELAY )
udelay ( 1 ) ;
}
return 0 ;
}
2014-03-20 13:20:57 +04:00
/*
* Read an address range from the flash chip . The address range
* may be any size provided it is within the physical boundaries .
*/
static int stfsm_mtd_read ( struct mtd_info * mtd , loff_t from , size_t len ,
size_t * retlen , u_char * buf )
{
struct stfsm * fsm = dev_get_drvdata ( mtd - > dev . parent ) ;
uint32_t bytes ;
dev_dbg ( fsm - > dev , " %s from 0x%08x, len %zd \n " ,
__func__ , ( u32 ) from , len ) ;
mutex_lock ( & fsm - > lock ) ;
while ( len > 0 ) {
bytes = min_t ( size_t , len , FLASH_PAGESIZE ) ;
stfsm_read ( fsm , buf , bytes , from ) ;
buf + = bytes ;
from + = bytes ;
len - = bytes ;
* retlen + = bytes ;
}
mutex_unlock ( & fsm - > lock ) ;
return 0 ;
}
2014-03-20 15:11:43 +04:00
static int stfsm_erase_sector ( struct stfsm * fsm , uint32_t offset )
2014-03-20 13:21:00 +04:00
{
struct stfsm_seq * seq = & stfsm_seq_erase_sector ;
int ret ;
dev_dbg ( fsm - > dev , " erasing sector at 0x%08x \n " , offset ) ;
/* Enter 32-bit address mode, if required */
if ( fsm - > configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR )
stfsm_enter_32bit_addr ( fsm , 1 ) ;
seq - > addr1 = ( offset > > 16 ) & 0xffff ;
seq - > addr2 = offset & 0xffff ;
stfsm_load_seq ( fsm , seq ) ;
stfsm_wait_seq ( fsm ) ;
/* Wait for completion */
ret = stfsm_wait_busy ( fsm ) ;
2014-03-20 13:21:04 +04:00
if ( ret & & fsm - > configuration & CFG_S25FL_CHECK_ERROR_FLAGS )
stfsm_s25fl_clear_status_reg ( fsm ) ;
2014-03-20 13:21:00 +04:00
/* Exit 32-bit address mode, if required */
if ( fsm - > configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR )
stfsm_enter_32bit_addr ( fsm , 0 ) ;
return ret ;
}
static int stfsm_erase_chip ( struct stfsm * fsm )
{
const struct stfsm_seq * seq = & stfsm_seq_erase_chip ;
dev_dbg ( fsm - > dev , " erasing chip \n " ) ;
stfsm_load_seq ( fsm , seq ) ;
stfsm_wait_seq ( fsm ) ;
return stfsm_wait_busy ( fsm ) ;
}
2014-03-20 13:20:59 +04:00
/*
* Write an address range to the flash chip . Data must be written in
* FLASH_PAGESIZE chunks . The address range may be any size provided
* it is within the physical boundaries .
*/
static int stfsm_mtd_write ( struct mtd_info * mtd , loff_t to , size_t len ,
size_t * retlen , const u_char * buf )
{
struct stfsm * fsm = dev_get_drvdata ( mtd - > dev . parent ) ;
u32 page_offs ;
u32 bytes ;
uint8_t * b = ( uint8_t * ) buf ;
int ret = 0 ;
dev_dbg ( fsm - > dev , " %s to 0x%08x, len %zd \n " , __func__ , ( u32 ) to , len ) ;
/* Offset within page */
page_offs = to % FLASH_PAGESIZE ;
mutex_lock ( & fsm - > lock ) ;
while ( len ) {
/* Write up to page boundary */
bytes = min ( FLASH_PAGESIZE - page_offs , len ) ;
ret = stfsm_write ( fsm , b , bytes , to ) ;
if ( ret )
goto out1 ;
b + = bytes ;
len - = bytes ;
to + = bytes ;
/* We are now page-aligned */
page_offs = 0 ;
* retlen + = bytes ;
}
out1 :
mutex_unlock ( & fsm - > lock ) ;
return ret ;
}
2014-03-20 13:21:00 +04:00
/*
* Erase an address range on the flash chip . The address range may extend
* one or more erase sectors . Return an error is there is a problem erasing .
*/
static int stfsm_mtd_erase ( struct mtd_info * mtd , struct erase_info * instr )
{
struct stfsm * fsm = dev_get_drvdata ( mtd - > dev . parent ) ;
u32 addr , len ;
int ret ;
dev_dbg ( fsm - > dev , " %s at 0x%llx, len %lld \n " , __func__ ,
( long long ) instr - > addr , ( long long ) instr - > len ) ;
addr = instr - > addr ;
len = instr - > len ;
mutex_lock ( & fsm - > lock ) ;
/* Whole-chip erase? */
if ( len = = mtd - > size ) {
ret = stfsm_erase_chip ( fsm ) ;
if ( ret )
goto out1 ;
} else {
while ( len ) {
ret = stfsm_erase_sector ( fsm , addr ) ;
if ( ret )
goto out1 ;
addr + = mtd - > erasesize ;
len - = mtd - > erasesize ;
}
}
mutex_unlock ( & fsm - > lock ) ;
instr - > state = MTD_ERASE_DONE ;
mtd_erase_callback ( instr ) ;
return 0 ;
out1 :
instr - > state = MTD_ERASE_FAILED ;
mutex_unlock ( & fsm - > lock ) ;
return ret ;
}
2014-03-20 15:11:43 +04:00
static void stfsm_read_jedec ( struct stfsm * fsm , uint8_t * jedec )
2014-03-20 13:20:38 +04:00
{
const struct stfsm_seq * seq = & stfsm_seq_read_jedec ;
uint32_t tmp [ 2 ] ;
stfsm_load_seq ( fsm , seq ) ;
stfsm_read_fifo ( fsm , tmp , 8 ) ;
memcpy ( jedec , tmp , 5 ) ;
stfsm_wait_seq ( fsm ) ;
}
static struct flash_info * stfsm_jedec_probe ( struct stfsm * fsm )
{
2014-03-20 13:20:41 +04:00
struct flash_info * info ;
2014-03-20 13:20:38 +04:00
u16 ext_jedec ;
u32 jedec ;
u8 id [ 5 ] ;
stfsm_read_jedec ( fsm , id ) ;
jedec = id [ 0 ] < < 16 | id [ 1 ] < < 8 | id [ 2 ] ;
/*
* JEDEC also defines an optional " extended device information "
* string for after vendor - specific data , after the three bytes
* we use here . Supporting some chips might require using it .
*/
ext_jedec = id [ 3 ] < < 8 | id [ 4 ] ;
dev_dbg ( fsm - > dev , " JEDEC = 0x%08x [%02x %02x %02x %02x %02x] \n " ,
jedec , id [ 0 ] , id [ 1 ] , id [ 2 ] , id [ 3 ] , id [ 4 ] ) ;
2014-03-20 13:20:41 +04:00
for ( info = flash_types ; info - > name ; info + + ) {
if ( info - > jedec_id = = jedec ) {
if ( info - > ext_id & & info - > ext_id ! = ext_jedec )
continue ;
return info ;
}
}
dev_err ( fsm - > dev , " Unrecognized JEDEC id %06x \n " , jedec ) ;
2014-03-20 13:20:38 +04:00
return NULL ;
}
2014-03-20 13:20:35 +04:00
static int stfsm_set_mode ( struct stfsm * fsm , uint32_t mode )
{
int ret , timeout = 10 ;
/* Wait for controller to accept mode change */
while ( - - timeout ) {
ret = readl ( fsm - > base + SPI_STA_MODE_CHANGE ) ;
if ( ret & 0x1 )
break ;
udelay ( 1 ) ;
}
if ( ! timeout )
return - EBUSY ;
writel ( mode , fsm - > base + SPI_MODESELECT ) ;
return 0 ;
}
static void stfsm_set_freq ( struct stfsm * fsm , uint32_t spi_freq )
{
uint32_t emi_freq ;
uint32_t clk_div ;
/* TODO: Make this dynamic */
emi_freq = STFSM_DEFAULT_EMI_FREQ ;
/*
* Calculate clk_div - values between 2 and 128
* Multiple of 2 , rounded up
*/
clk_div = 2 * DIV_ROUND_UP ( emi_freq , 2 * spi_freq ) ;
if ( clk_div < 2 )
clk_div = 2 ;
else if ( clk_div > 128 )
clk_div = 128 ;
/*
* Determine a suitable delay for the IP to complete a change of
* direction of the FIFO . The required delay is related to the clock
* divider used . The following heuristics are based on empirical tests ,
* using a 100 MHz EMI clock .
*/
if ( clk_div < = 4 )
fsm - > fifo_dir_delay = 0 ;
else if ( clk_div < = 10 )
fsm - > fifo_dir_delay = 1 ;
else
fsm - > fifo_dir_delay = DIV_ROUND_UP ( clk_div , 10 ) ;
dev_dbg ( fsm - > dev , " emi_clk = %uHZ, spi_freq = %uHZ, clk_div = %u \n " ,
emi_freq , spi_freq , clk_div ) ;
writel ( clk_div , fsm - > base + SPI_CLOCKDIV ) ;
}
static int stfsm_init ( struct stfsm * fsm )
{
int ret ;
/* Perform a soft reset of the FSM controller */
writel ( SEQ_CFG_SWRESET , fsm - > base + SPI_FAST_SEQ_CFG ) ;
udelay ( 1 ) ;
writel ( 0 , fsm - > base + SPI_FAST_SEQ_CFG ) ;
/* Set clock to 'safe' frequency initially */
stfsm_set_freq ( fsm , STFSM_FLASH_SAFE_FREQ ) ;
/* Switch to FSM */
ret = stfsm_set_mode ( fsm , SPI_MODESELECT_FSM ) ;
if ( ret )
return ret ;
/* Set timing parameters */
writel ( SPI_CFG_DEVICE_ST |
SPI_CFG_DEFAULT_MIN_CS_HIGH |
SPI_CFG_DEFAULT_CS_SETUPHOLD |
SPI_CFG_DEFAULT_DATA_HOLD ,
fsm - > base + SPI_CONFIGDATA ) ;
writel ( STFSM_DEFAULT_WR_TIME , fsm - > base + SPI_STATUS_WR_TIME_REG ) ;
/* Clear FIFO, just in case */
stfsm_clear_fifo ( fsm ) ;
return 0 ;
}
2014-03-20 13:20:46 +04:00
static void stfsm_fetch_platform_configs ( struct platform_device * pdev )
{
struct stfsm * fsm = platform_get_drvdata ( pdev ) ;
struct device_node * np = pdev - > dev . of_node ;
struct regmap * regmap ;
uint32_t boot_device_reg ;
uint32_t boot_device_spi ;
uint32_t boot_device ; /* Value we read from *boot_device_reg */
int ret ;
/* Booting from SPI NOR Flash is the default */
fsm - > booted_from_spi = true ;
regmap = syscon_regmap_lookup_by_phandle ( np , " st,syscfg " ) ;
if ( IS_ERR ( regmap ) )
goto boot_device_fail ;
2014-03-20 13:20:50 +04:00
fsm - > reset_signal = of_property_read_bool ( np , " st,reset-signal " ) ;
fsm - > reset_por = of_property_read_bool ( np , " st,reset-por " ) ;
2014-03-20 13:20:46 +04:00
/* Where in the syscon the boot device information lives */
ret = of_property_read_u32 ( np , " st,boot-device-reg " , & boot_device_reg ) ;
if ( ret )
goto boot_device_fail ;
/* Boot device value when booted from SPI NOR */
ret = of_property_read_u32 ( np , " st,boot-device-spi " , & boot_device_spi ) ;
if ( ret )
goto boot_device_fail ;
ret = regmap_read ( regmap , boot_device_reg , & boot_device ) ;
if ( ret )
goto boot_device_fail ;
if ( boot_device ! = boot_device_spi )
fsm - > booted_from_spi = false ;
return ;
boot_device_fail :
dev_warn ( & pdev - > dev ,
" failed to fetch boot device, assuming boot from SPI \n " ) ;
}
2014-03-20 13:20:33 +04:00
static int stfsm_probe ( struct platform_device * pdev )
{
struct device_node * np = pdev - > dev . of_node ;
2014-03-20 13:21:07 +04:00
struct mtd_part_parser_data ppdata ;
2014-03-20 13:20:41 +04:00
struct flash_info * info ;
2014-03-20 13:20:33 +04:00
struct resource * res ;
struct stfsm * fsm ;
2014-03-20 13:20:35 +04:00
int ret ;
2014-03-20 13:20:33 +04:00
if ( ! np ) {
dev_err ( & pdev - > dev , " No DT found \n " ) ;
return - EINVAL ;
}
2014-03-20 13:21:07 +04:00
ppdata . of_node = np ;
2014-03-20 13:20:33 +04:00
fsm = devm_kzalloc ( & pdev - > dev , sizeof ( * fsm ) , GFP_KERNEL ) ;
if ( ! fsm )
return - ENOMEM ;
fsm - > dev = & pdev - > dev ;
platform_set_drvdata ( pdev , fsm ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " Resource not found \n " ) ;
return - ENODEV ;
}
fsm - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( fsm - > base ) ) {
dev_err ( & pdev - > dev ,
" Failed to reserve memory region %pR \n " , res ) ;
return PTR_ERR ( fsm - > base ) ;
}
mutex_init ( & fsm - > lock ) ;
2014-03-20 13:20:35 +04:00
ret = stfsm_init ( fsm ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Failed to initialise FSM Controller \n " ) ;
return ret ;
}
2014-03-20 13:20:46 +04:00
stfsm_fetch_platform_configs ( pdev ) ;
2014-03-20 13:20:38 +04:00
/* Detect SPI FLASH device */
2014-03-20 13:20:41 +04:00
info = stfsm_jedec_probe ( fsm ) ;
if ( ! info )
return - ENODEV ;
fsm - > info = info ;
2014-03-20 13:20:38 +04:00
2014-03-20 13:20:43 +04:00
/* Use device size to determine address width */
if ( info - > sector_size * info - > n_sectors > 0x1000000 )
info - > flags | = FLASH_FLAG_32BIT_ADDR ;
2014-03-20 13:20:55 +04:00
/*
* Configure READ / WRITE / ERASE sequences according to platform and
* device flags .
*/
if ( info - > config ) {
ret = info - > config ( fsm ) ;
if ( ret )
return ret ;
2014-03-20 13:20:56 +04:00
} else {
ret = stfsm_prepare_rwe_seqs_default ( fsm ) ;
if ( ret )
return ret ;
2014-03-20 13:20:55 +04:00
}
2014-03-20 13:21:07 +04:00
fsm - > mtd . name = info - > name ;
2014-03-20 13:20:33 +04:00
fsm - > mtd . dev . parent = & pdev - > dev ;
fsm - > mtd . type = MTD_NORFLASH ;
fsm - > mtd . writesize = 4 ;
fsm - > mtd . writebufsize = fsm - > mtd . writesize ;
fsm - > mtd . flags = MTD_CAP_NORFLASH ;
2014-03-20 13:20:41 +04:00
fsm - > mtd . size = info - > sector_size * info - > n_sectors ;
fsm - > mtd . erasesize = info - > sector_size ;
2014-03-20 13:20:57 +04:00
fsm - > mtd . _read = stfsm_mtd_read ;
2014-03-20 13:20:59 +04:00
fsm - > mtd . _write = stfsm_mtd_write ;
2014-03-20 13:21:00 +04:00
fsm - > mtd . _erase = stfsm_mtd_erase ;
2014-03-20 13:20:57 +04:00
2014-03-20 13:21:00 +04:00
dev_info ( & pdev - > dev ,
2014-03-20 13:20:41 +04:00
" Found serial flash device: %s \n "
" size = %llx (%lldMiB) erasesize = 0x%08x (%uKiB) \n " ,
info - > name ,
( long long ) fsm - > mtd . size , ( long long ) ( fsm - > mtd . size > > 20 ) ,
fsm - > mtd . erasesize , ( fsm - > mtd . erasesize > > 10 ) ) ;
2014-03-20 13:20:33 +04:00
2014-03-20 13:21:07 +04:00
return mtd_device_parse_register ( & fsm - > mtd , NULL , & ppdata , NULL , 0 ) ;
2014-03-20 13:20:33 +04:00
}
static int stfsm_remove ( struct platform_device * pdev )
{
struct stfsm * fsm = platform_get_drvdata ( pdev ) ;
2014-03-20 15:11:47 +04:00
return mtd_device_unregister ( & fsm - > mtd ) ;
2014-03-20 13:20:33 +04:00
}
static struct of_device_id stfsm_match [ ] = {
{ . compatible = " st,spi-fsm " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , stfsm_match ) ;
static struct platform_driver stfsm_driver = {
. probe = stfsm_probe ,
. remove = stfsm_remove ,
. driver = {
. name = " st-spi-fsm " ,
. owner = THIS_MODULE ,
. of_match_table = stfsm_match ,
} ,
} ;
module_platform_driver ( stfsm_driver ) ;
MODULE_AUTHOR ( " Angus Clark <angus.clark@st.com> " ) ;
MODULE_DESCRIPTION ( " ST SPI FSM driver " ) ;
MODULE_LICENSE ( " GPL " ) ;