From patchwork Tue Oct 26 09:41:33 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: caydinc@gmail.com X-Patchwork-Id: 71933 X-Patchwork-Delegate: galak@kernel.crashing.org Return-Path: X-Original-To: wd@gemini.denx.de Delivered-To: wd@gemini.denx.de Received: from diddl.denx.de (diddl.denx.de [10.0.0.6]) by gemini.denx.de (Postfix) with ESMTP id 5B645152452 for ; Tue, 26 Oct 2010 11:45:28 +0200 (CEST) Received: from diddl.denx.de (localhost.localdomain [127.0.0.1]) by diddl.denx.de (Postfix) with ESMTP id 47C0E3364F8D for ; Tue, 26 Oct 2010 11:45:28 +0200 (CEST) Received: from pop.mnet-online.de by diddl.denx.de with POP3 (fetchmail-6.3.17) for (single-drop); Tue, 26 Oct 2010 11:45:28 +0200 (CEST) Received: from murder ([192.168.8.180]) by backend2 (Cyrus v2.2.12) with LMTPA; Tue, 26 Oct 2010 11:42:27 +0200 X-Sieve: CMU Sieve 2.2 Received: from mail.m-online.net (localhost [127.0.0.1]) by frontend1.mail.m-online.net (Cyrus v2.2.12) with LMTPA; Tue, 26 Oct 2010 11:42:26 +0200 Received: from scanner-3.m-online.net (unknown [192.168.6.168]) by mail.m-online.net (Postfix) with ESMTP id AD65B1C0012D; Tue, 26 Oct 2010 11:42:26 +0200 (CEST) Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by mxin-3.m-online.net (Postfix) with ESMTP id DCDD646AF21; Tue, 26 Oct 2010 11:42:24 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F30B7281DC; Tue, 26 Oct 2010 11:42:22 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id iuX+JFL2MvXs; Tue, 26 Oct 2010 11:42:22 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A9536281DD; Tue, 26 Oct 2010 11:42:15 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 29F68281D1 for ; Tue, 26 Oct 2010 11:42:11 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Z3j7Hi0MvQKo for ; Tue, 26 Oct 2010 11:42:08 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-px0-f172.google.com (mail-px0-f172.google.com [209.85.212.172]) by theia.denx.de (Postfix) with ESMTP id 12CD8281BD for ; Tue, 26 Oct 2010 11:42:05 +0200 (CEST) Received: by pxi13 with SMTP id 13so758584pxi.3 for ; Tue, 26 Oct 2010 02:42:04 -0700 (PDT) Received: by 10.142.156.3 with SMTP id d3mr3033229wfe.202.1288086124108; Tue, 26 Oct 2010 02:42:04 -0700 (PDT) Received: from localhost.localdomain (110-175-254-198.static.tpgi.com.au [110.175.254.198]) by mx.google.com with ESMTPS id x35sm12864988wfd.13.2010.10.26.02.42.01 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 26 Oct 2010 02:42:02 -0700 (PDT) From: Can Aydin To: u-boot@lists.denx.de Date: Tue, 26 Oct 2010 20:41:33 +1100 Message-Id: <1288086093-2442-1-git-send-email-can.aydin@locatacorp.com> X-Mailer: git-send-email 1.7.0.4 Subject: [U-Boot] [PATCH v3 1/2] Freescale 85xx/P1/P2 eSPI controller driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de X-Virus-Scanned: by amavisd-new at m-online.net Driver for the Freescale eSPI controller found in 85xx, P1/P2 and P4xx SoCs. Signed-off-by: Can Aydin --- Changes for v2: - Coding style cleanup - Removed modifications to common code Changes for v3: - fixed whitespace between function calls and parameters - replaced unneeded byte copy test function with memcpy - removed dead code and C++ style comments - separated board configuration patch from driver patch drivers/spi/Makefile | 1 + drivers/spi/fsl_espi.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++ include/fsl_espi.h | 50 ++++++++++ 3 files changed, 291 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/fsl_espi.c create mode 100644 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 100644 index 0000000..749d3f1 --- /dev/null +++ b/drivers/spi/fsl_espi.c @@ -0,0 +1,240 @@ +/* + * Freescale eSPI controller driver. + * + * Copyright 2010 Locata Corporation Pty. Ltd. + * Author: Can Aydin can.aydin@locatacorp.com + * Collab: Clayton Gumbrell clayton.gumbrell@locatacorp.com + * + * Adapted from Freescale ltib code by Mingkai Hu (Mingkai.hu@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 + +#include +#include +#include +#include + +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; +} + +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: oversize xfer(%u), max %u(0x%X)\n", + len, ESPI_MAX_TRANLEN, 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 */ + memcpy(&tmpdout, dout, 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 */ + memcpy(din, &tmpdin, 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) +{ + +} diff --git a/include/fsl_espi.h b/include/fsl_espi.h new file mode 100644 index 0000000..a8d6035 --- /dev/null +++ b/include/fsl_espi.h @@ -0,0 +1,50 @@ +/* + * Include header for Freescale eSPI controller + * + * Copyright 2010 Locata Corporation Pty. Ltd. + * Can Aydin can.aydin@locatacorp.com + * + * Adapted from Freescale ltib code by Mingkai Hu (Mingkai.hu@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__ */