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