[U-Boot] [PATCH 14/17] LEON: added support for GRLIB SPI Memory controller, spi command interface.

Daniel Hellstrom daniel at gaisler.com
Thu Jan 28 13:16:33 CET 2010


Signed-off-by: Daniel Hellstrom <daniel at gaisler.com>
---
 drivers/spi/Makefile       |    1 +
 drivers/spi/spimctrl_spi.c |  261 ++++++++++++++++++++++++++++++++++++++++++++
 include/grlib/spimctrl.h   |   69 ++++++++++++
 lib_sparc/board.c          |   14 +++
 4 files changed, 345 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spimctrl_spi.c
 create mode 100644 include/grlib/spimctrl.h

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 824d8e7..a730d45 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -34,6 +34,7 @@ COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
 COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
 COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
 COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
+COBJS-$(CONFIG_SPIMCTRL_SPI) += spimctrl_spi.o
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/spi/spimctrl_spi.c b/drivers/spi/spimctrl_spi.c
new file mode 100644
index 0000000..a37cfa9
--- /dev/null
+++ b/drivers/spi/spimctrl_spi.c
@@ -0,0 +1,261 @@
+/* SPI interface driver for GRLIB SPIMCTRL (SPI Memory controller)
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom <daniel at gaisler.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 <malloc.h>
+#include <spi.h>
+#include <ambapp.h>
+#include <grlib/spimctrl.h>
+
+struct spimctrl_priv {
+	struct spimctrl_regs *regs;
+	int irq;
+	unsigned int mode;
+	unsigned int max_hz;
+};
+
+struct spi_slave_internal {
+	struct spi_slave dev;
+	struct spimctrl_priv *priv;
+	int locked;
+};
+
+static int spimctrl_cnt = 0;
+static struct spimctrl_priv *spimctrl_devs;
+
+int spimctrl_probe(void)
+{
+	int cnt, i, found;
+	ambapp_ahbdev ahbdev;
+	struct spimctrl_priv *priv;
+
+	cnt = ambapp_ahbslv_count(&ambapp_plb,VENDOR_GAISLER,GAISLER_SPIMCTRL);
+	debug("Found %d SPIMCTRLS\n", cnt);
+	if ( cnt < 1 )
+		return 0;
+
+	spimctrl_cnt = cnt;
+	spimctrl_devs = (struct spimctrl_priv *) malloc(sizeof(*priv) * cnt);
+	memset(spimctrl_devs, 0, sizeof(struct spimctrl_priv) * cnt);
+
+	for (i=0; i<cnt; i++) {
+		found = ambapp_ahbslv_find(&ambapp_plb, VENDOR_GAISLER,
+				GAISLER_SPIMCTRL, i, &ahbdev);
+		if ( !found ) {
+			printf("spimctrl_probe: internal AMBA error\n");
+			while (1) ;
+		}
+
+		priv = &spimctrl_devs[i];
+		priv->regs = (struct spimctrl_regs *)ahbdev.address[0];
+		priv->irq = ahbdev.irq;
+
+		debug("SPIMCTRL[%d]: 0x%x irq %d\n",
+			i, (unsigned int)priv->regs, priv->irq);
+	}
+
+	return cnt;
+}
+
+void spimctrl_init(struct spimctrl_priv *priv)
+{
+	debug("SPIMCTRL_INIT\n");
+
+	/* Finish any previous ongoing user activity, this should
+	 * not normally happen, but may when debugging.
+	 */
+	if ( priv->regs->stat & SPIMCTRL_STAT_DONE )
+		priv->regs->stat = SPIMCTRL_STAT_DONE;
+
+	if ( priv->regs->ctrl & SPIMCTRL_CTRL_USRC ) {
+		/* Exit User mode */
+		priv->regs->ctrl = SPIMCTRL_CTRL_CSN;
+	}
+}
+
+void spimctrl_cs_activate(struct spimctrl_priv *priv)
+{
+	debug("CS ACT\n");
+
+	if ( priv->regs->stat & SPIMCTRL_STAT_DONE )
+		priv->regs->stat = SPIMCTRL_STAT_DONE;
+
+	/* Enter User mode */
+	priv->regs->ctrl = SPIMCTRL_CTRL_CSN | SPIMCTRL_CTRL_USRC;
+
+	/* Lower chip-select */
+	priv->regs->ctrl = SPIMCTRL_CTRL_USRC;
+}
+
+void spimctrl_cs_deactivate(struct spimctrl_priv *priv)
+{
+	debug("CS INACT\n");
+
+	/* Rise chip select */
+	priv->regs->ctrl = SPIMCTRL_CTRL_CSN | SPIMCTRL_CTRL_USRC;
+
+	/* Exit User mode */
+	priv->regs->ctrl = SPIMCTRL_CTRL_CSN;
+}
+
+void spimctrl_transfer_byte(struct spimctrl_priv *priv, char *out, char *in)
+{
+	unsigned int stat;
+	unsigned char rx;
+
+	while( (stat=priv->regs->stat) & 
+		(SPIMCTRL_STAT_BUSY|SPIMCTRL_STAT_DONE) ) {
+		debug("WAITING1: 0x%x\n", stat);
+	}
+	debug("OK STAT1: 0x%x\n", stat);
+
+	if ( out ) {
+		priv->regs->tx = out[0];	
+	} else {
+		priv->regs->tx = 0;
+	}
+
+	while ( ((stat=priv->regs->stat) & SPIMCTRL_STAT_DONE) == 0 ) {
+		debug("WAITING2: 0x%x\n", stat);
+	}
+	debug("OK STAT2: 0x%x\n", stat);
+	rx = priv->regs->rx;
+	if ( in ) {
+		in[0] = rx;
+	}
+	priv->regs->stat = SPIMCTRL_STAT_DONE;
+
+	if ( out && in ) {
+		debug("OUT 0x%02x ; IN 0x%02x\n", out[0], in[0]);
+	} else if ( out ) {
+		debug("OUT 0x%02x\n", out[0]);
+	} else if ( in ) {
+		debug("IN: 0x%02x\n", in[0]);
+	}
+}
+
+void spi_init(void)
+{
+	int i;
+
+	debug("SPI INIT\n");
+
+	/* Find SPIMCTRL cores */
+	spimctrl_probe();
+
+	/* Init SPIMCTRL Core */
+	for ( i=0; i<spimctrl_cnt; i++) {
+		spimctrl_init(&spimctrl_devs[i]);
+	}
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+				  unsigned int max_hz, unsigned int mode)
+{
+	struct spi_slave_internal *slave;
+
+	debug("spi_setup_slave(%d, %d, %d, %d)\n", bus, cs, max_hz, mode);
+
+	if ( bus >= spimctrl_cnt ) {
+		printf("spi_setup_slave: NO SUCH BUS: %d\n", bus);
+		return NULL;
+	}
+
+	slave = malloc(sizeof(struct spi_slave_internal));
+	if (!slave)
+		return NULL;
+
+	slave->dev.bus = bus;
+	slave->dev.cs = cs;
+	slave->priv = &spimctrl_devs[bus];
+	slave->priv->mode = mode;
+	slave->priv->max_hz = max_hz;
+	slave->locked = 0;
+
+	return &slave->dev;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct spi_slave_internal *slv = (void *)slave;
+
+	if ( slv->locked )
+		return -1;
+	slv->locked = 1;
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct spi_slave_internal *slv = (void *)slave;
+
+	slv->locked = 0;
+	return;
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+		void *din, unsigned long flags)
+{
+	struct spi_slave_internal *slv = (void *)slave;
+	int i, cnt;
+	unsigned char *out, *in;
+
+	debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
+		slave->bus, slave->cs, (uint)dout, (uint)din, bitlen);
+
+	if ( (bitlen & 0x7) != 0 ) {
+		printf("spi_xfer: Bitlength of != 8 not supported\n");
+		return -1;
+	}
+
+	if (flags & SPI_XFER_BEGIN) {
+		/* Set Chip Select */
+		spimctrl_cs_activate(slv->priv);
+	}
+
+	out = (unsigned char *)dout;
+	in = (unsigned char *)din;
+	cnt = bitlen / 8;
+	for (i=0; i<cnt; i++){
+		spimctrl_transfer_byte(slv->priv, out, in);
+
+		if ( out )
+			out++;
+		if ( in )
+			in++;
+	}
+
+	if (flags & SPI_XFER_END) {
+		/* End transfer by rising ChipSelect again */
+		spimctrl_cs_deactivate(slv->priv);
+	}
+
+	return 0;
+}
diff --git a/include/grlib/spimctrl.h b/include/grlib/spimctrl.h
new file mode 100644
index 0000000..8329745
--- /dev/null
+++ b/include/grlib/spimctrl.h
@@ -0,0 +1,69 @@
+/* GRLIB SPI Memory controller (SPIMCTRL) definitions
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom, Aeroflex Gaisler, daniel at gaisler.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#ifndef __GRLIB_SPIMCTRL_H__
+#define __GRLIB_SPIMCTRL_H__
+
+/*** REGISTER LAYOUT ***/
+struct spimctrl_regs {
+	volatile unsigned int conf;		/* 0x00 */
+	volatile unsigned int ctrl;		/* 0x04 */
+	volatile unsigned int stat;		/* 0x08 */
+	volatile unsigned int rx;		/* 0x0C */
+	volatile unsigned int tx;		/* 0x10 */
+};
+
+/*** CONFIGURATION REGISTER 0x00 ***/
+#define SPIMCTRL_CONF_READCMD_BIT	0
+#define SPIMCTRL_CONF_READCMD		0xff
+
+/*** CONTROL REGISTER 0x04 ***/
+#define SPIMCTRL_CTRL_USRC_BIT	0
+#define SPIMCTRL_CTRL_IEN_BIT	1
+#define SPIMCTRL_CTRL_EAS_BIT	2
+#define SPIMCTRL_CTRL_CSN_BIT	3
+#define SPIMCTRL_CTRL_RST_BIT	4
+
+#define SPIMCTRL_CTRL_USRC	(1<<SPIMCTRL_CTRL_USRC_BIT)
+#define SPIMCTRL_CTRL_IEN	(1<<SPIMCTRL_CTRL_IEN_BIT)
+#define SPIMCTRL_CTRL_EAS	(1<<SPIMCTRL_CTRL_EAS_BIT)
+#define SPIMCTRL_CTRL_CSN	(1<<SPIMCTRL_CTRL_CSN_BIT)
+#define SPIMCTRL_CTRL_RST	(1<<SPIMCTRL_CTRL_RST_BIT)
+
+/*** STATUS REGISTER 0x08 ***/
+#define SPIMCTRL_STAT_DONE_BIT	0
+#define SPIMCTRL_STAT_BUSY_BIT	1
+#define SPIMCTRL_STAT_INT_BIT	2
+#define SPIMCTRL_STAT_ERR_BIT	3
+#define SPIMCTRL_STAT_TO_BIT	4
+#define SPIMCTRL_STAT_CD_BIT	5
+
+#define SPIMCTRL_STAT_DONE	(1<<SPIMCTRL_STAT_DONE_BIT)
+#define SPIMCTRL_STAT_BUSY	(1<<SPIMCTRL_STAT_BUSY_BIT)
+#define SPIMCTRL_STAT_INT	(1<<SPIMCTRL_STAT_INT_BIT)
+#define SPIMCTRL_STAT_ERR	(1<<SPIMCTRL_STAT_ERR_BIT)
+#define SPIMCTRL_STAT_TO	(1<<SPIMCTRL_STAT_TO_BIT)
+#define SPIMCTRL_STAT_CD	(1<<SPIMCTRL_STAT_CD_BIT)
+
+#endif
diff --git a/lib_sparc/board.c b/lib_sparc/board.c
index d829af0..3362f39 100644
--- a/lib_sparc/board.c
+++ b/lib_sparc/board.c
@@ -97,6 +97,16 @@ static int init_baudrate(void)
 	return (0);
 }
 
+#if defined(CONFIG_HARD_SPI)
+static int init_func_spi (void)
+{
+        puts ("SPI:   ");
+        spi_init ();
+        puts ("ready\n");
+        return (0);
+}
+#endif
+
 /***********************************************************************/
 
 /*
@@ -304,6 +314,10 @@ void board_init_f(ulong bootflag)
 			CONFIG_SYS_MALLOC_END - CONFIG_SYS_MALLOC_BASE);
 	malloc_bin_reloc();
 
+#if defined(CONFIG_HARD_SPI)
+	init_func_spi();
+#endif
+
 #if !defined(CONFIG_SYS_NO_FLASH)
 	puts("FLASH: ");
 
-- 
1.5.4



More information about the U-Boot mailing list