diff options
author | Justin Waters <justin.waters@timesys.com> | 2009-06-17 10:09:00 -0400 |
---|---|---|
committer | Justin Waters <justin.waters@timesys.com> | 2009-06-17 10:09:00 -0400 |
commit | 4e35d9f7af6cb5d553511d6064f224885fd905f4 (patch) | |
tree | 7ae0aec6dffc515af7c84c1d25f9c4ec6d0bc9f6 /drivers/spi | |
parent | 180a90abdae72587c0f679edf8991455e559440d (diff) |
Add omapl137 support1.3.3-omapl137-evm-200906171409
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/spi/atmel_spi.c | 210 | ||||
-rw-r--r-- | drivers/spi/atmel_spi.h | 95 | ||||
-rw-r--r-- | drivers/spi/davinci_spi.c | 284 | ||||
-rw-r--r-- | drivers/spi/davinci_spi.h | 46 | ||||
-rw-r--r-- | drivers/spi/mpc8xxx_spi.c | 54 | ||||
-rw-r--r-- | drivers/spi/mxc_spi.c | 88 | ||||
-rw-r--r-- | drivers/spi/spirom.c | 212 | ||||
-rw-r--r-- | drivers/spi/spirom.h | 77 |
9 files changed, 1030 insertions, 38 deletions
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bc8a1041210..a917ba5c1d6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk LIB := $(obj)libspi.a COBJS-y += mpc8xxx_spi.o +COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o +COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c new file mode 100644 index 00000000000..317c0b41b6f --- /dev/null +++ b/drivers/spi/atmel_spi.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2007 Atmel Corporation + * + * 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 <spi.h> +#include <malloc.h> + +#include <asm/io.h> + +#include <asm/arch/clk.h> +#include <asm/arch/memory-map.h> + +#include "atmel_spi.h" + +void spi_init() +{ + +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct atmel_spi_slave *as; + unsigned int scbr; + u32 csrx; + void *regs; + + if (cs > 3 || !spi_cs_is_valid(bus, cs)) + return NULL; + + switch (bus) { + case 0: + regs = (void *)SPI0_BASE; + break; +#ifdef SPI1_BASE + case 1: + regs = (void *)SPI1_BASE; + break; +#endif +#ifdef SPI2_BASE + case 2: + regs = (void *)SPI2_BASE; + break; +#endif +#ifdef SPI3_BASE + case 3: + regs = (void *)SPI3_BASE; + break; +#endif + default: + return NULL; + } + + + scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz; + if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) + /* Too low max SCK rate */ + return NULL; + if (scbr < 1) + scbr = 1; + + csrx = ATMEL_SPI_CSRx_SCBR(scbr); + csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); + if (!(mode & SPI_CPHA)) + csrx |= ATMEL_SPI_CSRx_NCPHA; + if (mode & SPI_CPOL) + csrx |= ATMEL_SPI_CSRx_CPOL; + + as = malloc(sizeof(struct atmel_spi_slave)); + if (!as) + return NULL; + + as->slave.bus = bus; + as->slave.cs = cs; + as->regs = regs; + as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS + | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf); + spi_writel(as, CSR(cs), csrx); + + return &as->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + free(as); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + /* Enable the SPI hardware */ + spi_writel(as, CR, ATMEL_SPI_CR_SPIEN); + + /* + * Select the slave. This should set SCK to the correct + * initial state, etc. + */ + spi_writel(as, MR, as->mr); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + /* Disable the SPI hardware */ + spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + unsigned int len_tx; + unsigned int len_rx; + unsigned int len; + int ret; + u32 status; + const u8 *txp = dout; + u8 *rxp = din; + u8 value; + + ret = 0; + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * TODO: The controller can do non-multiple-of-8 bit + * transfers, but this driver currently doesn't support it. + * + * It's also not clear how such transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + /* + * The controller can do automatic CS control, but it is + * somewhat quirky, and it doesn't really buy us much anyway + * in the context of U-Boot. + */ + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + for (len_tx = 0, len_rx = 0; len_rx < len; ) { + status = spi_readl(as, SR); + + if (status & ATMEL_SPI_SR_OVRES) + return -1; + + if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) { + if (txp) + value = *txp++; + else + value = 0; + spi_writel(as, TDR, value); + len_tx++; + } + if (status & ATMEL_SPI_SR_RDRF) { + value = spi_readl(as, RDR); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + +out: + if (flags & SPI_XFER_END) { + /* + * Wait until the transfer is completely done before + * we deactivate CS. + */ + do { + status = spi_readl(as, SR); + } while (!(status & ATMEL_SPI_SR_TXEMPTY)); + + spi_cs_deactivate(slave); + } + + return 0; +} diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h new file mode 100644 index 00000000000..2baf9c76ef2 --- /dev/null +++ b/drivers/spi/atmel_spi.h @@ -0,0 +1,95 @@ +/* + * Register definitions for the DaVinci SPI Controller + */ + +/* Register offsets */ +#define DAVINCI_SPI_CR 0x0000 +#define ATMEL_SPI_MR 0x0004 +#define ATMEL_SPI_RDR 0x0008 +#define ATMEL_SPI_TDR 0x000c +#define ATMEL_SPI_SR 0x0010 +#define ATMEL_SPI_IER 0x0014 +#define ATMEL_SPI_IDR 0x0018 +#define ATMEL_SPI_IMR 0x001c +#define ATMEL_SPI_CSR(x) (0x0030 + 4 * (x)) +#define ATMEL_SPI_VERSION 0x00fc + +/* Bits in CR */ +#define ATMEL_SPI_CR_SPIEN (1 << 0) +#define ATMEL_SPI_CR_SPIDIS (1 << 1) +#define ATMEL_SPI_CR_SWRST (1 << 7) +#define ATMEL_SPI_CR_LASTXFER (1 << 24) + +/* Bits in MR */ +#define ATMEL_SPI_MR_MSTR (1 << 0) +#define ATMEL_SPI_MR_PS (1 << 1) +#define ATMEL_SPI_MR_PCSDEC (1 << 2) +#define ATMEL_SPI_MR_FDIV (1 << 3) +#define ATMEL_SPI_MR_MODFDIS (1 << 4) +#define ATMEL_SPI_MR_LLB (1 << 7) +#define ATMEL_SPI_MR_PCS(x) (((x) & 15) << 16) +#define ATMEL_SPI_MR_DLYBCS(x) ((x) << 24) + +/* Bits in RDR */ +#define ATMEL_SPI_RDR_RD(x) (x) +#define ATMEL_SPI_RDR_PCS(x) ((x) << 16) + +/* Bits in TDR */ +#define ATMEL_SPI_TDR_TD(x) (x) +#define ATMEL_SPI_TDR_PCS(x) ((x) << 16) +#define ATMEL_SPI_TDR_LASTXFER (1 << 24) + +/* Bits in SR/IER/IDR/IMR */ +#define ATMEL_SPI_SR_RDRF (1 << 0) +#define ATMEL_SPI_SR_TDRE (1 << 1) +#define ATMEL_SPI_SR_MODF (1 << 2) +#define ATMEL_SPI_SR_OVRES (1 << 3) +#define ATMEL_SPI_SR_ENDRX (1 << 4) +#define ATMEL_SPI_SR_ENDTX (1 << 5) +#define ATMEL_SPI_SR_RXBUFF (1 << 6) +#define ATMEL_SPI_SR_TXBUFE (1 << 7) +#define ATMEL_SPI_SR_NSSR (1 << 8) +#define ATMEL_SPI_SR_TXEMPTY (1 << 9) +#define ATMEL_SPI_SR_SPIENS (1 << 16) + +/* Bits in CSRx */ +#define ATMEL_SPI_CSRx_CPOL (1 << 0) +#define ATMEL_SPI_CSRx_NCPHA (1 << 1) +#define ATMEL_SPI_CSRx_CSAAT (1 << 3) +#define ATMEL_SPI_CSRx_BITS(x) ((x) << 4) +#define ATMEL_SPI_CSRx_SCBR(x) ((x) << 8) +#define ATMEL_SPI_CSRx_SCBR_MAX 0xff +#define ATMEL_SPI_CSRx_DLYBS(x) ((x) << 16) +#define ATMEL_SPI_CSRx_DLYBCT(x) ((x) << 24) + +/* Bits in VERSION */ +#define ATMEL_SPI_VERSION_REV(x) ((x) << 0) +#define ATMEL_SPI_VERSION_MFN(x) ((x) << 16) + +/* Constants for CSRx:BITS */ +#define ATMEL_SPI_BITS_8 0 +#define ATMEL_SPI_BITS_9 1 +#define ATMEL_SPI_BITS_10 2 +#define ATMEL_SPI_BITS_11 3 +#define ATMEL_SPI_BITS_12 4 +#define ATMEL_SPI_BITS_13 5 +#define ATMEL_SPI_BITS_14 6 +#define ATMEL_SPI_BITS_15 7 +#define ATMEL_SPI_BITS_16 8 + +struct atmel_spi_slave { + struct spi_slave slave; + void *regs; + u32 mr; +}; + +static inline struct atmel_spi_slave *to_atmel_spi(struct spi_slave *slave) +{ + return container_of(slave, struct atmel_spi_slave, slave); +} + +/* Register access macros */ +#define spi_readl(as, reg) \ + readl(as->regs + ATMEL_SPI_##reg) +#define spi_writel(as, reg, value) \ + writel(value, as->regs + ATMEL_SPI_##reg) diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c new file mode 100644 index 00000000000..ed895212bd0 --- /dev/null +++ b/drivers/spi/davinci_spi.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2008 Sekhar Nori, Texas Instruments, Inc <www.ti.com> + * + * Driver for SPI controller on DaVinci. Based on atmel_spi.c + * by Atmel Corporation + * + * Copyright (C) 2007 Atmel Corporation + * + * 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 <spi.h> +#include <malloc.h> + +#include <asm/io.h> + +#include <asm/arch/hardware.h> + +#include "davinci_spi.h" + +static unsigned int data1_reg_val; + + +void spi_init() +{ + /* do nothing */ + +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct davinci_spi_slave *ds; + void *regs; + unsigned int fmt0; + + ds = malloc(sizeof(struct davinci_spi_slave)); + if (!ds) + return NULL; + + ds->slave.bus = bus; + ds->slave.cs = cs; + ds->regs = CFG_SPI_BASE; + ds->freq = max_hz; + + return &ds->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + free(ds); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + unsigned int scalar; + + /* Enable the SPI hardware */ + spi_writel(ds, GCR0, 0); + udelay(1000); + spi_writel(ds, GCR0, 1); + + /* Set master mode, powered up and not activated */ + spi_writel(ds, GCR1, 0x3); + + /* CS, CLK, SIMO and SOMI are functional pins */ + spi_writel(ds, PC0, (1 << 0) | (1 << 9) | (1 << 10) | (1 << 11)); + + /* setup format */ + scalar = ((CFG_SPI_CLK / ds->freq) - 1 ) & 0xFF; + + spi_writel(ds, FMT0, 8 | /* character length */ + (scalar << 8) | + (1 << 16) | /* clock signal delayed by half clk cycle */ + (0 << 17) | /* clock low in idle state - Mode 0 */ + (0 << 20)); /* MSB shifted out first */ + + /* hold cs active at end of transfer until explicitly de-asserted */ + data1_reg_val = (1 << 28) | (slave->cs << 16); + spi_writel(ds, DAT1, data1_reg_val); + + /* including a minor delay. No science here. Should be good even with + * no delay + */ + spi_writel(ds, DELAY, (50 << 24) | (50 << 16)); + + /* default chip select register */ + spi_writel(ds, DEF, 1); + + /* no interrupts */ + spi_writel(ds, INT0, 0); + spi_writel(ds, LVL, 0); + + /* enable SPI */ + spi_writel(ds, GCR1, spi_readl(ds, GCR1) | (1 << 24)); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + /* Disable the SPI hardware */ + spi_writel(ds, GCR0, 0); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + unsigned int len_tx; + unsigned int len_rx; + unsigned int len; + int ret, i; + u32 status; + const u8 *txp = dout; + u8 *rxp = din; + u8 value, dummy = 0; + + ret = 0; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * It's not clear how non-8-bit-aligned transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface - here we terminate on receiving such a + * transfer request. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + /* do an empty read to clear the current contents */ + spi_readl(ds, BUF); + + /* keep writing and reading 1 byte until done */ + for (i = 0; i < len; i++) { + + /* wait till TXFULL is asserted */ + while(spi_readl(ds, BUF) & (1 << 29)); + + /* write the data */ + data1_reg_val &= ~0xFFFF; + if(txp) { + data1_reg_val |= *txp & 0xFF; + txp++; + } + + /* write to DAT1 is required to keep the serial transfer going */ + /* we just terminate when we reach the end */ + if((i == (len -1)) && (flags & SPI_XFER_END)) { + spi_writel(ds, DAT1, data1_reg_val & ~(1 << 28)); /* clear CS hold */ + } else { + spi_writel(ds, DAT1, data1_reg_val); + } + + + /* read the data - wait for data availability */ + while(spi_readl(ds, BUF) & (1 << 31)); + + if(rxp) { + *rxp = spi_readl(ds, BUF) & 0xFF; + rxp++; + } else { + spi_readl(ds, BUF); /* simply drop the read character */ + } + + } + + return 0; + +out: + if (flags & SPI_XFER_END) { + spi_writel(ds, DAT1, data1_reg_val & ~(1 << 28)); + } + + return 0; +} + + +#ifdef CONFIG_CMD_EEPROM + +/* ------------------------------------------------------------------------ * + * SPI ROM Definitions * + * ------------------------------------------------------------------------ */ +#define SPIROM_SIZE 0x00008000 +#define SPIROM_BASE 0x00000000 +#define SPIROM_PAGESIZE 32 +#define SPIROM_PAGEMASK 0xffffffc0 + +/* ------------------------------------------------------------------------ * + * SPI ROM Commands * + * ------------------------------------------------------------------------ */ +#define SPIROM_CMD_WRSR 0x01 +#define SPIROM_CMD_WRITE 0x02 +#define SPIROM_CMD_READ 0x03 +#define SPIROM_CMD_WRDI 0x04 +#define SPIROM_CMD_RDSR 0x05 +#define SPIROM_CMD_WREN 0x06 + +static struct spi_slave *slave; + +void spi_init_f(void) +{ + slave = spi_setup_slave(0, 0, 1*1024*1024, 0); + spi_claim_bus(slave); +} + +static char spirombuf[3]; + +/* ------------------------------------------------------------------------ * + * spirom_status( ) * + * ------------------------------------------------------------------------ */ +static unsigned char spi_get_status( ) +{ + /* Issue read status command */ + spirombuf[0] = SPIROM_CMD_RDSR; + spirombuf[1] = 0; + + spi_xfer(slave, (2)*8, spirombuf, spirombuf, SPI_XFER_BEGIN | SPI_XFER_END); + + return spirombuf[1]; +} + +ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len) +{ + + spirombuf[0] = SPIROM_CMD_WREN; + spi_xfer(slave, 1*8, spirombuf, NULL, SPI_XFER_BEGIN | SPI_XFER_END); + + /* Create command block for program operation */ + spirombuf[0] = SPIROM_CMD_WRITE; + spirombuf[1] = addr[0]; + spirombuf[2] = addr[1]; + + spi_xfer(slave, 3 * 8, spirombuf, NULL, SPI_XFER_BEGIN); + spi_xfer(slave, len * 8, buffer, NULL, SPI_XFER_END); + + /* Wait while busy */ + while( (spi_get_status( ) & 0x01 ) ); + + return len; +} + +ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len) +{ + spirombuf[0] = 0x3; + spirombuf[1] = addr[0]; + spirombuf[2] = addr[1]; + + spi_xfer(slave, 3*8, spirombuf, NULL, SPI_XFER_BEGIN); + spi_xfer(slave, len*8, NULL, buffer, SPI_XFER_END); + + return len; +} + +#endif diff --git a/drivers/spi/davinci_spi.h b/drivers/spi/davinci_spi.h new file mode 100644 index 00000000000..0f2b0877baa --- /dev/null +++ b/drivers/spi/davinci_spi.h @@ -0,0 +1,46 @@ +/* + * Register definitions for the DaVinci SPI Controller + */ + +/* Register offsets */ +#define DAVINCI_SPI_GCR0 0x0000 +#define DAVINCI_SPI_GCR1 0x0004 +#define DAVINCI_SPI_INT0 0x0008 +#define DAVINCI_SPI_LVL 0x000c +#define DAVINCI_SPI_FLG 0x0010 +#define DAVINCI_SPI_PC0 0x0014 +#define DAVINCI_SPI_PC1 0x0018 +#define DAVINCI_SPI_PC2 0x001c +#define DAVINCI_SPI_PC3 0x0020 +#define DAVINCI_SPI_PC4 0x0024 +#define DAVINCI_SPI_PC5 0x0028 +#define DAVINCI_SPI_DAT0 0x0038 +#define DAVINCI_SPI_DAT1 0x003c +#define DAVINCI_SPI_BUF 0x0040 +#define DAVINCI_SPI_EMU 0x0044 +#define DAVINCI_SPI_DELAY 0x0048 +#define DAVINCI_SPI_DEF 0x004c +#define DAVINCI_SPI_FMT0 0x0050 +#define DAVINCI_SPI_FMT1 0x0054 +#define DAVINCI_SPI_FMT2 0x0058 +#define DAVINCI_SPI_FMT3 0x005c +#define DAVINCI_SPI_INTVEC0 0x0060 +#define DAVINCI_SPI_INTVEC1 0x0064 + +struct davinci_spi_slave { + struct spi_slave slave; + void *regs; + u32 mr; + unsigned int freq; +}; + +static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) +{ + return container_of(slave, struct davinci_spi_slave, slave); +} + +#define spi_readl(as, reg) \ + readl(CFG_SPI_BASE + DAVINCI_SPI_##reg) +#define spi_writel(as, reg, value) \ + writel(value, CFG_SPI_BASE + DAVINCI_SPI_##reg) + diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index 2fe838c45d5..136fb50052f 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -24,6 +24,7 @@ #include <common.h> #if defined(CONFIG_MPC8XXX_SPI) && defined(CONFIG_HARD_SPI) +#include <malloc.h> #include <spi.h> #include <asm/mpc8xxx_spi.h> @@ -37,6 +38,34 @@ #define SPI_TIMEOUT 1000 +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct spi_slave *slave; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + slave = malloc(sizeof(struct spi_slave)); + if (!slave) + return NULL; + + slave->bus = bus; + slave->cs = cs; + + /* + * TODO: Some of the code in spi_init() should probably move + * here, or into spi_claim_bus() below. + */ + + return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + void spi_init(void) { volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; @@ -53,7 +82,18 @@ void spi_init(void) spi->com = 0; /* LST bit doesn't do anything, so disregard */ } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_claim_bus(struct spi_slave *slave) +{ + 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) { volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; unsigned int tmpdout, tmpdin, event; @@ -61,11 +101,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) int tm, isRead = 0; unsigned char charSize = 32; - debug("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", - (int)chipsel, *(uint *) dout, *(uint *) din, bitlen); + debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", + slave->bus, slave->cs, *(uint *) dout, *(uint *) din, bitlen); - if (chipsel != NULL) - (*chipsel) (1); /* select the target chip */ + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); spi->event = 0xffffffff; /* Clear all SPI events */ @@ -135,8 +175,8 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin); } - if (chipsel != NULL) - (*chipsel) (0); /* deselect the target chip */ + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); return 0; } diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index b2e3ab9b676..e0809593d10 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -19,6 +19,7 @@ */ #include <common.h> +#include <malloc.h> #include <spi.h> #include <asm/io.h> @@ -61,17 +62,18 @@ static unsigned long spi_bases[] = { 0x53f84000, }; -static unsigned long spi_base; - #endif -spi_chipsel_type spi_chipsel[] = { - (spi_chipsel_type)0, - (spi_chipsel_type)1, - (spi_chipsel_type)2, - (spi_chipsel_type)3, +struct mxc_spi_slave { + struct spi_slave slave; + unsigned long base; + u32 ctrl_reg; }; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); + +static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) +{ + return container_of(slave, struct mxc_spi_slave, slave); +} static inline u32 reg_read(unsigned long addr) { @@ -83,30 +85,31 @@ static inline void reg_write(unsigned long addr, u32 val) *(volatile unsigned long*)addr = val; } -static u32 spi_xchg_single(u32 data, int bitlen) +static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen) { - - unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL); + struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL); if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) { cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) | MXC_CSPICTRL_BITCOUNT(bitlen - 1); - reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); } - reg_write(spi_base + MXC_CSPITXDATA, data); + reg_write(mxcs->base + MXC_CSPITXDATA, data); cfg_reg |= MXC_CSPICTRL_XCH; - reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); - while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) + while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) ; - return reg_read(spi_base + MXC_CSPIRXDATA); + return reg_read(mxcs->base + MXC_CSPIRXDATA); } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) { int n_blks = (bitlen + 31) / 32; u32 *out_l, *in_l; @@ -117,13 +120,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) return 1; } - if (!spi_base) - spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH); - for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout; i < n_blks; i++, in_l++, out_l++, bitlen -= 32) - *in_l = spi_xchg_single(*out_l, bitlen); + *in_l = spi_xchg_single(slave, *out_l, bitlen); return 0; } @@ -132,17 +132,17 @@ void spi_init(void) { } -int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) { unsigned int ctrl_reg; + struct mxc_spi_slave *mxcs; if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || - dev > 3) - return 1; - - spi_base = spi_bases[bus]; + cs > 3) + return NULL; - ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) | + ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) | MXC_CSPICTRL_BITCOUNT(31) | MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ MXC_CSPICTRL_EN | @@ -155,12 +155,38 @@ int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) if (mode & SPI_CS_HIGH) ctrl_reg |= MXC_CSPICTRL_SSPOL; - reg_write(spi_base + MXC_CSPIRESET, 1); + mxcs = malloc(sizeof(struct mxc_spi_slave)); + if (!mxcs) + return NULL; + + mxcs->slave.bus = bus; + mxcs->slave.cs = cs; + mxcs->base = spi_bases[bus]; + mxcs->ctrl_reg = ctrl_reg; + + return &mxcs->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + + reg_write(mxcs->base + MXC_CSPIRESET, 1); udelay(1); - reg_write(spi_base + MXC_CSPICTRL, ctrl_reg); - reg_write(spi_base + MXC_CSPIPERIOD, + reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg); + reg_write(mxcs->base + MXC_CSPIPERIOD, MXC_CSPIPERIOD_32KHZ); - reg_write(spi_base + MXC_CSPIINT, 0); + reg_write(mxcs->base + MXC_CSPIINT, 0); return 0; } + +void spi_release_bus(struct spi_slave *slave) +{ + /* TODO: Shut the controller down */ +} diff --git a/drivers/spi/spirom.c b/drivers/spi/spirom.c new file mode 100644 index 00000000000..87c93668ed3 --- /dev/null +++ b/drivers/spi/spirom.c @@ -0,0 +1,212 @@ +/* + * Copyright 2007 b7 Spectrum Digital Incorporated. + * All rights reserved. Property of Spectrum Digital Incorporated. + */ + +/* + * SPI ROM interface + * + */ + +#include "spirom.h" + +static Uint8 spirombuf[SPIROM_PAGESIZE + 5]; +static Uint8 statusbuf[8]; +static Uint32 spidat1; + +/* ------------------------------------------------------------------------ * + * * + * _wait( delay ) * + * Wait in a software loop for 'x' delay * + * * + * ------------------------------------------------------------------------ */ +void DAVINCIHD_wait( Uint32 delay ) +{ + volatile Uint32 i; + for ( i = 0 ; i < delay ; i++ ){ }; +} + + +/* ------------------------------------------------------------------------ * + * spirom_init( ) * + * ------------------------------------------------------------------------ */ +void spirom_init( ) +{ + /* Reset SPI */ + SPI_SPIGCR0 = 0; + _wait( 1000 ); + + /* Release SPI */ + SPI_SPIGCR0 = 1; + + /* SPI 4-Pin Mode setup */ + SPI_SPIGCR1 = 0 + | ( 0 << 24 ) + | ( 0 << 16 ) + | ( 1 << 1 ) + | ( 1 << 0 ); + + SPI_SPIPC0 = 0 + | ( 1 << 11 ) // DI + | ( 1 << 10 ) // DO + | ( 1 << 9 ) // CLK + | ( 1 << 1 ) // EN1 + | ( 1 << 0 ); // EN0 + + SPI_SPIFMT0 = 0 + | ( 0 << 20 ) // SHIFTDIR + | ( 0 << 17 ) // Polarity + | ( 1 << 16 ) // Phase + | ( 50 << 8 ) // Prescale + | ( 8 << 0 ); // Char Len + + spidat1 = 0 + | ( 1 << 28 ) // CSHOLD + | ( 0 << 24 ) // Format [0] + | ( 2 << 16 ) // CSNR [only CS0 enbled] + | ( 0 << 0 ); // + + SPI_SPIDAT1 = spidat1; + + SPI_SPIDELAY = 0 + | ( 8 << 24 ) // C2TDELAY + | ( 8 << 16 ); // T2CDELAY + + SPI_SPIDEF = 0 + | ( 1 << 1 ) // EN1 inactive high + | ( 1 << 0 ); // EN0 inactive high + + SPI_SPIINT = 0 + | ( 0 << 16 ) // + | ( 0 << 8 ) // + | ( 0 << 6 ) // + | ( 1 << 4 ); // + + SPI_SPILVL = 0 + | ( 0 << 8 ) // EN0 + | ( 0 << 6 ) // EN0 + | ( 0 << 4 ); // EN0 + + + /* Enable SPI */ + SPI_SPIGCR1 |= ( 1 << 24 ); +} + +/* ------------------------------------------------------------------------ * + * spirom_cycle( buf, len ) * + * * + * Execute a SPI spirom data transfer cycle. Each byte in buf is shifted * + * out and replaced with data coming back from the spirom. * + * ------------------------------------------------------------------------ */ +void spirom_cycle( Uint8 *buf, Uint16 len ) +{ + Uint16 i; + + /* Clear any old data */ + SPI_SPIBUF; + + /* SPIROM access cycle */ + for ( i = 0 ; i <= len ; i++ ) + { + /* Wait for transmit ready */ + while ( SPI_SPIBUF & 0x10000000 ); + + if ( i == len ) + SPI_SPIDAT1 = ( spidat1 & 0x0ffcffff ) | buf[i]; + else + SPI_SPIDAT1 = spidat1 | buf[i]; + + /* Wait for receive data ready */ + while ( SPI_SPIBUF & 0x80000000 ); + + /* Read 1 byte */ + buf[i] = SPI_SPIBUF; + } +} + +/* ------------------------------------------------------------------------ * + * spirom_status( ) * + * ------------------------------------------------------------------------ */ +Uint8 spirom_status( ) +{ + /* Issue read status command */ + statusbuf[0] = SPIROM_CMD_RDSR; + statusbuf[1] = 0; + + spirom_cycle( statusbuf, 2 ); + + return statusbuf[1]; +} + +/* ------------------------------------------------------------------------ * + * spirom_read( src, dst, length ) * + * ------------------------------------------------------------------------ */ +void spirom_read( Uint16 src, Uint32 dst, Uint32 length ) +{ + Int32 i; + Uint8 *psrc, *pdst; + + // Setup command + spirombuf[0] = SPIROM_CMD_READ; + spirombuf[1] = ( src >> 8 ); + spirombuf[2] = ( src >> 0 ); + + // Execute spirom read cycle + spirom_cycle( spirombuf, length + 3 ); + + // Copy returned data + pdst = ( Uint8 * )dst; + psrc = spirombuf + 3; + for ( i = 0 ; i < length ; i++ ) + *pdst++ = *psrc++; +} + +/* ------------------------------------------------------------------------ * + * spirom_write( src, dst, length ) * + * ------------------------------------------------------------------------ */ +void spirom_write( Uint32 src, Uint16 dst, Uint32 length ) +{ + Int32 i; + Int32 bytes_left; + Int32 bytes_to_program; + Uint8 *psrc; + + /* Establish source */ + psrc = ( Uint8 * )src; + bytes_left = length; + + while ( bytes_left > 0 ) + { + bytes_to_program = bytes_left; + + /* Most to program is SPIROM_CMD_BLOCKSIZE */ + if ( bytes_to_program > SPIROM_PAGESIZE ) + bytes_to_program = SPIROM_PAGESIZE; + + /* Make sure you don't run off the end of a block */ + if ( ( dst & SPIROM_PAGEMASK ) != ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK ) ) + bytes_to_program -= ( dst + bytes_to_program ) - ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK ); + + /* Issue WPEN */ + spirombuf[0] = SPIROM_CMD_WREN; + spirom_cycle( spirombuf, 0 ); + + /* Create command block for program operation */ + spirombuf[0] = SPIROM_CMD_WRITE; + spirombuf[1] = ( Uint8 )( dst >> 8 ); + spirombuf[2] = ( Uint8 )( dst ); + + for ( i = 0 ; i < bytes_to_program ; i++ ) + spirombuf[3+i] = *psrc++; + + /* Execute write command */ + spirom_cycle( spirombuf, bytes_to_program + 2 ); + + /* Wait while busy */ + while( ( spirom_status( ) & 0x01 ) ); + + /* Get ready for next iteration */ + bytes_left -= bytes_to_program; + dst += bytes_to_program; + } +} diff --git a/drivers/spi/spirom.h b/drivers/spi/spirom.h new file mode 100644 index 00000000000..2dfe3bc32f7 --- /dev/null +++ b/drivers/spi/spirom.h @@ -0,0 +1,77 @@ +/* + * Copyright 2007 by Spectrum Digital Incorporated. + * All rights reserved. Property of Spectrum Digital Incorporated. + */ + +/* + * SPI ROM header file + * + */ + +#ifndef SPIROM_ +#define SPIROM_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "davincihd.h" + +/* ------------------------------------------------------------------------ * + * SPI ROM Definitions * + * ------------------------------------------------------------------------ */ +#define SPIROM_SIZE 0x00008000 +#define SPIROM_BASE 0x00000000 +#define SPIROM_PAGESIZE 32 +#define SPIROM_PAGEMASK 0xffffffc0 + +/* ------------------------------------------------------------------------ * + * SPI ROM Commands * + * ------------------------------------------------------------------------ */ +#define SPIROM_CMD_WRSR 0x01 +#define SPIROM_CMD_WRITE 0x02 +#define SPIROM_CMD_READ 0x03 +#define SPIROM_CMD_WRDI 0x04 +#define SPIROM_CMD_RDSR 0x05 +#define SPIROM_CMD_WREN 0x06 + +/* ------------------------------------------------------------------------ * + * SPI Controller * + * ------------------------------------------------------------------------ */ +#define SPI_BASE 0x01c66800 +#define SPI_SPIGCR0 *( volatile Uint32* )( SPI_BASE + 0x0 ) +#define SPI_SPIGCR1 *( volatile Uint32* )( SPI_BASE + 0x4 ) +#define SPI_SPIINT *( volatile Uint32* )( SPI_BASE + 0x8 ) +#define SPI_SPILVL *( volatile Uint32* )( SPI_BASE + 0xc ) +#define SPI_SPIFLG *( volatile Uint32* )( SPI_BASE + 0x10 ) +#define SPI_SPIPC0 *( volatile Uint32* )( SPI_BASE + 0x14 ) +#define SPI_SPIPC2 *( volatile Uint32* )( SPI_BASE + 0x1c ) +#define SPI_SPIDAT1_TOP *( volatile Uint16* )( SPI_BASE + 0x3c ) +#define SPI_SPIDAT1 *( volatile Uint32* )( SPI_BASE + 0x3c ) +#define SPI_SPIDAT1_PTR16 *( volatile Uint16* )( SPI_BASE + 0x3e ) +#define SPI_SPIDAT1_PTR8 *( volatile Uint8* ) ( SPI_BASE + 0x3f ) +#define SPI_SPIBUF *( volatile Uint32* )( SPI_BASE + 0x40 ) +#define SPI_SPIBUF_PTR16 *( volatile Uint16* )( SPI_BASE + 0x42 ) +#define SPI_SPIBUF_PTR8 *( volatile Uint8* ) ( SPI_BASE + 0x43 ) +#define SPI_SPIEMU *( volatile Uint32* )( SPI_BASE + 0x44 ) +#define SPI_SPIDELAY *( volatile Uint32* )( SPI_BASE + 0x48 ) +#define SPI_SPIDEF *( volatile Uint32* )( SPI_BASE + 0x4c ) +#define SPI_SPIFMT0 *( volatile Uint32* )( SPI_BASE + 0x50 ) +#define SPI_SPIFMT1 *( volatile Uint32* )( SPI_BASE + 0x54 ) +#define SPI_SPIFMT2 *( volatile Uint32* )( SPI_BASE + 0x58 ) +#define SPI_SPIFMT3 *( volatile Uint32* )( SPI_BASE + 0x5c ) +#define SPI_INTVEC0 *( volatile Uint32* )( SPI_BASE + 0x60 ) +#define SPI_INTVEC1 *( volatile Uint32* )( SPI_BASE + 0x64 ) + +/* ------------------------------------------------------------------------ * + * Prototype * + * ------------------------------------------------------------------------ */ +void spirom_init( ); +void spirom_read( Uint16 src, Uint32 dst, Uint32 length ); +void spirom_write( Uint32 src, Uint16 dst, Uint32 length ); + +#ifdef __cplusplus +} +#endif + +#endif |