ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/uboot/drivers/spi/pxa2xx_spi.c b/marvell/uboot/drivers/spi/pxa2xx_spi.c
new file mode 100644
index 0000000..95d2288
--- /dev/null
+++ b/marvell/uboot/drivers/spi/pxa2xx_spi.c
@@ -0,0 +1,473 @@
+/*
+ * Driver for simulating ssp as spi device for pxa
+ *
+ * Copyright (c) 2009 Marvell Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <asm/arch/pxa2xx_spi.h>
+#include <asm/gpio.h>
+#include <asm/arch/pxa_dma.h>
+#include <asm/arch/cpu.h>
+
+#define to_pxa_spi_slave(s)	container_of(s, struct pxa_spi_slave, slave)
+
+int cs_continuous;
+
+#ifndef CONFIG_PXA_SPI_ENABLE_AUTO_CS
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct pxa_spi_slave *pss = to_pxa_spi_slave(slave);
+	gpio_set_value(slave->cs, pss->gpio_cs_inverted);
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	struct pxa_spi_slave *pss = to_pxa_spi_slave(slave);
+	gpio_set_value(slave->cs, !pss->gpio_cs_inverted);
+}
+#endif
+
+static int spi_pxa_write(struct pxa_spi_slave *pss, unsigned int bitlen)
+{
+	int wait_timeout = SSP_FLUSH_NUM;
+	int bytes = bitlen / pss->slave.wordlen;
+
+	while (--wait_timeout && !(readl(&pss->spi_reg->sssr) & SSSR_TNF))
+		;
+	if (!wait_timeout) {
+		debug("%s: timeout error\n", __func__);
+		return -1;
+	}
+
+	while (bytes--) {
+		if (pss->tx != NULL) {
+			if (pss->slave.wordlen > 16) {
+				writel(*(u32 *)pss->tx, &pss->spi_reg->ssdr);
+				pss->tx += 4;
+			} else if (pss->slave.wordlen > 8) {
+				writel(*(u16 *)pss->tx, &pss->spi_reg->ssdr);
+				pss->tx += 2;
+			} else {
+				writel(*(u8 *)pss->tx, &pss->spi_reg->ssdr);
+				++pss->tx;
+			}
+		} else
+			writel(0, &pss->spi_reg->ssdr);
+
+		while ((readl(&pss->spi_reg->sssr)&0xF10) && wait_timeout--) {
+			nop();
+			nop();
+		}
+		if (!wait_timeout) {
+			debug("%s: timeout error\n", __func__);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int spi_pxa_read(struct pxa_spi_slave *pss, unsigned int bitlen)
+{
+	int wait_timeout = SSP_FLUSH_NUM;
+	int bytes = bitlen / pss->slave.wordlen;	
+
+	while (--wait_timeout && !(readl(&pss->spi_reg->sssr) & SSSR_TNF))
+		;
+	if (!wait_timeout) {
+		debug("%s: timeout error\n", __func__);
+		return -1;
+	}
+
+	while (bytes--) {
+		wait_timeout = SSP_FLUSH_NUM;	
+		writel(0xff, &pss->spi_reg->ssdr);
+		while ((readl(&pss->spi_reg->sssr)&0xF10) && wait_timeout--) {
+			nop();
+			nop();
+		}
+		if (!wait_timeout) {
+			printf("%s: timeout error, sssr:0x%x. byte:0x%x.\n",
+				__func__, readl(&pss->spi_reg->sssr), bytes);
+			return -1;
+		}
+
+		wait_timeout = SSP_FLUSH_NUM;
+		while (--wait_timeout && !(readl(&pss->spi_reg->sssr) & SSSR_RNE))
+		;
+		if (!wait_timeout) {
+			printf("%s: timeout error sssr:0x%x.\n", __func__,
+					readl(&pss->spi_reg->sssr));
+			return -1;
+		}
+
+		if (pss->rx != NULL) {
+			if (pss->slave.wordlen > 16) {
+				*(u32 *)pss->rx = readl(&pss->spi_reg->ssdr);
+				pss->rx += 4;
+			} else if (pss->slave.wordlen > 8) {
+				*(u16 *)pss->rx = readl(&pss->spi_reg->ssdr);
+				pss->rx += 2;
+			} else {
+				*(u8 *)pss->rx = readl(&pss->spi_reg->ssdr);
+				++pss->rx;
+			}
+		} else
+			readl(&pss->spi_reg->ssdr);
+	}	
+
+	return 0;
+}
+
+static int spi_pxa_flush(struct pxa_spi_slave *pss)
+{
+	unsigned long limit = SSP_FLUSH_NUM;
+
+	do {
+		while (readl(&pss->spi_reg->sssr) & SSSR_RNE)
+			readl(&pss->spi_reg->ssdr);
+	} while ((readl(&pss->spi_reg->sssr) & SSSR_BSY) && limit--);
+
+	writel(SSSR_ROR, &pss->spi_reg->sssr);
+
+	return limit;
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+		unsigned int max_hz, unsigned int mode)
+{
+	struct pxa_spi_slave *pss;
+
+	pss = spi_alloc_slave(struct pxa_spi_slave, bus, cs);
+	if (!pss)
+		return NULL;
+
+	pss->slave.bus = bus;
+#ifndef CONFIG_PXA_SPI_ENABLE_AUTO_CS
+	pss->slave.cs = cs;
+#endif
+	pss->spi_reg = (struct ssp_reg *)CONFIG_SYS_SSP_BASE;
+#ifdef CONFIG_SPI_52M_ENABLE
+	pss->cr0 = SSCR0_MOTO | SSCR0_DATASIZE(DEFAULT_WORD_LEN)
+		 | SSCR0_SSE | SSCR0_52MM;
+#else
+	pss->cr0 = SSCR0_MOTO | SSCR0_DATASIZE(DEFAULT_WORD_LEN)
+		 | SSCR0_SSE;
+#endif
+
+	pss->cr1 = SSCR1_TTE | SSCR1_TTELP |
+		(SSCR1_RXTRESH(RX_THRESH_DEF) & SSCR1_RFT) |
+		(SSCR1_TXTRESH(TX_THRESH_DEF) & SSCR1_TFT);
+
+	pss->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
+	pss->cr1 |= (((mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
+		| (((mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
+
+	pss->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
+	pss->clear_sr = SSSR_ROR | SSSR_TINT;
+
+	if (cs) {
+#ifndef CONFIG_PXA_SPI_ENABLE_AUTO_CS
+		gpio_direction_output(cs, !pss->gpio_cs_inverted);
+		pss->gpio_cs_inverted = mode & SPI_CS_HIGH;
+		gpio_set_value(cs, !pss->gpio_cs_inverted);
+#endif
+	}
+	cs_continuous = 0;
+
+	return &pss->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	struct pxa_spi_slave *pss = to_pxa_spi_slave(slave);
+	free(pss);
+}
+#ifdef CONFIG_PXA_DMA
+__attribute__ ((aligned(32))) unsigned int dummy[0x400];
+#endif
+void spi_init(void)
+{
+	unsigned int reg;
+	int clk = SSP_26M; // default 26M
+	if (CONFIG_SYS_SSP_BASE == SSP0_BASE)
+		reg = APBC_SSP0_CLK_RST;
+	else if (CONFIG_SYS_SSP_BASE == SSP1_BASE)
+		reg = APBC_SSP1_CLK_RST;
+	else if (CONFIG_SYS_SSP_BASE == SSP2_BASE)
+		reg = APBC_SSP2_CLK_RST;
+	else {
+		printf("Fatal error: unsupportted ssp base: 0x%x.\n", CONFIG_SYS_SSP_BASE);
+		return;
+	}
+
+#ifdef CONFIG_SPI_52M_ENABLE
+	clk = SSP_52M;
+#else
+	#ifdef CONFIG_SPI_26M_ENABLE
+		clk = SSP_26M;
+	#else
+		#ifdef CONFIG_SPI_13M_ENABLE
+			clk = SSP_13M;
+		#else
+			#ifdef CONFIG_SPI_6P5M_ENABLE
+				clk = SSP_6P5M;
+			#endif
+		#endif
+	#endif
+#endif
+
+	__raw_writel(APBC_SSP_BCLKEN | APBC_SSP_FNCLKEN |
+		(clk << APBC_SSP_FNCLKSEL_SHIFT),  reg);
+
+#ifdef CONFIG_PXA_DMA
+	memset(dummy, 0x0, 0x400*4);
+#endif
+	/* Load default SSP configuration */
+	writel(0, CONFIG_SYS_SSP_BASE + SSCR0);
+	writel(SSCR1_RXTRESH(RX_THRESH_DEF) |
+		SSCR1_TXTRESH(TX_THRESH_DEF), CONFIG_SYS_SSP_BASE + SSCR1);
+	writel(SSCR0_MOTO | SSCR0_DATASIZE(DEFAULT_WORD_LEN)
+			, CONFIG_SYS_SSP_BASE + SSCR0);
+	writel(0, CONFIG_SYS_SSP_BASE + SSTO);
+	writel(0, CONFIG_SYS_SSP_BASE + SSPSP);
+
+	__raw_writel(DMA_CLK_AXICLK_EN | DMA_CLK_AXI_RST,
+		PMUA_DMA_CLK_RES_CTRL);	/* enable DMA clock */
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct pxa_spi_slave *pss = to_pxa_spi_slave(slave);
+	slave->wordlen = 8;	/* set default wordlen */
+
+	if (spi_pxa_flush(pss) == 0)
+		return -1;
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+		void *din, unsigned long flags)
+{
+	struct pxa_spi_slave *pss = to_pxa_spi_slave(slave);
+	int ret = 0;
+
+	if (slave->wordlen < 4 || slave->wordlen > 32) {
+		printf("pxa2xx_spi: invalid wordlen %d\n", slave->wordlen);
+		return -1;
+	}
+
+	if (bitlen % slave->wordlen)
+		return -1;
+
+	pss->rx = din;
+	pss->tx = dout;
+
+	writel(0, &pss->spi_reg->sscr0);
+	pss->cr0 &=  ~(0xf);
+	if (slave->wordlen > 16)
+		pss->cr0 |= SSCR0_EDSS | (slave->wordlen - 1);
+	else
+		pss->cr0 |= 0xc00000 | (slave->wordlen - 1);
+	writel(pss->cr1, &pss->spi_reg->sscr1);
+	writel(TIMEOUT_DEF, &pss->spi_reg->ssto);
+	writel(pss->cr0, &pss->spi_reg->sscr0);
+
+	if (flags & SPI_XFER_BEGIN) {
+#ifndef CONFIG_PXA_SPI_ENABLE_AUTO_CS
+		if (!cs_continuous)
+			spi_cs_activate(slave);
+#endif
+	}
+
+	if (dout != NULL && din != NULL) {
+		ret = spi_pxa_write(pss, bitlen - slave->wordlen);
+		if(ret)
+			return -1;
+		
+		ret = spi_pxa_read(pss, slave->wordlen);
+		if(ret)
+			return -1;
+	} else if (dout != NULL) {
+		ret = spi_pxa_write(pss, bitlen);
+		if(ret)
+			return -1;
+	} else if (din != NULL) {
+		ret = spi_pxa_read(pss, bitlen);
+		if(ret)
+			return -1;
+	}
+
+	if (flags & SPI_XFER_END) {
+		writel(pss->clear_sr, &pss->spi_reg->sssr);
+		writel(0, &pss->spi_reg->ssto);
+		writel(0, &pss->spi_reg->sscr0);
+#ifndef CONFIG_PXA_SPI_ENABLE_AUTO_CS
+		if (!cs_continuous)
+			spi_cs_deactivate(slave);
+#endif
+	}
+	return ret;
+}
+#ifdef CONFIG_PXA_DMA
+static int spi_dma_read(void *din, unsigned int len)
+{
+	int i, init = 0;
+	if (!init) {
+		if (cpu_is_pxa1826_z3() || cpu_is_pxa1826_a0()) {
+			dmac_map_device_to_channel(DMAC_SSP2_RX,
+				SSP_RX_CHANNEL);
+			dmac_map_device_to_channel(DMAC_SSP2_TX,
+				SSP_TX_CHANNEL);
+		} else {
+			dmac_map_device_to_channel(DMAC_SSP2_RX_Z12,
+				SSP_RX_CHANNEL);
+			dmac_map_device_to_channel(DMAC_SSP2_TX_Z12,
+				SSP_TX_CHANNEL);
+		}
+
+		dmac_user_aligment(SSP_RX_CHANNEL);
+		dmac_user_aligment(SSP_TX_CHANNEL);
+		init = 1;
+	}
+
+	pxa_dma_read((unsigned int)din, SSP_SSDR, len, SSP_RX_CHANNEL);
+	pxa_dma_write(SSP_SSDR, (unsigned int)dummy, len, SSP_TX_CHANNEL);
+
+	dmac_start_transfer(SSP_RX_CHANNEL);
+	dmac_start_transfer(SSP_TX_CHANNEL);
+
+	do {
+		for (i = 0; i < 500; i++)
+			nop();
+		if (dmac_read_dcsr(SSP_TX_CHANNEL) & DCSR_STOPSTATE)
+			break;
+
+	} while (1);
+
+	do {
+		if (dmac_read_dcsr(SSP_RX_CHANNEL) & DCSR_STOPSTATE)
+			break;
+	} while (1);
+
+
+	for (i = 0; i < len; i += 4)
+		swab32s(din+i);
+
+	if (!(dmac_read_dcsr(SSP_TX_CHANNEL) & DCSR_STOPSTATE)) {
+		printf("Error:DMA write operate timeout.\n");
+		return 1;
+	}
+	if (!(dmac_read_dcsr(SSP_RX_CHANNEL) & DCSR_STOPSTATE)) {
+		printf("Error:DMA read operate timeout.\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int spi_dma_write(void *dout, unsigned int len)
+{
+	int i, init = 0;
+
+	for (i = 0; i < len; i += 4)
+		swab32s(dout+i);
+
+	flush_dcache_all();
+	if (!init) {
+		if (cpu_is_pxa1826_z3() || cpu_is_pxa1826_a0())
+			dmac_map_device_to_channel(DMAC_SSP2_TX,
+				SSP_TX_CHANNEL);
+		else
+			dmac_map_device_to_channel(DMAC_SSP2_TX_Z12,
+				SSP_TX_CHANNEL);
+
+		dmac_user_aligment(SSP_TX_CHANNEL);
+		init = 1;
+	}
+
+	pxa_dma_write(SSP_SSDR, (unsigned int)dout, len, SSP_TX_CHANNEL);
+	dmac_start_transfer(SSP_TX_CHANNEL);
+
+	do {
+		for (i = 0; i < 500; i++)
+			nop();
+		if (dmac_read_dcsr(SSP_TX_CHANNEL) & DCSR_STOPSTATE)
+			break;
+	} while (1);
+
+	if (!(dmac_read_dcsr(SSP_TX_CHANNEL) & DCSR_STOPSTATE)) {
+		printf("Error:DMA write operate timeout.\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+int spi_dma_xfer(struct spi_slave *slave, const u8 *cmd, size_t cmd_len,
+			const void *dout, const void *din, size_t data_len)
+{
+	struct pxa_spi_slave *pss = to_pxa_spi_slave(slave);
+	int ret = 0;
+
+#ifndef CONFIG_PXA_SPI_ENABLE_AUTO_CS
+	spi_cs_activate(slave);
+#endif
+
+	if (cmd) {
+		cs_continuous = 1;
+		spi_xfer(slave, cmd_len*8, cmd, NULL,
+			SPI_XFER_BEGIN | SPI_XFER_END);
+	}
+
+	if (dout || din) {
+		writel(TIMEOUT_DEF, &pss->spi_reg->ssto);
+#ifdef CONFIG_SPI_52M_ENABLE
+		writel(SSCR1_TTELP | SSCR1_TTE | SSCR1_RXTRESH(0x3)
+			| SSCR1_TRAIL | SSCR1_TSRE | SSCR1_RSRE |
+			SSCR1_TXTRESH(0x4), &pss->spi_reg->sscr1);
+		writel(SSCR0_52MM | SSCR0_SSE | SSCR0_EDSS |
+			SSCR0_DATASIZE(0x10), &pss->spi_reg->sscr0);
+#else
+		writel(SSCR1_TTELP | SSCR1_TTE | SSCR1_RXTRESH(0x9)
+			| SSCR1_TRAIL | SSCR1_TSRE | SSCR1_RSRE |
+			SSCR1_TXTRESH(0x4), &pss->spi_reg->sscr1);
+
+		writel(SSCR0_SSE | SSCR0_EDSS |
+			SSCR0_DATASIZE(0x10), &pss->spi_reg->sscr0);
+#endif
+	}
+
+	if (dout)
+		ret = spi_dma_write((void *)dout, data_len);
+	if (din)
+		ret = spi_dma_read((void *)din, data_len);
+
+	while (readl(&pss->spi_reg->sssr) & 0xF10)
+		;
+	if (dout || din) {
+		writel(pss->clear_sr, &pss->spi_reg->sssr);
+		clrbits_le32(&pss->spi_reg->sscr1, pss->int_cr1);
+		writel(0, &pss->spi_reg->sscr0);
+#ifndef CONFIG_PXA_SPI_ENABLE_AUTO_CS
+		spi_cs_deactivate(slave);
+#endif
+	}
+	cs_continuous = 0;
+	return ret;
+}
+#endif