[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