tegrakernel/kernel/kernel-4.9/drivers/mtd/devices/qspi_mtd.c

2231 lines
54 KiB
C
Raw Normal View History

2022-02-16 09:13:02 -06:00
/*
* MTD SPI driver for qspi flash chips
*
* Author: Mike Lavender, mike@steroidmicros.com
* Copyright (c) 2005, Intec Automation Inc.
* Copyright (c) 2013-2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/math64.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mod_devicetable.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/of_platform.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/mtd/qspi_mtd.h>
/*
* NOTE: Below Macro is used to optimize the QPI/QUAD mode switch logic...
* - QPI/QUAD mode is used for flash write. QUAD mode is used for flash read.
* - When QPI is enabled, QUAD is don't care.
* - If below macro is disabled...
* o QPI/QUAD mode is enabled/disabled at the start/end of each flash write
* function call.
* o QUAD mode is enabled/disabled at the start/end of each flash read
* function call.
* - If below macro is enabled...
* o QPI/QUAD mode is enabled at the start of flash write. QPI/QUAD mode is
* disabled whenever erase is invoked. QPI mode is disabled on read.
* o QUAD mode is enabled at the start of flash read. QUAD mode is disabled
* whenever erase is invoked. QUAD is don't care in QPI mode.
*/
#define QMODE_SWITCH_OPTIMIZED
#define COMMAND_WIDTH 1
#define ADDRESS_WIDTH 4
#define WE_RETRY_COUNT 200
#define WIP_RETRY_COUNT 2000000
#define QUAD_ENABLE_WAIT_TIME 1000
#define WRITE_ENABLE_WAIT_TIME 10
#define WRITE_ENABLE_SLEEP_TIME 10
#define WIP_ENABLE_WAIT_TIME 10
#define WIP_ENABLE_SLEEP_TIME 50
#define BITS8_PER_WORD 8
#define BITS16_PER_WORD 16
#define BITS32_PER_WORD 32
#define RWAR_SR1NV 0x0
#define RWAR_CR1NV 0x2
#define RWAR_SR1V 0x00800000
#define RWAR_CR1V 0x00800002
#define RWAR_CR2V 0x00800003
#define RWAR_CR3V 0x00800004
#define WRAR 0x71
#define SR1NV_WRITE_DIS (1<<7)
#define SR1NV_BLOCK_PROT (0x7<<2)
#define CR3V_512PAGE_SIZE (1<<4)
#define RDCR_DUMMY_CYCLE (3<<6)
#define JEDEC_ID_S25FX512S 0x010220
#define JEDEC_ID_S25FS256S 0x010219
#define JEDEC_ID_MX25U51279G 0xC2953A
#define JEDEC_ID_MX75U25690F 0xC22939
#define JEDEC_ID_MX25U3235F 0xC22536
static uint8_t macronix_device_id;
static int qspi_write_en(struct qspi *flash,
uint8_t is_enable, uint8_t is_sleep);
static int wait_till_ready(struct qspi *flash, uint8_t is_sleep);
static int qspi_read_any_reg(struct qspi *flash,
uint32_t regaddr, uint8_t *pdata);
static int qspi_write_any_reg(struct qspi *flash,
uint32_t regaddr, uint8_t data);
static void set_mode(struct spi_transfer *tfr, uint8_t is_ddr,
uint8_t bus_width, uint8_t op_code);
static inline struct qspi *mtd_to_qspi(struct mtd_info *mtd)
{
return container_of(mtd, struct qspi, mtd);
}
#ifdef QSPI_BRINGUP_BUILD
static int max_qpi_set(struct qspi *flash, uint8_t is_set)
{
uint8_t tx_buf[1];
int err, status = PASS;
struct spi_message m;
struct spi_transfer t;
uint8_t code;
code = (is_set) ? OPCODE_QPI_ENABLE : OPCODE_QPI_DISABLE;
tx_buf[0] = code;
spi_message_init(&m);
memset(&t, 0, sizeof(t));
t.len = COMMAND_WIDTH;
t.tx_buf = tx_buf;
t.bits_per_word = BITS8_PER_WORD;
set_mode(&t, FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t, &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed %d", __func__, err);
status = FAIL;
}
return status;
}
/*
* Enable/ Disable QPI Mode. Shall be called with
* 1. flash->lock taken.
* 2. WIP bit cleared
*/
static int qspi_qpi_flag_set(struct qspi *flash, uint8_t is_set)
{
uint8_t regval;
int status = PASS;
dev_dbg(&flash->spi->dev, "%s %d\n", __func__, is_set);
if (((flash->curr_cmd_mode == X4) && is_set) ||
((flash->curr_cmd_mode == X1) && !is_set)) {
return status;
}
if (flash->flash_info->jedec_id == JEDEC_ID_MX25U51279G) {
max_qpi_set(flash, is_set);
} else {
status = qspi_read_any_reg(flash, RWAR_CR2V, &regval);
if (status) {
dev_err(&flash->spi->dev,
"error: %s CR2V read failed: ", __func__);
dev_err(&flash->spi->dev,
"bset: %d, status: x%x\n", is_set, status);
return status;
}
if (is_set)
regval |= QPI_ENABLE;
else
regval &= ~QPI_ENABLE;
status = qspi_write_any_reg(flash, RWAR_CR2V, regval);
if (status) {
dev_err(&flash->spi->dev,
"error: %s CR2V write failed: ", __func__);
dev_err(&flash->spi->dev,
"bset: %d, status: x%x\n", is_set, status);
return status;
}
}
if (is_set)
flash->curr_cmd_mode = X4;
else
flash->curr_cmd_mode = X1;
status = wait_till_ready(flash, FALSE);
if (status) {
dev_err(&flash->spi->dev,
"error: %s: WIP failed: ", __func__);
dev_err(&flash->spi->dev,
"bset:%d, status: x%x\n", is_set, status);
}
return status;
}
static ssize_t force_sdr_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct qspi *flash = dev_get_drvdata(dev);
if (flash && count) {
flash->force_sdr = ((buf[0] - '0') > 0);
return count;
}
return -ENODEV;
}
static ssize_t force_sdr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct qspi *flash = dev_get_drvdata(dev);
return sprintf(buf, "%d", flash->force_sdr);
return -ENODEV;
}
static DEVICE_ATTR(qspi_force_sdr, 0644, force_sdr_show,
force_sdr_set);
static ssize_t qspi_mode_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct qspi *flash = dev_get_drvdata(dev);
u16 mode;
if (flash && count) {
mode = (buf[0] - '0') & (SPI_CPHA|SPI_CPOL);
flash->spi->mode &= ~(SPI_CPHA|SPI_CPOL);
flash->spi->mode |= mode;
return count;
}
return -ENODEV;
}
static ssize_t qspi_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct qspi *flash = dev_get_drvdata(dev);
u16 mode = flash->spi->mode & (SPI_CPHA|SPI_CPOL);
return sprintf(buf, "%d\n", mode);
}
static DEVICE_ATTR(qspi_mode, 0644, qspi_mode_show, qspi_mode_set);
static ssize_t enable_qpi_mode_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct qspi *flash = dev_get_drvdata(dev);
if (flash && count) {
flash->enable_qpi_mode = ((buf[0] - '0') > 0);
if (flash->enable_qpi_mode)
qspi_qpi_flag_set(flash, TRUE);
else
qspi_qpi_flag_set(flash, FALSE);
return count;
}
return -ENODEV;
}
static ssize_t enable_qpi_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct qspi *flash = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", flash->enable_qpi_mode);
}
static DEVICE_ATTR(qspi_enable_qpi_mode, 0644, enable_qpi_mode_show,
enable_qpi_mode_set);
static ssize_t force_bus_width_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct qspi *flash = dev_get_drvdata(dev);
u8 bus_width;
if (flash && count) {
bus_width = buf[0] - '0';
flash->override_bus_width = 1;
switch (bus_width) {
case 1:
flash->qspi_bus_width = X1;
break;
case 2:
flash->qspi_bus_width = X2;
break;
case 4:
flash->qspi_bus_width = X4;
break;
default:
flash->override_bus_width = 0;
break;
}
return count;
}
return -ENODEV;
}
static ssize_t force_bus_width_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct qspi *flash = dev_get_drvdata(dev);
char *bus_width_str = "invalid";
switch (flash->qspi_bus_width) {
case X1:
bus_width_str = "X1";
break;
case X2:
bus_width_str = "X2";
break;
case X4:
bus_width_str = "X4";
break;
default:
bus_width_str = "invalid";
break;
}
return sprintf(buf, "overide = %d bus_width = %s\n",
flash->override_bus_width, bus_width_str);
return -ENODEV;
}
static DEVICE_ATTR(qspi_force_bus_width, 0644, force_bus_width_show,
force_bus_width_set);
static ssize_t bits_per_word_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qspi *flash;
u16 bits_per_word;
char tmp;
int8_t read;
/* Read upto a maximum of 3 characters. */
const int8_t MAX_READ = 3;
if (dev == NULL || buf == NULL)
return -EINVAL;
flash = dev_get_drvdata(dev);
if (flash == NULL)
return -ENODEV;
bits_per_word = 0;
read = (int8_t) ((count <= MAX_READ) ? count : MAX_READ);
while (read-- > 0) {
tmp = *buf++;
if (tmp < '0' || tmp > '9')
break;
bits_per_word = bits_per_word * 10 + (tmp - '0');
}
/* Set iff the input is a valid BPW. */
if (bits_per_word == BITS8_PER_WORD ||
bits_per_word == BITS16_PER_WORD ||
bits_per_word == BITS32_PER_WORD)
flash->qspi_bits_per_word = (u8) bits_per_word;
return count;
}
static ssize_t bits_per_word_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qspi *flash;
if (dev == NULL || buf == NULL)
return -EINVAL;
flash = dev_get_drvdata(dev);
if (flash == NULL)
return -ENODEV;
return sprintf(buf, "%u", flash->qspi_bits_per_word);
}
static DEVICE_ATTR(qspi_bits_per_word, 0644, bits_per_word_show,
bits_per_word_set);
static struct attribute *qspi_mtd_attrs[] = {
&dev_attr_qspi_force_sdr.attr,
&dev_attr_qspi_mode.attr,
&dev_attr_qspi_enable_qpi_mode.attr,
&dev_attr_qspi_force_bus_width.attr,
&dev_attr_qspi_bits_per_word.attr,
NULL,
};
ATTRIBUTE_GROUPS(qspi_mtd);
#endif
/*
* Set Mode for transfer request
* Function sets Bus width, DDR/SDR and opcode
*/
static void set_mode(struct spi_transfer *tfr, uint8_t is_ddr,
uint8_t bus_width, uint8_t op_code)
{
tfr->delay_usecs = set_op_mode(op_code) | set_bus_width(bus_width);
if (is_ddr)
tfr->delay_usecs |= set_sdr_ddr;
}
/*
* Copy Paramters from default command table
* Command table contains command, address and data
* related information associated with opcode
*/
static void copy_cmd_default(struct qcmdset *qcmd, struct qcmdset *cmd_table)
{
qcmd->qcmd.op_code = cmd_table->qcmd.op_code;
qcmd->qcmd.is_ddr = cmd_table->qcmd.is_ddr;
qcmd->qcmd.bus_width = cmd_table->qcmd.bus_width;
qcmd->qcmd.post_txn = cmd_table->qcmd.post_txn;
qcmd->qaddr.address = cmd_table->qaddr.address;
qcmd->qaddr.is_ddr = cmd_table->qaddr.is_ddr;
qcmd->qaddr.len = cmd_table->qaddr.len;
qcmd->qaddr.bus_width = cmd_table->qaddr.bus_width;
qcmd->qaddr.dummy_cycles = cmd_table->qaddr.dummy_cycles;
qcmd->qdata.is_ddr = cmd_table->qdata.is_ddr;
qcmd->qdata.bus_width = cmd_table->qdata.bus_width;
}
static int max_enable_4byte(struct qspi *flash)
{
uint8_t tx_buf[1];
int err, status = PASS;
struct spi_message m;
struct spi_transfer t;
uint8_t code = OPCODE_4BYTE_ENABLE;
tx_buf[0] = code;
spi_message_init(&m);
memset(&t, 0, sizeof(t));
t.len = COMMAND_WIDTH;
t.tx_buf = tx_buf;
t.bits_per_word = BITS8_PER_WORD;
set_mode(&t, FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t, &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed %d", __func__, err);
status = FAIL;
}
return status;
}
/*
* Copy Paramters from default command table
* Command table contains command, address and data
* related information associated with opcode
*/
static int read_sr1_reg(struct qspi *flash, uint8_t *regval)
{
uint8_t tx_buf[1], rx_buf[1];
int status = PASS, err;
struct spi_transfer t[2];
struct spi_message m;
uint8_t code = RDSR1;
spi_message_init(&m);
memset(t, 0, sizeof(t));
tx_buf[0] = code;
t[0].len = COMMAND_WIDTH;
t[0].tx_buf = tx_buf;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0], FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t[0], &m);
t[1].len = COMMAND_WIDTH;
t[1].rx_buf = rx_buf;
t[1].bits_per_word = BITS8_PER_WORD;
set_mode(&t[1], FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t[1], &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed %d",
__func__, status);
status = FAIL;
}
*regval = rx_buf[0];
return status;
}
static int read_max_cfg_reg(struct qspi *flash, uint8_t *regval)
{
uint8_t rx_buf[1], tx_buf[1];
int err, status = PASS;
struct spi_message m;
struct spi_transfer t[2];
uint8_t code = MX_RDCR;
tx_buf[0] = code;
spi_message_init(&m);
memset(t, 0, sizeof(t));
t[0].len = COMMAND_WIDTH;
t[0].tx_buf = tx_buf;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0], FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t[0], &m);
t[1].len = COMMAND_WIDTH;
t[1].rx_buf = rx_buf;
t[1].bits_per_word = BITS8_PER_WORD;
set_mode(&t[1], FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t[1], &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed %d", __func__, err);
status = FAIL;
}
*regval = rx_buf[0];
return status;
}
static int qspi_write_status_cfgr_reg(struct qspi *flash, uint8_t sr,
uint8_t cfgr, bool write_cfg)
{
uint8_t tx_buf[3];
int err, status = PASS;
struct spi_message m;
struct spi_transfer t;
uint8_t code = MX_WRSR;
tx_buf[0] = code;
tx_buf[1] = sr;
if (write_cfg)
tx_buf[2] = cfgr;
err = qspi_write_en(flash, TRUE, FALSE);
if (err) {
dev_err(&flash->spi->dev, "%s: WE failed\n", __func__);
return err;
}
spi_message_init(&m);
memset(&t, 0, sizeof(t));
if (write_cfg)
t.len = COMMAND_WIDTH + 2;
else
t.len = COMMAND_WIDTH + 1;
t.tx_buf = tx_buf;
t.bits_per_word = BITS8_PER_WORD;
set_mode(&t, FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t, &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed %d", __func__, err);
status = FAIL;
}
return status;
}
static int qspi_write_status_reg(struct qspi *flash, uint8_t sr, uint8_t cfgr)
{
return qspi_write_status_cfgr_reg(flash, sr, cfgr, TRUE);
}
/*
* Function to read mutiple bytes for eg
* can be used for RDID command
*/
static __maybe_unused int read_multi(struct qspi *flash, uint8_t code,
uint8_t *buff, uint32_t len)
{
int err = PASS;
struct spi_transfer t[2];
struct spi_message m;
spi_message_init(&m);
memset(t, 0, sizeof(t));
t[0].len = COMMAND_WIDTH;
t[0].tx_buf = &code;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0], FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t[0], &m);
t[1].len = len;
t[1].rx_buf = buff;
t[1].bits_per_word = BITS8_PER_WORD;
set_mode(&t[1], FALSE, flash->curr_cmd_mode, STATUS_READ);
spi_message_add_tail(&t[1], &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed %d",
__func__, err);
return err;
}
return err;
}
/*
* Function for WRAR command. Shall be called with
* 1. flash->lock taken.
* 2. WIP bit cleared
* NOTE: Caller needs to poll for WIP
*/
static int qspi_write_any_reg(struct qspi *flash,
uint32_t regaddr, uint8_t data)
{
uint8_t cmd_addr_buf[4];
struct spi_transfer t[3];
struct spi_message m;
struct qcmdset *cmd_table;
int err;
cmd_table = &flash->cmd_info_table[WRITE_ANY_REG];
err = qspi_write_en(flash, TRUE, FALSE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WE failed: reg:x%x data:x%x, Status: x%x ",
__func__, regaddr, data, err);
return err;
}
spi_message_init(&m);
memset(t, 0, sizeof(t));
cmd_addr_buf[0] = cmd_table->qcmd.op_code;
cmd_addr_buf[1] = (regaddr >> 16) & 0xFF;
cmd_addr_buf[2] = (regaddr >> 8) & 0xFF;
cmd_addr_buf[3] = regaddr & 0xFF;
t[0].tx_buf = cmd_addr_buf;
t[0].len = cmd_table->qaddr.len + 1;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0], cmd_table->qaddr.is_ddr,
flash->curr_cmd_mode, cmd_table->qcmd.op_code);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = &data;
t[1].len = 1;
t[1].bits_per_word = BITS8_PER_WORD;
set_mode(&t[1], cmd_table->qdata.is_ddr,
flash->curr_cmd_mode, cmd_table->qcmd.op_code);
t[1].cs_change = TRUE;
spi_message_add_tail(&t[1], &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync Failed: reg:x%x dat:x%x sts:x%x\n",
__func__, regaddr, data, err);
return err;
}
return err;
}
/*
* Function for RDAR command. Shall be called with
* 1. flash->lock taken.
* 2. WIP bit cleared
*/
static int qspi_read_any_reg(struct qspi *flash,
uint32_t regaddr, uint8_t *pdata)
{
uint8_t cmd_addr_buf[5];
struct spi_transfer t[3];
struct spi_message m;
struct qcmdset *cmd_table;
int err;
cmd_table = &flash->cmd_info_table[READ_ANY_REG];
spi_message_init(&m);
memset(t, 0, sizeof(t));
cmd_addr_buf[0] = cmd_table->qcmd.op_code;
cmd_addr_buf[1] = (regaddr >> 16) & 0xFF;
cmd_addr_buf[2] = (regaddr >> 8) & 0xFF;
cmd_addr_buf[3] = regaddr & 0xFF;
t[0].len = 1;
t[0].bits_per_word = BITS8_PER_WORD;
t[0].tx_buf = &cmd_addr_buf[0];
set_mode(&t[0], cmd_table->qcmd.is_ddr,
flash->curr_cmd_mode, cmd_table->qcmd.op_code);
spi_message_add_tail(&t[0], &m);
if (flash->curr_cmd_mode == X4)
t[1].len = cmd_table->qaddr.len +
4 * cmd_table->qaddr.dummy_cycles;
else
t[1].len = cmd_table->qaddr.len + cmd_table->qaddr.dummy_cycles;
t[1].bits_per_word = BITS8_PER_WORD;
t[1].tx_buf = &cmd_addr_buf[1];
set_mode(&t[1], cmd_table->qaddr.is_ddr,
flash->curr_cmd_mode, cmd_table->qcmd.op_code);
spi_message_add_tail(&t[1], &m);
t[2].len = 1;
t[2].bits_per_word = BITS8_PER_WORD;
t[2].rx_buf = pdata;
set_mode(&t[2], cmd_table->qdata.is_ddr,
flash->curr_cmd_mode, cmd_table->qcmd.op_code);
/* in-activate the cs at the end */
t[2].cs_change = TRUE;
spi_message_add_tail(&t[2], &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call Failed: ", __func__);
dev_err(&flash->spi->dev, "reg:x%x, Status: x%x ",
regaddr, err);
return err;
}
return 0;
}
static uint8_t qspi_flash_get_sfdp_id_macronix(struct qspi *flash)
{
struct spi_transfer t[3];
struct spi_message m;
int ret;
/* 3-byte address for getting SFDP-Value at address 0x0b from
* SFDP table. MSB first
*/
uint8_t cmd_addr_buf[4] = {0, 0, 0, SFDP_ADDR};
uint8_t rx_buff[2];
spi_message_init(&m);
memset(t, 0, sizeof(t));
/* take lock here to protect race condition
* in case of concurrent read and write with
* different cmd_mode selection.
*/
mutex_lock(&flash->lock);
/* Set Controller data Parameters
* Set DDR/SDR, X1/X4 and Dummy Cycles from DT
*/
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[READ_SFDP]);
cmd_addr_buf[0] = flash->cmd_table.qcmd.op_code;
t[0].len = 1;
t[0].bits_per_word = BITS8_PER_WORD;
t[0].tx_buf = &cmd_addr_buf[0];
set_mode(&t[0],
flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qcmd.bus_width,
flash->cmd_table.qcmd.op_code);
spi_message_add_tail(&t[0], &m);
t[1].len = ((flash->cmd_table.qaddr.len +
(flash->cmd_table.qaddr.dummy_cycles/8)));
t[1].bits_per_word = BITS8_PER_WORD;
t[1].tx_buf = &cmd_addr_buf[1];
set_mode(&t[1],
flash->cmd_table.qaddr.is_ddr,
flash->cmd_table.qaddr.bus_width,
flash->cmd_table.qcmd.op_code);
spi_message_add_tail(&t[1], &m);
t[2].len = 2;
t[2].bits_per_word = BITS8_PER_WORD;
t[2].rx_buf = rx_buff;
set_mode(&t[2],
flash->cmd_table.qdata.is_ddr,
flash->cmd_table.qdata.bus_width,
flash->cmd_table.qcmd.op_code);
/* in-activate the cs at the end */
t[2].cs_change = TRUE;
spi_message_add_tail(&t[2], &m);
ret = spi_sync(flash->spi, &m);
mutex_unlock(&flash->lock);
/* since rx_buff[0] has the SPDF value for address 0x0b, so return
* rx_buff[0]
*/
return rx_buff[0];
}
static int max_dummy_cyle_set(struct qspi *flash, uint8_t cmd_code, int dummy)
{
int status = PASS;
uint8_t my_status, my_cfg, dummy_code = 0;
if (cmd_code == flash->cmd_info_table[FAST_READ].qcmd.op_code) {
switch (dummy) {
case 6:
dummy_code = 2;
break;
case 8:
dummy_code = 1;
break;
case 10:
dummy_code = 0;
break;
}
}
if (cmd_code == flash->cmd_info_table[DUAL_IO_READ].qcmd.op_code) {
switch (dummy / 2) {
case 4:
dummy_code = 3;
break;
case 6:
dummy_code = 2;
break;
case 8:
dummy_code = 1;
break;
case 10:
dummy_code = 0;
break;
}
}
if (cmd_code == flash->cmd_info_table[QUAD_IO_READ].qcmd.op_code) {
switch (dummy / 4) {
case 4:
dummy_code = 2;
break;
case 6:
dummy_code = 3;
break;
case 8:
dummy_code = 1;
break;
case 10:
dummy_code = 0;
break;
}
}
if (cmd_code == flash->cmd_info_table[DDR_QUAD_IO_READ].qcmd.op_code) {
switch (dummy / 8) {
case 4:
dummy_code = 2;
break;
case 6:
dummy_code = 3;
break;
case 8:
dummy_code = 1;
break;
case 10:
dummy_code = 0;
break;
}
}
read_sr1_reg(flash, &my_status);
read_max_cfg_reg(flash, &my_cfg);
dev_dbg(&flash->spi->dev, "status:%02x, cfg:%02x\n", my_status, my_cfg);
if (macronix_device_id == SFDP_ID_MX25U3235F) {
my_cfg &= ~RDCR_DUMMY_CYCLE;
my_cfg |= dummy_code << 6;
} else if ((macronix_device_id == SFDP_ID_MX25U3232F) ||
(flash->flash_info->jedec_id == JEDEC_ID_MX75U25690F)) {
/* If DC[1:0]=0b11 for MX25U3232F sets, dummy-cycle increased
* from 6-cycle to 10-cycle
*/
my_cfg &= ~(3<<10);
my_cfg |= dummy_code << 10;
} else {
dev_err(&flash->spi->dev, "Invalid macronix_device_id:%x\n",
macronix_device_id);
return -EINVAL;
}
qspi_write_status_reg(flash, my_status, my_cfg);
read_sr1_reg(flash, &my_status);
read_max_cfg_reg(flash, &my_cfg);
dev_dbg(&flash->spi->dev, "status:%02x, cfg:%02x\n", my_status, my_cfg);
return status;
}
/*
* Enable/Disable QUAD flasg when QPI mode is disabled
* Shall be called with...
* 1. flash->lock taken.
* 2. WIP bit cleared
*/
static int qspi_quad_flag_set(struct qspi *flash, uint8_t is_set)
{
uint8_t regval;
int status = PASS;
uint8_t my_status, my_cfg;
dev_dbg(&flash->spi->dev, "%s %d\n", __func__, is_set);
if ((flash->is_quad_set && is_set) ||
(!flash->is_quad_set && !is_set)) {
return status;
}
if (flash->flash_info->jedec_id == JEDEC_ID_MX25U3235F) {
read_sr1_reg(flash, &my_status);
if (is_set)
my_status |= MX_QUAD_ENABLE;
else
my_status &= ~MX_QUAD_ENABLE;
qspi_write_status_cfgr_reg(flash, my_status, 0, FALSE);
} else if ((flash->flash_info->jedec_id == JEDEC_ID_MX25U51279G) ||
(flash->flash_info->jedec_id == JEDEC_ID_MX75U25690F)) {
read_sr1_reg(flash, &my_status);
read_max_cfg_reg(flash, &my_cfg);
if (is_set)
my_status |= MX_QUAD_ENABLE;
else
my_status &= ~MX_QUAD_ENABLE;
qspi_write_status_reg(flash, my_status, my_cfg);
read_sr1_reg(flash, &my_status);
read_max_cfg_reg(flash, &my_cfg);
} else {
status = qspi_read_any_reg(flash, RWAR_CR1V, &regval);
if (status) {
dev_err(&flash->spi->dev,
"error: %s CR1V read failed: ", __func__);
dev_err(&flash->spi->dev,
"bset: %d, status: x%x\n", is_set, status);
return status;
}
if (is_set)
regval |= QUAD_ENABLE;
else
regval &= ~QUAD_ENABLE;
status = qspi_write_any_reg(flash, RWAR_CR1V, regval);
if (status) {
dev_err(&flash->spi->dev,
"error: %s CR1V write failed: ", __func__);
dev_err(&flash->spi->dev,
"bset: %d, status: x%x\n", is_set, status);
return status;
}
}
status = wait_till_ready(flash, FALSE);
if (status) {
dev_err(&flash->spi->dev,
"error: %s: WIP failed: ", __func__);
dev_err(&flash->spi->dev,
"bset:%d, status: x%x\n", is_set, status);
}
flash->is_quad_set = is_set;
return status;
}
/*
* Enable/ Disable Write Enable Bit in Configuration Register
* Set WEL bit to 1 before Erase and Write Operations
*/
static int qspi_write_en(struct qspi *flash,
uint8_t is_enable, uint8_t is_sleep)
{
struct spi_transfer t[1];
uint8_t cmd_buf[5], regval;
int status = 0, err, tried = 0, comp;
struct spi_message m;
do {
if (tried++ == WE_RETRY_COUNT) {
dev_err(&flash->spi->dev,
"tired max times not changing WE bit\n");
return FAIL;
}
memset(t, 0, sizeof(t));
spi_message_init(&m);
if (is_enable) {
cmd_buf[0] = OPCODE_WRITE_ENABLE;
comp = WEL_ENABLE;
} else {
cmd_buf[0] = OPCODE_WRITE_DISABLE;
comp = WEL_DISABLE;
}
t[0].len = COMMAND_WIDTH;
t[0].tx_buf = cmd_buf;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0], FALSE, flash->curr_cmd_mode,
STATUS_READ);
spi_message_add_tail(&t[0], &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed x%x",
__func__, status);
return 1;
}
if (is_sleep)
msleep(WRITE_ENABLE_SLEEP_TIME);
else
udelay(WRITE_ENABLE_WAIT_TIME);
status = read_sr1_reg(flash, &regval);
if (status) {
dev_err(&flash->spi->dev,
"error: %s: RDSR1 failed: Status: x%x ",
__func__, status);
return status;
}
} while ((regval & WEL_ENABLE) != comp);
return status;
}
/*
* Wait till flash is ready for erase/write operations.
* Returns negative if error occurred.
*/
static int wait_till_ready(struct qspi *flash, uint8_t is_sleep)
{
uint8_t regval, status = PASS;
int tried = 0;
do {
if (tried++ == WIP_RETRY_COUNT) {
dev_err(&flash->spi->dev,
"tired max times not changing WIP bit\n");
return FAIL;
}
if ((tried % 20) == 0)
dev_dbg(&flash->spi->dev,
"Waiting in WIP iter: %d\n", tried);
if (is_sleep)
msleep(WIP_ENABLE_SLEEP_TIME);
else
udelay(WIP_ENABLE_WAIT_TIME);
status = read_sr1_reg(flash, &regval);
if (status) {
dev_err(&flash->spi->dev,
"error: %s: RDSR1 failed: Status: x%x ",
__func__, status);
return status;
}
} while ((regval & WIP_ENABLE) == WIP_ENABLE);
return status;
}
/*
* Erase the whole flash memory
*
* Returns 0 if successful, non-zero otherwise.
*/
static int erase_chip(struct qspi *flash)
{
uint8_t cmd_opcode;
struct spi_transfer t[1];
struct spi_message m;
int status;
dev_dbg(&flash->spi->dev, "%s %lldKiB\n", __func__,
(long long)(flash->mtd.size >> 10));
/* Send write enable, then erase commands. */
status = qspi_write_en(flash, TRUE, TRUE);
if (status) {
dev_err(&flash->spi->dev,
"error: %s: WE failed: Status: x%x ", __func__,
status);
return status;
}
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[ERASE_BULK]);
/* Set up command buffer. */
cmd_opcode = OPCODE_CHIP_ERASE;
spi_message_init(&m);
memset(t, 0, sizeof(t));
t[0].len = COMMAND_WIDTH;
t[0].bits_per_word = BITS8_PER_WORD;
t[0].tx_buf = &cmd_opcode;
t[0].cs_change = TRUE;
set_mode(&t[0], FALSE,
X1, cmd_opcode);
#ifdef QSPI_BRINGUP_BUILD
if (flash->enable_qpi_mode)
set_mode(&t[0], FALSE, flash->curr_cmd_mode, cmd_opcode);
#endif
spi_message_add_tail(&t[0], &m);
status = spi_sync(flash->spi, &m);
if (status < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed x%x", __func__, status);
return status;
}
status = wait_till_ready(flash, TRUE);
if (status) {
dev_err(&flash->spi->dev,
"error: %s: WIP failed: Status: x%x ", __func__,
status);
return status;
}
return 0;
}
/*
* Erase one sector of flash memory at offset ``offset'' which is any
* address within the sector which should be erased.
*
* Returns 0 if successful, non-zero otherwise.
*/
static int erase_sector(struct qspi *flash, u32 offset,
uint8_t erase_opcode, u32 size)
{
uint8_t cmd_addr_buf[5];
struct spi_transfer t[1];
struct spi_message m;
int err = 0;
dev_dbg(&flash->spi->dev, "%s %dKiB at 0x%08x\n", __func__,
size / 1024, offset);
/* Send write enable, then erase commands. */
err = qspi_write_en(flash, TRUE, TRUE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WE failed: Status: x%x ", __func__, err);
return err;
}
cmd_addr_buf[0] = erase_opcode;
if (flash->cmd_table.qaddr.len == 3) {
cmd_addr_buf[1] = (offset >> 16) & 0xFF;
cmd_addr_buf[2] = (offset >> 8) & 0xFF;
cmd_addr_buf[3] = offset & 0xFF;
} else {
cmd_addr_buf[1] = (offset >> 24) & 0xFF;
cmd_addr_buf[2] = (offset >> 16) & 0xFF;
cmd_addr_buf[3] = (offset >> 8) & 0xFF;
cmd_addr_buf[4] = offset & 0xFF;
}
spi_message_init(&m);
memset(t, 0, sizeof(t));
t[0].len = (COMMAND_WIDTH + flash->cmd_table.qaddr.len);
t[0].bits_per_word = BITS8_PER_WORD;
t[0].tx_buf = cmd_addr_buf;
t[0].cs_change = TRUE;
set_mode(&t[0], FALSE,
X1, flash->erase_opcode);
#ifdef QSPI_BRINGUP_BUILD
if (flash->enable_qpi_mode)
set_mode(&t[0], FALSE,
flash->curr_cmd_mode, flash->erase_opcode);
#endif
spi_message_add_tail(&t[0], &m);
err = spi_sync(flash->spi, &m);
if (err < 0) {
dev_err(&flash->spi->dev,
"error: %s spi_sync call failed x%x", __func__, err);
return err;
}
err = wait_till_ready(flash, TRUE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WIP failed: Status: x%x ", __func__, err);
return err;
}
return 0;
}
/****************************************************************************/
/*
* MTD Erase, Read and Write implementation
*/
/****************************************************************************/
/*
* Erase an address range on the flash chip. The address range may extend
* one or more erase sectors. Return an error is there is a problem erasing.
*/
static int qspi_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct qspi *flash = mtd_to_qspi(mtd);
u32 addr, len;
uint32_t rem;
dev_dbg(&flash->spi->dev, "%s at 0x%llx, len %lld\n", __func__,
(long long)instr->addr, (long long)instr->len);
div_u64_rem(instr->len, mtd->erasesize, &rem);
if (rem)
return -EINVAL;
addr = instr->addr;
len = instr->len;
mutex_lock(&flash->lock);
/* whole-chip erase? */
if (len == flash->mtd.size) {
if (erase_chip(flash)) {
instr->state = MTD_ERASE_FAILED;
mutex_unlock(&flash->lock);
return -EIO;
}
/* "sector"-at-a-time erase */
} else {
if (flash->flash_info->jedec_id == JEDEC_ID_MX75U25690F)
flash->cmd_info_table[ERASE_SECT].qaddr.len = 4;
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[ERASE_SECT]);
/* Set up command buffer. */
flash->erase_opcode = flash->cmd_table.qcmd.op_code;
while (len) {
if (erase_sector(flash, addr,
flash->erase_opcode, mtd->erasesize)) {
instr->state = MTD_ERASE_FAILED;
mutex_unlock(&flash->lock);
return -EIO;
}
/* Take care of subsectors erase if required */
if (flash->flash_info->n_subsectors) {
struct flash_info *flinfo = flash->flash_info;
u32 ssaddr = addr;
u32 eaddr = min((addr + mtd->erasesize),
flinfo->ss_endoffset);
while ((ssaddr >= flinfo->ss_soffset) &&
((ssaddr + flinfo->ss_size) <= eaddr)) {
dev_dbg(&flash->spi->dev,
"Erasing subblock @ x%x, ",
ssaddr);
dev_dbg(&flash->spi->dev, "len x%x\n",
flinfo->ss_size);
if (erase_sector(flash, ssaddr,
flinfo->ss_erase_opcode,
flinfo->ss_size)) {
instr->state = MTD_ERASE_FAILED;
mutex_unlock(&flash->lock);
return -EIO;
}
ssaddr += flinfo->ss_size;
}
}
addr += mtd->erasesize;
len -= mtd->erasesize;
}
}
mutex_unlock(&flash->lock);
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
return 0;
}
/*
* Read an address range from the flash chip. The address range
* may be any size provided it is within the physical boundaries.
*/
static int qspi_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct qspi *flash = mtd_to_qspi(mtd);
struct spi_transfer t[3];
struct spi_message m;
uint8_t merge_cmd_addr = FALSE;
uint8_t cmd_addr_buf[5];
int err;
struct tegra_qspi_device_controller_data *cdata
= flash->spi->controller_data;
#ifdef QSPI_BRINGUP_BUILD
u8 bytes_per_word = flash->qspi_bits_per_word / 8;
#endif
dev_dbg(&flash->spi->dev, "%s from 0x%08x, len %zd\n", __func__,
(u32)from, len);
if (!macronix_device_id &&
(flash->flash_info->jedec_id == JEDEC_ID_MX25U3235F)) {
macronix_device_id = qspi_flash_get_sfdp_id_macronix(flash);
}
spi_message_init(&m);
memset(t, 0, sizeof(t));
/* take lock here to protect race condition
* in case of concurrent read and write with
* different cmd_mode selection.
*/
mutex_lock(&flash->lock);
/* Set Controller data Parameters
* Set DDR/SDR, X1/X4 and Dummy Cycles from DT
*/
if (cdata) {
if (len > cdata->x1_len_limit) {
if (cdata->x4_is_ddr) {
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[DDR_QUAD_IO_READ]);
} else {
if (flash->flash_info->jedec_id ==
JEDEC_ID_MX75U25690F)
flash->cmd_info_table[QUAD_IO_READ].
qaddr.len = 4;
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[QUAD_IO_READ]);
}
} else {
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[FAST_READ]);
}
} else {
if (flash->flash_info->jedec_id == JEDEC_ID_MX75U25690F)
flash->cmd_info_table[QUAD_IO_READ].qaddr.len = 4;
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[QUAD_IO_READ]);
}
#ifdef QSPI_BRINGUP_BUILD
if (flash->force_sdr)
if (flash->cmd_table.qcmd.op_code ==
flash->cmd_info_table[DDR_QUAD_IO_READ].qcmd.op_code) {
if (flash->flash_info->jedec_id == JEDEC_ID_MX75U25690F)
flash->cmd_info_table[QUAD_IO_READ].qaddr.
len = 4;
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[QUAD_IO_READ]);
}
if (flash->override_bus_width) {
if (flash->force_sdr)
switch (flash->qspi_bus_width) {
case X1:
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[FAST_READ]);
break;
case X2:
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[DUAL_IO_READ]);
break;
case X4:
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[QUAD_IO_READ]);
break;
}
else
switch (flash->qspi_bus_width) {
case X1:
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[DDR_FAST_READ]);
break;
case X2:
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[DDR_DUAL_IO_READ]);
break;
case X4:
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[DDR_QUAD_IO_READ]);
break;
}
}
#endif
/* check if possible to merge cmd and address */
if ((flash->cmd_table.qcmd.is_ddr ==
flash->cmd_table.qaddr.is_ddr) &&
(flash->cmd_table.qcmd.bus_width ==
flash->cmd_table.qaddr.bus_width) &&
flash->cmd_table.qcmd.post_txn > 0) {
merge_cmd_addr = TRUE;
flash->cmd_table.qcmd.post_txn =
flash->cmd_table.qcmd.post_txn - 1;
}
cmd_addr_buf[0] = flash->cmd_table.qcmd.op_code;
if (flash->cmd_table.qaddr.len == 3) {
cmd_addr_buf[1] = (from >> 16) & 0xFF;
cmd_addr_buf[2] = (from >> 8) & 0xFF;
cmd_addr_buf[3] = from & 0xFF;
} else {
cmd_addr_buf[1] = (from >> 24) & 0xFF;
cmd_addr_buf[2] = (from >> 16) & 0xFF;
cmd_addr_buf[3] = (from >> 8) & 0xFF;
cmd_addr_buf[4] = from & 0xFF;
}
if (merge_cmd_addr) {
t[0].len = (flash->cmd_table.qaddr.len + 1
+ (flash->cmd_table.qaddr.dummy_cycles/8));
t[0].bits_per_word = BITS8_PER_WORD;
t[0].tx_buf = cmd_addr_buf;
set_mode(&t[0],
flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qcmd.bus_width,
flash->cmd_table.qcmd.op_code);
spi_message_add_tail(&t[0], &m);
t[1].len = len;
#ifdef QSPI_BRINGUP_BUILD
t[1].bits_per_word = ((t[1].len % bytes_per_word) == 0) ?
flash->qspi_bits_per_word :
BITS8_PER_WORD;
#else
t[1].bits_per_word = BITS8_PER_WORD;
#endif
t[1].rx_buf = buf;
set_mode(&t[1],
flash->cmd_table.qdata.is_ddr,
flash->cmd_table.qdata.bus_width,
flash->cmd_table.qcmd.op_code);
/* in-activate the cs at the end */
t[1].cs_change = TRUE;
spi_message_add_tail(&t[1], &m);
} else {
t[0].len = 1;
t[0].bits_per_word = BITS8_PER_WORD;
t[0].tx_buf = &cmd_addr_buf[0];
set_mode(&t[0],
flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qcmd.bus_width,
flash->cmd_table.qcmd.op_code);
spi_message_add_tail(&t[0], &m);
t[1].len = ((flash->cmd_table.qaddr.len +
(flash->cmd_table.qaddr.dummy_cycles/8)));
t[1].bits_per_word = BITS8_PER_WORD;
t[1].tx_buf = &cmd_addr_buf[1];
set_mode(&t[1],
flash->cmd_table.qaddr.is_ddr,
flash->cmd_table.qaddr.bus_width,
flash->cmd_table.qcmd.op_code);
spi_message_add_tail(&t[1], &m);
t[2].len = len;
#ifdef QSPI_BRINGUP_BUILD
t[2].bits_per_word = ((t[2].len % bytes_per_word) == 0) ?
flash->qspi_bits_per_word :
BITS8_PER_WORD;
#else
t[2].bits_per_word = BITS8_PER_WORD;
#endif
t[2].rx_buf = buf;
set_mode(&t[2],
flash->cmd_table.qdata.is_ddr,
flash->cmd_table.qdata.bus_width,
flash->cmd_table.qcmd.op_code);
/* in-activate the cs at the end */
t[2].cs_change = TRUE;
spi_message_add_tail(&t[2], &m);
}
if (flash->flash_info->jedec_id == JEDEC_ID_MX25U51279G ||
flash->flash_info->jedec_id == JEDEC_ID_MX25U3235F ||
flash->flash_info->jedec_id == JEDEC_ID_MX75U25690F) {
max_dummy_cyle_set(flash,
flash->cmd_table.qcmd.op_code,
flash->cmd_table.qaddr.dummy_cycles);
}
#ifdef QSPI_BRINGUP_BUILD
if (flash->enable_qpi_mode)
qspi_qpi_flag_set(flash, FALSE);
#endif
/* Enable QUAD bit before doing QUAD i/o operation */
if (flash->cmd_table.qdata.bus_width == X4) {
err = qspi_quad_flag_set(flash, TRUE);
if (err) {
mutex_unlock(&flash->lock);
return err;
}
}
spi_sync(flash->spi, &m);
*retlen = m.actual_length -
(flash->cmd_table.qaddr.len + 1 +
(flash->cmd_table.qaddr.dummy_cycles/8));
mutex_unlock(&flash->lock);
return 0;
}
static int qspi_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct qspi *flash = mtd_to_qspi(mtd);
u32 page_offset, page_size;
struct spi_transfer t[2];
struct spi_message m;
uint8_t cmd_addr_buf[5];
uint8_t opcode;
int err = 0;
u32 offset = (unsigned long)to;
struct tegra_qspi_device_controller_data *cdata =
flash->spi->controller_data;
#ifdef QSPI_BRINGUP_BUILD
u8 bytes_per_word = flash->qspi_bits_per_word / 8;
#endif
dev_dbg(&flash->spi->dev, "%s to 0x%08x, len %zd\n", __func__, (u32)to,
len);
mutex_lock(&flash->lock);
if (flash->flash_info->jedec_id == JEDEC_ID_MX75U25690F)
flash->cmd_info_table[PAGE_PROGRAM].qaddr.len = 4;
/* Set Controller data Parameters
* Set DDR/SDR, X1/X4 and Dummy Cycles from DT
*/
if (cdata) {
if (len > cdata->x1_len_limit) {
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[PAGE_PROGRAM]);
} else {
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[PAGE_PROGRAM]);
}
} else {
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[PAGE_PROGRAM]);
}
#ifdef QSPI_BRINGUP_BUILD
if (flash->enable_qpi_mode) {
copy_cmd_default(&flash->cmd_table,
&flash->cmd_info_table[QPI_PAGE_PROGRAM]);
}
#endif
cmd_addr_buf[0] = opcode = flash->cmd_table.qcmd.op_code;
if (flash->cmd_table.qaddr.len != 4) {
cmd_addr_buf[1] = (offset >> 16) & 0xFF;
cmd_addr_buf[2] = (offset >> 8) & 0xFF;
cmd_addr_buf[3] = offset & 0xFF;
} else {
cmd_addr_buf[1] = (offset >> 24) & 0xFF;
cmd_addr_buf[2] = (offset >> 16) & 0xFF;
cmd_addr_buf[3] = (offset >> 8) & 0xFF;
cmd_addr_buf[4] = offset & 0xFF;
}
page_offset = offset & (flash->page_size - 1);
/* do all the bytes fit onto one page? */
if (page_offset + len <= flash->page_size) {
spi_message_init(&m);
memset(t, 0, sizeof(t));
t[0].tx_buf = cmd_addr_buf;
t[0].len = flash->cmd_table.qaddr.len + 1;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0], flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qcmd.bus_width, opcode);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
t[1].len = len;
#ifdef QSPI_BRINGUP_BUILD
t[1].bits_per_word = ((t[1].len % bytes_per_word) == 0) ?
flash->qspi_bits_per_word :
BITS8_PER_WORD;
#else
t[1].bits_per_word = BITS8_PER_WORD;
#endif
set_mode(&t[1], flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qdata.bus_width, opcode);
t[1].cs_change = TRUE;
spi_message_add_tail(&t[1], &m);
/* Wait until finished previous write command. */
#ifdef QSPI_BRINGUP_BUILD
if (flash->enable_qpi_mode)
err = qspi_qpi_flag_set(flash, TRUE);
#endif
if (err) {
dev_err(&flash->spi->dev,
"error: %s: QPI/QUAD set failed: Status: x%x ",
__func__, err);
mutex_unlock(&flash->lock);
return err;
}
err = qspi_write_en(flash, TRUE, FALSE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WE failed: Status: x%x ",
__func__, err);
goto clear_qmode;
}
spi_sync(flash->spi, &m);
err = wait_till_ready(flash, FALSE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WIP failed: Status: x%x ",
__func__, err);
goto clear_qmode;
}
*retlen = m.actual_length - (flash->cmd_table.qaddr.len + 1);
clear_qmode:
mutex_unlock(&flash->lock);
return err;
} else {
u32 i;
spi_message_init(&m);
memset(t, 0, sizeof(t));
/* the size of data remaining on the first page */
page_size = flash->page_size - page_offset;
t[0].tx_buf = cmd_addr_buf;
t[0].len = flash->cmd_table.qaddr.len + 1;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0], flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qcmd.bus_width, opcode);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
t[1].len = page_size;
#ifdef QSPI_BRINGUP_BUILD
t[1].bits_per_word = ((t[1].len % bytes_per_word) == 0) ?
flash->qspi_bits_per_word :
BITS8_PER_WORD;
#else
t[1].bits_per_word = BITS8_PER_WORD;
#endif
set_mode(&t[1], flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qdata.bus_width, opcode);
t[1].cs_change = TRUE;
spi_message_add_tail(&t[1], &m);
#ifdef QSPI_BRINGUP_BUILD
if (flash->enable_qpi_mode)
err = qspi_qpi_flag_set(flash, TRUE);
#endif
if (err) {
dev_err(&flash->spi->dev,
"error: %s: QPI/QUAD set failed: Status: x%x ",
__func__, err);
mutex_unlock(&flash->lock);
return 1;
}
err = qspi_write_en(flash, TRUE, FALSE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WE failed: Status: x%x ",
__func__, err);
goto clear_qmode1;
}
spi_sync(flash->spi, &m);
err = wait_till_ready(flash, FALSE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WIP failed: Status: x%x ",
__func__, err);
goto clear_qmode1;
}
*retlen = m.actual_length - (flash->cmd_table.qaddr.len + 1);
/* write everything in flash->page_size chunks */
for (i = page_size; i < len; i += page_size) {
page_size = len - i;
if (page_size > flash->page_size)
page_size = flash->page_size;
/* Need to check for auto address increment */
/* Check line no 584 to 597 code is required */
spi_message_init(&m);
memset(t, 0, sizeof(t));
offset = to + i;
/* write the next page to flash */
cmd_addr_buf[0] = opcode =
flash->cmd_table.qcmd.op_code;
if (flash->cmd_table.qaddr.len == 3) {
cmd_addr_buf[1] = (offset >> 16) & 0xFF;
cmd_addr_buf[2] = (offset >> 8) & 0xFF;
cmd_addr_buf[3] = offset & 0xFF;
} else {
cmd_addr_buf[1] = (offset >> 24) & 0xFF;
cmd_addr_buf[2] = (offset >> 16) & 0xFF;
cmd_addr_buf[3] = (offset >> 8) & 0xFF;
cmd_addr_buf[4] = offset & 0xFF;
}
t[0].tx_buf = cmd_addr_buf;
t[0].len = flash->cmd_table.qaddr.len + 1;
t[0].bits_per_word = BITS8_PER_WORD;
set_mode(&t[0],
flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qcmd.bus_width,
opcode);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = (buf + i);
t[1].len = page_size;
#ifdef QSPI_BRINGUP_BUILD
t[1].bits_per_word = ((t[1].len % bytes_per_word) ==
0) ? flash->qspi_bits_per_word :
BITS8_PER_WORD;
#else
t[1].bits_per_word = BITS8_PER_WORD;
#endif
set_mode(&t[1],
flash->cmd_table.qcmd.is_ddr,
flash->cmd_table.qdata.bus_width,
opcode);
t[1].cs_change = TRUE;
spi_message_add_tail(&t[1], &m);
err = qspi_write_en(flash, TRUE, FALSE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WE failed: Status: x%x ",
__func__, err);
goto clear_qmode1;
}
spi_sync(flash->spi, &m);
err = wait_till_ready(flash, FALSE);
if (err) {
dev_err(&flash->spi->dev,
"error: %s: WIP failed: Status: x%x ",
__func__, err);
goto clear_qmode1;
}
*retlen +=
m.actual_length -
(flash->cmd_table.qaddr.len + 1);
}
clear_qmode1:
mutex_unlock(&flash->lock);
return err;
}
}
static const struct spi_device_id *jedec_probe(struct spi_device *spi)
{
int tmp;
u8 code = OPCODE_RDID;
u8 id[5];
u32 jedec;
u16 ext_jedec;
struct flash_info *info;
/* JEDEC also defines an optional "extended device information"
* string for after vendor-specific data, after the three bytes
* we use here. Supporting some chips might require using it.
*/
tmp = spi_write_then_read(spi, &code, 1, id, 5);
if (tmp < 0) {
dev_dbg(&spi->dev, "error %d reading JEDEC ID\n", tmp);
return ERR_PTR(tmp);
}
jedec = id[0];
jedec = jedec << 8;
jedec |= id[1];
jedec = jedec << 8;
jedec |= id[2];
ext_jedec = id[3] << 8 | id[4];
for (tmp = 0; tmp < ARRAY_SIZE(qspi_ids) - 1; tmp++) {
info = (void *)qspi_ids[tmp].driver_data;
if (info->jedec_id == jedec) {
if (info->ext_id != 0 && info->ext_id != ext_jedec)
continue;
return &qspi_ids[tmp];
}
}
dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
return ERR_PTR(-ENODEV);
}
static int qspi_init(struct qspi *flash)
{
uint8_t regval;
int ret;
struct spi_device *spi = flash->spi;
const struct spi_device_id *id = spi_get_device_id(spi);
struct flash_info *info = (void *)id->driver_data;
dev_dbg(&spi->dev, "%s ENTRY\n", __func__);
if (info->jedec_id == JEDEC_ID_MX25U3235F) {
max_qpi_set(flash, FALSE);
return 0;
}
/*
* FIXME: Unlock the flash if locked. It is WAR to unlock the flash
* as locked bit is setting unexpectedly
*/
ret = qspi_read_any_reg(flash, RWAR_SR1NV, &regval);
if (ret) {
dev_err(&spi->dev,
"error: %s RWAR_CR2V read failed: Status: x%x ",
__func__, ret);
return ret;
}
if (regval & (SR1NV_WRITE_DIS | SR1NV_BLOCK_PROT)) {
regval = regval & ~(SR1NV_WRITE_DIS | SR1NV_BLOCK_PROT);
qspi_write_any_reg(flash, RWAR_SR1NV, regval);
wait_till_ready(flash, FALSE);
}
/* Set 512 page size when s25fx512s */
if ((info->jedec_id == JEDEC_ID_S25FX512S) && (info->page_size == 512)) {
ret = qspi_read_any_reg(flash, RWAR_CR3V, &regval);
if (ret) {
dev_err(&spi->dev,
"error: %s RWAR_CR3V read failed: Status: x%x ",
__func__, ret);
return ret;
}
if ((regval & CR3V_512PAGE_SIZE) == 0) {
regval = regval | CR3V_512PAGE_SIZE;
qspi_write_any_reg(flash, RWAR_CR3V, regval);
wait_till_ready(flash, FALSE);
}
}
if (info->jedec_id == JEDEC_ID_MX25U51279G ||
info->jedec_id == JEDEC_ID_MX75U25690F) {
max_qpi_set(flash, FALSE);
max_enable_4byte(flash);
}
dev_dbg(&spi->dev, "%s EXIT\n", __func__);
return 0;
}
static int qspi_probe(struct spi_device *spi)
{
const struct spi_device_id *id;
struct flash_platform_data *data;
struct qspi *flash;
struct flash_info *info;
unsigned i;
struct mtd_part_parser_data ppdata;
struct device_node __maybe_unused *np;
struct tegra_qspi_device_controller_data *cdata = spi->controller_data;
int ret;
id = spi_get_device_id(spi);
np = spi->dev.of_node;
#ifdef CONFIG_MTD_OF_PARTS
if (!of_device_is_available(np))
return -ENODEV;
#endif
data = spi->dev.platform_data;
if (data && data->type) {
const struct spi_device_id *plat_id;
for (i = 0; i < ARRAY_SIZE(qspi_ids) - 1; i++) {
plat_id = &qspi_ids[i];
if (strcmp(data->type, plat_id->name))
continue;
break;
}
if (i < ARRAY_SIZE(qspi_ids) - 1)
id = plat_id;
else
dev_warn(&spi->dev, "unrecognized id %s\n", data->type);
}
info = (void *)id->driver_data;
if (info->jedec_id) {
const struct spi_device_id *jid;
jid = jedec_probe(spi);
if (IS_ERR(jid)) {
return PTR_ERR(jid);
} else if (jid != id) {
dev_warn(&spi->dev, "found %s, expected %s\n",
jid->name, id->name);
id = jid;
info = (void *)jid->driver_data;
}
}
flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
if (!flash)
return -ENOMEM;
if (info->jedec_id == JEDEC_ID_MX25U51279G)
flash->cmd_info_table = macronix_cmd_info_table;
else if (info->jedec_id == JEDEC_ID_S25FX512S ||
info->jedec_id == JEDEC_ID_S25FS256S)
flash->cmd_info_table = spansion_cmd_info_table;
else if (info->jedec_id == JEDEC_ID_MX25U3235F ||
info->jedec_id == JEDEC_ID_MX75U25690F)
flash->cmd_info_table = macronix_porg_cmd_info_table;
else {
dev_err(&spi->dev, "error: %s: unsupported flash\n", __func__);
return -EINVAL;
}
flash->spi = spi;
flash->flash_info = info;
mutex_init(&flash->lock);
dev_set_drvdata(&spi->dev, flash);
/*
* Atmel, SST and Intel/Numonyx serial flash tend to power
* up with the software protection bits set
*/
if (data && data->name)
flash->mtd.name = data->name;
else
flash->mtd.name = dev_name(&spi->dev);
flash->mtd.type = MTD_NORFLASH;
flash->mtd.writesize = 1;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = info->sector_size * info->n_sectors;
flash->mtd._erase = qspi_erase;
flash->mtd._read = qspi_read;
flash->mtd._write = qspi_write;
flash->erase_opcode = OPCODE_SE;
flash->mtd.erasesize = info->sector_size;
flash->mtd.dev.parent = &spi->dev;
flash->page_size = info->page_size;
flash->mtd.writebufsize = flash->page_size;
mtd_set_of_node(&flash->mtd, spi->dev.of_node);
flash->addr_width = ADDRESS_WIDTH;
cdata = flash->spi->controller_data;
if (info->n_subsectors) {
info->ss_endoffset = info->ss_soffset +
info->ss_size * info->n_subsectors;
if (info->ss_endoffset > flash->mtd.size) {
dev_err(&spi->dev, "%s SSErr %x %x %x %llx\n", id->name,
info->n_subsectors, info->ss_soffset,
info->ss_size, flash->mtd.size);
ret = -EINVAL;
goto err_free_flash;
}
dev_info(&spi->dev, "%s SSG %x %x %x %llx\n", id->name,
info->n_subsectors, info->ss_soffset,
info->ss_size, flash->mtd.size);
}
dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
(long long)flash->mtd.size >> 10);
dev_info(&spi->dev,
"mtd .name = %s, .size = 0x%llx (%lldMiB) .erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
flash->mtd.name,
(long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
flash->mtd.erasesize, flash->mtd.erasesize / 1024,
flash->mtd.numeraseregions);
if (flash->mtd.numeraseregions)
for (i = 0; i < flash->mtd.numeraseregions; i++)
dev_info(&spi->dev,
"mtd.eraseregions[%d] ={.offset = 0x%llx,.erasesize = "
"0x%.8x (%uKiB),.numblocks = %d}\n",
i,
(long long)flash->mtd.eraseregions[i].offset,
flash->mtd.eraseregions[i].erasesize,
flash->mtd.eraseregions[i].erasesize / 1024,
flash->mtd.eraseregions[i].numblocks);
ret = qspi_init(flash);
if (ret != 0)
goto err_free_flash;
#ifdef QSPI_BRINGUP_BUILD
ret = sysfs_create_group(&spi->dev.kobj, qspi_mtd_groups[0]);
if (ret)
goto err_free_flash;
#endif
/* partitions should match sector boundaries; and it may be good to
* use readonly partitions for writeprotected sectors (BP2..BP0).
*/
ret = mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
data ? data->parts : NULL,
data ? data->nr_parts : 0);
if (ret < 0)
goto err_remove_qspi_attrs;
return ret;
err_remove_qspi_attrs:
sysfs_remove_group(&spi->dev.kobj, qspi_mtd_groups[0]);
err_free_flash:
return ret;
}
static int qspi_remove(struct spi_device *spi)
{
struct qspi *flash = dev_get_drvdata(&spi->dev);
#ifdef QSPI_BRINGUP_BUILD
sysfs_remove_group(&spi->dev.kobj, qspi_mtd_groups[0]);
#endif
mtd_device_unregister(&flash->mtd);
return 0;
}
#ifdef CONFIG_PM
static int qspi_suspend(struct device *dev)
{
int ret;
uint8_t regval;
struct qspi *flash = dev_get_drvdata(dev);
struct spi_device *spi = flash->spi;
const struct spi_device_id *id = spi_get_device_id(spi);
struct flash_info *info = (void *)id->driver_data;
dev_dbg(dev, "%s ENTRY\n", __func__);
/* configuration registers are not supported by macronix */
if (info->jedec_id == JEDEC_ID_MX25U3235F)
return 0;
ret = qspi_read_any_reg(flash, RWAR_CR1V, &regval);
if (ret) {
dev_err(&flash->spi->dev,
"error: %s CR1V read failed: status: %d", __func__, ret);
return ret;
}
flash->rwar_cr1v_value = regval;
ret = qspi_read_any_reg(flash, RWAR_CR2V, &regval);
if (ret) {
dev_err(&flash->spi->dev,
"error: %s CR2V read failed: status: %d", __func__, ret);
return ret;
}
flash->rwar_cr2v_value = regval;
return ret;
}
static int qspi_resume(struct device *dev)
{
int ret;
struct qspi *flash = dev_get_drvdata(dev);
struct spi_device *spi = flash->spi;
const struct spi_device_id *id = spi_get_device_id(spi);
struct flash_info *info = (void *)id->driver_data;
dev_dbg(dev, "%s ENTRY\n", __func__);
/* configuration registers are not supported by macronix */
if (info->jedec_id == JEDEC_ID_MX25U3235F)
return 0;
ret = qspi_init(flash);
if (ret) {
dev_err(dev,
"error: %s qspi_init failed: Status: %d ",
__func__, ret);
return ret;
}
ret = qspi_write_any_reg(flash, RWAR_CR1V, flash->rwar_cr1v_value );
if (ret) {
dev_err(&flash->spi->dev,
"error: %s CR1V write failed: status: %d", __func__, ret);
return ret;
}
ret = qspi_write_any_reg(flash, RWAR_CR2V, flash->rwar_cr2v_value );
if (ret) {
dev_err(&flash->spi->dev,
"error: %s CR2V write failed: status: %d", __func__, ret);
return ret;
}
/* set suspend status to false */
flash->suspend_status= false;
return ret;
}
#else /* CONFIG_PM */
#define qspi_suspend NULL
#define qspi_resume NULL
#endif /* CONFIG_PM */
static const struct dev_pm_ops qspi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(qspi_suspend, qspi_resume)
};
static struct spi_driver qspi_mtd_driver = {
.driver = {
.name = "qspi_mtd",
.owner = THIS_MODULE,
.pm = &qspi_pm_ops,
},
.id_table = qspi_ids,
.probe = qspi_probe,
.remove = qspi_remove,
};
module_spi_driver(qspi_mtd_driver);
MODULE_AUTHOR("Amlan Kundu <akundu@nvidia.com>, Ashutosh Patel <ashutoshp@nvidia.com>");
MODULE_DESCRIPTION("MTD SPI driver for Spansion/micron QSPI flash chips");
MODULE_LICENSE("GPL v2");