Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b9ef8f9 authored by Brian Norris's avatar Brian Norris
Browse files

Merge tag 'spi-nor/for-4.13' into MTD

From Cyrille:
"""
This pull request contains the following notable changes:
- introduce support to the SPI 1-2-2 and 1-4-4 protocols.
- introduce support to the Double Data Rate (DDR) mode.
- introduce support to the Octo SPI protocols.
- add support to new memory parts for Spansion, Macronix and Winbond.
- add fixes for the Aspeed, STM32 and Cadence QSPI controler drivers.
- clean up the st_spi_fsm driver.
"""
parents b9504247 9447332f
Loading
Loading
Loading
Loading
+87 −34
Original line number Diff line number Diff line
@@ -78,11 +78,17 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
{
	struct m25p *flash = nor->priv;
	struct spi_device *spi = flash->spi;
	struct spi_transfer t[2] = {};
	unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
	struct spi_transfer t[3] = {};
	struct spi_message m;
	int cmd_sz = m25p_cmdsz(nor);
	ssize_t ret;

	/* get transfer protocols. */
	inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto);
	addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto);
	data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto);

	spi_message_init(&m);

	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
@@ -92,13 +98,28 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
	m25p_addr2cmd(nor, to, flash->command);

	t[0].tx_buf = flash->command;
	t[0].tx_nbits = inst_nbits;
	t[0].len = cmd_sz;
	spi_message_add_tail(&t[0], &m);

	t[1].tx_buf = buf;
	t[1].len = len;
	/* split the op code and address bytes into two transfers if needed. */
	data_idx = 1;
	if (addr_nbits != inst_nbits) {
		t[0].len = 1;

		t[1].tx_buf = &flash->command[1];
		t[1].tx_nbits = addr_nbits;
		t[1].len = cmd_sz - 1;
		spi_message_add_tail(&t[1], &m);

		data_idx = 2;
	}

	t[data_idx].tx_buf = buf;
	t[data_idx].tx_nbits = data_nbits;
	t[data_idx].len = len;
	spi_message_add_tail(&t[data_idx], &m);

	ret = spi_sync(spi, &m);
	if (ret)
		return ret;
@@ -109,18 +130,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
	return ret;
}

static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
{
	switch (nor->flash_read) {
	case SPI_NOR_DUAL:
		return 2;
	case SPI_NOR_QUAD:
		return 4;
	default:
		return 0;
	}
}

/*
 * Read an address range from the nor chip.  The address range
 * may be any size provided it is within the physical boundaries.
@@ -130,13 +139,20 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
{
	struct m25p *flash = nor->priv;
	struct spi_device *spi = flash->spi;
	struct spi_transfer t[2];
	unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
	struct spi_transfer t[3];
	struct spi_message m;
	unsigned int dummy = nor->read_dummy;
	ssize_t ret;
	int cmd_sz;

	/* get transfer protocols. */
	inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto);
	addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto);
	data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto);

	/* convert the dummy cycles to the number of bytes */
	dummy /= 8;
	dummy = (dummy * addr_nbits) / 8;

	if (spi_flash_read_supported(spi)) {
		struct spi_flash_read_message msg;
@@ -149,10 +165,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
		msg.read_opcode = nor->read_opcode;
		msg.addr_width = nor->addr_width;
		msg.dummy_bytes = dummy;
		/* TODO: Support other combinations */
		msg.opcode_nbits = SPI_NBITS_SINGLE;
		msg.addr_nbits = SPI_NBITS_SINGLE;
		msg.data_nbits = m25p80_rx_nbits(nor);
		msg.opcode_nbits = inst_nbits;
		msg.addr_nbits = addr_nbits;
		msg.data_nbits = data_nbits;

		ret = spi_flash_read(spi, &msg);
		if (ret < 0)
@@ -167,20 +182,45 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
	m25p_addr2cmd(nor, from, flash->command);

	t[0].tx_buf = flash->command;
	t[0].tx_nbits = inst_nbits;
	t[0].len = m25p_cmdsz(nor) + dummy;
	spi_message_add_tail(&t[0], &m);

	t[1].rx_buf = buf;
	t[1].rx_nbits = m25p80_rx_nbits(nor);
	t[1].len = min3(len, spi_max_transfer_size(spi),
			spi_max_message_size(spi) - t[0].len);
	/*
	 * Set all dummy/mode cycle bits to avoid sending some manufacturer
	 * specific pattern, which might make the memory enter its Continuous
	 * Read mode by mistake.
	 * Based on the different mode cycle bit patterns listed and described
	 * in the JESD216B specification, the 0xff value works for all memories
	 * and all manufacturers.
	 */
	cmd_sz = t[0].len;
	memset(flash->command + cmd_sz - dummy, 0xff, dummy);

	/* split the op code and address bytes into two transfers if needed. */
	data_idx = 1;
	if (addr_nbits != inst_nbits) {
		t[0].len = 1;

		t[1].tx_buf = &flash->command[1];
		t[1].tx_nbits = addr_nbits;
		t[1].len = cmd_sz - 1;
		spi_message_add_tail(&t[1], &m);

		data_idx = 2;
	}

	t[data_idx].rx_buf = buf;
	t[data_idx].rx_nbits = data_nbits;
	t[data_idx].len = min3(len, spi_max_transfer_size(spi),
			       spi_max_message_size(spi) - cmd_sz);
	spi_message_add_tail(&t[data_idx], &m);

	ret = spi_sync(spi, &m);
	if (ret)
		return ret;

	ret = m.actual_length - m25p_cmdsz(nor) - dummy;
	ret = m.actual_length - cmd_sz;
	if (ret < 0)
		return -EIO;
	return ret;
@@ -196,7 +236,11 @@ static int m25p_probe(struct spi_device *spi)
	struct flash_platform_data	*data;
	struct m25p *flash;
	struct spi_nor *nor;
	enum read_mode mode = SPI_NOR_NORMAL;
	struct spi_nor_hwcaps hwcaps = {
		.mask = SNOR_HWCAPS_READ |
			SNOR_HWCAPS_READ_FAST |
			SNOR_HWCAPS_PP,
	};
	char *flash_name;
	int ret;

@@ -221,10 +265,19 @@ static int m25p_probe(struct spi_device *spi)
	spi_set_drvdata(spi, flash);
	flash->spi = spi;

	if (spi->mode & SPI_RX_QUAD)
		mode = SPI_NOR_QUAD;
	else if (spi->mode & SPI_RX_DUAL)
		mode = SPI_NOR_DUAL;
	if (spi->mode & SPI_RX_QUAD) {
		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;

		if (spi->mode & SPI_TX_QUAD)
			hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
					SNOR_HWCAPS_PP_1_1_4 |
					SNOR_HWCAPS_PP_1_4_4);
	} else if (spi->mode & SPI_RX_DUAL) {
		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;

		if (spi->mode & SPI_TX_DUAL)
			hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
	}

	if (data && data->name)
		nor->mtd.name = data->name;
@@ -241,7 +294,7 @@ static int m25p_probe(struct spi_device *spi)
	else
		flash_name = spi->modalias;

	ret = spi_nor_scan(nor, flash_name, mode);
	ret = spi_nor_scan(nor, flash_name, &hwcaps);
	if (ret)
		return ret;

+0 −1
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@
#define _MTD_SERIAL_FLASH_CMDS_H

/* Generic Flash Commands/OPCODEs */
#define SPINOR_OP_RDSR2		0x35
#define SPINOR_OP_WRVCR		0x81
#define SPINOR_OP_RDVCR		0x85

+2 −2
Original line number Diff line number Diff line
@@ -1445,7 +1445,7 @@ static int stfsm_s25fl_config(struct stfsm *fsm)
	}

	/* Check status of 'QE' bit, update if required. */
	stfsm_read_status(fsm, SPINOR_OP_RDSR2, &cr1, 1);
	stfsm_read_status(fsm, SPINOR_OP_RDCR, &cr1, 1);
	data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
	if (data_pads == 4) {
		if (!(cr1 & STFSM_S25FL_CONFIG_QE)) {
@@ -1490,7 +1490,7 @@ static int stfsm_w25q_config(struct stfsm *fsm)
		return ret;

	/* Check status of 'QE' bit, update if required. */
	stfsm_read_status(fsm, SPINOR_OP_RDSR2, &sr2, 1);
	stfsm_read_status(fsm, SPINOR_OP_RDCR, &sr2, 1);
	data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
	if (data_pads == 4) {
		if (!(sr2 & W25Q_STATUS_QE)) {
+1 −1
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ config SPI_INTEL_SPI_PLATFORM

config SPI_STM32_QUADSPI
	tristate "STM32 Quad SPI controller"
	depends on ARCH_STM32
	depends on ARCH_STM32 || COMPILE_TEST
	help
	  This enables support for the STM32 Quad SPI controller.
	  We only connect the NOR to this controller.
+168 −15
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/mtd/spi-nor.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/sizes.h>
#include <linux/sysfs.h>

#define DEVICE_NAME	"aspeed-smc"
@@ -97,6 +98,7 @@ struct aspeed_smc_chip {
	struct aspeed_smc_controller *controller;
	void __iomem *ctl;			/* control register */
	void __iomem *ahb_base;			/* base of chip window */
	u32 ahb_window_size;			/* chip mapping window size */
	u32 ctl_val[smc_max];			/* control settings */
	enum aspeed_smc_flash_type type;	/* what type of flash */
	struct spi_nor nor;
@@ -109,6 +111,7 @@ struct aspeed_smc_controller {
	const struct aspeed_smc_info *info;	/* type info of controller */
	void __iomem *regs;			/* controller registers */
	void __iomem *ahb_base;			/* per-chip windows resource */
	u32 ahb_window_size;			/* full mapping window size */

	struct aspeed_smc_chip *chips[0];	/* pointers to attached chips */
};
@@ -180,8 +183,7 @@ struct aspeed_smc_controller {

#define CONTROL_KEEP_MASK						\
	(CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
	 CONTROL_IO_DUMMY_MASK | CONTROL_CLOCK_FREQ_SEL_MASK |		\
	 CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
	 CONTROL_CLOCK_FREQ_SEL_MASK | CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)

/*
 * The Segment Register uses a 8MB unit to encode the start address
@@ -194,6 +196,10 @@ struct aspeed_smc_controller {
#define SEGMENT_ADDR_REG0		0x30
#define SEGMENT_ADDR_START(_r)		((((_r) >> 16) & 0xFF) << 23)
#define SEGMENT_ADDR_END(_r)		((((_r) >> 24) & 0xFF) << 23)
#define SEGMENT_ADDR_VALUE(start, end)					\
	(((((start) >> 23) & 0xFF) << 16) | ((((end) >> 23) & 0xFF) << 24))
#define SEGMENT_ADDR_REG(controller, cs)	\
	((controller)->regs + SEGMENT_ADDR_REG0 + (cs) * 4)

/*
 * In user mode all data bytes read or written to the chip decode address
@@ -439,8 +445,7 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
	u32 reg;

	if (controller->info->nce > 1) {
		reg = readl(controller->regs + SEGMENT_ADDR_REG0 +
			    chip->cs * 4);
		reg = readl(SEGMENT_ADDR_REG(controller, chip->cs));

		if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
			return NULL;
@@ -451,6 +456,146 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
	return controller->ahb_base + offset;
}

static u32 aspeed_smc_ahb_base_phy(struct aspeed_smc_controller *controller)
{
	u32 seg0_val = readl(SEGMENT_ADDR_REG(controller, 0));

	return SEGMENT_ADDR_START(seg0_val);
}

static u32 chip_set_segment(struct aspeed_smc_chip *chip, u32 cs, u32 start,
			    u32 size)
{
	struct aspeed_smc_controller *controller = chip->controller;
	void __iomem *seg_reg;
	u32 seg_oldval, seg_newval, ahb_base_phy, end;

	ahb_base_phy = aspeed_smc_ahb_base_phy(controller);

	seg_reg = SEGMENT_ADDR_REG(controller, cs);
	seg_oldval = readl(seg_reg);

	/*
	 * If the chip size is not specified, use the default segment
	 * size, but take into account the possible overlap with the
	 * previous segment
	 */
	if (!size)
		size = SEGMENT_ADDR_END(seg_oldval) - start;

	/*
	 * The segment cannot exceed the maximum window size of the
	 * controller.
	 */
	if (start + size > ahb_base_phy + controller->ahb_window_size) {
		size = ahb_base_phy + controller->ahb_window_size - start;
		dev_warn(chip->nor.dev, "CE%d window resized to %dMB",
			 cs, size >> 20);
	}

	end = start + size;
	seg_newval = SEGMENT_ADDR_VALUE(start, end);
	writel(seg_newval, seg_reg);

	/*
	 * Restore default value if something goes wrong. The chip
	 * might have set some bogus value and we would loose access
	 * to the chip.
	 */
	if (seg_newval != readl(seg_reg)) {
		dev_err(chip->nor.dev, "CE%d window invalid", cs);
		writel(seg_oldval, seg_reg);
		start = SEGMENT_ADDR_START(seg_oldval);
		end = SEGMENT_ADDR_END(seg_oldval);
		size = end - start;
	}

	dev_info(chip->nor.dev, "CE%d window [ 0x%.8x - 0x%.8x ] %dMB",
		 cs, start, end, size >> 20);

	return size;
}

/*
 * The segment register defines the mapping window on the AHB bus and
 * it needs to be configured depending on the chip size. The segment
 * register of the following CE also needs to be tuned in order to
 * provide a contiguous window across multiple chips.
 *
 * This is expected to be called in increasing CE order
 */
static u32 aspeed_smc_chip_set_segment(struct aspeed_smc_chip *chip)
{
	struct aspeed_smc_controller *controller = chip->controller;
	u32 ahb_base_phy, start;
	u32 size = chip->nor.mtd.size;

	/*
	 * Each controller has a chip size limit for direct memory
	 * access
	 */
	if (size > controller->info->maxsize)
		size = controller->info->maxsize;

	/*
	 * The AST2400 SPI controller only handles one chip and does
	 * not have segment registers. Let's use the chip size for the
	 * AHB window.
	 */
	if (controller->info == &spi_2400_info)
		goto out;

	/*
	 * The AST2500 SPI controller has a HW bug when the CE0 chip
	 * size reaches 128MB. Enforce a size limit of 120MB to
	 * prevent the controller from using bogus settings in the
	 * segment register.
	 */
	if (chip->cs == 0 && controller->info == &spi_2500_info &&
	    size == SZ_128M) {
		size = 120 << 20;
		dev_info(chip->nor.dev,
			 "CE%d window resized to %dMB (AST2500 HW quirk)",
			 chip->cs, size >> 20);
	}

	ahb_base_phy = aspeed_smc_ahb_base_phy(controller);

	/*
	 * As a start address for the current segment, use the default
	 * start address if we are handling CE0 or use the previous
	 * segment ending address
	 */
	if (chip->cs) {
		u32 prev = readl(SEGMENT_ADDR_REG(controller, chip->cs - 1));

		start = SEGMENT_ADDR_END(prev);
	} else {
		start = ahb_base_phy;
	}

	size = chip_set_segment(chip, chip->cs, start, size);

	/* Update chip base address on the AHB bus */
	chip->ahb_base = controller->ahb_base + (start - ahb_base_phy);

	/*
	 * Now, make sure the next segment does not overlap with the
	 * current one we just configured, even if there is no
	 * available chip. That could break access in Command Mode.
	 */
	if (chip->cs < controller->info->nce - 1)
		chip_set_segment(chip, chip->cs + 1, start + size, 0);

out:
	if (size < chip->nor.mtd.size)
		dev_warn(chip->nor.dev,
			 "CE%d window too small for chip %dMB",
			 chip->cs, (u32)chip->nor.mtd.size >> 20);

	return size;
}

static void aspeed_smc_chip_enable_write(struct aspeed_smc_chip *chip)
{
	struct aspeed_smc_controller *controller = chip->controller;
@@ -524,7 +669,7 @@ static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
	 */
	chip->ahb_base = aspeed_smc_chip_base(chip, res);
	if (!chip->ahb_base) {
		dev_warn(chip->nor.dev, "CE segment window closed.\n");
		dev_warn(chip->nor.dev, "CE%d window closed", chip->cs);
		return -EINVAL;
	}

@@ -571,6 +716,9 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
	if (chip->nor.addr_width == 4 && info->set_4b)
		info->set_4b(chip);

	/* This is for direct AHB access when using Command Mode. */
	chip->ahb_window_size = aspeed_smc_chip_set_segment(chip);

	/*
	 * base mode has not been optimized yet. use it for writes.
	 */
@@ -585,14 +733,12 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
	 * TODO: Adjust clocks if fast read is supported and interpret
	 * SPI-NOR flags to adjust controller settings.
	 */
	switch (chip->nor.flash_read) {
	case SPI_NOR_NORMAL:
	if (chip->nor.read_proto == SNOR_PROTO_1_1_1) {
		if (chip->nor.read_dummy == 0)
			cmd = CONTROL_COMMAND_MODE_NORMAL;
		break;
	case SPI_NOR_FAST:
		else
			cmd = CONTROL_COMMAND_MODE_FREAD;
		break;
	default:
	} else {
		dev_err(chip->nor.dev, "unsupported SPI read mode\n");
		return -EINVAL;
	}
@@ -608,6 +754,11 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
				  struct device_node *np, struct resource *r)
{
	const struct spi_nor_hwcaps hwcaps = {
		.mask = SNOR_HWCAPS_READ |
			SNOR_HWCAPS_READ_FAST |
			SNOR_HWCAPS_PP,
	};
	const struct aspeed_smc_info *info = controller->info;
	struct device *dev = controller->dev;
	struct device_node *child;
@@ -671,11 +822,11 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
			break;

		/*
		 * TODO: Add support for SPI_NOR_QUAD and SPI_NOR_DUAL
		 * TODO: Add support for Dual and Quad SPI protocols
		 * attach when board support is present as determined
		 * by of property.
		 */
		ret = spi_nor_scan(nor, NULL, SPI_NOR_NORMAL);
		ret = spi_nor_scan(nor, NULL, &hwcaps);
		if (ret)
			break;

@@ -731,6 +882,8 @@ static int aspeed_smc_probe(struct platform_device *pdev)
	if (IS_ERR(controller->ahb_base))
		return PTR_ERR(controller->ahb_base);

	controller->ahb_window_size = resource_size(res);

	ret = aspeed_smc_setup_flash(controller, np, res);
	if (ret)
		dev_err(dev, "Aspeed SMC probe failed %d\n", ret);
Loading