Signed-off-by: Daniel Hellstrom <dan...@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 <dan...@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, dan...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to