162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * st_spi_fsm.c - ST Fast Sequence Mode (FSM) Serial Flash Controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Angus Clark <angus.clark@st.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2010-2014 STMicroelectronics Limited 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * JEDEC probe based on drivers/mtd/devices/m25p80.c 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1662306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 1762306a36Sopenharmony_ci#include <linux/mtd/partitions.h> 1862306a36Sopenharmony_ci#include <linux/mtd/spi-nor.h> 1962306a36Sopenharmony_ci#include <linux/sched.h> 2062306a36Sopenharmony_ci#include <linux/delay.h> 2162306a36Sopenharmony_ci#include <linux/io.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <linux/clk.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "serial_flash_cmds.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * FSM SPI Controller Registers 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#define SPI_CLOCKDIV 0x0010 3162306a36Sopenharmony_ci#define SPI_MODESELECT 0x0018 3262306a36Sopenharmony_ci#define SPI_CONFIGDATA 0x0020 3362306a36Sopenharmony_ci#define SPI_STA_MODE_CHANGE 0x0028 3462306a36Sopenharmony_ci#define SPI_FAST_SEQ_TRANSFER_SIZE 0x0100 3562306a36Sopenharmony_ci#define SPI_FAST_SEQ_ADD1 0x0104 3662306a36Sopenharmony_ci#define SPI_FAST_SEQ_ADD2 0x0108 3762306a36Sopenharmony_ci#define SPI_FAST_SEQ_ADD_CFG 0x010c 3862306a36Sopenharmony_ci#define SPI_FAST_SEQ_OPC1 0x0110 3962306a36Sopenharmony_ci#define SPI_FAST_SEQ_OPC2 0x0114 4062306a36Sopenharmony_ci#define SPI_FAST_SEQ_OPC3 0x0118 4162306a36Sopenharmony_ci#define SPI_FAST_SEQ_OPC4 0x011c 4262306a36Sopenharmony_ci#define SPI_FAST_SEQ_OPC5 0x0120 4362306a36Sopenharmony_ci#define SPI_MODE_BITS 0x0124 4462306a36Sopenharmony_ci#define SPI_DUMMY_BITS 0x0128 4562306a36Sopenharmony_ci#define SPI_FAST_SEQ_FLASH_STA_DATA 0x012c 4662306a36Sopenharmony_ci#define SPI_FAST_SEQ_1 0x0130 4762306a36Sopenharmony_ci#define SPI_FAST_SEQ_2 0x0134 4862306a36Sopenharmony_ci#define SPI_FAST_SEQ_3 0x0138 4962306a36Sopenharmony_ci#define SPI_FAST_SEQ_4 0x013c 5062306a36Sopenharmony_ci#define SPI_FAST_SEQ_CFG 0x0140 5162306a36Sopenharmony_ci#define SPI_FAST_SEQ_STA 0x0144 5262306a36Sopenharmony_ci#define SPI_QUAD_BOOT_SEQ_INIT_1 0x0148 5362306a36Sopenharmony_ci#define SPI_QUAD_BOOT_SEQ_INIT_2 0x014c 5462306a36Sopenharmony_ci#define SPI_QUAD_BOOT_READ_SEQ_1 0x0150 5562306a36Sopenharmony_ci#define SPI_QUAD_BOOT_READ_SEQ_2 0x0154 5662306a36Sopenharmony_ci#define SPI_PROGRAM_ERASE_TIME 0x0158 5762306a36Sopenharmony_ci#define SPI_MULT_PAGE_REPEAT_SEQ_1 0x015c 5862306a36Sopenharmony_ci#define SPI_MULT_PAGE_REPEAT_SEQ_2 0x0160 5962306a36Sopenharmony_ci#define SPI_STATUS_WR_TIME_REG 0x0164 6062306a36Sopenharmony_ci#define SPI_FAST_SEQ_DATA_REG 0x0300 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * Register: SPI_MODESELECT 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci#define SPI_MODESELECT_CONTIG 0x01 6662306a36Sopenharmony_ci#define SPI_MODESELECT_FASTREAD 0x02 6762306a36Sopenharmony_ci#define SPI_MODESELECT_DUALIO 0x04 6862306a36Sopenharmony_ci#define SPI_MODESELECT_FSM 0x08 6962306a36Sopenharmony_ci#define SPI_MODESELECT_QUADBOOT 0x10 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * Register: SPI_CONFIGDATA 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci#define SPI_CFG_DEVICE_ST 0x1 7562306a36Sopenharmony_ci#define SPI_CFG_DEVICE_ATMEL 0x4 7662306a36Sopenharmony_ci#define SPI_CFG_MIN_CS_HIGH(x) (((x) & 0xfff) << 4) 7762306a36Sopenharmony_ci#define SPI_CFG_CS_SETUPHOLD(x) (((x) & 0xff) << 16) 7862306a36Sopenharmony_ci#define SPI_CFG_DATA_HOLD(x) (((x) & 0xff) << 24) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define SPI_CFG_DEFAULT_MIN_CS_HIGH SPI_CFG_MIN_CS_HIGH(0x0AA) 8162306a36Sopenharmony_ci#define SPI_CFG_DEFAULT_CS_SETUPHOLD SPI_CFG_CS_SETUPHOLD(0xA0) 8262306a36Sopenharmony_ci#define SPI_CFG_DEFAULT_DATA_HOLD SPI_CFG_DATA_HOLD(0x00) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * Register: SPI_FAST_SEQ_TRANSFER_SIZE 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci#define TRANSFER_SIZE(x) ((x) * 8) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Register: SPI_FAST_SEQ_ADD_CFG 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci#define ADR_CFG_CYCLES_ADD1(x) ((x) << 0) 9362306a36Sopenharmony_ci#define ADR_CFG_PADS_1_ADD1 (0x0 << 6) 9462306a36Sopenharmony_ci#define ADR_CFG_PADS_2_ADD1 (0x1 << 6) 9562306a36Sopenharmony_ci#define ADR_CFG_PADS_4_ADD1 (0x3 << 6) 9662306a36Sopenharmony_ci#define ADR_CFG_CSDEASSERT_ADD1 (1 << 8) 9762306a36Sopenharmony_ci#define ADR_CFG_CYCLES_ADD2(x) ((x) << (0+16)) 9862306a36Sopenharmony_ci#define ADR_CFG_PADS_1_ADD2 (0x0 << (6+16)) 9962306a36Sopenharmony_ci#define ADR_CFG_PADS_2_ADD2 (0x1 << (6+16)) 10062306a36Sopenharmony_ci#define ADR_CFG_PADS_4_ADD2 (0x3 << (6+16)) 10162306a36Sopenharmony_ci#define ADR_CFG_CSDEASSERT_ADD2 (1 << (8+16)) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Register: SPI_FAST_SEQ_n 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci#define SEQ_OPC_OPCODE(x) ((x) << 0) 10762306a36Sopenharmony_ci#define SEQ_OPC_CYCLES(x) ((x) << 8) 10862306a36Sopenharmony_ci#define SEQ_OPC_PADS_1 (0x0 << 14) 10962306a36Sopenharmony_ci#define SEQ_OPC_PADS_2 (0x1 << 14) 11062306a36Sopenharmony_ci#define SEQ_OPC_PADS_4 (0x3 << 14) 11162306a36Sopenharmony_ci#define SEQ_OPC_CSDEASSERT (1 << 16) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * Register: SPI_FAST_SEQ_CFG 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci#define SEQ_CFG_STARTSEQ (1 << 0) 11762306a36Sopenharmony_ci#define SEQ_CFG_SWRESET (1 << 5) 11862306a36Sopenharmony_ci#define SEQ_CFG_CSDEASSERT (1 << 6) 11962306a36Sopenharmony_ci#define SEQ_CFG_READNOTWRITE (1 << 7) 12062306a36Sopenharmony_ci#define SEQ_CFG_ERASE (1 << 8) 12162306a36Sopenharmony_ci#define SEQ_CFG_PADS_1 (0x0 << 16) 12262306a36Sopenharmony_ci#define SEQ_CFG_PADS_2 (0x1 << 16) 12362306a36Sopenharmony_ci#define SEQ_CFG_PADS_4 (0x3 << 16) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* 12662306a36Sopenharmony_ci * Register: SPI_MODE_BITS 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci#define MODE_DATA(x) (x & 0xff) 12962306a36Sopenharmony_ci#define MODE_CYCLES(x) ((x & 0x3f) << 16) 13062306a36Sopenharmony_ci#define MODE_PADS_1 (0x0 << 22) 13162306a36Sopenharmony_ci#define MODE_PADS_2 (0x1 << 22) 13262306a36Sopenharmony_ci#define MODE_PADS_4 (0x3 << 22) 13362306a36Sopenharmony_ci#define DUMMY_CSDEASSERT (1 << 24) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 13662306a36Sopenharmony_ci * Register: SPI_DUMMY_BITS 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci#define DUMMY_CYCLES(x) ((x & 0x3f) << 16) 13962306a36Sopenharmony_ci#define DUMMY_PADS_1 (0x0 << 22) 14062306a36Sopenharmony_ci#define DUMMY_PADS_2 (0x1 << 22) 14162306a36Sopenharmony_ci#define DUMMY_PADS_4 (0x3 << 22) 14262306a36Sopenharmony_ci#define DUMMY_CSDEASSERT (1 << 24) 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * Register: SPI_FAST_SEQ_FLASH_STA_DATA 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci#define STA_DATA_BYTE1(x) ((x & 0xff) << 0) 14862306a36Sopenharmony_ci#define STA_DATA_BYTE2(x) ((x & 0xff) << 8) 14962306a36Sopenharmony_ci#define STA_PADS_1 (0x0 << 16) 15062306a36Sopenharmony_ci#define STA_PADS_2 (0x1 << 16) 15162306a36Sopenharmony_ci#define STA_PADS_4 (0x3 << 16) 15262306a36Sopenharmony_ci#define STA_CSDEASSERT (0x1 << 20) 15362306a36Sopenharmony_ci#define STA_RDNOTWR (0x1 << 21) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * FSM SPI Instruction Opcodes 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci#define STFSM_OPC_CMD 0x1 15962306a36Sopenharmony_ci#define STFSM_OPC_ADD 0x2 16062306a36Sopenharmony_ci#define STFSM_OPC_STA 0x3 16162306a36Sopenharmony_ci#define STFSM_OPC_MODE 0x4 16262306a36Sopenharmony_ci#define STFSM_OPC_DUMMY 0x5 16362306a36Sopenharmony_ci#define STFSM_OPC_DATA 0x6 16462306a36Sopenharmony_ci#define STFSM_OPC_WAIT 0x7 16562306a36Sopenharmony_ci#define STFSM_OPC_JUMP 0x8 16662306a36Sopenharmony_ci#define STFSM_OPC_GOTO 0x9 16762306a36Sopenharmony_ci#define STFSM_OPC_STOP 0xF 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* 17062306a36Sopenharmony_ci * FSM SPI Instructions (== opcode + operand). 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci#define STFSM_INSTR(cmd, op) ((cmd) | ((op) << 4)) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define STFSM_INST_CMD1 STFSM_INSTR(STFSM_OPC_CMD, 1) 17562306a36Sopenharmony_ci#define STFSM_INST_CMD2 STFSM_INSTR(STFSM_OPC_CMD, 2) 17662306a36Sopenharmony_ci#define STFSM_INST_CMD3 STFSM_INSTR(STFSM_OPC_CMD, 3) 17762306a36Sopenharmony_ci#define STFSM_INST_CMD4 STFSM_INSTR(STFSM_OPC_CMD, 4) 17862306a36Sopenharmony_ci#define STFSM_INST_CMD5 STFSM_INSTR(STFSM_OPC_CMD, 5) 17962306a36Sopenharmony_ci#define STFSM_INST_ADD1 STFSM_INSTR(STFSM_OPC_ADD, 1) 18062306a36Sopenharmony_ci#define STFSM_INST_ADD2 STFSM_INSTR(STFSM_OPC_ADD, 2) 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#define STFSM_INST_DATA_WRITE STFSM_INSTR(STFSM_OPC_DATA, 1) 18362306a36Sopenharmony_ci#define STFSM_INST_DATA_READ STFSM_INSTR(STFSM_OPC_DATA, 2) 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define STFSM_INST_STA_RD1 STFSM_INSTR(STFSM_OPC_STA, 0x1) 18662306a36Sopenharmony_ci#define STFSM_INST_STA_WR1 STFSM_INSTR(STFSM_OPC_STA, 0x1) 18762306a36Sopenharmony_ci#define STFSM_INST_STA_RD2 STFSM_INSTR(STFSM_OPC_STA, 0x2) 18862306a36Sopenharmony_ci#define STFSM_INST_STA_WR1_2 STFSM_INSTR(STFSM_OPC_STA, 0x3) 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci#define STFSM_INST_MODE STFSM_INSTR(STFSM_OPC_MODE, 0) 19162306a36Sopenharmony_ci#define STFSM_INST_DUMMY STFSM_INSTR(STFSM_OPC_DUMMY, 0) 19262306a36Sopenharmony_ci#define STFSM_INST_WAIT STFSM_INSTR(STFSM_OPC_WAIT, 0) 19362306a36Sopenharmony_ci#define STFSM_INST_STOP STFSM_INSTR(STFSM_OPC_STOP, 0) 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci#define STFSM_DEFAULT_EMI_FREQ 100000000UL /* 100 MHz */ 19662306a36Sopenharmony_ci#define STFSM_DEFAULT_WR_TIME (STFSM_DEFAULT_EMI_FREQ * (15/1000)) /* 15ms */ 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#define STFSM_FLASH_SAFE_FREQ 10000000UL /* 10 MHz */ 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#define STFSM_MAX_WAIT_SEQ_MS 1000 /* FSM execution time */ 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* S25FLxxxS commands */ 20362306a36Sopenharmony_ci#define S25FL_CMD_WRITE4_1_1_4 0x34 20462306a36Sopenharmony_ci#define S25FL_CMD_SE4 0xdc 20562306a36Sopenharmony_ci#define S25FL_CMD_CLSR 0x30 20662306a36Sopenharmony_ci#define S25FL_CMD_DYBWR 0xe1 20762306a36Sopenharmony_ci#define S25FL_CMD_DYBRD 0xe0 20862306a36Sopenharmony_ci#define S25FL_CMD_WRITE4 0x12 /* Note, opcode clashes with 20962306a36Sopenharmony_ci * 'SPINOR_OP_WRITE_1_4_4' 21062306a36Sopenharmony_ci * as found on N25Qxxx devices! */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* Status register */ 21362306a36Sopenharmony_ci#define FLASH_STATUS_BUSY 0x01 21462306a36Sopenharmony_ci#define FLASH_STATUS_WEL 0x02 21562306a36Sopenharmony_ci#define FLASH_STATUS_BP0 0x04 21662306a36Sopenharmony_ci#define FLASH_STATUS_BP1 0x08 21762306a36Sopenharmony_ci#define FLASH_STATUS_BP2 0x10 21862306a36Sopenharmony_ci#define FLASH_STATUS_SRWP0 0x80 21962306a36Sopenharmony_ci#define FLASH_STATUS_TIMEOUT 0xff 22062306a36Sopenharmony_ci/* S25FL Error Flags */ 22162306a36Sopenharmony_ci#define S25FL_STATUS_E_ERR 0x20 22262306a36Sopenharmony_ci#define S25FL_STATUS_P_ERR 0x40 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define N25Q_CMD_WRVCR 0x81 22562306a36Sopenharmony_ci#define N25Q_CMD_RDVCR 0x85 22662306a36Sopenharmony_ci#define N25Q_CMD_RDVECR 0x65 22762306a36Sopenharmony_ci#define N25Q_CMD_RDNVCR 0xb5 22862306a36Sopenharmony_ci#define N25Q_CMD_WRNVCR 0xb1 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#define FLASH_PAGESIZE 256 /* In Bytes */ 23162306a36Sopenharmony_ci#define FLASH_PAGESIZE_32 (FLASH_PAGESIZE / 4) /* In uint32_t */ 23262306a36Sopenharmony_ci#define FLASH_MAX_BUSY_WAIT (300 * HZ) /* Maximum 'CHIPERASE' time */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/* 23562306a36Sopenharmony_ci * Flags to tweak operation of default read/write/erase routines 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci#define CFG_READ_TOGGLE_32BIT_ADDR 0x00000001 23862306a36Sopenharmony_ci#define CFG_WRITE_TOGGLE_32BIT_ADDR 0x00000002 23962306a36Sopenharmony_ci#define CFG_ERASESEC_TOGGLE_32BIT_ADDR 0x00000008 24062306a36Sopenharmony_ci#define CFG_S25FL_CHECK_ERROR_FLAGS 0x00000010 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistruct stfsm_seq { 24362306a36Sopenharmony_ci uint32_t data_size; 24462306a36Sopenharmony_ci uint32_t addr1; 24562306a36Sopenharmony_ci uint32_t addr2; 24662306a36Sopenharmony_ci uint32_t addr_cfg; 24762306a36Sopenharmony_ci uint32_t seq_opc[5]; 24862306a36Sopenharmony_ci uint32_t mode; 24962306a36Sopenharmony_ci uint32_t dummy; 25062306a36Sopenharmony_ci uint32_t status; 25162306a36Sopenharmony_ci uint8_t seq[16]; 25262306a36Sopenharmony_ci uint32_t seq_cfg; 25362306a36Sopenharmony_ci} __packed __aligned(4); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistruct stfsm { 25662306a36Sopenharmony_ci struct device *dev; 25762306a36Sopenharmony_ci void __iomem *base; 25862306a36Sopenharmony_ci struct mtd_info mtd; 25962306a36Sopenharmony_ci struct mutex lock; 26062306a36Sopenharmony_ci struct flash_info *info; 26162306a36Sopenharmony_ci struct clk *clk; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci uint32_t configuration; 26462306a36Sopenharmony_ci uint32_t fifo_dir_delay; 26562306a36Sopenharmony_ci bool booted_from_spi; 26662306a36Sopenharmony_ci bool reset_signal; 26762306a36Sopenharmony_ci bool reset_por; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci struct stfsm_seq stfsm_seq_read; 27062306a36Sopenharmony_ci struct stfsm_seq stfsm_seq_write; 27162306a36Sopenharmony_ci struct stfsm_seq stfsm_seq_en_32bit_addr; 27262306a36Sopenharmony_ci}; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/* Parameters to configure a READ or WRITE FSM sequence */ 27562306a36Sopenharmony_cistruct seq_rw_config { 27662306a36Sopenharmony_ci uint32_t flags; /* flags to support config */ 27762306a36Sopenharmony_ci uint8_t cmd; /* FLASH command */ 27862306a36Sopenharmony_ci int write; /* Write Sequence */ 27962306a36Sopenharmony_ci uint8_t addr_pads; /* No. of addr pads (MODE & DUMMY) */ 28062306a36Sopenharmony_ci uint8_t data_pads; /* No. of data pads */ 28162306a36Sopenharmony_ci uint8_t mode_data; /* MODE data */ 28262306a36Sopenharmony_ci uint8_t mode_cycles; /* No. of MODE cycles */ 28362306a36Sopenharmony_ci uint8_t dummy_cycles; /* No. of DUMMY cycles */ 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* SPI Flash Device Table */ 28762306a36Sopenharmony_cistruct flash_info { 28862306a36Sopenharmony_ci char *name; 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * JEDEC id zero means "no ID" (most older chips); otherwise it has 29162306a36Sopenharmony_ci * a high byte of zero plus three data bytes: the manufacturer id, 29262306a36Sopenharmony_ci * then a two byte device id. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci u32 jedec_id; 29562306a36Sopenharmony_ci u16 ext_id; 29662306a36Sopenharmony_ci /* 29762306a36Sopenharmony_ci * The size listed here is what works with SPINOR_OP_SE, which isn't 29862306a36Sopenharmony_ci * necessarily called a "sector" by the vendor. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci unsigned sector_size; 30162306a36Sopenharmony_ci u16 n_sectors; 30262306a36Sopenharmony_ci u32 flags; 30362306a36Sopenharmony_ci /* 30462306a36Sopenharmony_ci * Note, where FAST_READ is supported, freq_max specifies the 30562306a36Sopenharmony_ci * FAST_READ frequency, not the READ frequency. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci u32 max_freq; 30862306a36Sopenharmony_ci int (*config)(struct stfsm *); 30962306a36Sopenharmony_ci}; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int stfsm_n25q_config(struct stfsm *fsm); 31262306a36Sopenharmony_cistatic int stfsm_mx25_config(struct stfsm *fsm); 31362306a36Sopenharmony_cistatic int stfsm_s25fl_config(struct stfsm *fsm); 31462306a36Sopenharmony_cistatic int stfsm_w25q_config(struct stfsm *fsm); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic struct flash_info flash_types[] = { 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * ST Microelectronics/Numonyx -- 31962306a36Sopenharmony_ci * (newer production versions may have feature updates 32062306a36Sopenharmony_ci * (eg faster operating frequency) 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci#define M25P_FLAG (FLASH_FLAG_READ_WRITE | FLASH_FLAG_READ_FAST) 32362306a36Sopenharmony_ci { "m25p40", 0x202013, 0, 64 * 1024, 8, M25P_FLAG, 25, NULL }, 32462306a36Sopenharmony_ci { "m25p80", 0x202014, 0, 64 * 1024, 16, M25P_FLAG, 25, NULL }, 32562306a36Sopenharmony_ci { "m25p16", 0x202015, 0, 64 * 1024, 32, M25P_FLAG, 25, NULL }, 32662306a36Sopenharmony_ci { "m25p32", 0x202016, 0, 64 * 1024, 64, M25P_FLAG, 50, NULL }, 32762306a36Sopenharmony_ci { "m25p64", 0x202017, 0, 64 * 1024, 128, M25P_FLAG, 50, NULL }, 32862306a36Sopenharmony_ci { "m25p128", 0x202018, 0, 256 * 1024, 64, M25P_FLAG, 50, NULL }, 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci#define M25PX_FLAG (FLASH_FLAG_READ_WRITE | \ 33162306a36Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 33262306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 33362306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_1_2) 33462306a36Sopenharmony_ci { "m25px32", 0x207116, 0, 64 * 1024, 64, M25PX_FLAG, 75, NULL }, 33562306a36Sopenharmony_ci { "m25px64", 0x207117, 0, 64 * 1024, 128, M25PX_FLAG, 75, NULL }, 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Macronix MX25xxx 33862306a36Sopenharmony_ci * - Support for 'FLASH_FLAG_WRITE_1_4_4' is omitted for devices 33962306a36Sopenharmony_ci * where operating frequency must be reduced. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci#define MX25_FLAG (FLASH_FLAG_READ_WRITE | \ 34262306a36Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 34362306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 34462306a36Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 34562306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 34662306a36Sopenharmony_ci FLASH_FLAG_SE_4K | \ 34762306a36Sopenharmony_ci FLASH_FLAG_SE_32K) 34862306a36Sopenharmony_ci { "mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, 34962306a36Sopenharmony_ci (MX25_FLAG | FLASH_FLAG_WRITE_1_4_4), 86, 35062306a36Sopenharmony_ci stfsm_mx25_config}, 35162306a36Sopenharmony_ci { "mx25l25635e", 0xc22019, 0, 64*1024, 512, 35262306a36Sopenharmony_ci (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70, 35362306a36Sopenharmony_ci stfsm_mx25_config }, 35462306a36Sopenharmony_ci { "mx25l25655e", 0xc22619, 0, 64*1024, 512, 35562306a36Sopenharmony_ci (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70, 35662306a36Sopenharmony_ci stfsm_mx25_config}, 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci#define N25Q_FLAG (FLASH_FLAG_READ_WRITE | \ 35962306a36Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 36062306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 36162306a36Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 36262306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 36362306a36Sopenharmony_ci FLASH_FLAG_READ_1_4_4 | \ 36462306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_1_2 | \ 36562306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_2_2 | \ 36662306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_1_4 | \ 36762306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_4_4) 36862306a36Sopenharmony_ci { "n25q128", 0x20ba18, 0, 64 * 1024, 256, N25Q_FLAG, 108, 36962306a36Sopenharmony_ci stfsm_n25q_config }, 37062306a36Sopenharmony_ci { "n25q256", 0x20ba19, 0, 64 * 1024, 512, 37162306a36Sopenharmony_ci N25Q_FLAG | FLASH_FLAG_32BIT_ADDR, 108, stfsm_n25q_config }, 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* 37462306a36Sopenharmony_ci * Spansion S25FLxxxP 37562306a36Sopenharmony_ci * - 256KiB and 64KiB sector variants (identified by ext. JEDEC) 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ci#define S25FLXXXP_FLAG (FLASH_FLAG_READ_WRITE | \ 37862306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 37962306a36Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 38062306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 38162306a36Sopenharmony_ci FLASH_FLAG_READ_1_4_4 | \ 38262306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_1_4 | \ 38362306a36Sopenharmony_ci FLASH_FLAG_READ_FAST) 38462306a36Sopenharmony_ci { "s25fl032p", 0x010215, 0x4d00, 64 * 1024, 64, S25FLXXXP_FLAG, 80, 38562306a36Sopenharmony_ci stfsm_s25fl_config}, 38662306a36Sopenharmony_ci { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, S25FLXXXP_FLAG, 80, 38762306a36Sopenharmony_ci stfsm_s25fl_config }, 38862306a36Sopenharmony_ci { "s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, S25FLXXXP_FLAG, 80, 38962306a36Sopenharmony_ci stfsm_s25fl_config }, 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* 39262306a36Sopenharmony_ci * Spansion S25FLxxxS 39362306a36Sopenharmony_ci * - 256KiB and 64KiB sector variants (identified by ext. JEDEC) 39462306a36Sopenharmony_ci * - RESET# signal supported by die but not bristled out on all 39562306a36Sopenharmony_ci * package types. The package type is a function of board design, 39662306a36Sopenharmony_ci * so this information is captured in the board's flags. 39762306a36Sopenharmony_ci * - Supports 'DYB' sector protection. Depending on variant, sectors 39862306a36Sopenharmony_ci * may default to locked state on power-on. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci#define S25FLXXXS_FLAG (S25FLXXXP_FLAG | \ 40162306a36Sopenharmony_ci FLASH_FLAG_RESET | \ 40262306a36Sopenharmony_ci FLASH_FLAG_DYB_LOCKING) 40362306a36Sopenharmony_ci { "s25fl128s0", 0x012018, 0x0300, 256 * 1024, 64, S25FLXXXS_FLAG, 80, 40462306a36Sopenharmony_ci stfsm_s25fl_config }, 40562306a36Sopenharmony_ci { "s25fl128s1", 0x012018, 0x0301, 64 * 1024, 256, S25FLXXXS_FLAG, 80, 40662306a36Sopenharmony_ci stfsm_s25fl_config }, 40762306a36Sopenharmony_ci { "s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, 40862306a36Sopenharmony_ci S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config }, 40962306a36Sopenharmony_ci { "s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, 41062306a36Sopenharmony_ci S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config }, 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ 41362306a36Sopenharmony_ci#define W25X_FLAG (FLASH_FLAG_READ_WRITE | \ 41462306a36Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 41562306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 41662306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_1_2) 41762306a36Sopenharmony_ci { "w25x40", 0xef3013, 0, 64 * 1024, 8, W25X_FLAG, 75, NULL }, 41862306a36Sopenharmony_ci { "w25x80", 0xef3014, 0, 64 * 1024, 16, W25X_FLAG, 75, NULL }, 41962306a36Sopenharmony_ci { "w25x16", 0xef3015, 0, 64 * 1024, 32, W25X_FLAG, 75, NULL }, 42062306a36Sopenharmony_ci { "w25x32", 0xef3016, 0, 64 * 1024, 64, W25X_FLAG, 75, NULL }, 42162306a36Sopenharmony_ci { "w25x64", 0xef3017, 0, 64 * 1024, 128, W25X_FLAG, 75, NULL }, 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* Winbond -- w25q "blocks" are 64K, "sectors" are 4KiB */ 42462306a36Sopenharmony_ci#define W25Q_FLAG (FLASH_FLAG_READ_WRITE | \ 42562306a36Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 42662306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 42762306a36Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 42862306a36Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 42962306a36Sopenharmony_ci FLASH_FLAG_READ_1_4_4 | \ 43062306a36Sopenharmony_ci FLASH_FLAG_WRITE_1_1_4) 43162306a36Sopenharmony_ci { "w25q80", 0xef4014, 0, 64 * 1024, 16, W25Q_FLAG, 80, 43262306a36Sopenharmony_ci stfsm_w25q_config }, 43362306a36Sopenharmony_ci { "w25q16", 0xef4015, 0, 64 * 1024, 32, W25Q_FLAG, 80, 43462306a36Sopenharmony_ci stfsm_w25q_config }, 43562306a36Sopenharmony_ci { "w25q32", 0xef4016, 0, 64 * 1024, 64, W25Q_FLAG, 80, 43662306a36Sopenharmony_ci stfsm_w25q_config }, 43762306a36Sopenharmony_ci { "w25q64", 0xef4017, 0, 64 * 1024, 128, W25Q_FLAG, 80, 43862306a36Sopenharmony_ci stfsm_w25q_config }, 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Sentinel */ 44162306a36Sopenharmony_ci { NULL, 0x000000, 0, 0, 0, 0, 0, NULL }, 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci/* 44562306a36Sopenharmony_ci * FSM message sequence configurations: 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci * All configs are presented in order of preference 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/* Default READ configurations, in order of preference */ 45162306a36Sopenharmony_cistatic struct seq_rw_config default_read_configs[] = { 45262306a36Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4, 0, 4, 4, 0x00, 2, 4}, 45362306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4, 0, 1, 4, 0x00, 4, 0}, 45462306a36Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2, 0, 2, 2, 0x00, 4, 0}, 45562306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, 45662306a36Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST, 0, 1, 1, 0x00, 0, 8}, 45762306a36Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ, 0, 1, 1, 0x00, 0, 0}, 45862306a36Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 45962306a36Sopenharmony_ci}; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/* Default WRITE configurations */ 46262306a36Sopenharmony_cistatic struct seq_rw_config default_write_configs[] = { 46362306a36Sopenharmony_ci {FLASH_FLAG_WRITE_1_4_4, SPINOR_OP_WRITE_1_4_4, 1, 4, 4, 0x00, 0, 0}, 46462306a36Sopenharmony_ci {FLASH_FLAG_WRITE_1_1_4, SPINOR_OP_WRITE_1_1_4, 1, 1, 4, 0x00, 0, 0}, 46562306a36Sopenharmony_ci {FLASH_FLAG_WRITE_1_2_2, SPINOR_OP_WRITE_1_2_2, 1, 2, 2, 0x00, 0, 0}, 46662306a36Sopenharmony_ci {FLASH_FLAG_WRITE_1_1_2, SPINOR_OP_WRITE_1_1_2, 1, 1, 2, 0x00, 0, 0}, 46762306a36Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_WRITE, 1, 1, 1, 0x00, 0, 0}, 46862306a36Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* 47262306a36Sopenharmony_ci * [N25Qxxx] Configuration 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci#define N25Q_VCR_DUMMY_CYCLES(x) (((x) & 0xf) << 4) 47562306a36Sopenharmony_ci#define N25Q_VCR_XIP_DISABLED ((uint8_t)0x1 << 3) 47662306a36Sopenharmony_ci#define N25Q_VCR_WRAP_CONT 0x3 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/* N25Q 3-byte Address READ configurations 47962306a36Sopenharmony_ci * - 'FAST' variants configured for 8 dummy cycles. 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * Note, the number of dummy cycles used for 'FAST' READ operations is 48262306a36Sopenharmony_ci * configurable and would normally be tuned according to the READ command and 48362306a36Sopenharmony_ci * operating frequency. However, this applies universally to all 'FAST' READ 48462306a36Sopenharmony_ci * commands, including those used by the SPIBoot controller, and remains in 48562306a36Sopenharmony_ci * force until the device is power-cycled. Since the SPIBoot controller is 48662306a36Sopenharmony_ci * hard-wired to use 8 dummy cycles, we must configure the device to also use 8 48762306a36Sopenharmony_ci * cycles. 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_cistatic struct seq_rw_config n25q_read3_configs[] = { 49062306a36Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4, 0, 4, 4, 0x00, 0, 8}, 49162306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4, 0, 1, 4, 0x00, 0, 8}, 49262306a36Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2, 0, 2, 2, 0x00, 0, 8}, 49362306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, 49462306a36Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST, 0, 1, 1, 0x00, 0, 8}, 49562306a36Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ, 0, 1, 1, 0x00, 0, 0}, 49662306a36Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 49762306a36Sopenharmony_ci}; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci/* N25Q 4-byte Address READ configurations 50062306a36Sopenharmony_ci * - use special 4-byte address READ commands (reduces overheads, and 50162306a36Sopenharmony_ci * reduces risk of hitting watchdog reset issues). 50262306a36Sopenharmony_ci * - 'FAST' variants configured for 8 dummy cycles (see note above.) 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_cistatic struct seq_rw_config n25q_read4_configs[] = { 50562306a36Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8}, 50662306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8}, 50762306a36Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8}, 50862306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8}, 50962306a36Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8}, 51062306a36Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0}, 51162306a36Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 51262306a36Sopenharmony_ci}; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci/* 51562306a36Sopenharmony_ci * [MX25xxx] Configuration 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci#define MX25_STATUS_QE (0x1 << 6) 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | 52262306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 52362306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_EN4B) | 52462306a36Sopenharmony_ci SEQ_OPC_CSDEASSERT); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci seq->seq[0] = STFSM_INST_CMD1; 52762306a36Sopenharmony_ci seq->seq[1] = STFSM_INST_WAIT; 52862306a36Sopenharmony_ci seq->seq[2] = STFSM_INST_STOP; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci seq->seq_cfg = (SEQ_CFG_PADS_1 | 53162306a36Sopenharmony_ci SEQ_CFG_ERASE | 53262306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 53362306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 53462306a36Sopenharmony_ci SEQ_CFG_STARTSEQ); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/* 54062306a36Sopenharmony_ci * [S25FLxxx] Configuration 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_ci#define STFSM_S25FL_CONFIG_QE (0x1 << 1) 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/* 54562306a36Sopenharmony_ci * S25FLxxxS devices provide three ways of supporting 32-bit addressing: Bank 54662306a36Sopenharmony_ci * Register, Extended Address Modes, and a 32-bit address command set. The 54762306a36Sopenharmony_ci * 32-bit address command set is used here, since it avoids any problems with 54862306a36Sopenharmony_ci * entering a state that is incompatible with the SPIBoot Controller. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_cistatic struct seq_rw_config stfsm_s25fl_read4_configs[] = { 55162306a36Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 2, 4}, 55262306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8}, 55362306a36Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 4, 0}, 55462306a36Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8}, 55562306a36Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8}, 55662306a36Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0}, 55762306a36Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 55862306a36Sopenharmony_ci}; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic struct seq_rw_config stfsm_s25fl_write4_configs[] = { 56162306a36Sopenharmony_ci {FLASH_FLAG_WRITE_1_1_4, S25FL_CMD_WRITE4_1_1_4, 1, 1, 4, 0x00, 0, 0}, 56262306a36Sopenharmony_ci {FLASH_FLAG_READ_WRITE, S25FL_CMD_WRITE4, 1, 1, 1, 0x00, 0, 0}, 56362306a36Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 56462306a36Sopenharmony_ci}; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci/* 56762306a36Sopenharmony_ci * [W25Qxxx] Configuration 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ci#define W25Q_STATUS_QE (0x1 << 1) 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic struct stfsm_seq stfsm_seq_read_jedec = { 57262306a36Sopenharmony_ci .data_size = TRANSFER_SIZE(8), 57362306a36Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 57462306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 57562306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDID)), 57662306a36Sopenharmony_ci .seq = { 57762306a36Sopenharmony_ci STFSM_INST_CMD1, 57862306a36Sopenharmony_ci STFSM_INST_DATA_READ, 57962306a36Sopenharmony_ci STFSM_INST_STOP, 58062306a36Sopenharmony_ci }, 58162306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 58262306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 58362306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 58462306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 58562306a36Sopenharmony_ci}; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic struct stfsm_seq stfsm_seq_read_status_fifo = { 58862306a36Sopenharmony_ci .data_size = TRANSFER_SIZE(4), 58962306a36Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 59062306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 59162306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDSR)), 59262306a36Sopenharmony_ci .seq = { 59362306a36Sopenharmony_ci STFSM_INST_CMD1, 59462306a36Sopenharmony_ci STFSM_INST_DATA_READ, 59562306a36Sopenharmony_ci STFSM_INST_STOP, 59662306a36Sopenharmony_ci }, 59762306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 59862306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 59962306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 60062306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 60162306a36Sopenharmony_ci}; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic struct stfsm_seq stfsm_seq_erase_sector = { 60462306a36Sopenharmony_ci /* 'addr_cfg' configured during initialisation */ 60562306a36Sopenharmony_ci .seq_opc = { 60662306a36Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 60762306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 61062306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_SE)), 61162306a36Sopenharmony_ci }, 61262306a36Sopenharmony_ci .seq = { 61362306a36Sopenharmony_ci STFSM_INST_CMD1, 61462306a36Sopenharmony_ci STFSM_INST_CMD2, 61562306a36Sopenharmony_ci STFSM_INST_ADD1, 61662306a36Sopenharmony_ci STFSM_INST_ADD2, 61762306a36Sopenharmony_ci STFSM_INST_STOP, 61862306a36Sopenharmony_ci }, 61962306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 62062306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 62162306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 62262306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 62362306a36Sopenharmony_ci}; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic struct stfsm_seq stfsm_seq_erase_chip = { 62662306a36Sopenharmony_ci .seq_opc = { 62762306a36Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 62862306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 63162306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_CHIP_ERASE) | SEQ_OPC_CSDEASSERT), 63262306a36Sopenharmony_ci }, 63362306a36Sopenharmony_ci .seq = { 63462306a36Sopenharmony_ci STFSM_INST_CMD1, 63562306a36Sopenharmony_ci STFSM_INST_CMD2, 63662306a36Sopenharmony_ci STFSM_INST_WAIT, 63762306a36Sopenharmony_ci STFSM_INST_STOP, 63862306a36Sopenharmony_ci }, 63962306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 64062306a36Sopenharmony_ci SEQ_CFG_ERASE | 64162306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 64262306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 64362306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 64462306a36Sopenharmony_ci}; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic struct stfsm_seq stfsm_seq_write_status = { 64762306a36Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 64862306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), 64962306a36Sopenharmony_ci .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 65062306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WRSR)), 65162306a36Sopenharmony_ci .seq = { 65262306a36Sopenharmony_ci STFSM_INST_CMD1, 65362306a36Sopenharmony_ci STFSM_INST_CMD2, 65462306a36Sopenharmony_ci STFSM_INST_STA_WR1, 65562306a36Sopenharmony_ci STFSM_INST_STOP, 65662306a36Sopenharmony_ci }, 65762306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 65862306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 65962306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 66062306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 66162306a36Sopenharmony_ci}; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci/* Dummy sequence to read one byte of data from flash into the FIFO */ 66462306a36Sopenharmony_cistatic const struct stfsm_seq stfsm_seq_load_fifo_byte = { 66562306a36Sopenharmony_ci .data_size = TRANSFER_SIZE(1), 66662306a36Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 66762306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 66862306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDID)), 66962306a36Sopenharmony_ci .seq = { 67062306a36Sopenharmony_ci STFSM_INST_CMD1, 67162306a36Sopenharmony_ci STFSM_INST_DATA_READ, 67262306a36Sopenharmony_ci STFSM_INST_STOP, 67362306a36Sopenharmony_ci }, 67462306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 67562306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 67662306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 67762306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 67862306a36Sopenharmony_ci}; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 68362306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_EN4B)); 68462306a36Sopenharmony_ci seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 68562306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | 68662306a36Sopenharmony_ci SEQ_OPC_CSDEASSERT); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci seq->seq[0] = STFSM_INST_CMD2; 68962306a36Sopenharmony_ci seq->seq[1] = STFSM_INST_CMD1; 69062306a36Sopenharmony_ci seq->seq[2] = STFSM_INST_WAIT; 69162306a36Sopenharmony_ci seq->seq[3] = STFSM_INST_STOP; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci seq->seq_cfg = (SEQ_CFG_PADS_1 | 69462306a36Sopenharmony_ci SEQ_CFG_ERASE | 69562306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 69662306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 69762306a36Sopenharmony_ci SEQ_CFG_STARTSEQ); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci return 0; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic inline int stfsm_is_idle(struct stfsm *fsm) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci return readl(fsm->base + SPI_FAST_SEQ_STA) & 0x10; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic inline uint32_t stfsm_fifo_available(struct stfsm *fsm) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic inline void stfsm_load_seq(struct stfsm *fsm, 71362306a36Sopenharmony_ci const struct stfsm_seq *seq) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci void __iomem *dst = fsm->base + SPI_FAST_SEQ_TRANSFER_SIZE; 71662306a36Sopenharmony_ci const uint32_t *src = (const uint32_t *)seq; 71762306a36Sopenharmony_ci int words = sizeof(*seq) / sizeof(*src); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci BUG_ON(!stfsm_is_idle(fsm)); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci while (words--) { 72262306a36Sopenharmony_ci writel(*src, dst); 72362306a36Sopenharmony_ci src++; 72462306a36Sopenharmony_ci dst += 4; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic void stfsm_wait_seq(struct stfsm *fsm) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci unsigned long deadline; 73162306a36Sopenharmony_ci int timeout = 0; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci deadline = jiffies + msecs_to_jiffies(STFSM_MAX_WAIT_SEQ_MS); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci while (!timeout) { 73662306a36Sopenharmony_ci if (time_after_eq(jiffies, deadline)) 73762306a36Sopenharmony_ci timeout = 1; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (stfsm_is_idle(fsm)) 74062306a36Sopenharmony_ci return; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci cond_resched(); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci dev_err(fsm->dev, "timeout on sequence completion\n"); 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci uint32_t remaining = size >> 2; 75162306a36Sopenharmony_ci uint32_t avail; 75262306a36Sopenharmony_ci uint32_t words; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci dev_dbg(fsm->dev, "Reading %d bytes from FIFO\n", size); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3)); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci while (remaining) { 75962306a36Sopenharmony_ci for (;;) { 76062306a36Sopenharmony_ci avail = stfsm_fifo_available(fsm); 76162306a36Sopenharmony_ci if (avail) 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci udelay(1); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci words = min(avail, remaining); 76662306a36Sopenharmony_ci remaining -= words; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci readsl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words); 76962306a36Sopenharmony_ci buf += words; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci/* 77462306a36Sopenharmony_ci * Clear the data FIFO 77562306a36Sopenharmony_ci * 77662306a36Sopenharmony_ci * Typically, this is only required during driver initialisation, where no 77762306a36Sopenharmony_ci * assumptions can be made regarding the state of the FIFO. 77862306a36Sopenharmony_ci * 77962306a36Sopenharmony_ci * The process of clearing the FIFO is complicated by fact that while it is 78062306a36Sopenharmony_ci * possible for the FIFO to contain an arbitrary number of bytes [1], the 78162306a36Sopenharmony_ci * SPI_FAST_SEQ_STA register only reports the number of complete 32-bit words 78262306a36Sopenharmony_ci * present. Furthermore, data can only be drained from the FIFO by reading 78362306a36Sopenharmony_ci * complete 32-bit words. 78462306a36Sopenharmony_ci * 78562306a36Sopenharmony_ci * With this in mind, a two stage process is used to the clear the FIFO: 78662306a36Sopenharmony_ci * 78762306a36Sopenharmony_ci * 1. Read any complete 32-bit words from the FIFO, as reported by the 78862306a36Sopenharmony_ci * SPI_FAST_SEQ_STA register. 78962306a36Sopenharmony_ci * 79062306a36Sopenharmony_ci * 2. Mop up any remaining bytes. At this point, it is not known if there 79162306a36Sopenharmony_ci * are 0, 1, 2, or 3 bytes in the FIFO. To handle all cases, a dummy FSM 79262306a36Sopenharmony_ci * sequence is used to load one byte at a time, until a complete 32-bit 79362306a36Sopenharmony_ci * word is formed; at most, 4 bytes will need to be loaded. 79462306a36Sopenharmony_ci * 79562306a36Sopenharmony_ci * [1] It is theoretically possible for the FIFO to contain an arbitrary number 79662306a36Sopenharmony_ci * of bits. However, since there are no known use-cases that leave 79762306a36Sopenharmony_ci * incomplete bytes in the FIFO, only words and bytes are considered here. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_cistatic void stfsm_clear_fifo(struct stfsm *fsm) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci const struct stfsm_seq *seq = &stfsm_seq_load_fifo_byte; 80262306a36Sopenharmony_ci uint32_t words, i; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* 1. Clear any 32-bit words */ 80562306a36Sopenharmony_ci words = stfsm_fifo_available(fsm); 80662306a36Sopenharmony_ci if (words) { 80762306a36Sopenharmony_ci for (i = 0; i < words; i++) 80862306a36Sopenharmony_ci readl(fsm->base + SPI_FAST_SEQ_DATA_REG); 80962306a36Sopenharmony_ci dev_dbg(fsm->dev, "cleared %d words from FIFO\n", words); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* 81362306a36Sopenharmony_ci * 2. Clear any remaining bytes 81462306a36Sopenharmony_ci * - Load the FIFO, one byte at a time, until a complete 32-bit word 81562306a36Sopenharmony_ci * is available. 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci for (i = 0, words = 0; i < 4 && !words; i++) { 81862306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 81962306a36Sopenharmony_ci stfsm_wait_seq(fsm); 82062306a36Sopenharmony_ci words = stfsm_fifo_available(fsm); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* - A single word must be available now */ 82462306a36Sopenharmony_ci if (words != 1) { 82562306a36Sopenharmony_ci dev_err(fsm->dev, "failed to clear bytes from the data FIFO\n"); 82662306a36Sopenharmony_ci return; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* - Read the 32-bit word */ 83062306a36Sopenharmony_ci readl(fsm->base + SPI_FAST_SEQ_DATA_REG); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci dev_dbg(fsm->dev, "cleared %d byte(s) from the data FIFO\n", 4 - i); 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf, 83662306a36Sopenharmony_ci uint32_t size) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci uint32_t words = size >> 2; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci dev_dbg(fsm->dev, "writing %d bytes to FIFO\n", size); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3)); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci writesl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return size; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic int stfsm_enter_32bit_addr(struct stfsm *fsm, int enter) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci struct stfsm_seq *seq = &fsm->stfsm_seq_en_32bit_addr; 85262306a36Sopenharmony_ci uint32_t cmd = enter ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | 85562306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 85662306a36Sopenharmony_ci SEQ_OPC_OPCODE(cmd) | 85762306a36Sopenharmony_ci SEQ_OPC_CSDEASSERT); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci stfsm_wait_seq(fsm); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic uint8_t stfsm_wait_busy(struct stfsm *fsm) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_read_status_fifo; 86962306a36Sopenharmony_ci unsigned long deadline; 87062306a36Sopenharmony_ci uint32_t status; 87162306a36Sopenharmony_ci int timeout = 0; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* Use RDRS1 */ 87462306a36Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | 87562306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 87662306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDSR)); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* Load read_status sequence */ 87962306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* 88262306a36Sopenharmony_ci * Repeat until busy bit is deasserted, or timeout, or error (S25FLxxxS) 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci deadline = jiffies + FLASH_MAX_BUSY_WAIT; 88562306a36Sopenharmony_ci while (!timeout) { 88662306a36Sopenharmony_ci if (time_after_eq(jiffies, deadline)) 88762306a36Sopenharmony_ci timeout = 1; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci stfsm_wait_seq(fsm); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci stfsm_read_fifo(fsm, &status, 4); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if ((status & FLASH_STATUS_BUSY) == 0) 89462306a36Sopenharmony_ci return 0; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if ((fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) && 89762306a36Sopenharmony_ci ((status & S25FL_STATUS_P_ERR) || 89862306a36Sopenharmony_ci (status & S25FL_STATUS_E_ERR))) 89962306a36Sopenharmony_ci return (uint8_t)(status & 0xff); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (!timeout) 90262306a36Sopenharmony_ci /* Restart */ 90362306a36Sopenharmony_ci writel(seq->seq_cfg, fsm->base + SPI_FAST_SEQ_CFG); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci cond_resched(); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci dev_err(fsm->dev, "timeout on wait_busy\n"); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return FLASH_STATUS_TIMEOUT; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic int stfsm_read_status(struct stfsm *fsm, uint8_t cmd, 91462306a36Sopenharmony_ci uint8_t *data, int bytes) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_read_status_fifo; 91762306a36Sopenharmony_ci uint32_t tmp; 91862306a36Sopenharmony_ci uint8_t *t = (uint8_t *)&tmp; 91962306a36Sopenharmony_ci int i; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci dev_dbg(fsm->dev, "read 'status' register [0x%02x], %d byte(s)\n", 92262306a36Sopenharmony_ci cmd, bytes); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci BUG_ON(bytes != 1 && bytes != 2); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 92762306a36Sopenharmony_ci SEQ_OPC_OPCODE(cmd)); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci stfsm_read_fifo(fsm, &tmp, 4); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci for (i = 0; i < bytes; i++) 93462306a36Sopenharmony_ci data[i] = t[i]; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci stfsm_wait_seq(fsm); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return 0; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic int stfsm_write_status(struct stfsm *fsm, uint8_t cmd, 94262306a36Sopenharmony_ci uint16_t data, int bytes, int wait_busy) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_write_status; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci dev_dbg(fsm->dev, 94762306a36Sopenharmony_ci "write 'status' register [0x%02x], %d byte(s), 0x%04x\n" 94862306a36Sopenharmony_ci " %s wait-busy\n", cmd, bytes, data, wait_busy ? "with" : "no"); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci BUG_ON(bytes != 1 && bytes != 2); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 95362306a36Sopenharmony_ci SEQ_OPC_OPCODE(cmd)); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci seq->status = (uint32_t)data | STA_PADS_1 | STA_CSDEASSERT; 95662306a36Sopenharmony_ci seq->seq[2] = (bytes == 1) ? STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci stfsm_wait_seq(fsm); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (wait_busy) 96362306a36Sopenharmony_ci stfsm_wait_busy(fsm); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci return 0; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci/* 96962306a36Sopenharmony_ci * SoC reset on 'boot-from-spi' systems 97062306a36Sopenharmony_ci * 97162306a36Sopenharmony_ci * Certain modes of operation cause the Flash device to enter a particular state 97262306a36Sopenharmony_ci * for a period of time (e.g. 'Erase Sector', 'Quad Enable', and 'Enter 32-bit 97362306a36Sopenharmony_ci * Addr' commands). On boot-from-spi systems, it is important to consider what 97462306a36Sopenharmony_ci * happens if a warm reset occurs during this period. The SPIBoot controller 97562306a36Sopenharmony_ci * assumes that Flash device is in its default reset state, 24-bit address mode, 97662306a36Sopenharmony_ci * and ready to accept commands. This can be achieved using some form of 97762306a36Sopenharmony_ci * on-board logic/controller to force a device POR in response to a SoC-level 97862306a36Sopenharmony_ci * reset or by making use of the device reset signal if available (limited 97962306a36Sopenharmony_ci * number of devices only). 98062306a36Sopenharmony_ci * 98162306a36Sopenharmony_ci * Failure to take such precautions can cause problems following a warm reset. 98262306a36Sopenharmony_ci * For some operations (e.g. ERASE), there is little that can be done. For 98362306a36Sopenharmony_ci * other modes of operation (e.g. 32-bit addressing), options are often 98462306a36Sopenharmony_ci * available that can help minimise the window in which a reset could cause a 98562306a36Sopenharmony_ci * problem. 98662306a36Sopenharmony_ci * 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_cistatic bool stfsm_can_handle_soc_reset(struct stfsm *fsm) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci /* Reset signal is available on the board and supported by the device */ 99162306a36Sopenharmony_ci if (fsm->reset_signal && fsm->info->flags & FLASH_FLAG_RESET) 99262306a36Sopenharmony_ci return true; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* Board-level logic forces a power-on-reset */ 99562306a36Sopenharmony_ci if (fsm->reset_por) 99662306a36Sopenharmony_ci return true; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* Reset is not properly handled and may result in failure to reboot */ 99962306a36Sopenharmony_ci return false; 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci/* Configure 'addr_cfg' according to addressing mode */ 100362306a36Sopenharmony_cistatic void stfsm_prepare_erasesec_seq(struct stfsm *fsm, 100462306a36Sopenharmony_ci struct stfsm_seq *seq) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci int addr1_cycles = fsm->info->flags & FLASH_FLAG_32BIT_ADDR ? 16 : 8; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci seq->addr_cfg = (ADR_CFG_CYCLES_ADD1(addr1_cycles) | 100962306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 101062306a36Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 101162306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD2 | 101262306a36Sopenharmony_ci ADR_CFG_CSDEASSERT_ADD2); 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci/* Search for preferred configuration based on available flags */ 101662306a36Sopenharmony_cistatic struct seq_rw_config * 101762306a36Sopenharmony_cistfsm_search_seq_rw_configs(struct stfsm *fsm, 101862306a36Sopenharmony_ci struct seq_rw_config cfgs[]) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct seq_rw_config *config; 102162306a36Sopenharmony_ci int flags = fsm->info->flags; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci for (config = cfgs; config->cmd != 0; config++) 102462306a36Sopenharmony_ci if ((config->flags & flags) == config->flags) 102562306a36Sopenharmony_ci return config; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci return NULL; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci/* Prepare a READ/WRITE sequence according to configuration parameters */ 103162306a36Sopenharmony_cistatic void stfsm_prepare_rw_seq(struct stfsm *fsm, 103262306a36Sopenharmony_ci struct stfsm_seq *seq, 103362306a36Sopenharmony_ci struct seq_rw_config *cfg) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci int addr1_cycles, addr2_cycles; 103662306a36Sopenharmony_ci int i = 0; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci memset(seq, 0, sizeof(*seq)); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* Add READ/WRITE OPC */ 104162306a36Sopenharmony_ci seq->seq_opc[i++] = (SEQ_OPC_PADS_1 | 104262306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 104362306a36Sopenharmony_ci SEQ_OPC_OPCODE(cfg->cmd)); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* Add WREN OPC for a WRITE sequence */ 104662306a36Sopenharmony_ci if (cfg->write) 104762306a36Sopenharmony_ci seq->seq_opc[i++] = (SEQ_OPC_PADS_1 | 104862306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 104962306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | 105062306a36Sopenharmony_ci SEQ_OPC_CSDEASSERT); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci /* Address configuration (24 or 32-bit addresses) */ 105362306a36Sopenharmony_ci addr1_cycles = (fsm->info->flags & FLASH_FLAG_32BIT_ADDR) ? 16 : 8; 105462306a36Sopenharmony_ci addr1_cycles /= cfg->addr_pads; 105562306a36Sopenharmony_ci addr2_cycles = 16 / cfg->addr_pads; 105662306a36Sopenharmony_ci seq->addr_cfg = ((addr1_cycles & 0x3f) << 0 | /* ADD1 cycles */ 105762306a36Sopenharmony_ci (cfg->addr_pads - 1) << 6 | /* ADD1 pads */ 105862306a36Sopenharmony_ci (addr2_cycles & 0x3f) << 16 | /* ADD2 cycles */ 105962306a36Sopenharmony_ci ((cfg->addr_pads - 1) << 22)); /* ADD2 pads */ 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* Data/Sequence configuration */ 106262306a36Sopenharmony_ci seq->seq_cfg = ((cfg->data_pads - 1) << 16 | 106362306a36Sopenharmony_ci SEQ_CFG_STARTSEQ | 106462306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT); 106562306a36Sopenharmony_ci if (!cfg->write) 106662306a36Sopenharmony_ci seq->seq_cfg |= SEQ_CFG_READNOTWRITE; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* Mode configuration (no. of pads taken from addr cfg) */ 106962306a36Sopenharmony_ci seq->mode = ((cfg->mode_data & 0xff) << 0 | /* data */ 107062306a36Sopenharmony_ci (cfg->mode_cycles & 0x3f) << 16 | /* cycles */ 107162306a36Sopenharmony_ci (cfg->addr_pads - 1) << 22); /* pads */ 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* Dummy configuration (no. of pads taken from addr cfg) */ 107462306a36Sopenharmony_ci seq->dummy = ((cfg->dummy_cycles & 0x3f) << 16 | /* cycles */ 107562306a36Sopenharmony_ci (cfg->addr_pads - 1) << 22); /* pads */ 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Instruction sequence */ 107962306a36Sopenharmony_ci i = 0; 108062306a36Sopenharmony_ci if (cfg->write) 108162306a36Sopenharmony_ci seq->seq[i++] = STFSM_INST_CMD2; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci seq->seq[i++] = STFSM_INST_CMD1; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci seq->seq[i++] = STFSM_INST_ADD1; 108662306a36Sopenharmony_ci seq->seq[i++] = STFSM_INST_ADD2; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (cfg->mode_cycles) 108962306a36Sopenharmony_ci seq->seq[i++] = STFSM_INST_MODE; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci if (cfg->dummy_cycles) 109262306a36Sopenharmony_ci seq->seq[i++] = STFSM_INST_DUMMY; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci seq->seq[i++] = 109562306a36Sopenharmony_ci cfg->write ? STFSM_INST_DATA_WRITE : STFSM_INST_DATA_READ; 109662306a36Sopenharmony_ci seq->seq[i++] = STFSM_INST_STOP; 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic int stfsm_search_prepare_rw_seq(struct stfsm *fsm, 110062306a36Sopenharmony_ci struct stfsm_seq *seq, 110162306a36Sopenharmony_ci struct seq_rw_config *cfgs) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci struct seq_rw_config *config; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci config = stfsm_search_seq_rw_configs(fsm, cfgs); 110662306a36Sopenharmony_ci if (!config) { 110762306a36Sopenharmony_ci dev_err(fsm->dev, "failed to find suitable config\n"); 110862306a36Sopenharmony_ci return -EINVAL; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci stfsm_prepare_rw_seq(fsm, seq, config); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return 0; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci/* Prepare a READ/WRITE/ERASE 'default' sequences */ 111762306a36Sopenharmony_cistatic int stfsm_prepare_rwe_seqs_default(struct stfsm *fsm) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci uint32_t flags = fsm->info->flags; 112062306a36Sopenharmony_ci int ret; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* Configure 'READ' sequence */ 112362306a36Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 112462306a36Sopenharmony_ci default_read_configs); 112562306a36Sopenharmony_ci if (ret) { 112662306a36Sopenharmony_ci dev_err(fsm->dev, 112762306a36Sopenharmony_ci "failed to prep READ sequence with flags [0x%08x]\n", 112862306a36Sopenharmony_ci flags); 112962306a36Sopenharmony_ci return ret; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* Configure 'WRITE' sequence */ 113362306a36Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write, 113462306a36Sopenharmony_ci default_write_configs); 113562306a36Sopenharmony_ci if (ret) { 113662306a36Sopenharmony_ci dev_err(fsm->dev, 113762306a36Sopenharmony_ci "failed to prep WRITE sequence with flags [0x%08x]\n", 113862306a36Sopenharmony_ci flags); 113962306a36Sopenharmony_ci return ret; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* Configure 'ERASE_SECTOR' sequence */ 114362306a36Sopenharmony_ci stfsm_prepare_erasesec_seq(fsm, &stfsm_seq_erase_sector); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic int stfsm_mx25_config(struct stfsm *fsm) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci uint32_t flags = fsm->info->flags; 115162306a36Sopenharmony_ci uint32_t data_pads; 115262306a36Sopenharmony_ci uint8_t sta; 115362306a36Sopenharmony_ci int ret; 115462306a36Sopenharmony_ci bool soc_reset; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* 115762306a36Sopenharmony_ci * Use default READ/WRITE sequences 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 116062306a36Sopenharmony_ci if (ret) 116162306a36Sopenharmony_ci return ret; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci /* 116462306a36Sopenharmony_ci * Configure 32-bit Address Support 116562306a36Sopenharmony_ci */ 116662306a36Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) { 116762306a36Sopenharmony_ci /* Configure 'enter_32bitaddr' FSM sequence */ 116862306a36Sopenharmony_ci stfsm_mx25_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci soc_reset = stfsm_can_handle_soc_reset(fsm); 117162306a36Sopenharmony_ci if (soc_reset || !fsm->booted_from_spi) 117262306a36Sopenharmony_ci /* If we can handle SoC resets, we enable 32-bit address 117362306a36Sopenharmony_ci * mode pervasively */ 117462306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci else 117762306a36Sopenharmony_ci /* Else, enable/disable 32-bit addressing before/after 117862306a36Sopenharmony_ci * each operation */ 117962306a36Sopenharmony_ci fsm->configuration = (CFG_READ_TOGGLE_32BIT_ADDR | 118062306a36Sopenharmony_ci CFG_WRITE_TOGGLE_32BIT_ADDR | 118162306a36Sopenharmony_ci CFG_ERASESEC_TOGGLE_32BIT_ADDR); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* Check status of 'QE' bit, update if required. */ 118562306a36Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDSR, &sta, 1); 118662306a36Sopenharmony_ci data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; 118762306a36Sopenharmony_ci if (data_pads == 4) { 118862306a36Sopenharmony_ci if (!(sta & MX25_STATUS_QE)) { 118962306a36Sopenharmony_ci /* Set 'QE' */ 119062306a36Sopenharmony_ci sta |= MX25_STATUS_QE; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci } else { 119562306a36Sopenharmony_ci if (sta & MX25_STATUS_QE) { 119662306a36Sopenharmony_ci /* Clear 'QE' */ 119762306a36Sopenharmony_ci sta &= ~MX25_STATUS_QE; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1); 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci return 0; 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic int stfsm_n25q_config(struct stfsm *fsm) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci uint32_t flags = fsm->info->flags; 120962306a36Sopenharmony_ci uint8_t vcr; 121062306a36Sopenharmony_ci int ret = 0; 121162306a36Sopenharmony_ci bool soc_reset; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* Configure 'READ' sequence */ 121462306a36Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) 121562306a36Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 121662306a36Sopenharmony_ci n25q_read4_configs); 121762306a36Sopenharmony_ci else 121862306a36Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 121962306a36Sopenharmony_ci n25q_read3_configs); 122062306a36Sopenharmony_ci if (ret) { 122162306a36Sopenharmony_ci dev_err(fsm->dev, 122262306a36Sopenharmony_ci "failed to prepare READ sequence with flags [0x%08x]\n", 122362306a36Sopenharmony_ci flags); 122462306a36Sopenharmony_ci return ret; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* Configure 'WRITE' sequence (default configs) */ 122862306a36Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write, 122962306a36Sopenharmony_ci default_write_configs); 123062306a36Sopenharmony_ci if (ret) { 123162306a36Sopenharmony_ci dev_err(fsm->dev, 123262306a36Sopenharmony_ci "preparing WRITE sequence using flags [0x%08x] failed\n", 123362306a36Sopenharmony_ci flags); 123462306a36Sopenharmony_ci return ret; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* * Configure 'ERASE_SECTOR' sequence */ 123862306a36Sopenharmony_ci stfsm_prepare_erasesec_seq(fsm, &stfsm_seq_erase_sector); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* Configure 32-bit address support */ 124162306a36Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) { 124262306a36Sopenharmony_ci stfsm_n25q_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci soc_reset = stfsm_can_handle_soc_reset(fsm); 124562306a36Sopenharmony_ci if (soc_reset || !fsm->booted_from_spi) { 124662306a36Sopenharmony_ci /* 124762306a36Sopenharmony_ci * If we can handle SoC resets, we enable 32-bit 124862306a36Sopenharmony_ci * address mode pervasively 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 125162306a36Sopenharmony_ci } else { 125262306a36Sopenharmony_ci /* 125362306a36Sopenharmony_ci * If not, enable/disable for WRITE and ERASE 125462306a36Sopenharmony_ci * operations (READ uses special commands) 125562306a36Sopenharmony_ci */ 125662306a36Sopenharmony_ci fsm->configuration = (CFG_WRITE_TOGGLE_32BIT_ADDR | 125762306a36Sopenharmony_ci CFG_ERASESEC_TOGGLE_32BIT_ADDR); 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci /* 126262306a36Sopenharmony_ci * Configure device to use 8 dummy cycles 126362306a36Sopenharmony_ci */ 126462306a36Sopenharmony_ci vcr = (N25Q_VCR_DUMMY_CYCLES(8) | N25Q_VCR_XIP_DISABLED | 126562306a36Sopenharmony_ci N25Q_VCR_WRAP_CONT); 126662306a36Sopenharmony_ci stfsm_write_status(fsm, N25Q_CMD_WRVCR, vcr, 1, 0); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci return 0; 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cistatic void stfsm_s25fl_prepare_erasesec_seq_32(struct stfsm_seq *seq) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci seq->seq_opc[1] = (SEQ_OPC_PADS_1 | 127462306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 127562306a36Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_SE4)); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci seq->addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | 127862306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 127962306a36Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 128062306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD2 | 128162306a36Sopenharmony_ci ADR_CFG_CSDEASSERT_ADD2); 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic void stfsm_s25fl_read_dyb(struct stfsm *fsm, uint32_t offs, uint8_t *dby) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci uint32_t tmp; 128762306a36Sopenharmony_ci struct stfsm_seq seq = { 128862306a36Sopenharmony_ci .data_size = TRANSFER_SIZE(4), 128962306a36Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 129062306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 129162306a36Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_DYBRD)), 129262306a36Sopenharmony_ci .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | 129362306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 129462306a36Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 129562306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD2), 129662306a36Sopenharmony_ci .addr1 = (offs >> 16) & 0xffff, 129762306a36Sopenharmony_ci .addr2 = offs & 0xffff, 129862306a36Sopenharmony_ci .seq = { 129962306a36Sopenharmony_ci STFSM_INST_CMD1, 130062306a36Sopenharmony_ci STFSM_INST_ADD1, 130162306a36Sopenharmony_ci STFSM_INST_ADD2, 130262306a36Sopenharmony_ci STFSM_INST_DATA_READ, 130362306a36Sopenharmony_ci STFSM_INST_STOP, 130462306a36Sopenharmony_ci }, 130562306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 130662306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 130762306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 130862306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 130962306a36Sopenharmony_ci }; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci stfsm_load_seq(fsm, &seq); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci stfsm_read_fifo(fsm, &tmp, 4); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci *dby = (uint8_t)(tmp >> 24); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci stfsm_wait_seq(fsm); 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_cistatic void stfsm_s25fl_write_dyb(struct stfsm *fsm, uint32_t offs, uint8_t dby) 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci struct stfsm_seq seq = { 132362306a36Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 132462306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | 132562306a36Sopenharmony_ci SEQ_OPC_CSDEASSERT), 132662306a36Sopenharmony_ci .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 132762306a36Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_DYBWR)), 132862306a36Sopenharmony_ci .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | 132962306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 133062306a36Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 133162306a36Sopenharmony_ci ADR_CFG_PADS_1_ADD2), 133262306a36Sopenharmony_ci .status = (uint32_t)dby | STA_PADS_1 | STA_CSDEASSERT, 133362306a36Sopenharmony_ci .addr1 = (offs >> 16) & 0xffff, 133462306a36Sopenharmony_ci .addr2 = offs & 0xffff, 133562306a36Sopenharmony_ci .seq = { 133662306a36Sopenharmony_ci STFSM_INST_CMD1, 133762306a36Sopenharmony_ci STFSM_INST_CMD2, 133862306a36Sopenharmony_ci STFSM_INST_ADD1, 133962306a36Sopenharmony_ci STFSM_INST_ADD2, 134062306a36Sopenharmony_ci STFSM_INST_STA_WR1, 134162306a36Sopenharmony_ci STFSM_INST_STOP, 134262306a36Sopenharmony_ci }, 134362306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 134462306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 134562306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 134662306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 134762306a36Sopenharmony_ci }; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci stfsm_load_seq(fsm, &seq); 135062306a36Sopenharmony_ci stfsm_wait_seq(fsm); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci stfsm_wait_busy(fsm); 135362306a36Sopenharmony_ci} 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_cistatic int stfsm_s25fl_clear_status_reg(struct stfsm *fsm) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci struct stfsm_seq seq = { 135862306a36Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 135962306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 136062306a36Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_CLSR) | 136162306a36Sopenharmony_ci SEQ_OPC_CSDEASSERT), 136262306a36Sopenharmony_ci .seq_opc[1] = (SEQ_OPC_PADS_1 | 136362306a36Sopenharmony_ci SEQ_OPC_CYCLES(8) | 136462306a36Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WRDI) | 136562306a36Sopenharmony_ci SEQ_OPC_CSDEASSERT), 136662306a36Sopenharmony_ci .seq = { 136762306a36Sopenharmony_ci STFSM_INST_CMD1, 136862306a36Sopenharmony_ci STFSM_INST_CMD2, 136962306a36Sopenharmony_ci STFSM_INST_WAIT, 137062306a36Sopenharmony_ci STFSM_INST_STOP, 137162306a36Sopenharmony_ci }, 137262306a36Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 137362306a36Sopenharmony_ci SEQ_CFG_ERASE | 137462306a36Sopenharmony_ci SEQ_CFG_READNOTWRITE | 137562306a36Sopenharmony_ci SEQ_CFG_CSDEASSERT | 137662306a36Sopenharmony_ci SEQ_CFG_STARTSEQ), 137762306a36Sopenharmony_ci }; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci stfsm_load_seq(fsm, &seq); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci stfsm_wait_seq(fsm); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic int stfsm_s25fl_config(struct stfsm *fsm) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci struct flash_info *info = fsm->info; 138962306a36Sopenharmony_ci uint32_t flags = info->flags; 139062306a36Sopenharmony_ci uint32_t data_pads; 139162306a36Sopenharmony_ci uint32_t offs; 139262306a36Sopenharmony_ci uint16_t sta_wr; 139362306a36Sopenharmony_ci uint8_t sr1, cr1, dyb; 139462306a36Sopenharmony_ci int update_sr = 0; 139562306a36Sopenharmony_ci int ret; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) { 139862306a36Sopenharmony_ci /* 139962306a36Sopenharmony_ci * Prepare Read/Write/Erase sequences according to S25FLxxx 140062306a36Sopenharmony_ci * 32-bit address command set 140162306a36Sopenharmony_ci */ 140262306a36Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 140362306a36Sopenharmony_ci stfsm_s25fl_read4_configs); 140462306a36Sopenharmony_ci if (ret) 140562306a36Sopenharmony_ci return ret; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write, 140862306a36Sopenharmony_ci stfsm_s25fl_write4_configs); 140962306a36Sopenharmony_ci if (ret) 141062306a36Sopenharmony_ci return ret; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci stfsm_s25fl_prepare_erasesec_seq_32(&stfsm_seq_erase_sector); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci } else { 141562306a36Sopenharmony_ci /* Use default configurations for 24-bit addressing */ 141662306a36Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 141762306a36Sopenharmony_ci if (ret) 141862306a36Sopenharmony_ci return ret; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci /* 142262306a36Sopenharmony_ci * For devices that support 'DYB' sector locking, check lock status and 142362306a36Sopenharmony_ci * unlock sectors if necessary (some variants power-on with sectors 142462306a36Sopenharmony_ci * locked by default) 142562306a36Sopenharmony_ci */ 142662306a36Sopenharmony_ci if (flags & FLASH_FLAG_DYB_LOCKING) { 142762306a36Sopenharmony_ci offs = 0; 142862306a36Sopenharmony_ci for (offs = 0; offs < info->sector_size * info->n_sectors;) { 142962306a36Sopenharmony_ci stfsm_s25fl_read_dyb(fsm, offs, &dyb); 143062306a36Sopenharmony_ci if (dyb == 0x00) 143162306a36Sopenharmony_ci stfsm_s25fl_write_dyb(fsm, offs, 0xff); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* Handle bottom/top 4KiB parameter sectors */ 143462306a36Sopenharmony_ci if ((offs < info->sector_size * 2) || 143562306a36Sopenharmony_ci (offs >= (info->sector_size - info->n_sectors * 4))) 143662306a36Sopenharmony_ci offs += 0x1000; 143762306a36Sopenharmony_ci else 143862306a36Sopenharmony_ci offs += 0x10000; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* Check status of 'QE' bit, update if required. */ 144362306a36Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDCR, &cr1, 1); 144462306a36Sopenharmony_ci data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; 144562306a36Sopenharmony_ci if (data_pads == 4) { 144662306a36Sopenharmony_ci if (!(cr1 & STFSM_S25FL_CONFIG_QE)) { 144762306a36Sopenharmony_ci /* Set 'QE' */ 144862306a36Sopenharmony_ci cr1 |= STFSM_S25FL_CONFIG_QE; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci update_sr = 1; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci } else { 145362306a36Sopenharmony_ci if (cr1 & STFSM_S25FL_CONFIG_QE) { 145462306a36Sopenharmony_ci /* Clear 'QE' */ 145562306a36Sopenharmony_ci cr1 &= ~STFSM_S25FL_CONFIG_QE; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci update_sr = 1; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci if (update_sr) { 146162306a36Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1); 146262306a36Sopenharmony_ci sta_wr = ((uint16_t)cr1 << 8) | sr1; 146362306a36Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sta_wr, 2, 1); 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* 146762306a36Sopenharmony_ci * S25FLxxx devices support Program and Error error flags. 146862306a36Sopenharmony_ci * Configure driver to check flags and clear if necessary. 146962306a36Sopenharmony_ci */ 147062306a36Sopenharmony_ci fsm->configuration |= CFG_S25FL_CHECK_ERROR_FLAGS; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci return 0; 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic int stfsm_w25q_config(struct stfsm *fsm) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci uint32_t data_pads; 147862306a36Sopenharmony_ci uint8_t sr1, sr2; 147962306a36Sopenharmony_ci uint16_t sr_wr; 148062306a36Sopenharmony_ci int update_sr = 0; 148162306a36Sopenharmony_ci int ret; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 148462306a36Sopenharmony_ci if (ret) 148562306a36Sopenharmony_ci return ret; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* Check status of 'QE' bit, update if required. */ 148862306a36Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDCR, &sr2, 1); 148962306a36Sopenharmony_ci data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; 149062306a36Sopenharmony_ci if (data_pads == 4) { 149162306a36Sopenharmony_ci if (!(sr2 & W25Q_STATUS_QE)) { 149262306a36Sopenharmony_ci /* Set 'QE' */ 149362306a36Sopenharmony_ci sr2 |= W25Q_STATUS_QE; 149462306a36Sopenharmony_ci update_sr = 1; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci } else { 149762306a36Sopenharmony_ci if (sr2 & W25Q_STATUS_QE) { 149862306a36Sopenharmony_ci /* Clear 'QE' */ 149962306a36Sopenharmony_ci sr2 &= ~W25Q_STATUS_QE; 150062306a36Sopenharmony_ci update_sr = 1; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci if (update_sr) { 150462306a36Sopenharmony_ci /* Write status register */ 150562306a36Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1); 150662306a36Sopenharmony_ci sr_wr = ((uint16_t)sr2 << 8) | sr1; 150762306a36Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sr_wr, 2, 1); 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci return 0; 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size, 151462306a36Sopenharmony_ci uint32_t offset) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci struct stfsm_seq *seq = &fsm->stfsm_seq_read; 151762306a36Sopenharmony_ci uint32_t data_pads; 151862306a36Sopenharmony_ci uint32_t read_mask; 151962306a36Sopenharmony_ci uint32_t size_ub; 152062306a36Sopenharmony_ci uint32_t size_lb; 152162306a36Sopenharmony_ci uint32_t size_mop; 152262306a36Sopenharmony_ci uint32_t tmp[4]; 152362306a36Sopenharmony_ci uint32_t page_buf[FLASH_PAGESIZE_32]; 152462306a36Sopenharmony_ci uint8_t *p; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci dev_dbg(fsm->dev, "reading %d bytes from 0x%08x\n", size, offset); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* Enter 32-bit address mode, if required */ 152962306a36Sopenharmony_ci if (fsm->configuration & CFG_READ_TOGGLE_32BIT_ADDR) 153062306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci /* Must read in multiples of 32 cycles (or 32*pads/8 Bytes) */ 153362306a36Sopenharmony_ci data_pads = ((seq->seq_cfg >> 16) & 0x3) + 1; 153462306a36Sopenharmony_ci read_mask = (data_pads << 2) - 1; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci /* Handle non-aligned buf */ 153762306a36Sopenharmony_ci p = ((uintptr_t)buf & 0x3) ? (uint8_t *)page_buf : buf; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* Handle non-aligned size */ 154062306a36Sopenharmony_ci size_ub = (size + read_mask) & ~read_mask; 154162306a36Sopenharmony_ci size_lb = size & ~read_mask; 154262306a36Sopenharmony_ci size_mop = size & read_mask; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci seq->data_size = TRANSFER_SIZE(size_ub); 154562306a36Sopenharmony_ci seq->addr1 = (offset >> 16) & 0xffff; 154662306a36Sopenharmony_ci seq->addr2 = offset & 0xffff; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci if (size_lb) 155162306a36Sopenharmony_ci stfsm_read_fifo(fsm, (uint32_t *)p, size_lb); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci if (size_mop) { 155462306a36Sopenharmony_ci stfsm_read_fifo(fsm, tmp, read_mask + 1); 155562306a36Sopenharmony_ci memcpy(p + size_lb, &tmp, size_mop); 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci /* Handle non-aligned buf */ 155962306a36Sopenharmony_ci if ((uintptr_t)buf & 0x3) 156062306a36Sopenharmony_ci memcpy(buf, page_buf, size); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* Wait for sequence to finish */ 156362306a36Sopenharmony_ci stfsm_wait_seq(fsm); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci stfsm_clear_fifo(fsm); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci /* Exit 32-bit address mode, if required */ 156862306a36Sopenharmony_ci if (fsm->configuration & CFG_READ_TOGGLE_32BIT_ADDR) 156962306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 0); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci return 0; 157262306a36Sopenharmony_ci} 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cistatic int stfsm_write(struct stfsm *fsm, const uint8_t *buf, 157562306a36Sopenharmony_ci uint32_t size, uint32_t offset) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci struct stfsm_seq *seq = &fsm->stfsm_seq_write; 157862306a36Sopenharmony_ci uint32_t data_pads; 157962306a36Sopenharmony_ci uint32_t write_mask; 158062306a36Sopenharmony_ci uint32_t size_ub; 158162306a36Sopenharmony_ci uint32_t size_lb; 158262306a36Sopenharmony_ci uint32_t size_mop; 158362306a36Sopenharmony_ci uint32_t tmp[4]; 158462306a36Sopenharmony_ci uint32_t i; 158562306a36Sopenharmony_ci uint32_t page_buf[FLASH_PAGESIZE_32]; 158662306a36Sopenharmony_ci uint8_t *t = (uint8_t *)&tmp; 158762306a36Sopenharmony_ci const uint8_t *p; 158862306a36Sopenharmony_ci int ret; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci dev_dbg(fsm->dev, "writing %d bytes to 0x%08x\n", size, offset); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci /* Enter 32-bit address mode, if required */ 159362306a36Sopenharmony_ci if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) 159462306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* Must write in multiples of 32 cycles (or 32*pads/8 bytes) */ 159762306a36Sopenharmony_ci data_pads = ((seq->seq_cfg >> 16) & 0x3) + 1; 159862306a36Sopenharmony_ci write_mask = (data_pads << 2) - 1; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci /* Handle non-aligned buf */ 160162306a36Sopenharmony_ci if ((uintptr_t)buf & 0x3) { 160262306a36Sopenharmony_ci memcpy(page_buf, buf, size); 160362306a36Sopenharmony_ci p = (uint8_t *)page_buf; 160462306a36Sopenharmony_ci } else { 160562306a36Sopenharmony_ci p = buf; 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci /* Handle non-aligned size */ 160962306a36Sopenharmony_ci size_ub = (size + write_mask) & ~write_mask; 161062306a36Sopenharmony_ci size_lb = size & ~write_mask; 161162306a36Sopenharmony_ci size_mop = size & write_mask; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci seq->data_size = TRANSFER_SIZE(size_ub); 161462306a36Sopenharmony_ci seq->addr1 = (offset >> 16) & 0xffff; 161562306a36Sopenharmony_ci seq->addr2 = offset & 0xffff; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci /* Need to set FIFO to write mode, before writing data to FIFO (see 161862306a36Sopenharmony_ci * GNBvb79594) 161962306a36Sopenharmony_ci */ 162062306a36Sopenharmony_ci writel(0x00040000, fsm->base + SPI_FAST_SEQ_CFG); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* 162362306a36Sopenharmony_ci * Before writing data to the FIFO, apply a small delay to allow a 162462306a36Sopenharmony_ci * potential change of FIFO direction to complete. 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci if (fsm->fifo_dir_delay == 0) 162762306a36Sopenharmony_ci readl(fsm->base + SPI_FAST_SEQ_CFG); 162862306a36Sopenharmony_ci else 162962306a36Sopenharmony_ci udelay(fsm->fifo_dir_delay); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci /* Write data to FIFO, before starting sequence (see GNBvd79593) */ 163362306a36Sopenharmony_ci if (size_lb) { 163462306a36Sopenharmony_ci stfsm_write_fifo(fsm, (uint32_t *)p, size_lb); 163562306a36Sopenharmony_ci p += size_lb; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci /* Handle non-aligned size */ 163962306a36Sopenharmony_ci if (size_mop) { 164062306a36Sopenharmony_ci memset(t, 0xff, write_mask + 1); /* fill with 0xff's */ 164162306a36Sopenharmony_ci for (i = 0; i < size_mop; i++) 164262306a36Sopenharmony_ci t[i] = *p++; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci stfsm_write_fifo(fsm, tmp, write_mask + 1); 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* Start sequence */ 164862306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci /* Wait for sequence to finish */ 165162306a36Sopenharmony_ci stfsm_wait_seq(fsm); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci /* Wait for completion */ 165462306a36Sopenharmony_ci ret = stfsm_wait_busy(fsm); 165562306a36Sopenharmony_ci if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) 165662306a36Sopenharmony_ci stfsm_s25fl_clear_status_reg(fsm); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* Exit 32-bit address mode, if required */ 165962306a36Sopenharmony_ci if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) 166062306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 0); 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci return 0; 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci/* 166662306a36Sopenharmony_ci * Read an address range from the flash chip. The address range 166762306a36Sopenharmony_ci * may be any size provided it is within the physical boundaries. 166862306a36Sopenharmony_ci */ 166962306a36Sopenharmony_cistatic int stfsm_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, 167062306a36Sopenharmony_ci size_t *retlen, u_char *buf) 167162306a36Sopenharmony_ci{ 167262306a36Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); 167362306a36Sopenharmony_ci uint32_t bytes; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci dev_dbg(fsm->dev, "%s from 0x%08x, len %zd\n", 167662306a36Sopenharmony_ci __func__, (u32)from, len); 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci mutex_lock(&fsm->lock); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci while (len > 0) { 168162306a36Sopenharmony_ci bytes = min_t(size_t, len, FLASH_PAGESIZE); 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci stfsm_read(fsm, buf, bytes, from); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci buf += bytes; 168662306a36Sopenharmony_ci from += bytes; 168762306a36Sopenharmony_ci len -= bytes; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci *retlen += bytes; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci mutex_unlock(&fsm->lock); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci return 0; 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_cistatic int stfsm_erase_sector(struct stfsm *fsm, uint32_t offset) 169862306a36Sopenharmony_ci{ 169962306a36Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_erase_sector; 170062306a36Sopenharmony_ci int ret; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci dev_dbg(fsm->dev, "erasing sector at 0x%08x\n", offset); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci /* Enter 32-bit address mode, if required */ 170562306a36Sopenharmony_ci if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR) 170662306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci seq->addr1 = (offset >> 16) & 0xffff; 170962306a36Sopenharmony_ci seq->addr2 = offset & 0xffff; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci stfsm_wait_seq(fsm); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci /* Wait for completion */ 171662306a36Sopenharmony_ci ret = stfsm_wait_busy(fsm); 171762306a36Sopenharmony_ci if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) 171862306a36Sopenharmony_ci stfsm_s25fl_clear_status_reg(fsm); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci /* Exit 32-bit address mode, if required */ 172162306a36Sopenharmony_ci if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR) 172262306a36Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 0); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci return ret; 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic int stfsm_erase_chip(struct stfsm *fsm) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci const struct stfsm_seq *seq = &stfsm_seq_erase_chip; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci dev_dbg(fsm->dev, "erasing chip\n"); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci stfsm_wait_seq(fsm); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci return stfsm_wait_busy(fsm); 173862306a36Sopenharmony_ci} 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci/* 174162306a36Sopenharmony_ci * Write an address range to the flash chip. Data must be written in 174262306a36Sopenharmony_ci * FLASH_PAGESIZE chunks. The address range may be any size provided 174362306a36Sopenharmony_ci * it is within the physical boundaries. 174462306a36Sopenharmony_ci */ 174562306a36Sopenharmony_cistatic int stfsm_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, 174662306a36Sopenharmony_ci size_t *retlen, const u_char *buf) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci u32 page_offs; 175162306a36Sopenharmony_ci u32 bytes; 175262306a36Sopenharmony_ci uint8_t *b = (uint8_t *)buf; 175362306a36Sopenharmony_ci int ret = 0; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci dev_dbg(fsm->dev, "%s to 0x%08x, len %zd\n", __func__, (u32)to, len); 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci /* Offset within page */ 175862306a36Sopenharmony_ci page_offs = to % FLASH_PAGESIZE; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci mutex_lock(&fsm->lock); 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci while (len) { 176362306a36Sopenharmony_ci /* Write up to page boundary */ 176462306a36Sopenharmony_ci bytes = min_t(size_t, FLASH_PAGESIZE - page_offs, len); 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci ret = stfsm_write(fsm, b, bytes, to); 176762306a36Sopenharmony_ci if (ret) 176862306a36Sopenharmony_ci goto out1; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci b += bytes; 177162306a36Sopenharmony_ci len -= bytes; 177262306a36Sopenharmony_ci to += bytes; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* We are now page-aligned */ 177562306a36Sopenharmony_ci page_offs = 0; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci *retlen += bytes; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ciout1: 178262306a36Sopenharmony_ci mutex_unlock(&fsm->lock); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci return ret; 178562306a36Sopenharmony_ci} 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci/* 178862306a36Sopenharmony_ci * Erase an address range on the flash chip. The address range may extend 178962306a36Sopenharmony_ci * one or more erase sectors. Return an error is there is a problem erasing. 179062306a36Sopenharmony_ci */ 179162306a36Sopenharmony_cistatic int stfsm_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) 179262306a36Sopenharmony_ci{ 179362306a36Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); 179462306a36Sopenharmony_ci u32 addr, len; 179562306a36Sopenharmony_ci int ret; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci dev_dbg(fsm->dev, "%s at 0x%llx, len %lld\n", __func__, 179862306a36Sopenharmony_ci (long long)instr->addr, (long long)instr->len); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci addr = instr->addr; 180162306a36Sopenharmony_ci len = instr->len; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci mutex_lock(&fsm->lock); 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci /* Whole-chip erase? */ 180662306a36Sopenharmony_ci if (len == mtd->size) { 180762306a36Sopenharmony_ci ret = stfsm_erase_chip(fsm); 180862306a36Sopenharmony_ci if (ret) 180962306a36Sopenharmony_ci goto out1; 181062306a36Sopenharmony_ci } else { 181162306a36Sopenharmony_ci while (len) { 181262306a36Sopenharmony_ci ret = stfsm_erase_sector(fsm, addr); 181362306a36Sopenharmony_ci if (ret) 181462306a36Sopenharmony_ci goto out1; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci addr += mtd->erasesize; 181762306a36Sopenharmony_ci len -= mtd->erasesize; 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci mutex_unlock(&fsm->lock); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci return 0; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ciout1: 182662306a36Sopenharmony_ci mutex_unlock(&fsm->lock); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci return ret; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic void stfsm_read_jedec(struct stfsm *fsm, uint8_t *jedec) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci const struct stfsm_seq *seq = &stfsm_seq_read_jedec; 183462306a36Sopenharmony_ci uint32_t tmp[2]; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci stfsm_load_seq(fsm, seq); 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci stfsm_read_fifo(fsm, tmp, 8); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci memcpy(jedec, tmp, 5); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci stfsm_wait_seq(fsm); 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_cistatic struct flash_info *stfsm_jedec_probe(struct stfsm *fsm) 184662306a36Sopenharmony_ci{ 184762306a36Sopenharmony_ci struct flash_info *info; 184862306a36Sopenharmony_ci u16 ext_jedec; 184962306a36Sopenharmony_ci u32 jedec; 185062306a36Sopenharmony_ci u8 id[5]; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci stfsm_read_jedec(fsm, id); 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci jedec = id[0] << 16 | id[1] << 8 | id[2]; 185562306a36Sopenharmony_ci /* 185662306a36Sopenharmony_ci * JEDEC also defines an optional "extended device information" 185762306a36Sopenharmony_ci * string for after vendor-specific data, after the three bytes 185862306a36Sopenharmony_ci * we use here. Supporting some chips might require using it. 185962306a36Sopenharmony_ci */ 186062306a36Sopenharmony_ci ext_jedec = id[3] << 8 | id[4]; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci dev_dbg(fsm->dev, "JEDEC = 0x%08x [%5ph]\n", jedec, id); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci for (info = flash_types; info->name; info++) { 186562306a36Sopenharmony_ci if (info->jedec_id == jedec) { 186662306a36Sopenharmony_ci if (info->ext_id && info->ext_id != ext_jedec) 186762306a36Sopenharmony_ci continue; 186862306a36Sopenharmony_ci return info; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci dev_err(fsm->dev, "Unrecognized JEDEC id %06x\n", jedec); 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci return NULL; 187462306a36Sopenharmony_ci} 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_cistatic int stfsm_set_mode(struct stfsm *fsm, uint32_t mode) 187762306a36Sopenharmony_ci{ 187862306a36Sopenharmony_ci int ret, timeout = 10; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci /* Wait for controller to accept mode change */ 188162306a36Sopenharmony_ci while (--timeout) { 188262306a36Sopenharmony_ci ret = readl(fsm->base + SPI_STA_MODE_CHANGE); 188362306a36Sopenharmony_ci if (ret & 0x1) 188462306a36Sopenharmony_ci break; 188562306a36Sopenharmony_ci udelay(1); 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci if (!timeout) 188962306a36Sopenharmony_ci return -EBUSY; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci writel(mode, fsm->base + SPI_MODESELECT); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci return 0; 189462306a36Sopenharmony_ci} 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_cistatic void stfsm_set_freq(struct stfsm *fsm, uint32_t spi_freq) 189762306a36Sopenharmony_ci{ 189862306a36Sopenharmony_ci uint32_t emi_freq; 189962306a36Sopenharmony_ci uint32_t clk_div; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci emi_freq = clk_get_rate(fsm->clk); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci /* 190462306a36Sopenharmony_ci * Calculate clk_div - values between 2 and 128 190562306a36Sopenharmony_ci * Multiple of 2, rounded up 190662306a36Sopenharmony_ci */ 190762306a36Sopenharmony_ci clk_div = 2 * DIV_ROUND_UP(emi_freq, 2 * spi_freq); 190862306a36Sopenharmony_ci if (clk_div < 2) 190962306a36Sopenharmony_ci clk_div = 2; 191062306a36Sopenharmony_ci else if (clk_div > 128) 191162306a36Sopenharmony_ci clk_div = 128; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci /* 191462306a36Sopenharmony_ci * Determine a suitable delay for the IP to complete a change of 191562306a36Sopenharmony_ci * direction of the FIFO. The required delay is related to the clock 191662306a36Sopenharmony_ci * divider used. The following heuristics are based on empirical tests, 191762306a36Sopenharmony_ci * using a 100MHz EMI clock. 191862306a36Sopenharmony_ci */ 191962306a36Sopenharmony_ci if (clk_div <= 4) 192062306a36Sopenharmony_ci fsm->fifo_dir_delay = 0; 192162306a36Sopenharmony_ci else if (clk_div <= 10) 192262306a36Sopenharmony_ci fsm->fifo_dir_delay = 1; 192362306a36Sopenharmony_ci else 192462306a36Sopenharmony_ci fsm->fifo_dir_delay = DIV_ROUND_UP(clk_div, 10); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci dev_dbg(fsm->dev, "emi_clk = %uHZ, spi_freq = %uHZ, clk_div = %u\n", 192762306a36Sopenharmony_ci emi_freq, spi_freq, clk_div); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci writel(clk_div, fsm->base + SPI_CLOCKDIV); 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic int stfsm_init(struct stfsm *fsm) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci int ret; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* Perform a soft reset of the FSM controller */ 193762306a36Sopenharmony_ci writel(SEQ_CFG_SWRESET, fsm->base + SPI_FAST_SEQ_CFG); 193862306a36Sopenharmony_ci udelay(1); 193962306a36Sopenharmony_ci writel(0, fsm->base + SPI_FAST_SEQ_CFG); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci /* Set clock to 'safe' frequency initially */ 194262306a36Sopenharmony_ci stfsm_set_freq(fsm, STFSM_FLASH_SAFE_FREQ); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci /* Switch to FSM */ 194562306a36Sopenharmony_ci ret = stfsm_set_mode(fsm, SPI_MODESELECT_FSM); 194662306a36Sopenharmony_ci if (ret) 194762306a36Sopenharmony_ci return ret; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci /* Set timing parameters */ 195062306a36Sopenharmony_ci writel(SPI_CFG_DEVICE_ST | 195162306a36Sopenharmony_ci SPI_CFG_DEFAULT_MIN_CS_HIGH | 195262306a36Sopenharmony_ci SPI_CFG_DEFAULT_CS_SETUPHOLD | 195362306a36Sopenharmony_ci SPI_CFG_DEFAULT_DATA_HOLD, 195462306a36Sopenharmony_ci fsm->base + SPI_CONFIGDATA); 195562306a36Sopenharmony_ci writel(STFSM_DEFAULT_WR_TIME, fsm->base + SPI_STATUS_WR_TIME_REG); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* 195862306a36Sopenharmony_ci * Set the FSM 'WAIT' delay to the minimum workable value. Note, for 195962306a36Sopenharmony_ci * our purposes, the WAIT instruction is used purely to achieve 196062306a36Sopenharmony_ci * "sequence validity" rather than actually implement a delay. 196162306a36Sopenharmony_ci */ 196262306a36Sopenharmony_ci writel(0x00000001, fsm->base + SPI_PROGRAM_ERASE_TIME); 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci /* Clear FIFO, just in case */ 196562306a36Sopenharmony_ci stfsm_clear_fifo(fsm); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci return 0; 196862306a36Sopenharmony_ci} 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_cistatic void stfsm_fetch_platform_configs(struct platform_device *pdev) 197162306a36Sopenharmony_ci{ 197262306a36Sopenharmony_ci struct stfsm *fsm = platform_get_drvdata(pdev); 197362306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 197462306a36Sopenharmony_ci struct regmap *regmap; 197562306a36Sopenharmony_ci uint32_t boot_device_reg; 197662306a36Sopenharmony_ci uint32_t boot_device_spi; 197762306a36Sopenharmony_ci uint32_t boot_device; /* Value we read from *boot_device_reg */ 197862306a36Sopenharmony_ci int ret; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci /* Booting from SPI NOR Flash is the default */ 198162306a36Sopenharmony_ci fsm->booted_from_spi = true; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); 198462306a36Sopenharmony_ci if (IS_ERR(regmap)) 198562306a36Sopenharmony_ci goto boot_device_fail; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci fsm->reset_signal = of_property_read_bool(np, "st,reset-signal"); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci fsm->reset_por = of_property_read_bool(np, "st,reset-por"); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci /* Where in the syscon the boot device information lives */ 199262306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,boot-device-reg", &boot_device_reg); 199362306a36Sopenharmony_ci if (ret) 199462306a36Sopenharmony_ci goto boot_device_fail; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci /* Boot device value when booted from SPI NOR */ 199762306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,boot-device-spi", &boot_device_spi); 199862306a36Sopenharmony_ci if (ret) 199962306a36Sopenharmony_ci goto boot_device_fail; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci ret = regmap_read(regmap, boot_device_reg, &boot_device); 200262306a36Sopenharmony_ci if (ret) 200362306a36Sopenharmony_ci goto boot_device_fail; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci if (boot_device != boot_device_spi) 200662306a36Sopenharmony_ci fsm->booted_from_spi = false; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci return; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ciboot_device_fail: 201162306a36Sopenharmony_ci dev_warn(&pdev->dev, 201262306a36Sopenharmony_ci "failed to fetch boot device, assuming boot from SPI\n"); 201362306a36Sopenharmony_ci} 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_cistatic int stfsm_probe(struct platform_device *pdev) 201662306a36Sopenharmony_ci{ 201762306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 201862306a36Sopenharmony_ci struct flash_info *info; 201962306a36Sopenharmony_ci struct stfsm *fsm; 202062306a36Sopenharmony_ci int ret; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci if (!np) { 202362306a36Sopenharmony_ci dev_err(&pdev->dev, "No DT found\n"); 202462306a36Sopenharmony_ci return -EINVAL; 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci fsm = devm_kzalloc(&pdev->dev, sizeof(*fsm), GFP_KERNEL); 202862306a36Sopenharmony_ci if (!fsm) 202962306a36Sopenharmony_ci return -ENOMEM; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci fsm->dev = &pdev->dev; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci platform_set_drvdata(pdev, fsm); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci fsm->base = devm_platform_ioremap_resource(pdev, 0); 203662306a36Sopenharmony_ci if (IS_ERR(fsm->base)) 203762306a36Sopenharmony_ci return PTR_ERR(fsm->base); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci fsm->clk = devm_clk_get_enabled(&pdev->dev, NULL); 204062306a36Sopenharmony_ci if (IS_ERR(fsm->clk)) { 204162306a36Sopenharmony_ci dev_err(fsm->dev, "Couldn't find EMI clock.\n"); 204262306a36Sopenharmony_ci return PTR_ERR(fsm->clk); 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci mutex_init(&fsm->lock); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci ret = stfsm_init(fsm); 204862306a36Sopenharmony_ci if (ret) { 204962306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialise FSM Controller\n"); 205062306a36Sopenharmony_ci return ret; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci stfsm_fetch_platform_configs(pdev); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci /* Detect SPI FLASH device */ 205662306a36Sopenharmony_ci info = stfsm_jedec_probe(fsm); 205762306a36Sopenharmony_ci if (!info) 205862306a36Sopenharmony_ci return -ENODEV; 205962306a36Sopenharmony_ci fsm->info = info; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci /* Use device size to determine address width */ 206262306a36Sopenharmony_ci if (info->sector_size * info->n_sectors > 0x1000000) 206362306a36Sopenharmony_ci info->flags |= FLASH_FLAG_32BIT_ADDR; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci /* 206662306a36Sopenharmony_ci * Configure READ/WRITE/ERASE sequences according to platform and 206762306a36Sopenharmony_ci * device flags. 206862306a36Sopenharmony_ci */ 206962306a36Sopenharmony_ci if (info->config) 207062306a36Sopenharmony_ci ret = info->config(fsm); 207162306a36Sopenharmony_ci else 207262306a36Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 207362306a36Sopenharmony_ci if (ret) 207462306a36Sopenharmony_ci return ret; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci fsm->mtd.name = info->name; 207762306a36Sopenharmony_ci fsm->mtd.dev.parent = &pdev->dev; 207862306a36Sopenharmony_ci mtd_set_of_node(&fsm->mtd, np); 207962306a36Sopenharmony_ci fsm->mtd.type = MTD_NORFLASH; 208062306a36Sopenharmony_ci fsm->mtd.writesize = 4; 208162306a36Sopenharmony_ci fsm->mtd.writebufsize = fsm->mtd.writesize; 208262306a36Sopenharmony_ci fsm->mtd.flags = MTD_CAP_NORFLASH; 208362306a36Sopenharmony_ci fsm->mtd.size = info->sector_size * info->n_sectors; 208462306a36Sopenharmony_ci fsm->mtd.erasesize = info->sector_size; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci fsm->mtd._read = stfsm_mtd_read; 208762306a36Sopenharmony_ci fsm->mtd._write = stfsm_mtd_write; 208862306a36Sopenharmony_ci fsm->mtd._erase = stfsm_mtd_erase; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci dev_info(&pdev->dev, 209162306a36Sopenharmony_ci "Found serial flash device: %s\n" 209262306a36Sopenharmony_ci " size = %llx (%lldMiB) erasesize = 0x%08x (%uKiB)\n", 209362306a36Sopenharmony_ci info->name, 209462306a36Sopenharmony_ci (long long)fsm->mtd.size, (long long)(fsm->mtd.size >> 20), 209562306a36Sopenharmony_ci fsm->mtd.erasesize, (fsm->mtd.erasesize >> 10)); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci return mtd_device_register(&fsm->mtd, NULL, 0); 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_cistatic int stfsm_remove(struct platform_device *pdev) 210162306a36Sopenharmony_ci{ 210262306a36Sopenharmony_ci struct stfsm *fsm = platform_get_drvdata(pdev); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci WARN_ON(mtd_device_unregister(&fsm->mtd)); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci return 0; 210762306a36Sopenharmony_ci} 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 211062306a36Sopenharmony_cistatic int stfsmfsm_suspend(struct device *dev) 211162306a36Sopenharmony_ci{ 211262306a36Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(dev); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci clk_disable_unprepare(fsm->clk); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci return 0; 211762306a36Sopenharmony_ci} 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_cistatic int stfsmfsm_resume(struct device *dev) 212062306a36Sopenharmony_ci{ 212162306a36Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(dev); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci return clk_prepare_enable(fsm->clk); 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci#endif 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(stfsm_pm_ops, stfsmfsm_suspend, stfsmfsm_resume); 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_cistatic const struct of_device_id stfsm_match[] = { 213062306a36Sopenharmony_ci { .compatible = "st,spi-fsm", }, 213162306a36Sopenharmony_ci {}, 213262306a36Sopenharmony_ci}; 213362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stfsm_match); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_cistatic struct platform_driver stfsm_driver = { 213662306a36Sopenharmony_ci .probe = stfsm_probe, 213762306a36Sopenharmony_ci .remove = stfsm_remove, 213862306a36Sopenharmony_ci .driver = { 213962306a36Sopenharmony_ci .name = "st-spi-fsm", 214062306a36Sopenharmony_ci .of_match_table = stfsm_match, 214162306a36Sopenharmony_ci .pm = &stfsm_pm_ops, 214262306a36Sopenharmony_ci }, 214362306a36Sopenharmony_ci}; 214462306a36Sopenharmony_cimodule_platform_driver(stfsm_driver); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ciMODULE_AUTHOR("Angus Clark <angus.clark@st.com>"); 214762306a36Sopenharmony_ciMODULE_DESCRIPTION("ST SPI FSM driver"); 214862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2149