brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · 5aee62f Raw
460 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * SPI NOR driver for NXP SPI Flash Interface (SPIFI)4 *5 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>6 *7 * Based on Freescale QuadSPI driver:8 * Copyright (C) 2013 Freescale Semiconductor, Inc.9 */10 11#include <linux/clk.h>12#include <linux/err.h>13#include <linux/io.h>14#include <linux/iopoll.h>15#include <linux/module.h>16#include <linux/mtd/mtd.h>17#include <linux/mtd/partitions.h>18#include <linux/mtd/spi-nor.h>19#include <linux/of.h>20#include <linux/platform_device.h>21#include <linux/spi/spi.h>22 23/* NXP SPIFI registers, bits and macros */24#define SPIFI_CTRL				0x00025#define  SPIFI_CTRL_TIMEOUT(timeout)		(timeout)26#define  SPIFI_CTRL_CSHIGH(cshigh)		((cshigh) << 16)27#define  SPIFI_CTRL_MODE3			BIT(23)28#define  SPIFI_CTRL_DUAL			BIT(28)29#define  SPIFI_CTRL_FBCLK			BIT(30)30#define SPIFI_CMD				0x00431#define  SPIFI_CMD_DATALEN(dlen)		((dlen) & 0x3fff)32#define  SPIFI_CMD_DOUT				BIT(15)33#define  SPIFI_CMD_INTLEN(ilen)			((ilen) << 16)34#define  SPIFI_CMD_FIELDFORM(field)		((field) << 19)35#define  SPIFI_CMD_FIELDFORM_ALL_SERIAL		SPIFI_CMD_FIELDFORM(0x0)36#define  SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA	SPIFI_CMD_FIELDFORM(0x1)37#define  SPIFI_CMD_FRAMEFORM(frame)		((frame) << 21)38#define  SPIFI_CMD_FRAMEFORM_OPCODE_ONLY	SPIFI_CMD_FRAMEFORM(0x1)39#define  SPIFI_CMD_OPCODE(op)			((op) << 24)40#define SPIFI_ADDR				0x00841#define SPIFI_IDATA				0x00c42#define SPIFI_CLIMIT				0x01043#define SPIFI_DATA				0x01444#define SPIFI_MCMD				0x01845#define SPIFI_STAT				0x01c46#define  SPIFI_STAT_MCINIT			BIT(0)47#define  SPIFI_STAT_CMD				BIT(1)48#define  SPIFI_STAT_RESET			BIT(4)49 50#define SPI_NOR_MAX_ID_LEN	651 52struct nxp_spifi {53	struct device *dev;54	struct clk *clk_spifi;55	struct clk *clk_reg;56	void __iomem *io_base;57	void __iomem *flash_base;58	struct spi_nor nor;59	bool memory_mode;60	u32 mcmd;61};62 63static int nxp_spifi_wait_for_cmd(struct nxp_spifi *spifi)64{65	u8 stat;66	int ret;67 68	ret = readb_poll_timeout(spifi->io_base + SPIFI_STAT, stat,69				 !(stat & SPIFI_STAT_CMD), 10, 30);70	if (ret)71		dev_warn(spifi->dev, "command timed out\n");72 73	return ret;74}75 76static int nxp_spifi_reset(struct nxp_spifi *spifi)77{78	u8 stat;79	int ret;80 81	writel(SPIFI_STAT_RESET, spifi->io_base + SPIFI_STAT);82	ret = readb_poll_timeout(spifi->io_base + SPIFI_STAT, stat,83				 !(stat & SPIFI_STAT_RESET), 10, 30);84	if (ret)85		dev_warn(spifi->dev, "state reset timed out\n");86 87	return ret;88}89 90static int nxp_spifi_set_memory_mode_off(struct nxp_spifi *spifi)91{92	int ret;93 94	if (!spifi->memory_mode)95		return 0;96 97	ret = nxp_spifi_reset(spifi);98	if (ret)99		dev_err(spifi->dev, "unable to enter command mode\n");100	else101		spifi->memory_mode = false;102 103	return ret;104}105 106static int nxp_spifi_set_memory_mode_on(struct nxp_spifi *spifi)107{108	u8 stat;109	int ret;110 111	if (spifi->memory_mode)112		return 0;113 114	writel(spifi->mcmd, spifi->io_base + SPIFI_MCMD);115	ret = readb_poll_timeout(spifi->io_base + SPIFI_STAT, stat,116				 stat & SPIFI_STAT_MCINIT, 10, 30);117	if (ret)118		dev_err(spifi->dev, "unable to enter memory mode\n");119	else120		spifi->memory_mode = true;121 122	return ret;123}124 125static int nxp_spifi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,126			      size_t len)127{128	struct nxp_spifi *spifi = nor->priv;129	u32 cmd;130	int ret;131 132	ret = nxp_spifi_set_memory_mode_off(spifi);133	if (ret)134		return ret;135 136	cmd = SPIFI_CMD_DATALEN(len) |137	      SPIFI_CMD_OPCODE(opcode) |138	      SPIFI_CMD_FIELDFORM_ALL_SERIAL |139	      SPIFI_CMD_FRAMEFORM_OPCODE_ONLY;140	writel(cmd, spifi->io_base + SPIFI_CMD);141 142	while (len--)143		*buf++ = readb(spifi->io_base + SPIFI_DATA);144 145	return nxp_spifi_wait_for_cmd(spifi);146}147 148static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,149			       size_t len)150{151	struct nxp_spifi *spifi = nor->priv;152	u32 cmd;153	int ret;154 155	ret = nxp_spifi_set_memory_mode_off(spifi);156	if (ret)157		return ret;158 159	cmd = SPIFI_CMD_DOUT |160	      SPIFI_CMD_DATALEN(len) |161	      SPIFI_CMD_OPCODE(opcode) |162	      SPIFI_CMD_FIELDFORM_ALL_SERIAL |163	      SPIFI_CMD_FRAMEFORM_OPCODE_ONLY;164	writel(cmd, spifi->io_base + SPIFI_CMD);165 166	while (len--)167		writeb(*buf++, spifi->io_base + SPIFI_DATA);168 169	return nxp_spifi_wait_for_cmd(spifi);170}171 172static ssize_t nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len,173			      u_char *buf)174{175	struct nxp_spifi *spifi = nor->priv;176	int ret;177 178	ret = nxp_spifi_set_memory_mode_on(spifi);179	if (ret)180		return ret;181 182	memcpy_fromio(buf, spifi->flash_base + from, len);183 184	return len;185}186 187static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,188			       const u_char *buf)189{190	struct nxp_spifi *spifi = nor->priv;191	u32 cmd;192	int ret;193	size_t i;194 195	ret = nxp_spifi_set_memory_mode_off(spifi);196	if (ret)197		return ret;198 199	writel(to, spifi->io_base + SPIFI_ADDR);200 201	cmd = SPIFI_CMD_DOUT |202	      SPIFI_CMD_DATALEN(len) |203	      SPIFI_CMD_FIELDFORM_ALL_SERIAL |204	      SPIFI_CMD_OPCODE(nor->program_opcode) |205	      SPIFI_CMD_FRAMEFORM(spifi->nor.addr_nbytes + 1);206	writel(cmd, spifi->io_base + SPIFI_CMD);207 208	for (i = 0; i < len; i++)209		writeb(buf[i], spifi->io_base + SPIFI_DATA);210 211	ret = nxp_spifi_wait_for_cmd(spifi);212	if (ret)213		return ret;214 215	return len;216}217 218static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)219{220	struct nxp_spifi *spifi = nor->priv;221	u32 cmd;222	int ret;223 224	ret = nxp_spifi_set_memory_mode_off(spifi);225	if (ret)226		return ret;227 228	writel(offs, spifi->io_base + SPIFI_ADDR);229 230	cmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL |231	      SPIFI_CMD_OPCODE(nor->erase_opcode) |232	      SPIFI_CMD_FRAMEFORM(spifi->nor.addr_nbytes + 1);233	writel(cmd, spifi->io_base + SPIFI_CMD);234 235	return nxp_spifi_wait_for_cmd(spifi);236}237 238static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)239{240	switch (spifi->nor.read_proto) {241	case SNOR_PROTO_1_1_1:242		spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL;243		break;244	case SNOR_PROTO_1_1_2:245	case SNOR_PROTO_1_1_4:246		spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA;247		break;248	default:249		dev_err(spifi->dev, "unsupported SPI read mode\n");250		return -EINVAL;251	}252 253	/* Memory mode supports address length between 1 and 4 */254	if (spifi->nor.addr_nbytes < 1 || spifi->nor.addr_nbytes > 4)255		return -EINVAL;256 257	spifi->mcmd |= SPIFI_CMD_OPCODE(spifi->nor.read_opcode) |258		       SPIFI_CMD_INTLEN(spifi->nor.read_dummy / 8) |259		       SPIFI_CMD_FRAMEFORM(spifi->nor.addr_nbytes + 1);260 261	return 0;262}263 264static void nxp_spifi_dummy_id_read(struct spi_nor *nor)265{266	u8 id[SPI_NOR_MAX_ID_LEN];267	nor->controller_ops->read_reg(nor, SPINOR_OP_RDID, id,268				      SPI_NOR_MAX_ID_LEN);269}270 271static const struct spi_nor_controller_ops nxp_spifi_controller_ops = {272	.read_reg  = nxp_spifi_read_reg,273	.write_reg = nxp_spifi_write_reg,274	.read  = nxp_spifi_read,275	.write = nxp_spifi_write,276	.erase = nxp_spifi_erase,277};278 279static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,280				 struct device_node *np)281{282	struct spi_nor_hwcaps hwcaps = {283		.mask = SNOR_HWCAPS_READ |284			SNOR_HWCAPS_READ_FAST |285			SNOR_HWCAPS_PP,286	};287	u32 ctrl, property;288	u16 mode = 0;289	int ret;290 291	if (!of_property_read_u32(np, "spi-rx-bus-width", &property)) {292		switch (property) {293		case 1:294			break;295		case 2:296			mode |= SPI_RX_DUAL;297			break;298		case 4:299			mode |= SPI_RX_QUAD;300			break;301		default:302			dev_err(spifi->dev, "unsupported rx-bus-width\n");303			return -EINVAL;304		}305	}306 307	if (of_property_read_bool(np, "spi-cpha"))308		mode |= SPI_CPHA;309 310	if (of_property_read_bool(np, "spi-cpol"))311		mode |= SPI_CPOL;312 313	/* Setup control register defaults */314	ctrl = SPIFI_CTRL_TIMEOUT(1000) |315	       SPIFI_CTRL_CSHIGH(15) |316	       SPIFI_CTRL_FBCLK;317 318	if (mode & SPI_RX_DUAL) {319		ctrl |= SPIFI_CTRL_DUAL;320		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;321	} else if (mode & SPI_RX_QUAD) {322		ctrl &= ~SPIFI_CTRL_DUAL;323		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;324	} else {325		ctrl |= SPIFI_CTRL_DUAL;326	}327 328	switch (mode & SPI_MODE_X_MASK) {329	case SPI_MODE_0:330		ctrl &= ~SPIFI_CTRL_MODE3;331		break;332	case SPI_MODE_3:333		ctrl |= SPIFI_CTRL_MODE3;334		break;335	default:336		dev_err(spifi->dev, "only mode 0 and 3 supported\n");337		return -EINVAL;338	}339 340	writel(ctrl, spifi->io_base + SPIFI_CTRL);341 342	spifi->nor.dev   = spifi->dev;343	spi_nor_set_flash_node(&spifi->nor, np);344	spifi->nor.priv  = spifi;345	spifi->nor.controller_ops = &nxp_spifi_controller_ops;346 347	/*348	 * The first read on a hard reset isn't reliable so do a349	 * dummy read of the id before calling spi_nor_scan().350	 * The reason for this problem is unknown.351	 *352	 * The official NXP spifilib uses more or less the same353	 * workaround that is applied here by reading the device354	 * id multiple times.355	 */356	nxp_spifi_dummy_id_read(&spifi->nor);357 358	ret = spi_nor_scan(&spifi->nor, NULL, &hwcaps);359	if (ret) {360		dev_err(spifi->dev, "device scan failed\n");361		return ret;362	}363 364	ret = nxp_spifi_setup_memory_cmd(spifi);365	if (ret) {366		dev_err(spifi->dev, "memory command setup failed\n");367		return ret;368	}369 370	ret = mtd_device_register(&spifi->nor.mtd, NULL, 0);371	if (ret) {372		dev_err(spifi->dev, "mtd device parse failed\n");373		return ret;374	}375 376	return 0;377}378 379static int nxp_spifi_probe(struct platform_device *pdev)380{381	struct device_node *flash_np;382	struct nxp_spifi *spifi;383	int ret;384 385	spifi = devm_kzalloc(&pdev->dev, sizeof(*spifi), GFP_KERNEL);386	if (!spifi)387		return -ENOMEM;388 389	spifi->io_base = devm_platform_ioremap_resource_byname(pdev, "spifi");390	if (IS_ERR(spifi->io_base))391		return PTR_ERR(spifi->io_base);392 393	spifi->flash_base = devm_platform_ioremap_resource_byname(pdev, "flash");394	if (IS_ERR(spifi->flash_base))395		return PTR_ERR(spifi->flash_base);396 397	spifi->clk_spifi = devm_clk_get_enabled(&pdev->dev, "spifi");398	if (IS_ERR(spifi->clk_spifi)) {399		dev_err(&pdev->dev, "spifi clock not found or unable to enable\n");400		return PTR_ERR(spifi->clk_spifi);401	}402 403	spifi->clk_reg = devm_clk_get_enabled(&pdev->dev, "reg");404	if (IS_ERR(spifi->clk_reg)) {405		dev_err(&pdev->dev, "reg clock not found or unable to enable\n");406		return PTR_ERR(spifi->clk_reg);407	}408 409	spifi->dev = &pdev->dev;410	platform_set_drvdata(pdev, spifi);411 412	/* Initialize and reset device */413	nxp_spifi_reset(spifi);414	writel(0, spifi->io_base + SPIFI_IDATA);415	writel(0, spifi->io_base + SPIFI_MCMD);416	nxp_spifi_reset(spifi);417 418	flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);419	if (!flash_np) {420		dev_err(&pdev->dev, "no SPI flash device to configure\n");421		return -ENODEV;422	}423 424	ret = nxp_spifi_setup_flash(spifi, flash_np);425	of_node_put(flash_np);426	if (ret) {427		dev_err(&pdev->dev, "unable to setup flash chip\n");428		return ret;429	}430 431	return 0;432}433 434static void nxp_spifi_remove(struct platform_device *pdev)435{436	struct nxp_spifi *spifi = platform_get_drvdata(pdev);437 438	mtd_device_unregister(&spifi->nor.mtd);439}440 441static const struct of_device_id nxp_spifi_match[] = {442	{.compatible = "nxp,lpc1773-spifi"},443	{ /* sentinel */ }444};445MODULE_DEVICE_TABLE(of, nxp_spifi_match);446 447static struct platform_driver nxp_spifi_driver = {448	.probe	= nxp_spifi_probe,449	.remove_new = nxp_spifi_remove,450	.driver	= {451		.name = "nxp-spifi",452		.of_match_table = nxp_spifi_match,453	},454};455module_platform_driver(nxp_spifi_driver);456 457MODULE_DESCRIPTION("NXP SPI Flash Interface driver");458MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");459MODULE_LICENSE("GPL v2");460