| /* | 
 |  * NVIDIA Tegra SPI controller (T114 and later) | 
 |  * | 
 |  * Copyright (c) 2010-2013 NVIDIA Corporation | 
 |  * | 
 |  * See file CREDITS for list of people who contributed to this | 
 |  * project. | 
 |  * | 
 |  * This software is licensed under the terms of the GNU General Public | 
 |  * License version 2, as published by the Free Software Foundation, and | 
 |  * may be copied, distributed, and modified under those terms. | 
 |  * | 
 |  * This program is distributed in the hope that 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, write to the Free Software | 
 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
 |  * MA 02111-1307 USA | 
 |  */ | 
 |  | 
 | #include <common.h> | 
 | #include <dm.h> | 
 | #include <asm/io.h> | 
 | #include <asm/arch/clock.h> | 
 | #include <asm/arch-tegra/clk_rst.h> | 
 | #include <spi.h> | 
 | #include <fdtdec.h> | 
 | #include "tegra_spi.h" | 
 |  | 
 | DECLARE_GLOBAL_DATA_PTR; | 
 |  | 
 | /* COMMAND1 */ | 
 | #define SPI_CMD1_GO			BIT(31) | 
 | #define SPI_CMD1_M_S			BIT(30) | 
 | #define SPI_CMD1_MODE_MASK		GENMASK(1, 0) | 
 | #define SPI_CMD1_MODE_SHIFT		28 | 
 | #define SPI_CMD1_CS_SEL_MASK		GENMASK(1, 0) | 
 | #define SPI_CMD1_CS_SEL_SHIFT		26 | 
 | #define SPI_CMD1_CS_POL_INACTIVE3	BIT(25) | 
 | #define SPI_CMD1_CS_POL_INACTIVE2	BIT(24) | 
 | #define SPI_CMD1_CS_POL_INACTIVE1	BIT(23) | 
 | #define SPI_CMD1_CS_POL_INACTIVE0	BIT(22) | 
 | #define SPI_CMD1_CS_SW_HW		BIT(21) | 
 | #define SPI_CMD1_CS_SW_VAL		BIT(20) | 
 | #define SPI_CMD1_IDLE_SDA_MASK		GENMASK(1, 0) | 
 | #define SPI_CMD1_IDLE_SDA_SHIFT		18 | 
 | #define SPI_CMD1_BIDIR			BIT(17) | 
 | #define SPI_CMD1_LSBI_FE		BIT(16) | 
 | #define SPI_CMD1_LSBY_FE		BIT(15) | 
 | #define SPI_CMD1_BOTH_EN_BIT		BIT(14) | 
 | #define SPI_CMD1_BOTH_EN_BYTE		BIT(13) | 
 | #define SPI_CMD1_RX_EN			BIT(12) | 
 | #define SPI_CMD1_TX_EN			BIT(11) | 
 | #define SPI_CMD1_PACKED			BIT(5) | 
 | #define SPI_CMD1_BIT_LEN_MASK		GENMASK(4, 0) | 
 | #define SPI_CMD1_BIT_LEN_SHIFT		0 | 
 |  | 
 | /* COMMAND2 */ | 
 | #define SPI_CMD2_TX_CLK_TAP_DELAY	BIT(6) | 
 | #define SPI_CMD2_TX_CLK_TAP_DELAY_MASK	GENMASK(11, 6) | 
 | #define SPI_CMD2_RX_CLK_TAP_DELAY	BIT(0) | 
 | #define SPI_CMD2_RX_CLK_TAP_DELAY_MASK	GENMASK(5, 0) | 
 |  | 
 | /* TRANSFER STATUS */ | 
 | #define SPI_XFER_STS_RDY		BIT(30) | 
 |  | 
 | /* FIFO STATUS */ | 
 | #define SPI_FIFO_STS_CS_INACTIVE	BIT(31) | 
 | #define SPI_FIFO_STS_FRAME_END		BIT(30) | 
 | #define SPI_FIFO_STS_RX_FIFO_FLUSH	BIT(15) | 
 | #define SPI_FIFO_STS_TX_FIFO_FLUSH	BIT(14) | 
 | #define SPI_FIFO_STS_ERR		BIT(8) | 
 | #define SPI_FIFO_STS_TX_FIFO_OVF	BIT(7) | 
 | #define SPI_FIFO_STS_TX_FIFO_UNR	BIT(6) | 
 | #define SPI_FIFO_STS_RX_FIFO_OVF	BIT(5) | 
 | #define SPI_FIFO_STS_RX_FIFO_UNR	BIT(4) | 
 | #define SPI_FIFO_STS_TX_FIFO_FULL	BIT(3) | 
 | #define SPI_FIFO_STS_TX_FIFO_EMPTY	BIT(2) | 
 | #define SPI_FIFO_STS_RX_FIFO_FULL	BIT(1) | 
 | #define SPI_FIFO_STS_RX_FIFO_EMPTY	BIT(0) | 
 |  | 
 | #define SPI_TIMEOUT		1000 | 
 | #define TEGRA_SPI_MAX_FREQ	52000000 | 
 |  | 
 | struct spi_regs { | 
 | 	u32 command1;	/* 000:SPI_COMMAND1 register */ | 
 | 	u32 command2;	/* 004:SPI_COMMAND2 register */ | 
 | 	u32 timing1;	/* 008:SPI_CS_TIM1 register */ | 
 | 	u32 timing2;	/* 00c:SPI_CS_TIM2 register */ | 
 | 	u32 xfer_status;/* 010:SPI_TRANS_STATUS register */ | 
 | 	u32 fifo_status;/* 014:SPI_FIFO_STATUS register */ | 
 | 	u32 tx_data;	/* 018:SPI_TX_DATA register */ | 
 | 	u32 rx_data;	/* 01c:SPI_RX_DATA register */ | 
 | 	u32 dma_ctl;	/* 020:SPI_DMA_CTL register */ | 
 | 	u32 dma_blk;	/* 024:SPI_DMA_BLK register */ | 
 | 	u32 rsvd[56];	/* 028-107 reserved */ | 
 | 	u32 tx_fifo;	/* 108:SPI_FIFO1 register */ | 
 | 	u32 rsvd2[31];	/* 10c-187 reserved */ | 
 | 	u32 rx_fifo;	/* 188:SPI_FIFO2 register */ | 
 | 	u32 spare_ctl;	/* 18c:SPI_SPARE_CTRL register */ | 
 | }; | 
 |  | 
 | struct tegra114_spi_priv { | 
 | 	struct spi_regs *regs; | 
 | 	unsigned int freq; | 
 | 	unsigned int mode; | 
 | 	int periph_id; | 
 | 	int valid; | 
 | 	int last_transaction_us; | 
 | }; | 
 |  | 
 | static int tegra114_spi_ofdata_to_platdata(struct udevice *bus) | 
 | { | 
 | 	struct tegra_spi_platdata *plat = bus->platdata; | 
 | 	const void *blob = gd->fdt_blob; | 
 | 	int node = bus->of_offset; | 
 |  | 
 | 	plat->base = dev_get_addr(bus); | 
 | 	plat->periph_id = clock_decode_periph_id(blob, node); | 
 |  | 
 | 	if (plat->periph_id == PERIPH_ID_NONE) { | 
 | 		debug("%s: could not decode periph id %d\n", __func__, | 
 | 		      plat->periph_id); | 
 | 		return -FDT_ERR_NOTFOUND; | 
 | 	} | 
 |  | 
 | 	/* Use 500KHz as a suitable default */ | 
 | 	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", | 
 | 					500000); | 
 | 	plat->deactivate_delay_us = fdtdec_get_int(blob, node, | 
 | 					"spi-deactivate-delay", 0); | 
 | 	debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n", | 
 | 	      __func__, plat->base, plat->periph_id, plat->frequency, | 
 | 	      plat->deactivate_delay_us); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int tegra114_spi_probe(struct udevice *bus) | 
 | { | 
 | 	struct tegra_spi_platdata *plat = dev_get_platdata(bus); | 
 | 	struct tegra114_spi_priv *priv = dev_get_priv(bus); | 
 | 	struct spi_regs *regs; | 
 | 	ulong rate; | 
 |  | 
 | 	priv->regs = (struct spi_regs *)plat->base; | 
 | 	regs = priv->regs; | 
 |  | 
 | 	priv->last_transaction_us = timer_get_us(); | 
 | 	priv->freq = plat->frequency; | 
 | 	priv->periph_id = plat->periph_id; | 
 |  | 
 | 	/* | 
 | 	 * Change SPI clock to correct frequency, PLLP_OUT0 source, falling | 
 | 	 * back to the oscillator if that is too fast. | 
 | 	 */ | 
 | 	rate = clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH, | 
 | 				      priv->freq); | 
 | 	if (rate > priv->freq + 100000) { | 
 | 		rate = clock_start_periph_pll(priv->periph_id, CLOCK_ID_OSC, | 
 | 					      priv->freq); | 
 | 		if (rate != priv->freq) { | 
 | 			printf("Warning: SPI '%s' requested clock %u, actual clock %lu\n", | 
 | 			       bus->name, priv->freq, rate); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* Clear stale status here */ | 
 | 	setbits_le32(®s->fifo_status, | 
 | 		     SPI_FIFO_STS_ERR		| | 
 | 		     SPI_FIFO_STS_TX_FIFO_OVF	| | 
 | 		     SPI_FIFO_STS_TX_FIFO_UNR	| | 
 | 		     SPI_FIFO_STS_RX_FIFO_OVF	| | 
 | 		     SPI_FIFO_STS_RX_FIFO_UNR	| | 
 | 		     SPI_FIFO_STS_TX_FIFO_FULL	| | 
 | 		     SPI_FIFO_STS_TX_FIFO_EMPTY	| | 
 | 		     SPI_FIFO_STS_RX_FIFO_FULL	| | 
 | 		     SPI_FIFO_STS_RX_FIFO_EMPTY); | 
 | 	debug("%s: FIFO STATUS = %08x\n", __func__, readl(®s->fifo_status)); | 
 |  | 
 | 	setbits_le32(&priv->regs->command1, SPI_CMD1_M_S | SPI_CMD1_CS_SW_HW | | 
 | 		     (priv->mode << SPI_CMD1_MODE_SHIFT) | SPI_CMD1_CS_SW_VAL); | 
 | 	debug("%s: COMMAND1 = %08x\n", __func__, readl(®s->command1)); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * Activate the CS by driving it LOW | 
 |  * | 
 |  * @param slave	Pointer to spi_slave to which controller has to | 
 |  *		communicate with | 
 |  */ | 
 | static void spi_cs_activate(struct udevice *dev) | 
 | { | 
 | 	struct udevice *bus = dev->parent; | 
 | 	struct tegra_spi_platdata *pdata = dev_get_platdata(bus); | 
 | 	struct tegra114_spi_priv *priv = dev_get_priv(bus); | 
 |  | 
 | 	/* If it's too soon to do another transaction, wait */ | 
 | 	if (pdata->deactivate_delay_us && | 
 | 	    priv->last_transaction_us) { | 
 | 		ulong delay_us;		/* The delay completed so far */ | 
 | 		delay_us = timer_get_us() - priv->last_transaction_us; | 
 | 		if (delay_us < pdata->deactivate_delay_us) | 
 | 			udelay(pdata->deactivate_delay_us - delay_us); | 
 | 	} | 
 |  | 
 | 	clrbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL); | 
 | } | 
 |  | 
 | /** | 
 |  * Deactivate the CS by driving it HIGH | 
 |  * | 
 |  * @param slave	Pointer to spi_slave to which controller has to | 
 |  *		communicate with | 
 |  */ | 
 | static void spi_cs_deactivate(struct udevice *dev) | 
 | { | 
 | 	struct udevice *bus = dev->parent; | 
 | 	struct tegra_spi_platdata *pdata = dev_get_platdata(bus); | 
 | 	struct tegra114_spi_priv *priv = dev_get_priv(bus); | 
 |  | 
 | 	setbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL); | 
 |  | 
 | 	/* Remember time of this transaction so we can honour the bus delay */ | 
 | 	if (pdata->deactivate_delay_us) | 
 | 		priv->last_transaction_us = timer_get_us(); | 
 |  | 
 | 	debug("Deactivate CS, bus '%s'\n", bus->name); | 
 | } | 
 |  | 
 | static int tegra114_spi_xfer(struct udevice *dev, unsigned int bitlen, | 
 | 			     const void *data_out, void *data_in, | 
 | 			     unsigned long flags) | 
 | { | 
 | 	struct udevice *bus = dev->parent; | 
 | 	struct tegra114_spi_priv *priv = dev_get_priv(bus); | 
 | 	struct spi_regs *regs = priv->regs; | 
 | 	u32 reg, tmpdout, tmpdin = 0; | 
 | 	const u8 *dout = data_out; | 
 | 	u8 *din = data_in; | 
 | 	int num_bytes; | 
 | 	int ret; | 
 |  | 
 | 	debug("%s: slave %u:%u dout %p din %p bitlen %u\n", | 
 | 	      __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen); | 
 | 	if (bitlen % 8) | 
 | 		return -1; | 
 | 	num_bytes = bitlen / 8; | 
 |  | 
 | 	ret = 0; | 
 |  | 
 | 	if (flags & SPI_XFER_BEGIN) | 
 | 		spi_cs_activate(dev); | 
 |  | 
 | 	/* clear all error status bits */ | 
 | 	reg = readl(®s->fifo_status); | 
 | 	writel(reg, ®s->fifo_status); | 
 |  | 
 | 	clrsetbits_le32(®s->command1, SPI_CMD1_CS_SW_VAL, | 
 | 			SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE | | 
 | 			(spi_chip_select(dev) << SPI_CMD1_CS_SEL_SHIFT)); | 
 |  | 
 | 	/* set xfer size to 1 block (32 bits) */ | 
 | 	writel(0, ®s->dma_blk); | 
 |  | 
 | 	/* handle data in 32-bit chunks */ | 
 | 	while (num_bytes > 0) { | 
 | 		int bytes; | 
 | 		int tm, i; | 
 |  | 
 | 		tmpdout = 0; | 
 | 		bytes = (num_bytes > 4) ?  4 : num_bytes; | 
 |  | 
 | 		if (dout != NULL) { | 
 | 			for (i = 0; i < bytes; ++i) | 
 | 				tmpdout = (tmpdout << 8) | dout[i]; | 
 | 			dout += bytes; | 
 | 		} | 
 |  | 
 | 		num_bytes -= bytes; | 
 |  | 
 | 		/* clear ready bit */ | 
 | 		setbits_le32(®s->xfer_status, SPI_XFER_STS_RDY); | 
 |  | 
 | 		clrsetbits_le32(®s->command1, | 
 | 				SPI_CMD1_BIT_LEN_MASK << SPI_CMD1_BIT_LEN_SHIFT, | 
 | 				(bytes * 8 - 1) << SPI_CMD1_BIT_LEN_SHIFT); | 
 | 		writel(tmpdout, ®s->tx_fifo); | 
 | 		setbits_le32(®s->command1, SPI_CMD1_GO); | 
 |  | 
 | 		/* | 
 | 		 * Wait for SPI transmit FIFO to empty, or to time out. | 
 | 		 * The RX FIFO status will be read and cleared last | 
 | 		 */ | 
 | 		for (tm = 0; tm < SPI_TIMEOUT; ++tm) { | 
 | 			u32 fifo_status, xfer_status; | 
 |  | 
 | 			xfer_status = readl(®s->xfer_status); | 
 | 			if (!(xfer_status & SPI_XFER_STS_RDY)) | 
 | 				continue; | 
 |  | 
 | 			fifo_status = readl(®s->fifo_status); | 
 | 			if (fifo_status & SPI_FIFO_STS_ERR) { | 
 | 				debug("%s: got a fifo error: ", __func__); | 
 | 				if (fifo_status & SPI_FIFO_STS_TX_FIFO_OVF) | 
 | 					debug("tx FIFO overflow "); | 
 | 				if (fifo_status & SPI_FIFO_STS_TX_FIFO_UNR) | 
 | 					debug("tx FIFO underrun "); | 
 | 				if (fifo_status & SPI_FIFO_STS_RX_FIFO_OVF) | 
 | 					debug("rx FIFO overflow "); | 
 | 				if (fifo_status & SPI_FIFO_STS_RX_FIFO_UNR) | 
 | 					debug("rx FIFO underrun "); | 
 | 				if (fifo_status & SPI_FIFO_STS_TX_FIFO_FULL) | 
 | 					debug("tx FIFO full "); | 
 | 				if (fifo_status & SPI_FIFO_STS_TX_FIFO_EMPTY) | 
 | 					debug("tx FIFO empty "); | 
 | 				if (fifo_status & SPI_FIFO_STS_RX_FIFO_FULL) | 
 | 					debug("rx FIFO full "); | 
 | 				if (fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY) | 
 | 					debug("rx FIFO empty "); | 
 | 				debug("\n"); | 
 | 				break; | 
 | 			} | 
 |  | 
 | 			if (!(fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)) { | 
 | 				tmpdin = readl(®s->rx_fifo); | 
 |  | 
 | 				/* swap bytes read in */ | 
 | 				if (din != NULL) { | 
 | 					for (i = bytes - 1; i >= 0; --i) { | 
 | 						din[i] = tmpdin & 0xff; | 
 | 						tmpdin >>= 8; | 
 | 					} | 
 | 					din += bytes; | 
 | 				} | 
 |  | 
 | 				/* We can exit when we've had both RX and TX */ | 
 | 				break; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		if (tm >= SPI_TIMEOUT) | 
 | 			ret = tm; | 
 |  | 
 | 		/* clear ACK RDY, etc. bits */ | 
 | 		writel(readl(®s->fifo_status), ®s->fifo_status); | 
 | 	} | 
 |  | 
 | 	if (flags & SPI_XFER_END) | 
 | 		spi_cs_deactivate(dev); | 
 |  | 
 | 	debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n", | 
 | 	      __func__, tmpdin, readl(®s->fifo_status)); | 
 |  | 
 | 	if (ret) { | 
 | 		printf("%s: timeout during SPI transfer, tm %d\n", | 
 | 		       __func__, ret); | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static int tegra114_spi_set_speed(struct udevice *bus, uint speed) | 
 | { | 
 | 	struct tegra_spi_platdata *plat = bus->platdata; | 
 | 	struct tegra114_spi_priv *priv = dev_get_priv(bus); | 
 |  | 
 | 	if (speed > plat->frequency) | 
 | 		speed = plat->frequency; | 
 | 	priv->freq = speed; | 
 | 	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int tegra114_spi_set_mode(struct udevice *bus, uint mode) | 
 | { | 
 | 	struct tegra114_spi_priv *priv = dev_get_priv(bus); | 
 |  | 
 | 	priv->mode = mode; | 
 | 	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static const struct dm_spi_ops tegra114_spi_ops = { | 
 | 	.xfer		= tegra114_spi_xfer, | 
 | 	.set_speed	= tegra114_spi_set_speed, | 
 | 	.set_mode	= tegra114_spi_set_mode, | 
 | 	/* | 
 | 	 * cs_info is not needed, since we require all chip selects to be | 
 | 	 * in the device tree explicitly | 
 | 	 */ | 
 | }; | 
 |  | 
 | static const struct udevice_id tegra114_spi_ids[] = { | 
 | 	{ .compatible = "nvidia,tegra114-spi" }, | 
 | 	{ } | 
 | }; | 
 |  | 
 | U_BOOT_DRIVER(tegra114_spi) = { | 
 | 	.name	= "tegra114_spi", | 
 | 	.id	= UCLASS_SPI, | 
 | 	.of_match = tegra114_spi_ids, | 
 | 	.ops	= &tegra114_spi_ops, | 
 | 	.ofdata_to_platdata = tegra114_spi_ofdata_to_platdata, | 
 | 	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata), | 
 | 	.priv_auto_alloc_size = sizeof(struct tegra114_spi_priv), | 
 | 	.probe	= tegra114_spi_probe, | 
 | }; |