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