Driver for the Freescale eSPI controller found in 85xx, P1/P2 and P4xx SoCs.
Signed-off-by: Can Aydin<can.ay...@locatacorp.com> --- drivers/spi/Makefile | 1 + drivers/spi/fsl_espi.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++ include/fsl_espi.h | 50 ++++++++++ 3 files changed, 302 insertions(+), 0 deletions(-) create mode 100755 drivers/spi/fsl_espi.c create mode 100755 include/fsl_espi.h diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index dfcbb8b..1aaa8e7 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o COBJS-$(CONFIG_CF_SPI) += cf_spi.o COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o +COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c new file mode 100755 index 0000000..1a42827 --- /dev/null +++ b/drivers/spi/fsl_espi.c @@ -0,0 +1,251 @@ +/* + * Freescale eSPI controller driver. + * + * Copyright 2010 Locata Corporation Pty. Ltd. + * Author: Can Aydin can.ay...@locatacorp.com + * Collab: Clayton Gumbrell clayton.gumbr...@locatacorp.com + * + * Adapted from Freescale ltib code by Mingkai Hu (mingkai...@freescale.com) + * Copyright 2009 Freescale Semiconductor, Inc. + * + * 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<fsl_espi.h> +#include<asm/immap_85xx.h> + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + volatile ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + struct spi_slave *slave; + sys_info_t sysinfo; + unsigned long spibrg = 0; + unsigned char pm = 0; + int i; + + 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; + + /* Enable eSPI interface */ + espi->mode = ESPI_MODE_RXTHR(3) | ESPI_MODE_TXTHR(4) | ESPI_MODE_EN; + + espi->event = 0xffffffff; /* Clear all eSPI events */ + espi->mask = 0x00000000; /* Mask all eSPI interrupts */ + + /* Init CS mode interface */ + for (i = 0; i< ESPI_MAX_CS_NUM; i++) + espi->csmode[i] = ESPI_CSMODE_INIT_VAL; + + espi->csmode[cs]&= + ~(ESPI_CSMODE_PM(0xF) | ESPI_CSMODE_DIV16 + | ESPI_CSMODE_CI_INACTIVEHIGH | ESPI_CSMODE_CP_BEGIN_EDGCLK + | ESPI_CSMODE_REV_MSB_FIRST + | ESPI_CSMODE_LEN(ESPI_MAX_CHARSIZE)); + + /* Set eSPI BRG clock source */ + get_sys_info(&sysinfo); + spibrg = sysinfo.freqSystemBus / 2; + if ((spibrg / max_hz)> 32) { + espi->csmode[cs] |= ESPI_CSMODE_DIV16; + pm = spibrg / (max_hz * 16 * 2); + if (pm> 16) { + pm = 16; + debug("Requested speed is too low: %d Hz" + " %u Hz is used.\n", max_hz, (uint) (spibrg / (32 * 16))); + } + } else + pm = spibrg / (max_hz * 2); + if (pm) + pm--; + espi->csmode[cs] |= ESPI_CSMODE_PM(pm); + + /* Set eSPI mode */ + if (mode& SPI_CPHA) + espi->csmode[cs] |= ESPI_CSMODE_CP_BEGIN_EDGCLK; + if (mode& SPI_CPOL) + espi->csmode[cs] |= ESPI_CSMODE_CI_INACTIVEHIGH; + + /* Character bit order: msb first */ + espi->csmode[cs] |= ESPI_CSMODE_REV_MSB_FIRST; + + /* Character length in bits, between 0x3~0xf, i.e. 4bits~16bits */ + espi->csmode[cs] |= ESPI_CSMODE_LEN(ESPI_CHARSIZE); + + return slave; +} + + +static inline void write_u32_part(u32 * in, u32 * out, u8 size) +{ + int i; + u8 * ibyte = (u8 *) in; + u8 * obyte = (u8 *) out; + + for ( i = 0; i< size; i++) + obyte[i] = ibyte[i]; +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + volatile ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + u32 com; + u32 event; + u8 wordsize = 4; /* Fifo access registers are 32 bits */ + u32 tmpdout, tmpdin; + unsigned int len, rxcount, txcount; + + if (!(flags& (SPI_XFER_BEGIN|SPI_XFER_END))) + { + debug("spi_xfer: Segmented transfers not supported.\n"); + return 1; + } + + if ( ! bitlen ) + return 0; + + len = bitlen / ESPI_CHARSIZE + ((bitlen % ESPI_CHARSIZE) ? 1 : 0); + + if ( len> ESPI_MAX_TRANLEN ) { + debug("spi_xfer: Transfer length (%u) too long, max is (%u)\n", + len, ESPI_MAX_TRANLEN); + return 1; + } + + rxcount = len; + txcount = len; + debug("spi_xfer: slave %u:%u dout %08X(%08x) din %08X(%08x) len %u\n", + slave->bus, slave->cs, + *(uint *) dout, (uint) dout, *(uint *) din, (uint) din, len); + + /* Prepare eSPI transfer to slave cs with length len */ + com = 0; + com |= ESPI_COM_CS(slave->cs); + com |= ESPI_COM_TRANLEN(len); + espi->com = com; + + /* Clear all eSPI events and initiate new command */ + espi->event = 0xffffffff; + debugX(1,"spi_xfer: rxcount %08X, txcount %08X\n", rxcount, txcount); + while (rxcount) { + + event = espi->event; + debugX(4,"spi_xfer: SPIE 0x%08x\n", event); + debugX(3,"spi_xfer: SPIE (TXCNT): %u\n", + ESPI_EV_GET_TXCNT(event)); + if ((event& ESPI_EV_TNF)&& (txcount)) { + /* Tx fifo not full and we still have stuff to send */ + if ( (txcount>= wordsize)&& + (ESPI_EV_GET_TXCNT(event)>= wordsize)) { + /* Have a full word and room to put it */ + tmpdout = *(u32 *)dout; + txcount -= wordsize; + dout += wordsize; + espi->tx = tmpdout; + } else if (ESPI_EV_GET_TXCNT(event)>= txcount) { + /* Less than a word left and room to put it */ + tmpdout = 0; + /* Avoid dout buffer read overflow */ + write_u32_part((u32 *)dout,&tmpdout,txcount); + espi->tx = tmpdout; + txcount = 0; + } + espi->event |= ESPI_EV_TNF; + debugX(2,"*** spi_xfer: ... %08x written\n", tmpdout); + debugX(3,"spi_xfer: rxcount %08X, txcount %08X\n", rxcount, txcount); + } + + event = espi->event; + debugX(4,"spi_xfer: SPIE 0x%08x\n", event); + debugX(3,"spi_xfer: SPIE (RXCNT): %u\n", + ESPI_EV_GET_RXCNT(event)); + if (event& ESPI_EV_RNE) { /* Rx fifo has data */ + unsigned int count = ESPI_EV_GET_RXCNT(event); + if ( count>= wordsize) { + /* Have a full word to read */ + tmpdin = espi->rx; + *(u32 *) din = tmpdin; + if ( (rxcount -= wordsize)> 0 ) { + din += wordsize; + } + } else if ( count>= rxcount ) { + /* Less than a word left to read */ + tmpdin = espi->rx; + /* Avoid din buffer write overflow */ + write_u32_part(&tmpdin,(u32 *)din,rxcount); + rxcount = 0; + } + debugX(2,"*** spi_xfer: ... %08x read\n", tmpdin); + debugX(3,"spi_xfer: rxcount %08X, txcount %08X\n", rxcount, txcount); + espi->event |= ESPI_EV_RNE; + } + + } + + /* clear the RXCNT and TXCNT */ + espi->mode&= ~ESPI_MODE_EN; + espi->mode |= ESPI_MODE_EN; + + return 0; +} + + +void spi_free_slave(struct spi_slave *slave) +{ + free((struct espi_slave *) slave); +} + +void spi_init(void) +{ + +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return bus == 0&& cs< ESPI_MAX_CS_NUM; +} + +void spi_cs_activate(struct spi_slave *slave) +{ + +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + +} \ No newline at end of file diff --git a/include/fsl_espi.h b/include/fsl_espi.h new file mode 100755 index 0000000..9375615 --- /dev/null +++ b/include/fsl_espi.h @@ -0,0 +1,50 @@ +/* + * Include header for Freescale eSPI controller + * + * Copyright 2010 Locata Corporation Pty. Ltd. + * Can aydincan.ay...@locatacorp.com + * + * Adapted from Freescale ltib code by Mingkai Hu (mingkai...@freescale.com) + * Copyright 2009 Freescale Semiconductor, Inc. + */ + +#ifndef __FSL_ESPI_H__ +#define __FSL_ESPI_H__ + +#define ESPI_MAX_CS_NUM 4 + +#define ESPI_MAX_TRANLEN 0x10000 +#define ESPI_MAX_CHARSIZE 16 + +/* TODO: Add support for character sizes other than 8-bits */ +#define ESPI_CHARSIZE 8 + +#define ESPI_EV_TNF (1<< 8) /* Tx fifo not full */ +#define ESPI_EV_RNE (1<< 9) /* Rx fifo not empty */ +#define ESPI_EV_DONE (1<< 14) /* Transfer Complete */ +#define ESPI_EV_GET_TXCNT(spie) (((spie)>> 16)& 0x3F) /* Tx count */ +#define ESPI_EV_GET_RXCNT(spie) (((spie)>> 24)& 0x3F) /* Rx count */ + +#define ESPI_MODE_EN (1<< 31) /* Enable interface */ +#define ESPI_MODE_TXTHR(x) ((x)<< 8) /* Tx FIFO threshold */ +#define ESPI_MODE_RXTHR(x) ((x)<< 0) /* Rx FIFO threshold */ + +#define ESPI_COM_CS(x) ((x)<< 30) +#define ESPI_COM_TRANLEN(x) (((x)-1)<< 0) + +#define ESPI_CSMODE_CI_INACTIVEHIGH (1<< 31) +#define ESPI_CSMODE_CP_BEGIN_EDGCLK (1<< 30) +#define ESPI_CSMODE_REV_MSB_FIRST (1<< 29) +#define ESPI_CSMODE_DIV16 (1<< 28) +#define ESPI_CSMODE_PM(x) ((x)<< 24) +#define ESPI_CSMODE_POL_ASSERTED_LOW (1<< 20) +#define ESPI_CSMODE_LEN(x) (((x)-1)<< 16) +#define ESPI_CSMODE_CSBEF(x) ((x)<< 12) +#define ESPI_CSMODE_CSAFT(x) ((x)<< 8) +#define ESPI_CSMODE_CSCG(x) ((x)<< 3) + +#define ESPI_CSMODE_INIT_VAL (ESPI_CSMODE_POL_ASSERTED_LOW | \ + ESPI_CSMODE_CSBEF(0) | ESPI_CSMODE_CSAFT(0) | \ + ESPI_CSMODE_CSCG(1)) + +#endif /* __FSL_ESPI_H__ */ \ No newline at end of file -- 1.7.0.4 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot