18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * st_spi_fsm.c - ST Fast Sequence Mode (FSM) Serial Flash Controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Angus Clark <angus.clark@st.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2010-2014 STMicroelectronics Limited 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * JEDEC probe based on drivers/mtd/devices/m25p80.c 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/regmap.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 168c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 178c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h> 188c2ecf20Sopenharmony_ci#include <linux/mtd/spi-nor.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci#include <linux/delay.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/clk.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "serial_flash_cmds.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * FSM SPI Controller Registers 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci#define SPI_CLOCKDIV 0x0010 318c2ecf20Sopenharmony_ci#define SPI_MODESELECT 0x0018 328c2ecf20Sopenharmony_ci#define SPI_CONFIGDATA 0x0020 338c2ecf20Sopenharmony_ci#define SPI_STA_MODE_CHANGE 0x0028 348c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_TRANSFER_SIZE 0x0100 358c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_ADD1 0x0104 368c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_ADD2 0x0108 378c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_ADD_CFG 0x010c 388c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_OPC1 0x0110 398c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_OPC2 0x0114 408c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_OPC3 0x0118 418c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_OPC4 0x011c 428c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_OPC5 0x0120 438c2ecf20Sopenharmony_ci#define SPI_MODE_BITS 0x0124 448c2ecf20Sopenharmony_ci#define SPI_DUMMY_BITS 0x0128 458c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_FLASH_STA_DATA 0x012c 468c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_1 0x0130 478c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_2 0x0134 488c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_3 0x0138 498c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_4 0x013c 508c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_CFG 0x0140 518c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_STA 0x0144 528c2ecf20Sopenharmony_ci#define SPI_QUAD_BOOT_SEQ_INIT_1 0x0148 538c2ecf20Sopenharmony_ci#define SPI_QUAD_BOOT_SEQ_INIT_2 0x014c 548c2ecf20Sopenharmony_ci#define SPI_QUAD_BOOT_READ_SEQ_1 0x0150 558c2ecf20Sopenharmony_ci#define SPI_QUAD_BOOT_READ_SEQ_2 0x0154 568c2ecf20Sopenharmony_ci#define SPI_PROGRAM_ERASE_TIME 0x0158 578c2ecf20Sopenharmony_ci#define SPI_MULT_PAGE_REPEAT_SEQ_1 0x015c 588c2ecf20Sopenharmony_ci#define SPI_MULT_PAGE_REPEAT_SEQ_2 0x0160 598c2ecf20Sopenharmony_ci#define SPI_STATUS_WR_TIME_REG 0x0164 608c2ecf20Sopenharmony_ci#define SPI_FAST_SEQ_DATA_REG 0x0300 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * Register: SPI_MODESELECT 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci#define SPI_MODESELECT_CONTIG 0x01 668c2ecf20Sopenharmony_ci#define SPI_MODESELECT_FASTREAD 0x02 678c2ecf20Sopenharmony_ci#define SPI_MODESELECT_DUALIO 0x04 688c2ecf20Sopenharmony_ci#define SPI_MODESELECT_FSM 0x08 698c2ecf20Sopenharmony_ci#define SPI_MODESELECT_QUADBOOT 0x10 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * Register: SPI_CONFIGDATA 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci#define SPI_CFG_DEVICE_ST 0x1 758c2ecf20Sopenharmony_ci#define SPI_CFG_DEVICE_ATMEL 0x4 768c2ecf20Sopenharmony_ci#define SPI_CFG_MIN_CS_HIGH(x) (((x) & 0xfff) << 4) 778c2ecf20Sopenharmony_ci#define SPI_CFG_CS_SETUPHOLD(x) (((x) & 0xff) << 16) 788c2ecf20Sopenharmony_ci#define SPI_CFG_DATA_HOLD(x) (((x) & 0xff) << 24) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define SPI_CFG_DEFAULT_MIN_CS_HIGH SPI_CFG_MIN_CS_HIGH(0x0AA) 818c2ecf20Sopenharmony_ci#define SPI_CFG_DEFAULT_CS_SETUPHOLD SPI_CFG_CS_SETUPHOLD(0xA0) 828c2ecf20Sopenharmony_ci#define SPI_CFG_DEFAULT_DATA_HOLD SPI_CFG_DATA_HOLD(0x00) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * Register: SPI_FAST_SEQ_TRANSFER_SIZE 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci#define TRANSFER_SIZE(x) ((x) * 8) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Register: SPI_FAST_SEQ_ADD_CFG 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci#define ADR_CFG_CYCLES_ADD1(x) ((x) << 0) 938c2ecf20Sopenharmony_ci#define ADR_CFG_PADS_1_ADD1 (0x0 << 6) 948c2ecf20Sopenharmony_ci#define ADR_CFG_PADS_2_ADD1 (0x1 << 6) 958c2ecf20Sopenharmony_ci#define ADR_CFG_PADS_4_ADD1 (0x3 << 6) 968c2ecf20Sopenharmony_ci#define ADR_CFG_CSDEASSERT_ADD1 (1 << 8) 978c2ecf20Sopenharmony_ci#define ADR_CFG_CYCLES_ADD2(x) ((x) << (0+16)) 988c2ecf20Sopenharmony_ci#define ADR_CFG_PADS_1_ADD2 (0x0 << (6+16)) 998c2ecf20Sopenharmony_ci#define ADR_CFG_PADS_2_ADD2 (0x1 << (6+16)) 1008c2ecf20Sopenharmony_ci#define ADR_CFG_PADS_4_ADD2 (0x3 << (6+16)) 1018c2ecf20Sopenharmony_ci#define ADR_CFG_CSDEASSERT_ADD2 (1 << (8+16)) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * Register: SPI_FAST_SEQ_n 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci#define SEQ_OPC_OPCODE(x) ((x) << 0) 1078c2ecf20Sopenharmony_ci#define SEQ_OPC_CYCLES(x) ((x) << 8) 1088c2ecf20Sopenharmony_ci#define SEQ_OPC_PADS_1 (0x0 << 14) 1098c2ecf20Sopenharmony_ci#define SEQ_OPC_PADS_2 (0x1 << 14) 1108c2ecf20Sopenharmony_ci#define SEQ_OPC_PADS_4 (0x3 << 14) 1118c2ecf20Sopenharmony_ci#define SEQ_OPC_CSDEASSERT (1 << 16) 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* 1148c2ecf20Sopenharmony_ci * Register: SPI_FAST_SEQ_CFG 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci#define SEQ_CFG_STARTSEQ (1 << 0) 1178c2ecf20Sopenharmony_ci#define SEQ_CFG_SWRESET (1 << 5) 1188c2ecf20Sopenharmony_ci#define SEQ_CFG_CSDEASSERT (1 << 6) 1198c2ecf20Sopenharmony_ci#define SEQ_CFG_READNOTWRITE (1 << 7) 1208c2ecf20Sopenharmony_ci#define SEQ_CFG_ERASE (1 << 8) 1218c2ecf20Sopenharmony_ci#define SEQ_CFG_PADS_1 (0x0 << 16) 1228c2ecf20Sopenharmony_ci#define SEQ_CFG_PADS_2 (0x1 << 16) 1238c2ecf20Sopenharmony_ci#define SEQ_CFG_PADS_4 (0x3 << 16) 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* 1268c2ecf20Sopenharmony_ci * Register: SPI_MODE_BITS 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci#define MODE_DATA(x) (x & 0xff) 1298c2ecf20Sopenharmony_ci#define MODE_CYCLES(x) ((x & 0x3f) << 16) 1308c2ecf20Sopenharmony_ci#define MODE_PADS_1 (0x0 << 22) 1318c2ecf20Sopenharmony_ci#define MODE_PADS_2 (0x1 << 22) 1328c2ecf20Sopenharmony_ci#define MODE_PADS_4 (0x3 << 22) 1338c2ecf20Sopenharmony_ci#define DUMMY_CSDEASSERT (1 << 24) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * Register: SPI_DUMMY_BITS 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci#define DUMMY_CYCLES(x) ((x & 0x3f) << 16) 1398c2ecf20Sopenharmony_ci#define DUMMY_PADS_1 (0x0 << 22) 1408c2ecf20Sopenharmony_ci#define DUMMY_PADS_2 (0x1 << 22) 1418c2ecf20Sopenharmony_ci#define DUMMY_PADS_4 (0x3 << 22) 1428c2ecf20Sopenharmony_ci#define DUMMY_CSDEASSERT (1 << 24) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* 1458c2ecf20Sopenharmony_ci * Register: SPI_FAST_SEQ_FLASH_STA_DATA 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci#define STA_DATA_BYTE1(x) ((x & 0xff) << 0) 1488c2ecf20Sopenharmony_ci#define STA_DATA_BYTE2(x) ((x & 0xff) << 8) 1498c2ecf20Sopenharmony_ci#define STA_PADS_1 (0x0 << 16) 1508c2ecf20Sopenharmony_ci#define STA_PADS_2 (0x1 << 16) 1518c2ecf20Sopenharmony_ci#define STA_PADS_4 (0x3 << 16) 1528c2ecf20Sopenharmony_ci#define STA_CSDEASSERT (0x1 << 20) 1538c2ecf20Sopenharmony_ci#define STA_RDNOTWR (0x1 << 21) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* 1568c2ecf20Sopenharmony_ci * FSM SPI Instruction Opcodes 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci#define STFSM_OPC_CMD 0x1 1598c2ecf20Sopenharmony_ci#define STFSM_OPC_ADD 0x2 1608c2ecf20Sopenharmony_ci#define STFSM_OPC_STA 0x3 1618c2ecf20Sopenharmony_ci#define STFSM_OPC_MODE 0x4 1628c2ecf20Sopenharmony_ci#define STFSM_OPC_DUMMY 0x5 1638c2ecf20Sopenharmony_ci#define STFSM_OPC_DATA 0x6 1648c2ecf20Sopenharmony_ci#define STFSM_OPC_WAIT 0x7 1658c2ecf20Sopenharmony_ci#define STFSM_OPC_JUMP 0x8 1668c2ecf20Sopenharmony_ci#define STFSM_OPC_GOTO 0x9 1678c2ecf20Sopenharmony_ci#define STFSM_OPC_STOP 0xF 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * FSM SPI Instructions (== opcode + operand). 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci#define STFSM_INSTR(cmd, op) ((cmd) | ((op) << 4)) 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define STFSM_INST_CMD1 STFSM_INSTR(STFSM_OPC_CMD, 1) 1758c2ecf20Sopenharmony_ci#define STFSM_INST_CMD2 STFSM_INSTR(STFSM_OPC_CMD, 2) 1768c2ecf20Sopenharmony_ci#define STFSM_INST_CMD3 STFSM_INSTR(STFSM_OPC_CMD, 3) 1778c2ecf20Sopenharmony_ci#define STFSM_INST_CMD4 STFSM_INSTR(STFSM_OPC_CMD, 4) 1788c2ecf20Sopenharmony_ci#define STFSM_INST_CMD5 STFSM_INSTR(STFSM_OPC_CMD, 5) 1798c2ecf20Sopenharmony_ci#define STFSM_INST_ADD1 STFSM_INSTR(STFSM_OPC_ADD, 1) 1808c2ecf20Sopenharmony_ci#define STFSM_INST_ADD2 STFSM_INSTR(STFSM_OPC_ADD, 2) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define STFSM_INST_DATA_WRITE STFSM_INSTR(STFSM_OPC_DATA, 1) 1838c2ecf20Sopenharmony_ci#define STFSM_INST_DATA_READ STFSM_INSTR(STFSM_OPC_DATA, 2) 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci#define STFSM_INST_STA_RD1 STFSM_INSTR(STFSM_OPC_STA, 0x1) 1868c2ecf20Sopenharmony_ci#define STFSM_INST_STA_WR1 STFSM_INSTR(STFSM_OPC_STA, 0x1) 1878c2ecf20Sopenharmony_ci#define STFSM_INST_STA_RD2 STFSM_INSTR(STFSM_OPC_STA, 0x2) 1888c2ecf20Sopenharmony_ci#define STFSM_INST_STA_WR1_2 STFSM_INSTR(STFSM_OPC_STA, 0x3) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define STFSM_INST_MODE STFSM_INSTR(STFSM_OPC_MODE, 0) 1918c2ecf20Sopenharmony_ci#define STFSM_INST_DUMMY STFSM_INSTR(STFSM_OPC_DUMMY, 0) 1928c2ecf20Sopenharmony_ci#define STFSM_INST_WAIT STFSM_INSTR(STFSM_OPC_WAIT, 0) 1938c2ecf20Sopenharmony_ci#define STFSM_INST_STOP STFSM_INSTR(STFSM_OPC_STOP, 0) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define STFSM_DEFAULT_EMI_FREQ 100000000UL /* 100 MHz */ 1968c2ecf20Sopenharmony_ci#define STFSM_DEFAULT_WR_TIME (STFSM_DEFAULT_EMI_FREQ * (15/1000)) /* 15ms */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#define STFSM_FLASH_SAFE_FREQ 10000000UL /* 10 MHz */ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define STFSM_MAX_WAIT_SEQ_MS 1000 /* FSM execution time */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* S25FLxxxS commands */ 2038c2ecf20Sopenharmony_ci#define S25FL_CMD_WRITE4_1_1_4 0x34 2048c2ecf20Sopenharmony_ci#define S25FL_CMD_SE4 0xdc 2058c2ecf20Sopenharmony_ci#define S25FL_CMD_CLSR 0x30 2068c2ecf20Sopenharmony_ci#define S25FL_CMD_DYBWR 0xe1 2078c2ecf20Sopenharmony_ci#define S25FL_CMD_DYBRD 0xe0 2088c2ecf20Sopenharmony_ci#define S25FL_CMD_WRITE4 0x12 /* Note, opcode clashes with 2098c2ecf20Sopenharmony_ci * 'SPINOR_OP_WRITE_1_4_4' 2108c2ecf20Sopenharmony_ci * as found on N25Qxxx devices! */ 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/* Status register */ 2138c2ecf20Sopenharmony_ci#define FLASH_STATUS_BUSY 0x01 2148c2ecf20Sopenharmony_ci#define FLASH_STATUS_WEL 0x02 2158c2ecf20Sopenharmony_ci#define FLASH_STATUS_BP0 0x04 2168c2ecf20Sopenharmony_ci#define FLASH_STATUS_BP1 0x08 2178c2ecf20Sopenharmony_ci#define FLASH_STATUS_BP2 0x10 2188c2ecf20Sopenharmony_ci#define FLASH_STATUS_SRWP0 0x80 2198c2ecf20Sopenharmony_ci#define FLASH_STATUS_TIMEOUT 0xff 2208c2ecf20Sopenharmony_ci/* S25FL Error Flags */ 2218c2ecf20Sopenharmony_ci#define S25FL_STATUS_E_ERR 0x20 2228c2ecf20Sopenharmony_ci#define S25FL_STATUS_P_ERR 0x40 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci#define N25Q_CMD_WRVCR 0x81 2258c2ecf20Sopenharmony_ci#define N25Q_CMD_RDVCR 0x85 2268c2ecf20Sopenharmony_ci#define N25Q_CMD_RDVECR 0x65 2278c2ecf20Sopenharmony_ci#define N25Q_CMD_RDNVCR 0xb5 2288c2ecf20Sopenharmony_ci#define N25Q_CMD_WRNVCR 0xb1 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci#define FLASH_PAGESIZE 256 /* In Bytes */ 2318c2ecf20Sopenharmony_ci#define FLASH_PAGESIZE_32 (FLASH_PAGESIZE / 4) /* In uint32_t */ 2328c2ecf20Sopenharmony_ci#define FLASH_MAX_BUSY_WAIT (300 * HZ) /* Maximum 'CHIPERASE' time */ 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* 2358c2ecf20Sopenharmony_ci * Flags to tweak operation of default read/write/erase routines 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci#define CFG_READ_TOGGLE_32BIT_ADDR 0x00000001 2388c2ecf20Sopenharmony_ci#define CFG_WRITE_TOGGLE_32BIT_ADDR 0x00000002 2398c2ecf20Sopenharmony_ci#define CFG_ERASESEC_TOGGLE_32BIT_ADDR 0x00000008 2408c2ecf20Sopenharmony_ci#define CFG_S25FL_CHECK_ERROR_FLAGS 0x00000010 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistruct stfsm_seq { 2438c2ecf20Sopenharmony_ci uint32_t data_size; 2448c2ecf20Sopenharmony_ci uint32_t addr1; 2458c2ecf20Sopenharmony_ci uint32_t addr2; 2468c2ecf20Sopenharmony_ci uint32_t addr_cfg; 2478c2ecf20Sopenharmony_ci uint32_t seq_opc[5]; 2488c2ecf20Sopenharmony_ci uint32_t mode; 2498c2ecf20Sopenharmony_ci uint32_t dummy; 2508c2ecf20Sopenharmony_ci uint32_t status; 2518c2ecf20Sopenharmony_ci uint8_t seq[16]; 2528c2ecf20Sopenharmony_ci uint32_t seq_cfg; 2538c2ecf20Sopenharmony_ci} __packed __aligned(4); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistruct stfsm { 2568c2ecf20Sopenharmony_ci struct device *dev; 2578c2ecf20Sopenharmony_ci void __iomem *base; 2588c2ecf20Sopenharmony_ci struct mtd_info mtd; 2598c2ecf20Sopenharmony_ci struct mutex lock; 2608c2ecf20Sopenharmony_ci struct flash_info *info; 2618c2ecf20Sopenharmony_ci struct clk *clk; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci uint32_t configuration; 2648c2ecf20Sopenharmony_ci uint32_t fifo_dir_delay; 2658c2ecf20Sopenharmony_ci bool booted_from_spi; 2668c2ecf20Sopenharmony_ci bool reset_signal; 2678c2ecf20Sopenharmony_ci bool reset_por; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci struct stfsm_seq stfsm_seq_read; 2708c2ecf20Sopenharmony_ci struct stfsm_seq stfsm_seq_write; 2718c2ecf20Sopenharmony_ci struct stfsm_seq stfsm_seq_en_32bit_addr; 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* Parameters to configure a READ or WRITE FSM sequence */ 2758c2ecf20Sopenharmony_cistruct seq_rw_config { 2768c2ecf20Sopenharmony_ci uint32_t flags; /* flags to support config */ 2778c2ecf20Sopenharmony_ci uint8_t cmd; /* FLASH command */ 2788c2ecf20Sopenharmony_ci int write; /* Write Sequence */ 2798c2ecf20Sopenharmony_ci uint8_t addr_pads; /* No. of addr pads (MODE & DUMMY) */ 2808c2ecf20Sopenharmony_ci uint8_t data_pads; /* No. of data pads */ 2818c2ecf20Sopenharmony_ci uint8_t mode_data; /* MODE data */ 2828c2ecf20Sopenharmony_ci uint8_t mode_cycles; /* No. of MODE cycles */ 2838c2ecf20Sopenharmony_ci uint8_t dummy_cycles; /* No. of DUMMY cycles */ 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* SPI Flash Device Table */ 2878c2ecf20Sopenharmony_cistruct flash_info { 2888c2ecf20Sopenharmony_ci char *name; 2898c2ecf20Sopenharmony_ci /* 2908c2ecf20Sopenharmony_ci * JEDEC id zero means "no ID" (most older chips); otherwise it has 2918c2ecf20Sopenharmony_ci * a high byte of zero plus three data bytes: the manufacturer id, 2928c2ecf20Sopenharmony_ci * then a two byte device id. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci u32 jedec_id; 2958c2ecf20Sopenharmony_ci u16 ext_id; 2968c2ecf20Sopenharmony_ci /* 2978c2ecf20Sopenharmony_ci * The size listed here is what works with SPINOR_OP_SE, which isn't 2988c2ecf20Sopenharmony_ci * necessarily called a "sector" by the vendor. 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ci unsigned sector_size; 3018c2ecf20Sopenharmony_ci u16 n_sectors; 3028c2ecf20Sopenharmony_ci u32 flags; 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Note, where FAST_READ is supported, freq_max specifies the 3058c2ecf20Sopenharmony_ci * FAST_READ frequency, not the READ frequency. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci u32 max_freq; 3088c2ecf20Sopenharmony_ci int (*config)(struct stfsm *); 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int stfsm_n25q_config(struct stfsm *fsm); 3128c2ecf20Sopenharmony_cistatic int stfsm_mx25_config(struct stfsm *fsm); 3138c2ecf20Sopenharmony_cistatic int stfsm_s25fl_config(struct stfsm *fsm); 3148c2ecf20Sopenharmony_cistatic int stfsm_w25q_config(struct stfsm *fsm); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic struct flash_info flash_types[] = { 3178c2ecf20Sopenharmony_ci /* 3188c2ecf20Sopenharmony_ci * ST Microelectronics/Numonyx -- 3198c2ecf20Sopenharmony_ci * (newer production versions may have feature updates 3208c2ecf20Sopenharmony_ci * (eg faster operating frequency) 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci#define M25P_FLAG (FLASH_FLAG_READ_WRITE | FLASH_FLAG_READ_FAST) 3238c2ecf20Sopenharmony_ci { "m25p40", 0x202013, 0, 64 * 1024, 8, M25P_FLAG, 25, NULL }, 3248c2ecf20Sopenharmony_ci { "m25p80", 0x202014, 0, 64 * 1024, 16, M25P_FLAG, 25, NULL }, 3258c2ecf20Sopenharmony_ci { "m25p16", 0x202015, 0, 64 * 1024, 32, M25P_FLAG, 25, NULL }, 3268c2ecf20Sopenharmony_ci { "m25p32", 0x202016, 0, 64 * 1024, 64, M25P_FLAG, 50, NULL }, 3278c2ecf20Sopenharmony_ci { "m25p64", 0x202017, 0, 64 * 1024, 128, M25P_FLAG, 50, NULL }, 3288c2ecf20Sopenharmony_ci { "m25p128", 0x202018, 0, 256 * 1024, 64, M25P_FLAG, 50, NULL }, 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci#define M25PX_FLAG (FLASH_FLAG_READ_WRITE | \ 3318c2ecf20Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 3328c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 3338c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_1_2) 3348c2ecf20Sopenharmony_ci { "m25px32", 0x207116, 0, 64 * 1024, 64, M25PX_FLAG, 75, NULL }, 3358c2ecf20Sopenharmony_ci { "m25px64", 0x207117, 0, 64 * 1024, 128, M25PX_FLAG, 75, NULL }, 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Macronix MX25xxx 3388c2ecf20Sopenharmony_ci * - Support for 'FLASH_FLAG_WRITE_1_4_4' is omitted for devices 3398c2ecf20Sopenharmony_ci * where operating frequency must be reduced. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci#define MX25_FLAG (FLASH_FLAG_READ_WRITE | \ 3428c2ecf20Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 3438c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 3448c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 3458c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 3468c2ecf20Sopenharmony_ci FLASH_FLAG_SE_4K | \ 3478c2ecf20Sopenharmony_ci FLASH_FLAG_SE_32K) 3488c2ecf20Sopenharmony_ci { "mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, 3498c2ecf20Sopenharmony_ci (MX25_FLAG | FLASH_FLAG_WRITE_1_4_4), 86, 3508c2ecf20Sopenharmony_ci stfsm_mx25_config}, 3518c2ecf20Sopenharmony_ci { "mx25l25635e", 0xc22019, 0, 64*1024, 512, 3528c2ecf20Sopenharmony_ci (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70, 3538c2ecf20Sopenharmony_ci stfsm_mx25_config }, 3548c2ecf20Sopenharmony_ci { "mx25l25655e", 0xc22619, 0, 64*1024, 512, 3558c2ecf20Sopenharmony_ci (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70, 3568c2ecf20Sopenharmony_ci stfsm_mx25_config}, 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci#define N25Q_FLAG (FLASH_FLAG_READ_WRITE | \ 3598c2ecf20Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 3608c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 3618c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 3628c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 3638c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_4_4 | \ 3648c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_1_2 | \ 3658c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_2_2 | \ 3668c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_1_4 | \ 3678c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_4_4) 3688c2ecf20Sopenharmony_ci { "n25q128", 0x20ba18, 0, 64 * 1024, 256, N25Q_FLAG, 108, 3698c2ecf20Sopenharmony_ci stfsm_n25q_config }, 3708c2ecf20Sopenharmony_ci { "n25q256", 0x20ba19, 0, 64 * 1024, 512, 3718c2ecf20Sopenharmony_ci N25Q_FLAG | FLASH_FLAG_32BIT_ADDR, 108, stfsm_n25q_config }, 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* 3748c2ecf20Sopenharmony_ci * Spansion S25FLxxxP 3758c2ecf20Sopenharmony_ci * - 256KiB and 64KiB sector variants (identified by ext. JEDEC) 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci#define S25FLXXXP_FLAG (FLASH_FLAG_READ_WRITE | \ 3788c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 3798c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 3808c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 3818c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_4_4 | \ 3828c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_1_4 | \ 3838c2ecf20Sopenharmony_ci FLASH_FLAG_READ_FAST) 3848c2ecf20Sopenharmony_ci { "s25fl032p", 0x010215, 0x4d00, 64 * 1024, 64, S25FLXXXP_FLAG, 80, 3858c2ecf20Sopenharmony_ci stfsm_s25fl_config}, 3868c2ecf20Sopenharmony_ci { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, S25FLXXXP_FLAG, 80, 3878c2ecf20Sopenharmony_ci stfsm_s25fl_config }, 3888c2ecf20Sopenharmony_ci { "s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, S25FLXXXP_FLAG, 80, 3898c2ecf20Sopenharmony_ci stfsm_s25fl_config }, 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci * Spansion S25FLxxxS 3938c2ecf20Sopenharmony_ci * - 256KiB and 64KiB sector variants (identified by ext. JEDEC) 3948c2ecf20Sopenharmony_ci * - RESET# signal supported by die but not bristled out on all 3958c2ecf20Sopenharmony_ci * package types. The package type is a function of board design, 3968c2ecf20Sopenharmony_ci * so this information is captured in the board's flags. 3978c2ecf20Sopenharmony_ci * - Supports 'DYB' sector protection. Depending on variant, sectors 3988c2ecf20Sopenharmony_ci * may default to locked state on power-on. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ci#define S25FLXXXS_FLAG (S25FLXXXP_FLAG | \ 4018c2ecf20Sopenharmony_ci FLASH_FLAG_RESET | \ 4028c2ecf20Sopenharmony_ci FLASH_FLAG_DYB_LOCKING) 4038c2ecf20Sopenharmony_ci { "s25fl128s0", 0x012018, 0x0300, 256 * 1024, 64, S25FLXXXS_FLAG, 80, 4048c2ecf20Sopenharmony_ci stfsm_s25fl_config }, 4058c2ecf20Sopenharmony_ci { "s25fl128s1", 0x012018, 0x0301, 64 * 1024, 256, S25FLXXXS_FLAG, 80, 4068c2ecf20Sopenharmony_ci stfsm_s25fl_config }, 4078c2ecf20Sopenharmony_ci { "s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, 4088c2ecf20Sopenharmony_ci S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config }, 4098c2ecf20Sopenharmony_ci { "s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, 4108c2ecf20Sopenharmony_ci S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config }, 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ 4138c2ecf20Sopenharmony_ci#define W25X_FLAG (FLASH_FLAG_READ_WRITE | \ 4148c2ecf20Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 4158c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 4168c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_1_2) 4178c2ecf20Sopenharmony_ci { "w25x40", 0xef3013, 0, 64 * 1024, 8, W25X_FLAG, 75, NULL }, 4188c2ecf20Sopenharmony_ci { "w25x80", 0xef3014, 0, 64 * 1024, 16, W25X_FLAG, 75, NULL }, 4198c2ecf20Sopenharmony_ci { "w25x16", 0xef3015, 0, 64 * 1024, 32, W25X_FLAG, 75, NULL }, 4208c2ecf20Sopenharmony_ci { "w25x32", 0xef3016, 0, 64 * 1024, 64, W25X_FLAG, 75, NULL }, 4218c2ecf20Sopenharmony_ci { "w25x64", 0xef3017, 0, 64 * 1024, 128, W25X_FLAG, 75, NULL }, 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* Winbond -- w25q "blocks" are 64K, "sectors" are 4KiB */ 4248c2ecf20Sopenharmony_ci#define W25Q_FLAG (FLASH_FLAG_READ_WRITE | \ 4258c2ecf20Sopenharmony_ci FLASH_FLAG_READ_FAST | \ 4268c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_2 | \ 4278c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_2_2 | \ 4288c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_1_4 | \ 4298c2ecf20Sopenharmony_ci FLASH_FLAG_READ_1_4_4 | \ 4308c2ecf20Sopenharmony_ci FLASH_FLAG_WRITE_1_1_4) 4318c2ecf20Sopenharmony_ci { "w25q80", 0xef4014, 0, 64 * 1024, 16, W25Q_FLAG, 80, 4328c2ecf20Sopenharmony_ci stfsm_w25q_config }, 4338c2ecf20Sopenharmony_ci { "w25q16", 0xef4015, 0, 64 * 1024, 32, W25Q_FLAG, 80, 4348c2ecf20Sopenharmony_ci stfsm_w25q_config }, 4358c2ecf20Sopenharmony_ci { "w25q32", 0xef4016, 0, 64 * 1024, 64, W25Q_FLAG, 80, 4368c2ecf20Sopenharmony_ci stfsm_w25q_config }, 4378c2ecf20Sopenharmony_ci { "w25q64", 0xef4017, 0, 64 * 1024, 128, W25Q_FLAG, 80, 4388c2ecf20Sopenharmony_ci stfsm_w25q_config }, 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Sentinel */ 4418c2ecf20Sopenharmony_ci { NULL, 0x000000, 0, 0, 0, 0, 0, NULL }, 4428c2ecf20Sopenharmony_ci}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* 4458c2ecf20Sopenharmony_ci * FSM message sequence configurations: 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * All configs are presented in order of preference 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* Default READ configurations, in order of preference */ 4518c2ecf20Sopenharmony_cistatic struct seq_rw_config default_read_configs[] = { 4528c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4, 0, 4, 4, 0x00, 2, 4}, 4538c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4, 0, 1, 4, 0x00, 4, 0}, 4548c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2, 0, 2, 2, 0x00, 4, 0}, 4558c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, 4568c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST, 0, 1, 1, 0x00, 0, 8}, 4578c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ, 0, 1, 1, 0x00, 0, 0}, 4588c2ecf20Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 4598c2ecf20Sopenharmony_ci}; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci/* Default WRITE configurations */ 4628c2ecf20Sopenharmony_cistatic struct seq_rw_config default_write_configs[] = { 4638c2ecf20Sopenharmony_ci {FLASH_FLAG_WRITE_1_4_4, SPINOR_OP_WRITE_1_4_4, 1, 4, 4, 0x00, 0, 0}, 4648c2ecf20Sopenharmony_ci {FLASH_FLAG_WRITE_1_1_4, SPINOR_OP_WRITE_1_1_4, 1, 1, 4, 0x00, 0, 0}, 4658c2ecf20Sopenharmony_ci {FLASH_FLAG_WRITE_1_2_2, SPINOR_OP_WRITE_1_2_2, 1, 2, 2, 0x00, 0, 0}, 4668c2ecf20Sopenharmony_ci {FLASH_FLAG_WRITE_1_1_2, SPINOR_OP_WRITE_1_1_2, 1, 1, 2, 0x00, 0, 0}, 4678c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_WRITE, 1, 1, 1, 0x00, 0, 0}, 4688c2ecf20Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* 4728c2ecf20Sopenharmony_ci * [N25Qxxx] Configuration 4738c2ecf20Sopenharmony_ci */ 4748c2ecf20Sopenharmony_ci#define N25Q_VCR_DUMMY_CYCLES(x) (((x) & 0xf) << 4) 4758c2ecf20Sopenharmony_ci#define N25Q_VCR_XIP_DISABLED ((uint8_t)0x1 << 3) 4768c2ecf20Sopenharmony_ci#define N25Q_VCR_WRAP_CONT 0x3 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* N25Q 3-byte Address READ configurations 4798c2ecf20Sopenharmony_ci * - 'FAST' variants configured for 8 dummy cycles. 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci * Note, the number of dummy cycles used for 'FAST' READ operations is 4828c2ecf20Sopenharmony_ci * configurable and would normally be tuned according to the READ command and 4838c2ecf20Sopenharmony_ci * operating frequency. However, this applies universally to all 'FAST' READ 4848c2ecf20Sopenharmony_ci * commands, including those used by the SPIBoot controller, and remains in 4858c2ecf20Sopenharmony_ci * force until the device is power-cycled. Since the SPIBoot controller is 4868c2ecf20Sopenharmony_ci * hard-wired to use 8 dummy cycles, we must configure the device to also use 8 4878c2ecf20Sopenharmony_ci * cycles. 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_cistatic struct seq_rw_config n25q_read3_configs[] = { 4908c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4, 0, 4, 4, 0x00, 0, 8}, 4918c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4, 0, 1, 4, 0x00, 0, 8}, 4928c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2, 0, 2, 2, 0x00, 0, 8}, 4938c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, 4948c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST, 0, 1, 1, 0x00, 0, 8}, 4958c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ, 0, 1, 1, 0x00, 0, 0}, 4968c2ecf20Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 4978c2ecf20Sopenharmony_ci}; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/* N25Q 4-byte Address READ configurations 5008c2ecf20Sopenharmony_ci * - use special 4-byte address READ commands (reduces overheads, and 5018c2ecf20Sopenharmony_ci * reduces risk of hitting watchdog reset issues). 5028c2ecf20Sopenharmony_ci * - 'FAST' variants configured for 8 dummy cycles (see note above.) 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_cistatic struct seq_rw_config n25q_read4_configs[] = { 5058c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8}, 5068c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8}, 5078c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8}, 5088c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8}, 5098c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8}, 5108c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0}, 5118c2ecf20Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/* 5158c2ecf20Sopenharmony_ci * [MX25xxx] Configuration 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci#define MX25_STATUS_QE (0x1 << 6) 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | 5228c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 5238c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_EN4B) | 5248c2ecf20Sopenharmony_ci SEQ_OPC_CSDEASSERT); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci seq->seq[0] = STFSM_INST_CMD1; 5278c2ecf20Sopenharmony_ci seq->seq[1] = STFSM_INST_WAIT; 5288c2ecf20Sopenharmony_ci seq->seq[2] = STFSM_INST_STOP; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci seq->seq_cfg = (SEQ_CFG_PADS_1 | 5318c2ecf20Sopenharmony_ci SEQ_CFG_ERASE | 5328c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 5338c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 5348c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci/* 5408c2ecf20Sopenharmony_ci * [S25FLxxx] Configuration 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci#define STFSM_S25FL_CONFIG_QE (0x1 << 1) 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci/* 5458c2ecf20Sopenharmony_ci * S25FLxxxS devices provide three ways of supporting 32-bit addressing: Bank 5468c2ecf20Sopenharmony_ci * Register, Extended Address Modes, and a 32-bit address command set. The 5478c2ecf20Sopenharmony_ci * 32-bit address command set is used here, since it avoids any problems with 5488c2ecf20Sopenharmony_ci * entering a state that is incompatible with the SPIBoot Controller. 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_cistatic struct seq_rw_config stfsm_s25fl_read4_configs[] = { 5518c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 2, 4}, 5528c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8}, 5538c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 4, 0}, 5548c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8}, 5558c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8}, 5568c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0}, 5578c2ecf20Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 5588c2ecf20Sopenharmony_ci}; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic struct seq_rw_config stfsm_s25fl_write4_configs[] = { 5618c2ecf20Sopenharmony_ci {FLASH_FLAG_WRITE_1_1_4, S25FL_CMD_WRITE4_1_1_4, 1, 1, 4, 0x00, 0, 0}, 5628c2ecf20Sopenharmony_ci {FLASH_FLAG_READ_WRITE, S25FL_CMD_WRITE4, 1, 1, 1, 0x00, 0, 0}, 5638c2ecf20Sopenharmony_ci {0x00, 0, 0, 0, 0, 0x00, 0, 0}, 5648c2ecf20Sopenharmony_ci}; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci/* 5678c2ecf20Sopenharmony_ci * [W25Qxxx] Configuration 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci#define W25Q_STATUS_QE (0x1 << 1) 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic struct stfsm_seq stfsm_seq_read_jedec = { 5728c2ecf20Sopenharmony_ci .data_size = TRANSFER_SIZE(8), 5738c2ecf20Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 5748c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 5758c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDID)), 5768c2ecf20Sopenharmony_ci .seq = { 5778c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 5788c2ecf20Sopenharmony_ci STFSM_INST_DATA_READ, 5798c2ecf20Sopenharmony_ci STFSM_INST_STOP, 5808c2ecf20Sopenharmony_ci }, 5818c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 5828c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 5838c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 5848c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 5858c2ecf20Sopenharmony_ci}; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic struct stfsm_seq stfsm_seq_read_status_fifo = { 5888c2ecf20Sopenharmony_ci .data_size = TRANSFER_SIZE(4), 5898c2ecf20Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 5908c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 5918c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDSR)), 5928c2ecf20Sopenharmony_ci .seq = { 5938c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 5948c2ecf20Sopenharmony_ci STFSM_INST_DATA_READ, 5958c2ecf20Sopenharmony_ci STFSM_INST_STOP, 5968c2ecf20Sopenharmony_ci }, 5978c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 5988c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 5998c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 6008c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 6018c2ecf20Sopenharmony_ci}; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic struct stfsm_seq stfsm_seq_erase_sector = { 6048c2ecf20Sopenharmony_ci /* 'addr_cfg' configured during initialisation */ 6058c2ecf20Sopenharmony_ci .seq_opc = { 6068c2ecf20Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6078c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6108c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_SE)), 6118c2ecf20Sopenharmony_ci }, 6128c2ecf20Sopenharmony_ci .seq = { 6138c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 6148c2ecf20Sopenharmony_ci STFSM_INST_CMD2, 6158c2ecf20Sopenharmony_ci STFSM_INST_ADD1, 6168c2ecf20Sopenharmony_ci STFSM_INST_ADD2, 6178c2ecf20Sopenharmony_ci STFSM_INST_STOP, 6188c2ecf20Sopenharmony_ci }, 6198c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 6208c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 6218c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 6228c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 6238c2ecf20Sopenharmony_ci}; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic struct stfsm_seq stfsm_seq_erase_chip = { 6268c2ecf20Sopenharmony_ci .seq_opc = { 6278c2ecf20Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6288c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6318c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_CHIP_ERASE) | SEQ_OPC_CSDEASSERT), 6328c2ecf20Sopenharmony_ci }, 6338c2ecf20Sopenharmony_ci .seq = { 6348c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 6358c2ecf20Sopenharmony_ci STFSM_INST_CMD2, 6368c2ecf20Sopenharmony_ci STFSM_INST_WAIT, 6378c2ecf20Sopenharmony_ci STFSM_INST_STOP, 6388c2ecf20Sopenharmony_ci }, 6398c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 6408c2ecf20Sopenharmony_ci SEQ_CFG_ERASE | 6418c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 6428c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 6438c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 6448c2ecf20Sopenharmony_ci}; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic struct stfsm_seq stfsm_seq_write_status = { 6478c2ecf20Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6488c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), 6498c2ecf20Sopenharmony_ci .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6508c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WRSR)), 6518c2ecf20Sopenharmony_ci .seq = { 6528c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 6538c2ecf20Sopenharmony_ci STFSM_INST_CMD2, 6548c2ecf20Sopenharmony_ci STFSM_INST_STA_WR1, 6558c2ecf20Sopenharmony_ci STFSM_INST_STOP, 6568c2ecf20Sopenharmony_ci }, 6578c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 6588c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 6598c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 6608c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 6618c2ecf20Sopenharmony_ci}; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/* Dummy sequence to read one byte of data from flash into the FIFO */ 6648c2ecf20Sopenharmony_cistatic const struct stfsm_seq stfsm_seq_load_fifo_byte = { 6658c2ecf20Sopenharmony_ci .data_size = TRANSFER_SIZE(1), 6668c2ecf20Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 6678c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 6688c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDID)), 6698c2ecf20Sopenharmony_ci .seq = { 6708c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 6718c2ecf20Sopenharmony_ci STFSM_INST_DATA_READ, 6728c2ecf20Sopenharmony_ci STFSM_INST_STOP, 6738c2ecf20Sopenharmony_ci }, 6748c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 6758c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 6768c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 6778c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 6788c2ecf20Sopenharmony_ci}; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6838c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_EN4B)); 6848c2ecf20Sopenharmony_ci seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 6858c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | 6868c2ecf20Sopenharmony_ci SEQ_OPC_CSDEASSERT); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci seq->seq[0] = STFSM_INST_CMD2; 6898c2ecf20Sopenharmony_ci seq->seq[1] = STFSM_INST_CMD1; 6908c2ecf20Sopenharmony_ci seq->seq[2] = STFSM_INST_WAIT; 6918c2ecf20Sopenharmony_ci seq->seq[3] = STFSM_INST_STOP; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci seq->seq_cfg = (SEQ_CFG_PADS_1 | 6948c2ecf20Sopenharmony_ci SEQ_CFG_ERASE | 6958c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 6968c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 6978c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return 0; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic inline int stfsm_is_idle(struct stfsm *fsm) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci return readl(fsm->base + SPI_FAST_SEQ_STA) & 0x10; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic inline uint32_t stfsm_fifo_available(struct stfsm *fsm) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic inline void stfsm_load_seq(struct stfsm *fsm, 7138c2ecf20Sopenharmony_ci const struct stfsm_seq *seq) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci void __iomem *dst = fsm->base + SPI_FAST_SEQ_TRANSFER_SIZE; 7168c2ecf20Sopenharmony_ci const uint32_t *src = (const uint32_t *)seq; 7178c2ecf20Sopenharmony_ci int words = sizeof(*seq) / sizeof(*src); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci BUG_ON(!stfsm_is_idle(fsm)); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci while (words--) { 7228c2ecf20Sopenharmony_ci writel(*src, dst); 7238c2ecf20Sopenharmony_ci src++; 7248c2ecf20Sopenharmony_ci dst += 4; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic void stfsm_wait_seq(struct stfsm *fsm) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci unsigned long deadline; 7318c2ecf20Sopenharmony_ci int timeout = 0; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci deadline = jiffies + msecs_to_jiffies(STFSM_MAX_WAIT_SEQ_MS); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci while (!timeout) { 7368c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, deadline)) 7378c2ecf20Sopenharmony_ci timeout = 1; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (stfsm_is_idle(fsm)) 7408c2ecf20Sopenharmony_ci return; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci cond_resched(); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci dev_err(fsm->dev, "timeout on sequence completion\n"); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci uint32_t remaining = size >> 2; 7518c2ecf20Sopenharmony_ci uint32_t avail; 7528c2ecf20Sopenharmony_ci uint32_t words; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "Reading %d bytes from FIFO\n", size); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3)); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci while (remaining) { 7598c2ecf20Sopenharmony_ci for (;;) { 7608c2ecf20Sopenharmony_ci avail = stfsm_fifo_available(fsm); 7618c2ecf20Sopenharmony_ci if (avail) 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci udelay(1); 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci words = min(avail, remaining); 7668c2ecf20Sopenharmony_ci remaining -= words; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci readsl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words); 7698c2ecf20Sopenharmony_ci buf += words; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci/* 7748c2ecf20Sopenharmony_ci * Clear the data FIFO 7758c2ecf20Sopenharmony_ci * 7768c2ecf20Sopenharmony_ci * Typically, this is only required during driver initialisation, where no 7778c2ecf20Sopenharmony_ci * assumptions can be made regarding the state of the FIFO. 7788c2ecf20Sopenharmony_ci * 7798c2ecf20Sopenharmony_ci * The process of clearing the FIFO is complicated by fact that while it is 7808c2ecf20Sopenharmony_ci * possible for the FIFO to contain an arbitrary number of bytes [1], the 7818c2ecf20Sopenharmony_ci * SPI_FAST_SEQ_STA register only reports the number of complete 32-bit words 7828c2ecf20Sopenharmony_ci * present. Furthermore, data can only be drained from the FIFO by reading 7838c2ecf20Sopenharmony_ci * complete 32-bit words. 7848c2ecf20Sopenharmony_ci * 7858c2ecf20Sopenharmony_ci * With this in mind, a two stage process is used to the clear the FIFO: 7868c2ecf20Sopenharmony_ci * 7878c2ecf20Sopenharmony_ci * 1. Read any complete 32-bit words from the FIFO, as reported by the 7888c2ecf20Sopenharmony_ci * SPI_FAST_SEQ_STA register. 7898c2ecf20Sopenharmony_ci * 7908c2ecf20Sopenharmony_ci * 2. Mop up any remaining bytes. At this point, it is not known if there 7918c2ecf20Sopenharmony_ci * are 0, 1, 2, or 3 bytes in the FIFO. To handle all cases, a dummy FSM 7928c2ecf20Sopenharmony_ci * sequence is used to load one byte at a time, until a complete 32-bit 7938c2ecf20Sopenharmony_ci * word is formed; at most, 4 bytes will need to be loaded. 7948c2ecf20Sopenharmony_ci * 7958c2ecf20Sopenharmony_ci * [1] It is theoretically possible for the FIFO to contain an arbitrary number 7968c2ecf20Sopenharmony_ci * of bits. However, since there are no known use-cases that leave 7978c2ecf20Sopenharmony_ci * incomplete bytes in the FIFO, only words and bytes are considered here. 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_cistatic void stfsm_clear_fifo(struct stfsm *fsm) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci const struct stfsm_seq *seq = &stfsm_seq_load_fifo_byte; 8028c2ecf20Sopenharmony_ci uint32_t words, i; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* 1. Clear any 32-bit words */ 8058c2ecf20Sopenharmony_ci words = stfsm_fifo_available(fsm); 8068c2ecf20Sopenharmony_ci if (words) { 8078c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) 8088c2ecf20Sopenharmony_ci readl(fsm->base + SPI_FAST_SEQ_DATA_REG); 8098c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "cleared %d words from FIFO\n", words); 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* 8138c2ecf20Sopenharmony_ci * 2. Clear any remaining bytes 8148c2ecf20Sopenharmony_ci * - Load the FIFO, one byte at a time, until a complete 32-bit word 8158c2ecf20Sopenharmony_ci * is available. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci for (i = 0, words = 0; i < 4 && !words; i++) { 8188c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 8198c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 8208c2ecf20Sopenharmony_ci words = stfsm_fifo_available(fsm); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* - A single word must be available now */ 8248c2ecf20Sopenharmony_ci if (words != 1) { 8258c2ecf20Sopenharmony_ci dev_err(fsm->dev, "failed to clear bytes from the data FIFO\n"); 8268c2ecf20Sopenharmony_ci return; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* - Read the 32-bit word */ 8308c2ecf20Sopenharmony_ci readl(fsm->base + SPI_FAST_SEQ_DATA_REG); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "cleared %d byte(s) from the data FIFO\n", 4 - i); 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf, 8368c2ecf20Sopenharmony_ci uint32_t size) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci uint32_t words = size >> 2; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "writing %d bytes to FIFO\n", size); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3)); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci writesl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return size; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int stfsm_enter_32bit_addr(struct stfsm *fsm, int enter) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct stfsm_seq *seq = &fsm->stfsm_seq_en_32bit_addr; 8528c2ecf20Sopenharmony_ci uint32_t cmd = enter ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | 8558c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 8568c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(cmd) | 8578c2ecf20Sopenharmony_ci SEQ_OPC_CSDEASSERT); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci return 0; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic uint8_t stfsm_wait_busy(struct stfsm *fsm) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_read_status_fifo; 8698c2ecf20Sopenharmony_ci unsigned long deadline; 8708c2ecf20Sopenharmony_ci uint32_t status; 8718c2ecf20Sopenharmony_ci int timeout = 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* Use RDRS1 */ 8748c2ecf20Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | 8758c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 8768c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_RDSR)); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* Load read_status sequence */ 8798c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* 8828c2ecf20Sopenharmony_ci * Repeat until busy bit is deasserted, or timeout, or error (S25FLxxxS) 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_ci deadline = jiffies + FLASH_MAX_BUSY_WAIT; 8858c2ecf20Sopenharmony_ci while (!timeout) { 8868c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, deadline)) 8878c2ecf20Sopenharmony_ci timeout = 1; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci stfsm_read_fifo(fsm, &status, 4); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if ((status & FLASH_STATUS_BUSY) == 0) 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if ((fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) && 8978c2ecf20Sopenharmony_ci ((status & S25FL_STATUS_P_ERR) || 8988c2ecf20Sopenharmony_ci (status & S25FL_STATUS_E_ERR))) 8998c2ecf20Sopenharmony_ci return (uint8_t)(status & 0xff); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (!timeout) 9028c2ecf20Sopenharmony_ci /* Restart */ 9038c2ecf20Sopenharmony_ci writel(seq->seq_cfg, fsm->base + SPI_FAST_SEQ_CFG); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci cond_resched(); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci dev_err(fsm->dev, "timeout on wait_busy\n"); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci return FLASH_STATUS_TIMEOUT; 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic int stfsm_read_status(struct stfsm *fsm, uint8_t cmd, 9148c2ecf20Sopenharmony_ci uint8_t *data, int bytes) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_read_status_fifo; 9178c2ecf20Sopenharmony_ci uint32_t tmp; 9188c2ecf20Sopenharmony_ci uint8_t *t = (uint8_t *)&tmp; 9198c2ecf20Sopenharmony_ci int i; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "read 'status' register [0x%02x], %d byte(s)\n", 9228c2ecf20Sopenharmony_ci cmd, bytes); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci BUG_ON(bytes != 1 && bytes != 2); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 9278c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(cmd)), 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci stfsm_read_fifo(fsm, &tmp, 4); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci for (i = 0; i < bytes; i++) 9348c2ecf20Sopenharmony_ci data[i] = t[i]; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int stfsm_write_status(struct stfsm *fsm, uint8_t cmd, 9428c2ecf20Sopenharmony_ci uint16_t data, int bytes, int wait_busy) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_write_status; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, 9478c2ecf20Sopenharmony_ci "write 'status' register [0x%02x], %d byte(s), 0x%04x\n" 9488c2ecf20Sopenharmony_ci " %s wait-busy\n", cmd, bytes, data, wait_busy ? "with" : "no"); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci BUG_ON(bytes != 1 && bytes != 2); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 9538c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(cmd)); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci seq->status = (uint32_t)data | STA_PADS_1 | STA_CSDEASSERT; 9568c2ecf20Sopenharmony_ci seq->seq[2] = (bytes == 1) ? STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (wait_busy) 9638c2ecf20Sopenharmony_ci stfsm_wait_busy(fsm); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci return 0; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci/* 9698c2ecf20Sopenharmony_ci * SoC reset on 'boot-from-spi' systems 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * Certain modes of operation cause the Flash device to enter a particular state 9728c2ecf20Sopenharmony_ci * for a period of time (e.g. 'Erase Sector', 'Quad Enable', and 'Enter 32-bit 9738c2ecf20Sopenharmony_ci * Addr' commands). On boot-from-spi systems, it is important to consider what 9748c2ecf20Sopenharmony_ci * happens if a warm reset occurs during this period. The SPIBoot controller 9758c2ecf20Sopenharmony_ci * assumes that Flash device is in its default reset state, 24-bit address mode, 9768c2ecf20Sopenharmony_ci * and ready to accept commands. This can be achieved using some form of 9778c2ecf20Sopenharmony_ci * on-board logic/controller to force a device POR in response to a SoC-level 9788c2ecf20Sopenharmony_ci * reset or by making use of the device reset signal if available (limited 9798c2ecf20Sopenharmony_ci * number of devices only). 9808c2ecf20Sopenharmony_ci * 9818c2ecf20Sopenharmony_ci * Failure to take such precautions can cause problems following a warm reset. 9828c2ecf20Sopenharmony_ci * For some operations (e.g. ERASE), there is little that can be done. For 9838c2ecf20Sopenharmony_ci * other modes of operation (e.g. 32-bit addressing), options are often 9848c2ecf20Sopenharmony_ci * available that can help minimise the window in which a reset could cause a 9858c2ecf20Sopenharmony_ci * problem. 9868c2ecf20Sopenharmony_ci * 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_cistatic bool stfsm_can_handle_soc_reset(struct stfsm *fsm) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci /* Reset signal is available on the board and supported by the device */ 9918c2ecf20Sopenharmony_ci if (fsm->reset_signal && fsm->info->flags & FLASH_FLAG_RESET) 9928c2ecf20Sopenharmony_ci return true; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /* Board-level logic forces a power-on-reset */ 9958c2ecf20Sopenharmony_ci if (fsm->reset_por) 9968c2ecf20Sopenharmony_ci return true; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* Reset is not properly handled and may result in failure to reboot */ 9998c2ecf20Sopenharmony_ci return false; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci/* Configure 'addr_cfg' according to addressing mode */ 10038c2ecf20Sopenharmony_cistatic void stfsm_prepare_erasesec_seq(struct stfsm *fsm, 10048c2ecf20Sopenharmony_ci struct stfsm_seq *seq) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci int addr1_cycles = fsm->info->flags & FLASH_FLAG_32BIT_ADDR ? 16 : 8; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci seq->addr_cfg = (ADR_CFG_CYCLES_ADD1(addr1_cycles) | 10098c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 10108c2ecf20Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 10118c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD2 | 10128c2ecf20Sopenharmony_ci ADR_CFG_CSDEASSERT_ADD2); 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci/* Search for preferred configuration based on available flags */ 10168c2ecf20Sopenharmony_cistatic struct seq_rw_config * 10178c2ecf20Sopenharmony_cistfsm_search_seq_rw_configs(struct stfsm *fsm, 10188c2ecf20Sopenharmony_ci struct seq_rw_config cfgs[]) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci struct seq_rw_config *config; 10218c2ecf20Sopenharmony_ci int flags = fsm->info->flags; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci for (config = cfgs; config->cmd != 0; config++) 10248c2ecf20Sopenharmony_ci if ((config->flags & flags) == config->flags) 10258c2ecf20Sopenharmony_ci return config; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci return NULL; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci/* Prepare a READ/WRITE sequence according to configuration parameters */ 10318c2ecf20Sopenharmony_cistatic void stfsm_prepare_rw_seq(struct stfsm *fsm, 10328c2ecf20Sopenharmony_ci struct stfsm_seq *seq, 10338c2ecf20Sopenharmony_ci struct seq_rw_config *cfg) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci int addr1_cycles, addr2_cycles; 10368c2ecf20Sopenharmony_ci int i = 0; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci memset(seq, 0, sizeof(*seq)); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* Add READ/WRITE OPC */ 10418c2ecf20Sopenharmony_ci seq->seq_opc[i++] = (SEQ_OPC_PADS_1 | 10428c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 10438c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(cfg->cmd)); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci /* Add WREN OPC for a WRITE sequence */ 10468c2ecf20Sopenharmony_ci if (cfg->write) 10478c2ecf20Sopenharmony_ci seq->seq_opc[i++] = (SEQ_OPC_PADS_1 | 10488c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 10498c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | 10508c2ecf20Sopenharmony_ci SEQ_OPC_CSDEASSERT); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* Address configuration (24 or 32-bit addresses) */ 10538c2ecf20Sopenharmony_ci addr1_cycles = (fsm->info->flags & FLASH_FLAG_32BIT_ADDR) ? 16 : 8; 10548c2ecf20Sopenharmony_ci addr1_cycles /= cfg->addr_pads; 10558c2ecf20Sopenharmony_ci addr2_cycles = 16 / cfg->addr_pads; 10568c2ecf20Sopenharmony_ci seq->addr_cfg = ((addr1_cycles & 0x3f) << 0 | /* ADD1 cycles */ 10578c2ecf20Sopenharmony_ci (cfg->addr_pads - 1) << 6 | /* ADD1 pads */ 10588c2ecf20Sopenharmony_ci (addr2_cycles & 0x3f) << 16 | /* ADD2 cycles */ 10598c2ecf20Sopenharmony_ci ((cfg->addr_pads - 1) << 22)); /* ADD2 pads */ 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci /* Data/Sequence configuration */ 10628c2ecf20Sopenharmony_ci seq->seq_cfg = ((cfg->data_pads - 1) << 16 | 10638c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ | 10648c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT); 10658c2ecf20Sopenharmony_ci if (!cfg->write) 10668c2ecf20Sopenharmony_ci seq->seq_cfg |= SEQ_CFG_READNOTWRITE; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* Mode configuration (no. of pads taken from addr cfg) */ 10698c2ecf20Sopenharmony_ci seq->mode = ((cfg->mode_data & 0xff) << 0 | /* data */ 10708c2ecf20Sopenharmony_ci (cfg->mode_cycles & 0x3f) << 16 | /* cycles */ 10718c2ecf20Sopenharmony_ci (cfg->addr_pads - 1) << 22); /* pads */ 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Dummy configuration (no. of pads taken from addr cfg) */ 10748c2ecf20Sopenharmony_ci seq->dummy = ((cfg->dummy_cycles & 0x3f) << 16 | /* cycles */ 10758c2ecf20Sopenharmony_ci (cfg->addr_pads - 1) << 22); /* pads */ 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* Instruction sequence */ 10798c2ecf20Sopenharmony_ci i = 0; 10808c2ecf20Sopenharmony_ci if (cfg->write) 10818c2ecf20Sopenharmony_ci seq->seq[i++] = STFSM_INST_CMD2; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci seq->seq[i++] = STFSM_INST_CMD1; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci seq->seq[i++] = STFSM_INST_ADD1; 10868c2ecf20Sopenharmony_ci seq->seq[i++] = STFSM_INST_ADD2; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (cfg->mode_cycles) 10898c2ecf20Sopenharmony_ci seq->seq[i++] = STFSM_INST_MODE; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (cfg->dummy_cycles) 10928c2ecf20Sopenharmony_ci seq->seq[i++] = STFSM_INST_DUMMY; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci seq->seq[i++] = 10958c2ecf20Sopenharmony_ci cfg->write ? STFSM_INST_DATA_WRITE : STFSM_INST_DATA_READ; 10968c2ecf20Sopenharmony_ci seq->seq[i++] = STFSM_INST_STOP; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic int stfsm_search_prepare_rw_seq(struct stfsm *fsm, 11008c2ecf20Sopenharmony_ci struct stfsm_seq *seq, 11018c2ecf20Sopenharmony_ci struct seq_rw_config *cfgs) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci struct seq_rw_config *config; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci config = stfsm_search_seq_rw_configs(fsm, cfgs); 11068c2ecf20Sopenharmony_ci if (!config) { 11078c2ecf20Sopenharmony_ci dev_err(fsm->dev, "failed to find suitable config\n"); 11088c2ecf20Sopenharmony_ci return -EINVAL; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci stfsm_prepare_rw_seq(fsm, seq, config); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci return 0; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci/* Prepare a READ/WRITE/ERASE 'default' sequences */ 11178c2ecf20Sopenharmony_cistatic int stfsm_prepare_rwe_seqs_default(struct stfsm *fsm) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci uint32_t flags = fsm->info->flags; 11208c2ecf20Sopenharmony_ci int ret; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* Configure 'READ' sequence */ 11238c2ecf20Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 11248c2ecf20Sopenharmony_ci default_read_configs); 11258c2ecf20Sopenharmony_ci if (ret) { 11268c2ecf20Sopenharmony_ci dev_err(fsm->dev, 11278c2ecf20Sopenharmony_ci "failed to prep READ sequence with flags [0x%08x]\n", 11288c2ecf20Sopenharmony_ci flags); 11298c2ecf20Sopenharmony_ci return ret; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* Configure 'WRITE' sequence */ 11338c2ecf20Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write, 11348c2ecf20Sopenharmony_ci default_write_configs); 11358c2ecf20Sopenharmony_ci if (ret) { 11368c2ecf20Sopenharmony_ci dev_err(fsm->dev, 11378c2ecf20Sopenharmony_ci "failed to prep WRITE sequence with flags [0x%08x]\n", 11388c2ecf20Sopenharmony_ci flags); 11398c2ecf20Sopenharmony_ci return ret; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* Configure 'ERASE_SECTOR' sequence */ 11438c2ecf20Sopenharmony_ci stfsm_prepare_erasesec_seq(fsm, &stfsm_seq_erase_sector); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci return 0; 11468c2ecf20Sopenharmony_ci} 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_cistatic int stfsm_mx25_config(struct stfsm *fsm) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci uint32_t flags = fsm->info->flags; 11518c2ecf20Sopenharmony_ci uint32_t data_pads; 11528c2ecf20Sopenharmony_ci uint8_t sta; 11538c2ecf20Sopenharmony_ci int ret; 11548c2ecf20Sopenharmony_ci bool soc_reset; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* 11578c2ecf20Sopenharmony_ci * Use default READ/WRITE sequences 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 11608c2ecf20Sopenharmony_ci if (ret) 11618c2ecf20Sopenharmony_ci return ret; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* 11648c2ecf20Sopenharmony_ci * Configure 32-bit Address Support 11658c2ecf20Sopenharmony_ci */ 11668c2ecf20Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) { 11678c2ecf20Sopenharmony_ci /* Configure 'enter_32bitaddr' FSM sequence */ 11688c2ecf20Sopenharmony_ci stfsm_mx25_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci soc_reset = stfsm_can_handle_soc_reset(fsm); 11718c2ecf20Sopenharmony_ci if (soc_reset || !fsm->booted_from_spi) 11728c2ecf20Sopenharmony_ci /* If we can handle SoC resets, we enable 32-bit address 11738c2ecf20Sopenharmony_ci * mode pervasively */ 11748c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci else 11778c2ecf20Sopenharmony_ci /* Else, enable/disable 32-bit addressing before/after 11788c2ecf20Sopenharmony_ci * each operation */ 11798c2ecf20Sopenharmony_ci fsm->configuration = (CFG_READ_TOGGLE_32BIT_ADDR | 11808c2ecf20Sopenharmony_ci CFG_WRITE_TOGGLE_32BIT_ADDR | 11818c2ecf20Sopenharmony_ci CFG_ERASESEC_TOGGLE_32BIT_ADDR); 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* Check status of 'QE' bit, update if required. */ 11858c2ecf20Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDSR, &sta, 1); 11868c2ecf20Sopenharmony_ci data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; 11878c2ecf20Sopenharmony_ci if (data_pads == 4) { 11888c2ecf20Sopenharmony_ci if (!(sta & MX25_STATUS_QE)) { 11898c2ecf20Sopenharmony_ci /* Set 'QE' */ 11908c2ecf20Sopenharmony_ci sta |= MX25_STATUS_QE; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1); 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci } else { 11958c2ecf20Sopenharmony_ci if (sta & MX25_STATUS_QE) { 11968c2ecf20Sopenharmony_ci /* Clear 'QE' */ 11978c2ecf20Sopenharmony_ci sta &= ~MX25_STATUS_QE; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1); 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci return 0; 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cistatic int stfsm_n25q_config(struct stfsm *fsm) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci uint32_t flags = fsm->info->flags; 12098c2ecf20Sopenharmony_ci uint8_t vcr; 12108c2ecf20Sopenharmony_ci int ret = 0; 12118c2ecf20Sopenharmony_ci bool soc_reset; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* Configure 'READ' sequence */ 12148c2ecf20Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) 12158c2ecf20Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 12168c2ecf20Sopenharmony_ci n25q_read4_configs); 12178c2ecf20Sopenharmony_ci else 12188c2ecf20Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 12198c2ecf20Sopenharmony_ci n25q_read3_configs); 12208c2ecf20Sopenharmony_ci if (ret) { 12218c2ecf20Sopenharmony_ci dev_err(fsm->dev, 12228c2ecf20Sopenharmony_ci "failed to prepare READ sequence with flags [0x%08x]\n", 12238c2ecf20Sopenharmony_ci flags); 12248c2ecf20Sopenharmony_ci return ret; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* Configure 'WRITE' sequence (default configs) */ 12288c2ecf20Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write, 12298c2ecf20Sopenharmony_ci default_write_configs); 12308c2ecf20Sopenharmony_ci if (ret) { 12318c2ecf20Sopenharmony_ci dev_err(fsm->dev, 12328c2ecf20Sopenharmony_ci "preparing WRITE sequence using flags [0x%08x] failed\n", 12338c2ecf20Sopenharmony_ci flags); 12348c2ecf20Sopenharmony_ci return ret; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* * Configure 'ERASE_SECTOR' sequence */ 12388c2ecf20Sopenharmony_ci stfsm_prepare_erasesec_seq(fsm, &stfsm_seq_erase_sector); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* Configure 32-bit address support */ 12418c2ecf20Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) { 12428c2ecf20Sopenharmony_ci stfsm_n25q_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci soc_reset = stfsm_can_handle_soc_reset(fsm); 12458c2ecf20Sopenharmony_ci if (soc_reset || !fsm->booted_from_spi) { 12468c2ecf20Sopenharmony_ci /* 12478c2ecf20Sopenharmony_ci * If we can handle SoC resets, we enable 32-bit 12488c2ecf20Sopenharmony_ci * address mode pervasively 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 12518c2ecf20Sopenharmony_ci } else { 12528c2ecf20Sopenharmony_ci /* 12538c2ecf20Sopenharmony_ci * If not, enable/disable for WRITE and ERASE 12548c2ecf20Sopenharmony_ci * operations (READ uses special commands) 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci fsm->configuration = (CFG_WRITE_TOGGLE_32BIT_ADDR | 12578c2ecf20Sopenharmony_ci CFG_ERASESEC_TOGGLE_32BIT_ADDR); 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* 12628c2ecf20Sopenharmony_ci * Configure device to use 8 dummy cycles 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci vcr = (N25Q_VCR_DUMMY_CYCLES(8) | N25Q_VCR_XIP_DISABLED | 12658c2ecf20Sopenharmony_ci N25Q_VCR_WRAP_CONT); 12668c2ecf20Sopenharmony_ci stfsm_write_status(fsm, N25Q_CMD_WRVCR, vcr, 1, 0); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci return 0; 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_cistatic void stfsm_s25fl_prepare_erasesec_seq_32(struct stfsm_seq *seq) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci seq->seq_opc[1] = (SEQ_OPC_PADS_1 | 12748c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 12758c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_SE4)); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci seq->addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | 12788c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 12798c2ecf20Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 12808c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD2 | 12818c2ecf20Sopenharmony_ci ADR_CFG_CSDEASSERT_ADD2); 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic void stfsm_s25fl_read_dyb(struct stfsm *fsm, uint32_t offs, uint8_t *dby) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci uint32_t tmp; 12878c2ecf20Sopenharmony_ci struct stfsm_seq seq = { 12888c2ecf20Sopenharmony_ci .data_size = TRANSFER_SIZE(4), 12898c2ecf20Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 12908c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 12918c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_DYBRD)), 12928c2ecf20Sopenharmony_ci .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | 12938c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 12948c2ecf20Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 12958c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD2), 12968c2ecf20Sopenharmony_ci .addr1 = (offs >> 16) & 0xffff, 12978c2ecf20Sopenharmony_ci .addr2 = offs & 0xffff, 12988c2ecf20Sopenharmony_ci .seq = { 12998c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 13008c2ecf20Sopenharmony_ci STFSM_INST_ADD1, 13018c2ecf20Sopenharmony_ci STFSM_INST_ADD2, 13028c2ecf20Sopenharmony_ci STFSM_INST_DATA_READ, 13038c2ecf20Sopenharmony_ci STFSM_INST_STOP, 13048c2ecf20Sopenharmony_ci }, 13058c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 13068c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 13078c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 13088c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 13098c2ecf20Sopenharmony_ci }; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, &seq); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci stfsm_read_fifo(fsm, &tmp, 4); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci *dby = (uint8_t)(tmp >> 24); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic void stfsm_s25fl_write_dyb(struct stfsm *fsm, uint32_t offs, uint8_t dby) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci struct stfsm_seq seq = { 13238c2ecf20Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 13248c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WREN) | 13258c2ecf20Sopenharmony_ci SEQ_OPC_CSDEASSERT), 13268c2ecf20Sopenharmony_ci .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | 13278c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_DYBWR)), 13288c2ecf20Sopenharmony_ci .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | 13298c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD1 | 13308c2ecf20Sopenharmony_ci ADR_CFG_CYCLES_ADD2(16) | 13318c2ecf20Sopenharmony_ci ADR_CFG_PADS_1_ADD2), 13328c2ecf20Sopenharmony_ci .status = (uint32_t)dby | STA_PADS_1 | STA_CSDEASSERT, 13338c2ecf20Sopenharmony_ci .addr1 = (offs >> 16) & 0xffff, 13348c2ecf20Sopenharmony_ci .addr2 = offs & 0xffff, 13358c2ecf20Sopenharmony_ci .seq = { 13368c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 13378c2ecf20Sopenharmony_ci STFSM_INST_CMD2, 13388c2ecf20Sopenharmony_ci STFSM_INST_ADD1, 13398c2ecf20Sopenharmony_ci STFSM_INST_ADD2, 13408c2ecf20Sopenharmony_ci STFSM_INST_STA_WR1, 13418c2ecf20Sopenharmony_ci STFSM_INST_STOP, 13428c2ecf20Sopenharmony_ci }, 13438c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 13448c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 13458c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 13468c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 13478c2ecf20Sopenharmony_ci }; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, &seq); 13508c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci stfsm_wait_busy(fsm); 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_cistatic int stfsm_s25fl_clear_status_reg(struct stfsm *fsm) 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci struct stfsm_seq seq = { 13588c2ecf20Sopenharmony_ci .seq_opc[0] = (SEQ_OPC_PADS_1 | 13598c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 13608c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(S25FL_CMD_CLSR) | 13618c2ecf20Sopenharmony_ci SEQ_OPC_CSDEASSERT), 13628c2ecf20Sopenharmony_ci .seq_opc[1] = (SEQ_OPC_PADS_1 | 13638c2ecf20Sopenharmony_ci SEQ_OPC_CYCLES(8) | 13648c2ecf20Sopenharmony_ci SEQ_OPC_OPCODE(SPINOR_OP_WRDI) | 13658c2ecf20Sopenharmony_ci SEQ_OPC_CSDEASSERT), 13668c2ecf20Sopenharmony_ci .seq = { 13678c2ecf20Sopenharmony_ci STFSM_INST_CMD1, 13688c2ecf20Sopenharmony_ci STFSM_INST_CMD2, 13698c2ecf20Sopenharmony_ci STFSM_INST_WAIT, 13708c2ecf20Sopenharmony_ci STFSM_INST_STOP, 13718c2ecf20Sopenharmony_ci }, 13728c2ecf20Sopenharmony_ci .seq_cfg = (SEQ_CFG_PADS_1 | 13738c2ecf20Sopenharmony_ci SEQ_CFG_ERASE | 13748c2ecf20Sopenharmony_ci SEQ_CFG_READNOTWRITE | 13758c2ecf20Sopenharmony_ci SEQ_CFG_CSDEASSERT | 13768c2ecf20Sopenharmony_ci SEQ_CFG_STARTSEQ), 13778c2ecf20Sopenharmony_ci }; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, &seq); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci return 0; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic int stfsm_s25fl_config(struct stfsm *fsm) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct flash_info *info = fsm->info; 13898c2ecf20Sopenharmony_ci uint32_t flags = info->flags; 13908c2ecf20Sopenharmony_ci uint32_t data_pads; 13918c2ecf20Sopenharmony_ci uint32_t offs; 13928c2ecf20Sopenharmony_ci uint16_t sta_wr; 13938c2ecf20Sopenharmony_ci uint8_t sr1, cr1, dyb; 13948c2ecf20Sopenharmony_ci int update_sr = 0; 13958c2ecf20Sopenharmony_ci int ret; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (flags & FLASH_FLAG_32BIT_ADDR) { 13988c2ecf20Sopenharmony_ci /* 13998c2ecf20Sopenharmony_ci * Prepare Read/Write/Erase sequences according to S25FLxxx 14008c2ecf20Sopenharmony_ci * 32-bit address command set 14018c2ecf20Sopenharmony_ci */ 14028c2ecf20Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read, 14038c2ecf20Sopenharmony_ci stfsm_s25fl_read4_configs); 14048c2ecf20Sopenharmony_ci if (ret) 14058c2ecf20Sopenharmony_ci return ret; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write, 14088c2ecf20Sopenharmony_ci stfsm_s25fl_write4_configs); 14098c2ecf20Sopenharmony_ci if (ret) 14108c2ecf20Sopenharmony_ci return ret; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci stfsm_s25fl_prepare_erasesec_seq_32(&stfsm_seq_erase_sector); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci } else { 14158c2ecf20Sopenharmony_ci /* Use default configurations for 24-bit addressing */ 14168c2ecf20Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 14178c2ecf20Sopenharmony_ci if (ret) 14188c2ecf20Sopenharmony_ci return ret; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* 14228c2ecf20Sopenharmony_ci * For devices that support 'DYB' sector locking, check lock status and 14238c2ecf20Sopenharmony_ci * unlock sectors if necessary (some variants power-on with sectors 14248c2ecf20Sopenharmony_ci * locked by default) 14258c2ecf20Sopenharmony_ci */ 14268c2ecf20Sopenharmony_ci if (flags & FLASH_FLAG_DYB_LOCKING) { 14278c2ecf20Sopenharmony_ci offs = 0; 14288c2ecf20Sopenharmony_ci for (offs = 0; offs < info->sector_size * info->n_sectors;) { 14298c2ecf20Sopenharmony_ci stfsm_s25fl_read_dyb(fsm, offs, &dyb); 14308c2ecf20Sopenharmony_ci if (dyb == 0x00) 14318c2ecf20Sopenharmony_ci stfsm_s25fl_write_dyb(fsm, offs, 0xff); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* Handle bottom/top 4KiB parameter sectors */ 14348c2ecf20Sopenharmony_ci if ((offs < info->sector_size * 2) || 14358c2ecf20Sopenharmony_ci (offs >= (info->sector_size - info->n_sectors * 4))) 14368c2ecf20Sopenharmony_ci offs += 0x1000; 14378c2ecf20Sopenharmony_ci else 14388c2ecf20Sopenharmony_ci offs += 0x10000; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci /* Check status of 'QE' bit, update if required. */ 14438c2ecf20Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDCR, &cr1, 1); 14448c2ecf20Sopenharmony_ci data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; 14458c2ecf20Sopenharmony_ci if (data_pads == 4) { 14468c2ecf20Sopenharmony_ci if (!(cr1 & STFSM_S25FL_CONFIG_QE)) { 14478c2ecf20Sopenharmony_ci /* Set 'QE' */ 14488c2ecf20Sopenharmony_ci cr1 |= STFSM_S25FL_CONFIG_QE; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci update_sr = 1; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci } else { 14538c2ecf20Sopenharmony_ci if (cr1 & STFSM_S25FL_CONFIG_QE) { 14548c2ecf20Sopenharmony_ci /* Clear 'QE' */ 14558c2ecf20Sopenharmony_ci cr1 &= ~STFSM_S25FL_CONFIG_QE; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci update_sr = 1; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci if (update_sr) { 14618c2ecf20Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1); 14628c2ecf20Sopenharmony_ci sta_wr = ((uint16_t)cr1 << 8) | sr1; 14638c2ecf20Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sta_wr, 2, 1); 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci /* 14678c2ecf20Sopenharmony_ci * S25FLxxx devices support Program and Error error flags. 14688c2ecf20Sopenharmony_ci * Configure driver to check flags and clear if necessary. 14698c2ecf20Sopenharmony_ci */ 14708c2ecf20Sopenharmony_ci fsm->configuration |= CFG_S25FL_CHECK_ERROR_FLAGS; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci return 0; 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic int stfsm_w25q_config(struct stfsm *fsm) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci uint32_t data_pads; 14788c2ecf20Sopenharmony_ci uint8_t sr1, sr2; 14798c2ecf20Sopenharmony_ci uint16_t sr_wr; 14808c2ecf20Sopenharmony_ci int update_sr = 0; 14818c2ecf20Sopenharmony_ci int ret; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 14848c2ecf20Sopenharmony_ci if (ret) 14858c2ecf20Sopenharmony_ci return ret; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci /* Check status of 'QE' bit, update if required. */ 14888c2ecf20Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDCR, &sr2, 1); 14898c2ecf20Sopenharmony_ci data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; 14908c2ecf20Sopenharmony_ci if (data_pads == 4) { 14918c2ecf20Sopenharmony_ci if (!(sr2 & W25Q_STATUS_QE)) { 14928c2ecf20Sopenharmony_ci /* Set 'QE' */ 14938c2ecf20Sopenharmony_ci sr2 |= W25Q_STATUS_QE; 14948c2ecf20Sopenharmony_ci update_sr = 1; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci } else { 14978c2ecf20Sopenharmony_ci if (sr2 & W25Q_STATUS_QE) { 14988c2ecf20Sopenharmony_ci /* Clear 'QE' */ 14998c2ecf20Sopenharmony_ci sr2 &= ~W25Q_STATUS_QE; 15008c2ecf20Sopenharmony_ci update_sr = 1; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci if (update_sr) { 15048c2ecf20Sopenharmony_ci /* Write status register */ 15058c2ecf20Sopenharmony_ci stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1); 15068c2ecf20Sopenharmony_ci sr_wr = ((uint16_t)sr2 << 8) | sr1; 15078c2ecf20Sopenharmony_ci stfsm_write_status(fsm, SPINOR_OP_WRSR, sr_wr, 2, 1); 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci return 0; 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_cistatic int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size, 15148c2ecf20Sopenharmony_ci uint32_t offset) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci struct stfsm_seq *seq = &fsm->stfsm_seq_read; 15178c2ecf20Sopenharmony_ci uint32_t data_pads; 15188c2ecf20Sopenharmony_ci uint32_t read_mask; 15198c2ecf20Sopenharmony_ci uint32_t size_ub; 15208c2ecf20Sopenharmony_ci uint32_t size_lb; 15218c2ecf20Sopenharmony_ci uint32_t size_mop; 15228c2ecf20Sopenharmony_ci uint32_t tmp[4]; 15238c2ecf20Sopenharmony_ci uint32_t page_buf[FLASH_PAGESIZE_32]; 15248c2ecf20Sopenharmony_ci uint8_t *p; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "reading %d bytes from 0x%08x\n", size, offset); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* Enter 32-bit address mode, if required */ 15298c2ecf20Sopenharmony_ci if (fsm->configuration & CFG_READ_TOGGLE_32BIT_ADDR) 15308c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci /* Must read in multiples of 32 cycles (or 32*pads/8 Bytes) */ 15338c2ecf20Sopenharmony_ci data_pads = ((seq->seq_cfg >> 16) & 0x3) + 1; 15348c2ecf20Sopenharmony_ci read_mask = (data_pads << 2) - 1; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* Handle non-aligned buf */ 15378c2ecf20Sopenharmony_ci p = ((uintptr_t)buf & 0x3) ? (uint8_t *)page_buf : buf; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* Handle non-aligned size */ 15408c2ecf20Sopenharmony_ci size_ub = (size + read_mask) & ~read_mask; 15418c2ecf20Sopenharmony_ci size_lb = size & ~read_mask; 15428c2ecf20Sopenharmony_ci size_mop = size & read_mask; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci seq->data_size = TRANSFER_SIZE(size_ub); 15458c2ecf20Sopenharmony_ci seq->addr1 = (offset >> 16) & 0xffff; 15468c2ecf20Sopenharmony_ci seq->addr2 = offset & 0xffff; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (size_lb) 15518c2ecf20Sopenharmony_ci stfsm_read_fifo(fsm, (uint32_t *)p, size_lb); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (size_mop) { 15548c2ecf20Sopenharmony_ci stfsm_read_fifo(fsm, tmp, read_mask + 1); 15558c2ecf20Sopenharmony_ci memcpy(p + size_lb, &tmp, size_mop); 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci /* Handle non-aligned buf */ 15598c2ecf20Sopenharmony_ci if ((uintptr_t)buf & 0x3) 15608c2ecf20Sopenharmony_ci memcpy(buf, page_buf, size); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Wait for sequence to finish */ 15638c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci stfsm_clear_fifo(fsm); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* Exit 32-bit address mode, if required */ 15688c2ecf20Sopenharmony_ci if (fsm->configuration & CFG_READ_TOGGLE_32BIT_ADDR) 15698c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 0); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci return 0; 15728c2ecf20Sopenharmony_ci} 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_cistatic int stfsm_write(struct stfsm *fsm, const uint8_t *buf, 15758c2ecf20Sopenharmony_ci uint32_t size, uint32_t offset) 15768c2ecf20Sopenharmony_ci{ 15778c2ecf20Sopenharmony_ci struct stfsm_seq *seq = &fsm->stfsm_seq_write; 15788c2ecf20Sopenharmony_ci uint32_t data_pads; 15798c2ecf20Sopenharmony_ci uint32_t write_mask; 15808c2ecf20Sopenharmony_ci uint32_t size_ub; 15818c2ecf20Sopenharmony_ci uint32_t size_lb; 15828c2ecf20Sopenharmony_ci uint32_t size_mop; 15838c2ecf20Sopenharmony_ci uint32_t tmp[4]; 15848c2ecf20Sopenharmony_ci uint32_t i; 15858c2ecf20Sopenharmony_ci uint32_t page_buf[FLASH_PAGESIZE_32]; 15868c2ecf20Sopenharmony_ci uint8_t *t = (uint8_t *)&tmp; 15878c2ecf20Sopenharmony_ci const uint8_t *p; 15888c2ecf20Sopenharmony_ci int ret; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "writing %d bytes to 0x%08x\n", size, offset); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* Enter 32-bit address mode, if required */ 15938c2ecf20Sopenharmony_ci if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) 15948c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* Must write in multiples of 32 cycles (or 32*pads/8 bytes) */ 15978c2ecf20Sopenharmony_ci data_pads = ((seq->seq_cfg >> 16) & 0x3) + 1; 15988c2ecf20Sopenharmony_ci write_mask = (data_pads << 2) - 1; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci /* Handle non-aligned buf */ 16018c2ecf20Sopenharmony_ci if ((uintptr_t)buf & 0x3) { 16028c2ecf20Sopenharmony_ci memcpy(page_buf, buf, size); 16038c2ecf20Sopenharmony_ci p = (uint8_t *)page_buf; 16048c2ecf20Sopenharmony_ci } else { 16058c2ecf20Sopenharmony_ci p = buf; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci /* Handle non-aligned size */ 16098c2ecf20Sopenharmony_ci size_ub = (size + write_mask) & ~write_mask; 16108c2ecf20Sopenharmony_ci size_lb = size & ~write_mask; 16118c2ecf20Sopenharmony_ci size_mop = size & write_mask; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci seq->data_size = TRANSFER_SIZE(size_ub); 16148c2ecf20Sopenharmony_ci seq->addr1 = (offset >> 16) & 0xffff; 16158c2ecf20Sopenharmony_ci seq->addr2 = offset & 0xffff; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci /* Need to set FIFO to write mode, before writing data to FIFO (see 16188c2ecf20Sopenharmony_ci * GNBvb79594) 16198c2ecf20Sopenharmony_ci */ 16208c2ecf20Sopenharmony_ci writel(0x00040000, fsm->base + SPI_FAST_SEQ_CFG); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* 16238c2ecf20Sopenharmony_ci * Before writing data to the FIFO, apply a small delay to allow a 16248c2ecf20Sopenharmony_ci * potential change of FIFO direction to complete. 16258c2ecf20Sopenharmony_ci */ 16268c2ecf20Sopenharmony_ci if (fsm->fifo_dir_delay == 0) 16278c2ecf20Sopenharmony_ci readl(fsm->base + SPI_FAST_SEQ_CFG); 16288c2ecf20Sopenharmony_ci else 16298c2ecf20Sopenharmony_ci udelay(fsm->fifo_dir_delay); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci /* Write data to FIFO, before starting sequence (see GNBvd79593) */ 16338c2ecf20Sopenharmony_ci if (size_lb) { 16348c2ecf20Sopenharmony_ci stfsm_write_fifo(fsm, (uint32_t *)p, size_lb); 16358c2ecf20Sopenharmony_ci p += size_lb; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci /* Handle non-aligned size */ 16398c2ecf20Sopenharmony_ci if (size_mop) { 16408c2ecf20Sopenharmony_ci memset(t, 0xff, write_mask + 1); /* fill with 0xff's */ 16418c2ecf20Sopenharmony_ci for (i = 0; i < size_mop; i++) 16428c2ecf20Sopenharmony_ci t[i] = *p++; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci stfsm_write_fifo(fsm, tmp, write_mask + 1); 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci /* Start sequence */ 16488c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci /* Wait for sequence to finish */ 16518c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci /* Wait for completion */ 16548c2ecf20Sopenharmony_ci ret = stfsm_wait_busy(fsm); 16558c2ecf20Sopenharmony_ci if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) 16568c2ecf20Sopenharmony_ci stfsm_s25fl_clear_status_reg(fsm); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci /* Exit 32-bit address mode, if required */ 16598c2ecf20Sopenharmony_ci if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) 16608c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 0); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci return 0; 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci/* 16668c2ecf20Sopenharmony_ci * Read an address range from the flash chip. The address range 16678c2ecf20Sopenharmony_ci * may be any size provided it is within the physical boundaries. 16688c2ecf20Sopenharmony_ci */ 16698c2ecf20Sopenharmony_cistatic int stfsm_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, 16708c2ecf20Sopenharmony_ci size_t *retlen, u_char *buf) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); 16738c2ecf20Sopenharmony_ci uint32_t bytes; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "%s from 0x%08x, len %zd\n", 16768c2ecf20Sopenharmony_ci __func__, (u32)from, len); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci mutex_lock(&fsm->lock); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci while (len > 0) { 16818c2ecf20Sopenharmony_ci bytes = min_t(size_t, len, FLASH_PAGESIZE); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci stfsm_read(fsm, buf, bytes, from); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci buf += bytes; 16868c2ecf20Sopenharmony_ci from += bytes; 16878c2ecf20Sopenharmony_ci len -= bytes; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci *retlen += bytes; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci mutex_unlock(&fsm->lock); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci return 0; 16958c2ecf20Sopenharmony_ci} 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_cistatic int stfsm_erase_sector(struct stfsm *fsm, uint32_t offset) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci struct stfsm_seq *seq = &stfsm_seq_erase_sector; 17008c2ecf20Sopenharmony_ci int ret; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "erasing sector at 0x%08x\n", offset); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci /* Enter 32-bit address mode, if required */ 17058c2ecf20Sopenharmony_ci if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR) 17068c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 1); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci seq->addr1 = (offset >> 16) & 0xffff; 17098c2ecf20Sopenharmony_ci seq->addr2 = offset & 0xffff; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci /* Wait for completion */ 17168c2ecf20Sopenharmony_ci ret = stfsm_wait_busy(fsm); 17178c2ecf20Sopenharmony_ci if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) 17188c2ecf20Sopenharmony_ci stfsm_s25fl_clear_status_reg(fsm); 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Exit 32-bit address mode, if required */ 17218c2ecf20Sopenharmony_ci if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR) 17228c2ecf20Sopenharmony_ci stfsm_enter_32bit_addr(fsm, 0); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci return ret; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic int stfsm_erase_chip(struct stfsm *fsm) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci const struct stfsm_seq *seq = &stfsm_seq_erase_chip; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "erasing chip\n"); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci return stfsm_wait_busy(fsm); 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci/* 17418c2ecf20Sopenharmony_ci * Write an address range to the flash chip. Data must be written in 17428c2ecf20Sopenharmony_ci * FLASH_PAGESIZE chunks. The address range may be any size provided 17438c2ecf20Sopenharmony_ci * it is within the physical boundaries. 17448c2ecf20Sopenharmony_ci */ 17458c2ecf20Sopenharmony_cistatic int stfsm_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, 17468c2ecf20Sopenharmony_ci size_t *retlen, const u_char *buf) 17478c2ecf20Sopenharmony_ci{ 17488c2ecf20Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci u32 page_offs; 17518c2ecf20Sopenharmony_ci u32 bytes; 17528c2ecf20Sopenharmony_ci uint8_t *b = (uint8_t *)buf; 17538c2ecf20Sopenharmony_ci int ret = 0; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "%s to 0x%08x, len %zd\n", __func__, (u32)to, len); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci /* Offset within page */ 17588c2ecf20Sopenharmony_ci page_offs = to % FLASH_PAGESIZE; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci mutex_lock(&fsm->lock); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci while (len) { 17638c2ecf20Sopenharmony_ci /* Write up to page boundary */ 17648c2ecf20Sopenharmony_ci bytes = min_t(size_t, FLASH_PAGESIZE - page_offs, len); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci ret = stfsm_write(fsm, b, bytes, to); 17678c2ecf20Sopenharmony_ci if (ret) 17688c2ecf20Sopenharmony_ci goto out1; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci b += bytes; 17718c2ecf20Sopenharmony_ci len -= bytes; 17728c2ecf20Sopenharmony_ci to += bytes; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci /* We are now page-aligned */ 17758c2ecf20Sopenharmony_ci page_offs = 0; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci *retlen += bytes; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ciout1: 17828c2ecf20Sopenharmony_ci mutex_unlock(&fsm->lock); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci return ret; 17858c2ecf20Sopenharmony_ci} 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci/* 17888c2ecf20Sopenharmony_ci * Erase an address range on the flash chip. The address range may extend 17898c2ecf20Sopenharmony_ci * one or more erase sectors. Return an error is there is a problem erasing. 17908c2ecf20Sopenharmony_ci */ 17918c2ecf20Sopenharmony_cistatic int stfsm_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) 17928c2ecf20Sopenharmony_ci{ 17938c2ecf20Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); 17948c2ecf20Sopenharmony_ci u32 addr, len; 17958c2ecf20Sopenharmony_ci int ret; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "%s at 0x%llx, len %lld\n", __func__, 17988c2ecf20Sopenharmony_ci (long long)instr->addr, (long long)instr->len); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci addr = instr->addr; 18018c2ecf20Sopenharmony_ci len = instr->len; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci mutex_lock(&fsm->lock); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci /* Whole-chip erase? */ 18068c2ecf20Sopenharmony_ci if (len == mtd->size) { 18078c2ecf20Sopenharmony_ci ret = stfsm_erase_chip(fsm); 18088c2ecf20Sopenharmony_ci if (ret) 18098c2ecf20Sopenharmony_ci goto out1; 18108c2ecf20Sopenharmony_ci } else { 18118c2ecf20Sopenharmony_ci while (len) { 18128c2ecf20Sopenharmony_ci ret = stfsm_erase_sector(fsm, addr); 18138c2ecf20Sopenharmony_ci if (ret) 18148c2ecf20Sopenharmony_ci goto out1; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci addr += mtd->erasesize; 18178c2ecf20Sopenharmony_ci len -= mtd->erasesize; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci mutex_unlock(&fsm->lock); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci return 0; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ciout1: 18268c2ecf20Sopenharmony_ci mutex_unlock(&fsm->lock); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci return ret; 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic void stfsm_read_jedec(struct stfsm *fsm, uint8_t *jedec) 18328c2ecf20Sopenharmony_ci{ 18338c2ecf20Sopenharmony_ci const struct stfsm_seq *seq = &stfsm_seq_read_jedec; 18348c2ecf20Sopenharmony_ci uint32_t tmp[2]; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci stfsm_load_seq(fsm, seq); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci stfsm_read_fifo(fsm, tmp, 8); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci memcpy(jedec, tmp, 5); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci stfsm_wait_seq(fsm); 18438c2ecf20Sopenharmony_ci} 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_cistatic struct flash_info *stfsm_jedec_probe(struct stfsm *fsm) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci struct flash_info *info; 18488c2ecf20Sopenharmony_ci u16 ext_jedec; 18498c2ecf20Sopenharmony_ci u32 jedec; 18508c2ecf20Sopenharmony_ci u8 id[5]; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci stfsm_read_jedec(fsm, id); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci jedec = id[0] << 16 | id[1] << 8 | id[2]; 18558c2ecf20Sopenharmony_ci /* 18568c2ecf20Sopenharmony_ci * JEDEC also defines an optional "extended device information" 18578c2ecf20Sopenharmony_ci * string for after vendor-specific data, after the three bytes 18588c2ecf20Sopenharmony_ci * we use here. Supporting some chips might require using it. 18598c2ecf20Sopenharmony_ci */ 18608c2ecf20Sopenharmony_ci ext_jedec = id[3] << 8 | id[4]; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "JEDEC = 0x%08x [%5ph]\n", jedec, id); 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci for (info = flash_types; info->name; info++) { 18658c2ecf20Sopenharmony_ci if (info->jedec_id == jedec) { 18668c2ecf20Sopenharmony_ci if (info->ext_id && info->ext_id != ext_jedec) 18678c2ecf20Sopenharmony_ci continue; 18688c2ecf20Sopenharmony_ci return info; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci dev_err(fsm->dev, "Unrecognized JEDEC id %06x\n", jedec); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci return NULL; 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cistatic int stfsm_set_mode(struct stfsm *fsm, uint32_t mode) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci int ret, timeout = 10; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci /* Wait for controller to accept mode change */ 18818c2ecf20Sopenharmony_ci while (--timeout) { 18828c2ecf20Sopenharmony_ci ret = readl(fsm->base + SPI_STA_MODE_CHANGE); 18838c2ecf20Sopenharmony_ci if (ret & 0x1) 18848c2ecf20Sopenharmony_ci break; 18858c2ecf20Sopenharmony_ci udelay(1); 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (!timeout) 18898c2ecf20Sopenharmony_ci return -EBUSY; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci writel(mode, fsm->base + SPI_MODESELECT); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci return 0; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic void stfsm_set_freq(struct stfsm *fsm, uint32_t spi_freq) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci uint32_t emi_freq; 18998c2ecf20Sopenharmony_ci uint32_t clk_div; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci emi_freq = clk_get_rate(fsm->clk); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci /* 19048c2ecf20Sopenharmony_ci * Calculate clk_div - values between 2 and 128 19058c2ecf20Sopenharmony_ci * Multiple of 2, rounded up 19068c2ecf20Sopenharmony_ci */ 19078c2ecf20Sopenharmony_ci clk_div = 2 * DIV_ROUND_UP(emi_freq, 2 * spi_freq); 19088c2ecf20Sopenharmony_ci if (clk_div < 2) 19098c2ecf20Sopenharmony_ci clk_div = 2; 19108c2ecf20Sopenharmony_ci else if (clk_div > 128) 19118c2ecf20Sopenharmony_ci clk_div = 128; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci /* 19148c2ecf20Sopenharmony_ci * Determine a suitable delay for the IP to complete a change of 19158c2ecf20Sopenharmony_ci * direction of the FIFO. The required delay is related to the clock 19168c2ecf20Sopenharmony_ci * divider used. The following heuristics are based on empirical tests, 19178c2ecf20Sopenharmony_ci * using a 100MHz EMI clock. 19188c2ecf20Sopenharmony_ci */ 19198c2ecf20Sopenharmony_ci if (clk_div <= 4) 19208c2ecf20Sopenharmony_ci fsm->fifo_dir_delay = 0; 19218c2ecf20Sopenharmony_ci else if (clk_div <= 10) 19228c2ecf20Sopenharmony_ci fsm->fifo_dir_delay = 1; 19238c2ecf20Sopenharmony_ci else 19248c2ecf20Sopenharmony_ci fsm->fifo_dir_delay = DIV_ROUND_UP(clk_div, 10); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci dev_dbg(fsm->dev, "emi_clk = %uHZ, spi_freq = %uHZ, clk_div = %u\n", 19278c2ecf20Sopenharmony_ci emi_freq, spi_freq, clk_div); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci writel(clk_div, fsm->base + SPI_CLOCKDIV); 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cistatic int stfsm_init(struct stfsm *fsm) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci int ret; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* Perform a soft reset of the FSM controller */ 19378c2ecf20Sopenharmony_ci writel(SEQ_CFG_SWRESET, fsm->base + SPI_FAST_SEQ_CFG); 19388c2ecf20Sopenharmony_ci udelay(1); 19398c2ecf20Sopenharmony_ci writel(0, fsm->base + SPI_FAST_SEQ_CFG); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci /* Set clock to 'safe' frequency initially */ 19428c2ecf20Sopenharmony_ci stfsm_set_freq(fsm, STFSM_FLASH_SAFE_FREQ); 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci /* Switch to FSM */ 19458c2ecf20Sopenharmony_ci ret = stfsm_set_mode(fsm, SPI_MODESELECT_FSM); 19468c2ecf20Sopenharmony_ci if (ret) 19478c2ecf20Sopenharmony_ci return ret; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci /* Set timing parameters */ 19508c2ecf20Sopenharmony_ci writel(SPI_CFG_DEVICE_ST | 19518c2ecf20Sopenharmony_ci SPI_CFG_DEFAULT_MIN_CS_HIGH | 19528c2ecf20Sopenharmony_ci SPI_CFG_DEFAULT_CS_SETUPHOLD | 19538c2ecf20Sopenharmony_ci SPI_CFG_DEFAULT_DATA_HOLD, 19548c2ecf20Sopenharmony_ci fsm->base + SPI_CONFIGDATA); 19558c2ecf20Sopenharmony_ci writel(STFSM_DEFAULT_WR_TIME, fsm->base + SPI_STATUS_WR_TIME_REG); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci /* 19588c2ecf20Sopenharmony_ci * Set the FSM 'WAIT' delay to the minimum workable value. Note, for 19598c2ecf20Sopenharmony_ci * our purposes, the WAIT instruction is used purely to achieve 19608c2ecf20Sopenharmony_ci * "sequence validity" rather than actually implement a delay. 19618c2ecf20Sopenharmony_ci */ 19628c2ecf20Sopenharmony_ci writel(0x00000001, fsm->base + SPI_PROGRAM_ERASE_TIME); 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci /* Clear FIFO, just in case */ 19658c2ecf20Sopenharmony_ci stfsm_clear_fifo(fsm); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci return 0; 19688c2ecf20Sopenharmony_ci} 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_cistatic void stfsm_fetch_platform_configs(struct platform_device *pdev) 19718c2ecf20Sopenharmony_ci{ 19728c2ecf20Sopenharmony_ci struct stfsm *fsm = platform_get_drvdata(pdev); 19738c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 19748c2ecf20Sopenharmony_ci struct regmap *regmap; 19758c2ecf20Sopenharmony_ci uint32_t boot_device_reg; 19768c2ecf20Sopenharmony_ci uint32_t boot_device_spi; 19778c2ecf20Sopenharmony_ci uint32_t boot_device; /* Value we read from *boot_device_reg */ 19788c2ecf20Sopenharmony_ci int ret; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci /* Booting from SPI NOR Flash is the default */ 19818c2ecf20Sopenharmony_ci fsm->booted_from_spi = true; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); 19848c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) 19858c2ecf20Sopenharmony_ci goto boot_device_fail; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci fsm->reset_signal = of_property_read_bool(np, "st,reset-signal"); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci fsm->reset_por = of_property_read_bool(np, "st,reset-por"); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci /* Where in the syscon the boot device information lives */ 19928c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "st,boot-device-reg", &boot_device_reg); 19938c2ecf20Sopenharmony_ci if (ret) 19948c2ecf20Sopenharmony_ci goto boot_device_fail; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci /* Boot device value when booted from SPI NOR */ 19978c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "st,boot-device-spi", &boot_device_spi); 19988c2ecf20Sopenharmony_ci if (ret) 19998c2ecf20Sopenharmony_ci goto boot_device_fail; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci ret = regmap_read(regmap, boot_device_reg, &boot_device); 20028c2ecf20Sopenharmony_ci if (ret) 20038c2ecf20Sopenharmony_ci goto boot_device_fail; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (boot_device != boot_device_spi) 20068c2ecf20Sopenharmony_ci fsm->booted_from_spi = false; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci return; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ciboot_device_fail: 20118c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 20128c2ecf20Sopenharmony_ci "failed to fetch boot device, assuming boot from SPI\n"); 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_cistatic int stfsm_probe(struct platform_device *pdev) 20168c2ecf20Sopenharmony_ci{ 20178c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 20188c2ecf20Sopenharmony_ci struct flash_info *info; 20198c2ecf20Sopenharmony_ci struct resource *res; 20208c2ecf20Sopenharmony_ci struct stfsm *fsm; 20218c2ecf20Sopenharmony_ci int ret; 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci if (!np) { 20248c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No DT found\n"); 20258c2ecf20Sopenharmony_ci return -EINVAL; 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci fsm = devm_kzalloc(&pdev->dev, sizeof(*fsm), GFP_KERNEL); 20298c2ecf20Sopenharmony_ci if (!fsm) 20308c2ecf20Sopenharmony_ci return -ENOMEM; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci fsm->dev = &pdev->dev; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, fsm); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 20378c2ecf20Sopenharmony_ci if (!res) { 20388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Resource not found\n"); 20398c2ecf20Sopenharmony_ci return -ENODEV; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci fsm->base = devm_ioremap_resource(&pdev->dev, res); 20438c2ecf20Sopenharmony_ci if (IS_ERR(fsm->base)) { 20448c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 20458c2ecf20Sopenharmony_ci "Failed to reserve memory region %pR\n", res); 20468c2ecf20Sopenharmony_ci return PTR_ERR(fsm->base); 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci fsm->clk = devm_clk_get(&pdev->dev, NULL); 20508c2ecf20Sopenharmony_ci if (IS_ERR(fsm->clk)) { 20518c2ecf20Sopenharmony_ci dev_err(fsm->dev, "Couldn't find EMI clock.\n"); 20528c2ecf20Sopenharmony_ci return PTR_ERR(fsm->clk); 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci ret = clk_prepare_enable(fsm->clk); 20568c2ecf20Sopenharmony_ci if (ret) { 20578c2ecf20Sopenharmony_ci dev_err(fsm->dev, "Failed to enable EMI clock.\n"); 20588c2ecf20Sopenharmony_ci return ret; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci mutex_init(&fsm->lock); 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci ret = stfsm_init(fsm); 20648c2ecf20Sopenharmony_ci if (ret) { 20658c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialise FSM Controller\n"); 20668c2ecf20Sopenharmony_ci goto err_clk_unprepare; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci stfsm_fetch_platform_configs(pdev); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci /* Detect SPI FLASH device */ 20728c2ecf20Sopenharmony_ci info = stfsm_jedec_probe(fsm); 20738c2ecf20Sopenharmony_ci if (!info) { 20748c2ecf20Sopenharmony_ci ret = -ENODEV; 20758c2ecf20Sopenharmony_ci goto err_clk_unprepare; 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci fsm->info = info; 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci /* Use device size to determine address width */ 20808c2ecf20Sopenharmony_ci if (info->sector_size * info->n_sectors > 0x1000000) 20818c2ecf20Sopenharmony_ci info->flags |= FLASH_FLAG_32BIT_ADDR; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci /* 20848c2ecf20Sopenharmony_ci * Configure READ/WRITE/ERASE sequences according to platform and 20858c2ecf20Sopenharmony_ci * device flags. 20868c2ecf20Sopenharmony_ci */ 20878c2ecf20Sopenharmony_ci if (info->config) { 20888c2ecf20Sopenharmony_ci ret = info->config(fsm); 20898c2ecf20Sopenharmony_ci if (ret) 20908c2ecf20Sopenharmony_ci goto err_clk_unprepare; 20918c2ecf20Sopenharmony_ci } else { 20928c2ecf20Sopenharmony_ci ret = stfsm_prepare_rwe_seqs_default(fsm); 20938c2ecf20Sopenharmony_ci if (ret) 20948c2ecf20Sopenharmony_ci goto err_clk_unprepare; 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci fsm->mtd.name = info->name; 20988c2ecf20Sopenharmony_ci fsm->mtd.dev.parent = &pdev->dev; 20998c2ecf20Sopenharmony_ci mtd_set_of_node(&fsm->mtd, np); 21008c2ecf20Sopenharmony_ci fsm->mtd.type = MTD_NORFLASH; 21018c2ecf20Sopenharmony_ci fsm->mtd.writesize = 4; 21028c2ecf20Sopenharmony_ci fsm->mtd.writebufsize = fsm->mtd.writesize; 21038c2ecf20Sopenharmony_ci fsm->mtd.flags = MTD_CAP_NORFLASH; 21048c2ecf20Sopenharmony_ci fsm->mtd.size = info->sector_size * info->n_sectors; 21058c2ecf20Sopenharmony_ci fsm->mtd.erasesize = info->sector_size; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci fsm->mtd._read = stfsm_mtd_read; 21088c2ecf20Sopenharmony_ci fsm->mtd._write = stfsm_mtd_write; 21098c2ecf20Sopenharmony_ci fsm->mtd._erase = stfsm_mtd_erase; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 21128c2ecf20Sopenharmony_ci "Found serial flash device: %s\n" 21138c2ecf20Sopenharmony_ci " size = %llx (%lldMiB) erasesize = 0x%08x (%uKiB)\n", 21148c2ecf20Sopenharmony_ci info->name, 21158c2ecf20Sopenharmony_ci (long long)fsm->mtd.size, (long long)(fsm->mtd.size >> 20), 21168c2ecf20Sopenharmony_ci fsm->mtd.erasesize, (fsm->mtd.erasesize >> 10)); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci ret = mtd_device_register(&fsm->mtd, NULL, 0); 21198c2ecf20Sopenharmony_ci if (ret) { 21208c2ecf20Sopenharmony_cierr_clk_unprepare: 21218c2ecf20Sopenharmony_ci clk_disable_unprepare(fsm->clk); 21228c2ecf20Sopenharmony_ci } 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci return ret; 21258c2ecf20Sopenharmony_ci} 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_cistatic int stfsm_remove(struct platform_device *pdev) 21288c2ecf20Sopenharmony_ci{ 21298c2ecf20Sopenharmony_ci struct stfsm *fsm = platform_get_drvdata(pdev); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci return mtd_device_unregister(&fsm->mtd); 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 21358c2ecf20Sopenharmony_cistatic int stfsmfsm_suspend(struct device *dev) 21368c2ecf20Sopenharmony_ci{ 21378c2ecf20Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(dev); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci clk_disable_unprepare(fsm->clk); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci return 0; 21428c2ecf20Sopenharmony_ci} 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_cistatic int stfsmfsm_resume(struct device *dev) 21458c2ecf20Sopenharmony_ci{ 21468c2ecf20Sopenharmony_ci struct stfsm *fsm = dev_get_drvdata(dev); 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci return clk_prepare_enable(fsm->clk); 21498c2ecf20Sopenharmony_ci} 21508c2ecf20Sopenharmony_ci#endif 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(stfsm_pm_ops, stfsmfsm_suspend, stfsmfsm_resume); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_cistatic const struct of_device_id stfsm_match[] = { 21558c2ecf20Sopenharmony_ci { .compatible = "st,spi-fsm", }, 21568c2ecf20Sopenharmony_ci {}, 21578c2ecf20Sopenharmony_ci}; 21588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stfsm_match); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_cistatic struct platform_driver stfsm_driver = { 21618c2ecf20Sopenharmony_ci .probe = stfsm_probe, 21628c2ecf20Sopenharmony_ci .remove = stfsm_remove, 21638c2ecf20Sopenharmony_ci .driver = { 21648c2ecf20Sopenharmony_ci .name = "st-spi-fsm", 21658c2ecf20Sopenharmony_ci .of_match_table = stfsm_match, 21668c2ecf20Sopenharmony_ci .pm = &stfsm_pm_ops, 21678c2ecf20Sopenharmony_ci }, 21688c2ecf20Sopenharmony_ci}; 21698c2ecf20Sopenharmony_cimodule_platform_driver(stfsm_driver); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ciMODULE_AUTHOR("Angus Clark <angus.clark@st.com>"); 21728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ST SPI FSM driver"); 21738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2174