brintos

brintos / linux-shallow public Read only

0
0
Text · 10.2 KiB · 8427905 Raw
433 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 *  Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>5 */6 7#include <linux/module.h>8#include <linux/device.h>9#include <linux/platform_device.h>10#include <linux/spi/spi.h>11#include <linux/delay.h>12#include <linux/of.h>13#include <linux/of_platform.h>14 15#include <lantiq_soc.h>16 17#define DRV_NAME		"sflash-falcon"18 19#define FALCON_SPI_XFER_BEGIN	(1 << 0)20#define FALCON_SPI_XFER_END	(1 << 1)21 22/* Bus Read Configuration Register0 */23#define BUSRCON0		0x0000001024/* Bus Write Configuration Register0 */25#define BUSWCON0		0x0000001826/* Serial Flash Configuration Register */27#define SFCON			0x0000008028/* Serial Flash Time Register */29#define SFTIME			0x0000008430/* Serial Flash Status Register */31#define SFSTAT			0x0000008832/* Serial Flash Command Register */33#define SFCMD			0x0000008C34/* Serial Flash Address Register */35#define SFADDR			0x0000009036/* Serial Flash Data Register */37#define SFDATA			0x0000009438/* Serial Flash I/O Control Register */39#define SFIO			0x0000009840/* EBU Clock Control Register */41#define EBUCC			0x000000C442 43/* Dummy Phase Length */44#define SFCMD_DUMLEN_OFFSET	1645#define SFCMD_DUMLEN_MASK	0x000F000046/* Chip Select */47#define SFCMD_CS_OFFSET		2448#define SFCMD_CS_MASK		0x0700000049/* field offset */50#define SFCMD_ALEN_OFFSET	2051#define SFCMD_ALEN_MASK		0x0070000052/* SCK Rise-edge Position */53#define SFTIME_SCKR_POS_OFFSET	854#define SFTIME_SCKR_POS_MASK	0x00000F0055/* SCK Period */56#define SFTIME_SCK_PER_OFFSET	057#define SFTIME_SCK_PER_MASK	0x0000000F58/* SCK Fall-edge Position */59#define SFTIME_SCKF_POS_OFFSET	1260#define SFTIME_SCKF_POS_MASK	0x0000F00061/* Device Size */62#define SFCON_DEV_SIZE_A23_0	0x0300000063#define SFCON_DEV_SIZE_MASK	0x0F00000064/* Read Data Position */65#define SFTIME_RD_POS_MASK	0x000F000066/* Data Output */67#define SFIO_UNUSED_WD_MASK	0x0000000F68/* Command Opcode mask */69#define SFCMD_OPC_MASK		0x000000FF70/* dlen bytes of data to write */71#define SFCMD_DIR_WRITE		0x0000010072/* Data Length offset */73#define SFCMD_DLEN_OFFSET	974/* Command Error */75#define SFSTAT_CMD_ERR		0x2000000076/* Access Command Pending */77#define SFSTAT_CMD_PEND		0x0040000078/* Frequency set to 100MHz. */79#define EBUCC_EBUDIV_SELF100	0x0000000180/* Serial Flash */81#define BUSRCON0_AGEN_SERIAL_FLASH	0xF000000082/* 8-bit multiplexed */83#define BUSRCON0_PORTW_8_BIT_MUX	0x0000000084/* Serial Flash */85#define BUSWCON0_AGEN_SERIAL_FLASH	0xF000000086/* Chip Select after opcode */87#define SFCMD_KEEP_CS_KEEP_SELECTED	0x0000800088 89#define CLOCK_100M	10000000090#define CLOCK_50M	5000000091 92struct falcon_sflash {93	u32 sfcmd; /* for caching of opcode, direction, ... */94	struct spi_controller *host;95};96 97int falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,98		unsigned long flags)99{100	struct device *dev = &spi->dev;101	struct falcon_sflash *priv = spi_controller_get_devdata(spi->controller);102	const u8 *txp = t->tx_buf;103	u8 *rxp = t->rx_buf;104	unsigned int bytelen = ((8 * t->len + 7) / 8);105	unsigned int len, alen, dumlen;106	u32 val;107	enum {108		state_init,109		state_command_prepare,110		state_write,111		state_read,112		state_disable_cs,113		state_end114	} state = state_init;115 116	do {117		switch (state) {118		case state_init: /* detect phase of upper layer sequence */119		{120			/* initial write ? */121			if (flags & FALCON_SPI_XFER_BEGIN) {122				if (!txp) {123					dev_err(dev,124						"BEGIN without tx data!\n");125					return -ENODATA;126				}127				/*128				 * Prepare the parts of the sfcmd register,129				 * which should not change during a sequence!130				 * Only exception are the length fields,131				 * especially alen and dumlen.132				 */133 134				priv->sfcmd = ((spi_get_chipselect(spi, 0)135						<< SFCMD_CS_OFFSET)136					       & SFCMD_CS_MASK);137				priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;138				priv->sfcmd |= *txp;139				txp++;140				bytelen--;141				if (bytelen) {142					/*143					 * more data:144					 * maybe address and/or dummy145					 */146					state = state_command_prepare;147					break;148				} else {149					dev_dbg(dev, "write cmd %02X\n",150						priv->sfcmd & SFCMD_OPC_MASK);151				}152			}153			/* continued write ? */154			if (txp && bytelen) {155				state = state_write;156				break;157			}158			/* read data? */159			if (rxp && bytelen) {160				state = state_read;161				break;162			}163			/* end of sequence? */164			if (flags & FALCON_SPI_XFER_END)165				state = state_disable_cs;166			else167				state = state_end;168			break;169		}170		/* collect tx data for address and dummy phase */171		case state_command_prepare:172		{173			/* txp is valid, already checked */174			val = 0;175			alen = 0;176			dumlen = 0;177			while (bytelen > 0) {178				if (alen < 3) {179					val = (val << 8) | (*txp++);180					alen++;181				} else if ((dumlen < 15) && (*txp == 0)) {182					/*183					 * assume dummy bytes are set to 0184					 * from upper layer185					 */186					dumlen++;187					txp++;188				} else {189					break;190				}191				bytelen--;192			}193			priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);194			priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |195					 (dumlen << SFCMD_DUMLEN_OFFSET);196			if (alen > 0)197				ltq_ebu_w32(val, SFADDR);198 199			dev_dbg(dev, "wr %02X, alen=%d (addr=%06X) dlen=%d\n",200				priv->sfcmd & SFCMD_OPC_MASK,201				alen, val, dumlen);202 203			if (bytelen > 0) {204				/* continue with write */205				state = state_write;206			} else if (flags & FALCON_SPI_XFER_END) {207				/* end of sequence? */208				state = state_disable_cs;209			} else {210				/*211				 * go to end and expect another212				 * call (read or write)213				 */214				state = state_end;215			}216			break;217		}218		case state_write:219		{220			/* txp still valid */221			priv->sfcmd |= SFCMD_DIR_WRITE;222			len = 0;223			val = 0;224			do {225				if (bytelen--)226					val |= (*txp++) << (8 * len++);227				if ((flags & FALCON_SPI_XFER_END)228				    && (bytelen == 0)) {229					priv->sfcmd &=230						~SFCMD_KEEP_CS_KEEP_SELECTED;231				}232				if ((len == 4) || (bytelen == 0)) {233					ltq_ebu_w32(val, SFDATA);234					ltq_ebu_w32(priv->sfcmd235						| (len<<SFCMD_DLEN_OFFSET),236						SFCMD);237					len = 0;238					val = 0;239					priv->sfcmd &= ~(SFCMD_ALEN_MASK240							 | SFCMD_DUMLEN_MASK);241				}242			} while (bytelen);243			state = state_end;244			break;245		}246		case state_read:247		{248			/* read data */249			priv->sfcmd &= ~SFCMD_DIR_WRITE;250			do {251				if ((flags & FALCON_SPI_XFER_END)252				    && (bytelen <= 4)) {253					priv->sfcmd &=254						~SFCMD_KEEP_CS_KEEP_SELECTED;255				}256				len = (bytelen > 4) ? 4 : bytelen;257				bytelen -= len;258				ltq_ebu_w32(priv->sfcmd259					| (len << SFCMD_DLEN_OFFSET), SFCMD);260				priv->sfcmd &= ~(SFCMD_ALEN_MASK261						 | SFCMD_DUMLEN_MASK);262				do {263					val = ltq_ebu_r32(SFSTAT);264					if (val & SFSTAT_CMD_ERR) {265						/* reset error status */266						dev_err(dev, "SFSTAT: CMD_ERR");267						dev_err(dev, " (%x)\n", val);268						ltq_ebu_w32(SFSTAT_CMD_ERR,269							SFSTAT);270						return -EBADE;271					}272				} while (val & SFSTAT_CMD_PEND);273				val = ltq_ebu_r32(SFDATA);274				do {275					*rxp = (val & 0xFF);276					rxp++;277					val >>= 8;278					len--;279				} while (len);280			} while (bytelen);281			state = state_end;282			break;283		}284		case state_disable_cs:285		{286			priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED;287			ltq_ebu_w32(priv->sfcmd | (0 << SFCMD_DLEN_OFFSET),288				SFCMD);289			val = ltq_ebu_r32(SFSTAT);290			if (val & SFSTAT_CMD_ERR) {291				/* reset error status */292				dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val);293				ltq_ebu_w32(SFSTAT_CMD_ERR, SFSTAT);294				return -EBADE;295			}296			state = state_end;297			break;298		}299		case state_end:300			break;301		}302	} while (state != state_end);303 304	return 0;305}306 307static int falcon_sflash_setup(struct spi_device *spi)308{309	unsigned int i;310	unsigned long flags;311 312	spin_lock_irqsave(&ebu_lock, flags);313 314	if (spi->max_speed_hz >= CLOCK_100M) {315		/* set EBU clock to 100 MHz */316		ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, EBUCC);317		i = 1; /* divider */318	} else {319		/* set EBU clock to 50 MHz */320		ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, EBUCC);321 322		/* search for suitable divider */323		for (i = 1; i < 7; i++) {324			if (CLOCK_50M / i <= spi->max_speed_hz)325				break;326		}327	}328 329	/* setup period of serial clock */330	ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK331		     | SFTIME_SCKR_POS_MASK332		     | SFTIME_SCK_PER_MASK,333		     (i << SFTIME_SCKR_POS_OFFSET)334		     | (i << (SFTIME_SCK_PER_OFFSET + 1)),335		     SFTIME);336 337	/*338	 * set some bits of unused_wd, to not trigger HOLD/WP339	 * signals on non QUAD flashes340	 */341	ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), SFIO);342 343	ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,344			BUSRCON0);345	ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, BUSWCON0);346	/* set address wrap around to maximum for 24-bit addresses */347	ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, SFCON);348 349	spin_unlock_irqrestore(&ebu_lock, flags);350 351	return 0;352}353 354static int falcon_sflash_xfer_one(struct spi_controller *host,355					struct spi_message *m)356{357	struct falcon_sflash *priv = spi_controller_get_devdata(host);358	struct spi_transfer *t;359	unsigned long spi_flags;360	unsigned long flags;361	int ret = 0;362 363	priv->sfcmd = 0;364	m->actual_length = 0;365 366	spi_flags = FALCON_SPI_XFER_BEGIN;367	list_for_each_entry(t, &m->transfers, transfer_list) {368		if (list_is_last(&t->transfer_list, &m->transfers))369			spi_flags |= FALCON_SPI_XFER_END;370 371		spin_lock_irqsave(&ebu_lock, flags);372		ret = falcon_sflash_xfer(m->spi, t, spi_flags);373		spin_unlock_irqrestore(&ebu_lock, flags);374 375		if (ret)376			break;377 378		m->actual_length += t->len;379 380		WARN_ON(t->delay.value || t->cs_change);381		spi_flags = 0;382	}383 384	m->status = ret;385	spi_finalize_current_message(host);386 387	return 0;388}389 390static int falcon_sflash_probe(struct platform_device *pdev)391{392	struct falcon_sflash *priv;393	struct spi_controller *host;394	int ret;395 396	host = spi_alloc_host(&pdev->dev, sizeof(*priv));397	if (!host)398		return -ENOMEM;399 400	priv = spi_controller_get_devdata(host);401	priv->host = host;402 403	host->mode_bits = SPI_MODE_3;404	host->flags = SPI_CONTROLLER_HALF_DUPLEX;405	host->setup = falcon_sflash_setup;406	host->transfer_one_message = falcon_sflash_xfer_one;407	host->dev.of_node = pdev->dev.of_node;408 409	ret = devm_spi_register_controller(&pdev->dev, host);410	if (ret)411		spi_controller_put(host);412	return ret;413}414 415static const struct of_device_id falcon_sflash_match[] = {416	{ .compatible = "lantiq,sflash-falcon" },417	{},418};419MODULE_DEVICE_TABLE(of, falcon_sflash_match);420 421static struct platform_driver falcon_sflash_driver = {422	.probe	= falcon_sflash_probe,423	.driver = {424		.name	= DRV_NAME,425		.of_match_table = falcon_sflash_match,426	}427};428 429module_platform_driver(falcon_sflash_driver);430 431MODULE_LICENSE("GPL");432MODULE_DESCRIPTION("Lantiq Falcon SPI/SFLASH controller driver");433