// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2005, Intec Automation Inc.
* Copyright (C) 2014, Freescale Semiconductor, Inc.
*/
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/mtd/spi-nor.h>
#include "core.h"
#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb)
#define SFDP_PARAM_HEADER_PTP(p) \
(((p)->parameter_table_pointer[2] << 16) | \
((p)->parameter_table_pointer[1] << 8) | \
((p)->parameter_table_pointer[0] << 0))
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
#define SFDP_4BAIT_ID 0xff84 /* 4-byte Address Instruction Table */
#define SFDP_SIGNATURE 0x50444653U
struct sfdp_header {
u32 signature; /* Ox50444653U <=> "SFDP" */
u8 minor;
u8 major;
u8 nph; /* 0-base number of parameter headers */
u8 unused;
/* Basic Flash Parameter Table. */
struct sfdp_parameter_header bfpt_header;
};
/* Fast Read settings. */
struct sfdp_bfpt_read {
/* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */
u32 hwcaps;
/*
* The <supported_bit> bit in <supported_dword> BFPT DWORD tells us
* whether the Fast Read x-y-z command is supported.
*/
u32 supported_dword;
u32 supported_bit;
/*
* The half-word at offset <setting_shift> in <setting_dword> BFPT DWORD
* encodes the op code, the number of mode clocks and the number of wait
* states to be used by Fast Read x-y-z command.
*/
u32 settings_dword;
u32 settings_shift;
/* The SPI protocol for this Fast Read x-y-z command. */
enum spi_nor_protocol proto;
};
struct sfdp_bfpt_erase {
/*
* The half-word at offset <shift> in DWORD <dwoard> encodes the
* op code and erase sector size to be used by Sector Erase commands.
*/
u32 dword;
u32 shift;
};
#define SMPT_CMD_ADDRESS_LEN_MASK GENMASK(23, 22)
#define SMPT_CMD_ADDRESS_LEN_0 (0x0UL << 22)
#define SMPT_CMD_ADDRESS_LEN_3 (0x1UL << 22)
#define SMPT_CMD_ADDRESS_LEN_4 (0x2UL << 22)
#define SMPT_CMD_ADDRESS_LEN_USE_CURRENT (0x3UL << 22)
#define SMPT_CMD_READ_DUMMY_MASK GENMASK(19, 16)
#define SMPT_CMD_READ_DUMMY_SHIFT 16
#define SMPT_CMD_READ_DUMMY(_cmd) \
(((_cmd) & SMPT_CMD_READ_DUMMY_MASK) >> SMPT_CMD_READ_DUMMY_SHIFT)
#define SMPT_CMD_READ_DUMMY_IS_VARIABLE 0xfUL
#define SMPT_CMD_READ_DATA_MASK GENMASK(31, 24)
#define SMPT_CMD_READ_DATA_SHIFT 24
#define SMPT_CMD_READ_DATA(_cmd) \
(((_cmd) & SMPT_CMD_READ_DATA_MASK) >> SMPT_CMD_READ_DATA_SHIFT)
#define SMPT_CMD_OPCODE_MASK GENMASK(15, 8)
#define SMPT_CMD_OPCODE_SHIFT 8
#define SMPT_CMD_OPCODE(_cmd) \
(((_cmd) & SMPT_CMD_OPCODE_MASK) >> SMPT_CMD_OPCODE_SHIFT)
#define SMPT_MAP_REGION_COUNT_MASK GENMASK(23, 16)
#define SMPT_MAP_REGION_COUNT_SHIFT 16
#define SMPT_MAP_REGION_COUNT(_header) \
((((_header) & SMPT_MAP_REGION_COUNT_MASK) >> \
SMPT_MAP_REGION_COUNT_SHIFT) + 1)
#define SMPT_MAP_ID_MASK GENMASK(15, 8)
#define SMPT_MAP_ID_SHIFT 8
#define SMPT_MAP_ID(_header) \
(((_header) & SMPT_MAP_ID_MASK) >> SMPT_MAP_ID_SHIFT)
#define SMPT_MAP_REGION_SIZE_MASK GENMASK(31, 8)
#define SMPT_MAP_REGION_SIZE_SHIFT 8
#define SMPT_MAP_REGION_SIZE(_region) \
(((((_region) & SMPT_MAP_REGION_SIZE_MASK) >> \
SMPT_MAP_REGION_SIZE_SHIFT) + 1) * 256)
#define SMPT_MAP_REGION_ERASE_TYPE_MASK GENMASK(3, 0)
#define SMPT_MAP_REGION_ERASE_TYPE(_region) \
((_region) & SMPT_MAP_REGION_ERASE_TYPE_MASK)
#define SMPT_DESC_TYPE_MAP BIT(1)
#define SMPT_DESC_END BIT(0)
#define SFDP_4BAIT_DWORD_MAX 2
struct sfdp_4bait {
/* The hardware capability. */
u32 hwcaps;
/*
* The <supported_bit> bit in DWORD1 of the 4BAIT tells us whether
* the associated 4-byte address op code is supported.
*/
u32 supported_bit;
};
/**
* spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
* addr_width and read_dummy members of the struct spi_nor
* should be previously
* set.
* @nor: pointer to a 'struct spi_nor'
* @addr: offset in the serial flash memory
* @len: number of bytes to read
* @buf: buffer where the data is copied into (dma-safe memory)
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf)
{
ssize_t ret;
while (len) {
ret = spi_nor_read_data(nor, addr, len, buf);
if (ret < 0)
return ret;
if (!ret || ret > len)
return -EIO;
buf += ret;
addr += ret;
len -= ret;
}
return 0;
}
/**
* spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
* @addr: offset in the SFDP area to start reading data from
* @len: number of bytes to read
* @buf: buffer where the SFDP data are copied into (dma-safe memory)
*
* Whatever the actual numbers of bytes for address and dummy cycles are
* for (Fast) Read commands, the Read SFDP (5Ah) instruction is always
* followed by a 3-byte address and 8 dummy clock cycles.
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
size_t len, void *buf)
{
u8 addr_width, read_opcode, read_dummy;
int ret;
read_opcode = nor->read_opcode;
addr_width = nor->addr_width;