[U-Boot-Users] [PATCH 1/2] Add support for a Freescale non-CPM SPI controller

This patch adds support for the SPI controller found on Freescale PowerPC processors such as the MCP834x family. Additionally, a new config option, CONFIG_HARD_SPI, is added for general purpose SPI controller use.
Signed-off-by: Ben Warren biggerbadderben@gmail.com --- Makefile | 2 + README | 8 +++ drivers/spi/Makefile | 46 ++++++++++++++ drivers/spi/fsl_spi.c | 140 ++++++++++++++++++++++++++++++++++++++++++ include/asm-ppc/immap_83xx.h | 14 ++++- lib_ppc/board.c | 16 +++++ 6 files changed, 225 insertions(+), 1 deletions(-) create mode 100644 drivers/spi/Makefile create mode 100644 drivers/spi/fsl_spi.c
diff --git a/Makefile b/Makefile index eba9333..9f93c6b 100644 --- a/Makefile +++ b/Makefile @@ -230,6 +230,7 @@ LIBS += drivers/net/libnet.a LIBS += drivers/net/sk98lin/libsk98lin.a LIBS += drivers/pci/libpci.a LIBS += drivers/pcmcia/libpcmcia.a +LIBS += drivers/spi/libspi.a ifeq ($(CPU),mpc83xx) LIBS += drivers/qe/qe.a endif @@ -378,6 +379,7 @@ TAG_SUBDIRS += drivers/pcmcia TAG_SUBDIRS += drivers/qe TAG_SUBDIRS += drivers/rtc TAG_SUBDIRS += drivers/serial +TAG_SUBDIRS += drivers/spi TAG_SUBDIRS += drivers/usb TAG_SUBDIRS += drivers/video
diff --git a/README b/README index f2a4914..ce27c9d 100644 --- a/README +++ b/README @@ -1377,6 +1377,14 @@ The following options need to be configured: SPI configuration items (port pins to use, etc). For an example, see include/configs/sacsng.h.
+ CONFIG_HARD_SPI + + Enables a hardware SPI driver for general-purpose reads + and writes. As with CONFIG_SOFT_SPI, the board configuration + must define a list of chip-select function pointers. + Currently supported on MPC834x only. For an example, + see include/configs/mpc8349emds.h. + - FPGA Support: CONFIG_FPGA
Enables FPGA subsystem. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile new file mode 100644 index 0000000..f87c5b5 --- /dev/null +++ b/drivers/spi/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk + +LIB := $(obj)libspi.a + +COBJS-y += fsl_spi.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/spi/fsl_spi.c b/drivers/spi/fsl_spi.c new file mode 100644 index 0000000..e2caa4b --- /dev/null +++ b/drivers/spi/fsl_spi.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006 Ben Warren, Qstreams Networks Inc. + * With help from the common/soft_spi and cpu/mpc8260 drivers + * + * 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 <asm/immap_83xx.h> + +#ifdef CONFIG_HARD_SPI + +#define SPI_EV_NE 0x80000000 >> 22 /* Receiver Not Empty */ +#define SPI_EV_NF 0x80000000 >> 23 /* Transmitter Not Full */ + +#define SPI_MODE_LOOP 0x80000000 >> 1 /* Loopback mode */ +#define SPI_MODE_REV 0x80000000 >> 5 /* Reverse mode - MSB first */ +#define SPI_MODE_MS 0x80000000 >> 6 /* Always master */ +#define SPI_MODE_EN 0x80000000 >> 7 /* Enable interface */ + +#define SPI_PRESCALER(reg, div) (reg)=((reg) & 0xfff0ffff) | ((div)<<16) +#define SPI_CHARLENGTH(reg, div) (reg)=((reg) & 0xff0fffff) | ((div)<<20) + +#define SPI_TIMEOUT 1000 + +void spi_init(void) +{ + volatile spi834x_t *spi = &((immap_t *) (CFG_IMMR))->spi; + + /* ------------------------------------------------ + * SPI pins on the MPC83xx are not muxed, so all we do is initialize + * some registers + * ------------------------------------------------ */ + spi->mode = SPI_MODE_REV | SPI_MODE_MS | SPI_MODE_EN; + SPI_PRESCALER(spi->mode, 1); /* Use SYSCLK / 8 (16.67MHz typ.) */ + spi->event = 0xffffffff; /* Clear all SPI events */ + spi->mask = 0x00000000; /* Mask all SPI interrupts */ + spi->com = 0; /* LST bit doesn't do anything, so disregard */ + + return; +} + +int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar * dout, uchar * din) +{ + volatile spi834x_t *spi = &((immap_t *) (CFG_IMMR))->spi; + unsigned int tmpdout, tmpdin, event; + int numBlks = bitlen / 32 + (bitlen % 32 ? 1 : 0); + 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); + + if (chipsel != NULL) + (*chipsel) (1); /* select the target chip */ + + spi->event = 0xffffffff; /* Clear all SPI events */ + + /* handle data in 32-bit chunks */ + while (numBlks--) { + tmpdout = 0; + charSize = (bitlen >= 32 ? 32 : bitlen); + + /* Shift data so it's msb-justified */ + tmpdout = *(u32 *) dout >> (32 - charSize); + + /* The LEN field of the SPMODE register is set as follows: + * + * Bit length setting + * l <= 4 3 + * 4 < l <= 16 l - 1 + * l > 16 0 + */ + + if (bitlen <= 16) + SPI_CHARLENGTH(spi->mode, bitlen <= 4 ? 3 : bitlen - 1); + else { + SPI_CHARLENGTH(spi->mode, 0); + /* Set up the next iteration if sending > 32 bits */ + bitlen -= 32; + dout += 4; + } + + spi->tx = tmpdout; /* Write the data out */ + debug("*** spi_xfer: ... %08x written\n", tmpdout); + + /* -------------------------------- + * Wait for SPI transmit to get out + * or time out (1 second = 1000 ms) + * The NE event must be read and cleared first + * -------------------------------- */ + for (tm = 0, isRead = 0; tm < SPI_TIMEOUT; ++tm) { + event = spi->event; + if (event & SPI_EV_NE) { + tmpdin = spi->rx; + spi->event |= SPI_EV_NE; + isRead = 1; + + *(u32 *) din = (tmpdin << (32 - charSize)); + if (charSize == 32) { + /* Advance output buffer by 32 bits */ + din += 4; + } + } + /* Only bail when we've had both NE and NF events. + * This will cause timeouts on RO devices, so maybe + * in the future put an arbitrary delay after writing + * the device. Arbitrary delays suck, though... */ + if (isRead && (event & SPI_EV_NF)) + break; + } + if (tm >= SPI_TIMEOUT) + puts("*** spi_xfer: Time out during SPI transfer"); + + debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin); + } + + if (chipsel != NULL) + (*chipsel) (0); /* deselect the target chip */ + return (0); +} + +#endif /* CONFIG_HARD_SPI */ diff --git a/include/asm-ppc/immap_83xx.h b/include/asm-ppc/immap_83xx.h index 34ea295..07ff400 100644 --- a/include/asm-ppc/immap_83xx.h +++ b/include/asm-ppc/immap_83xx.h @@ -397,6 +397,18 @@ typedef struct spi83xx { u8 res1[0xFD8]; } spi83xx_t;
+typedef struct spi834x +{ + u8 res0[0x20]; /* 0x0-0x01f reserved */ + u32 mode; /* mode register */ + u32 event; /* event register */ + u32 mask; /* mask register */ + u32 com; /* command register */ + u32 tx; /* transmit register */ + u32 rx; /* receive register */ + u8 res1[0xC8]; /* fill up to 0x100 */ + } spi834x_t; + /* * DMA/Messaging Unit */ @@ -627,7 +639,7 @@ typedef struct immap { u8 res3[0x900]; lbus83xx_t lbus; /* Local Bus Controller Registers */ u8 res4[0x1000]; - spi83xx_t spi; /* Serial Peripheral Interface */ + spi834x_t spi; /* Serial Peripheral Interface */ dma83xx_t dma; /* DMA */ pciconf83xx_t pci_conf[2]; /* PCI Software Configuration Registers */ ios83xx_t ios; /* Sequencer */ diff --git a/lib_ppc/board.c b/lib_ppc/board.c index 7b95246..8b4095c 100644 --- a/lib_ppc/board.c +++ b/lib_ppc/board.c @@ -87,6 +87,9 @@ void doc_init (void); defined(CONFIG_SOFT_I2C) #include <i2c.h> #endif +#if defined(CONFIG_HARD_SPI) +#include <spi.h> +#endif #if defined(CONFIG_CMD_NAND) void nand_init (void); #endif @@ -247,6 +250,16 @@ static int init_func_i2c (void) } #endif
+#if defined(CONFIG_HARD_SPI) +static int init_func_spi (void) +{ + puts ("SPI: "); + spi_init (); + puts ("ready\n"); + return (0); +} +#endif + /***********************************************************************/
#if defined(CONFIG_WATCHDOG) @@ -329,6 +342,9 @@ init_fnc_t *init_sequence[] = { #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) init_func_i2c, #endif +#if defined(CONFIG_HARD_SPI) + init_func_spi, +#endif #if defined(CONFIG_DTT) /* Digital Thermometers and Thermostats */ dtt_init, #endif

On Sun, 2008-01-13 at 10:48 +0800, Ben Warren wrote:
This patch adds support for the SPI controller found on Freescale PowerPC processors such as the MCP834x family. Additionally, a new config option, CONFIG_HARD_SPI, is added for general purpose SPI controller use.
Ben, Could you make the SPI drivers more generic/reuseable? IIRC, the 85xx part has the same SPI controller.
[snip]
+#include <common.h> +#include <spi.h> +#include <asm/immap_83xx.h>
Could you use the fsl_spi.h head? not 83xx..
[snip]
diff --git a/include/asm-ppc/immap_83xx.h b/include/asm- ppc/immap_83xx.h index 34ea295..07ff400 100644 --- a/include/asm-ppc/immap_83xx.h +++ b/include/asm-ppc/immap_83xx.h @@ -397,6 +397,18 @@ typedef struct spi83xx { u8 res1[0xFD8]; } spi83xx_t;
+typedef struct spi834x +{
u8 res0[0x20]; /* 0x0-0x01f reserved */
u32 mode; /* mode register */
u32 event; /* event register */
u32 mask; /* mask register */
u32 com; /* command register */
u32 tx; /* transmit register */
u32 rx; /* receive register */
u8 res1[0xC8]; /* fill up to 0x100 */
- } spi834x_t;
please put this into fsl_spi.h to reuse for different 8xxx family.
Thanks, Dave

Dave Liu wrote:
On Sun, 2008-01-13 at 10:48 +0800, Ben Warren wrote:
This patch adds support for the SPI controller found on Freescale PowerPC processors such as the MCP834x family. Additionally, a new config option, CONFIG_HARD_SPI, is added for general purpose SPI controller use.
Ben, Could you make the SPI drivers more generic/reuseable? IIRC, the 85xx part has the same SPI controller.
Sure. I don't have nearly the insight into the various Freescale products that you and your colleagues do.
[snip]
+#include <common.h> +#include <spi.h> +#include <asm/immap_83xx.h>
Could you use the fsl_spi.h head? not 83xx..
If the memory map is reused identically, then yes.
[snip]
diff --git a/include/asm-ppc/immap_83xx.h b/include/asm- ppc/immap_83xx.h index 34ea295..07ff400 100644 --- a/include/asm-ppc/immap_83xx.h +++ b/include/asm-ppc/immap_83xx.h @@ -397,6 +397,18 @@ typedef struct spi83xx { u8 res1[0xFD8]; } spi83xx_t;
+typedef struct spi834x +{
u8 res0[0x20]; /* 0x0-0x01f reserved */
u32 mode; /* mode register */
u32 event; /* event register */
u32 mask; /* mask register */
u32 com; /* command register */
u32 tx; /* transmit register */
u32 rx; /* receive register */
u8 res1[0xC8]; /* fill up to 0x100 */
- } spi834x_t;
please put this into fsl_spi.h to reuse for different 8xxx family.
Can you confirm that the registers in 85xx are the same? If so, I'll move this.
Thanks, Dave

+typedef struct spi834x +{
u8 res0[0x20]; /* 0x0-0x01f reserved */
u32 mode; /* mode register */
u32 event; /* event register */
u32 mask; /* mask register */
u32 com; /* command register */
u32 tx; /* transmit register */
u32 rx; /* receive register */
u8 res1[0xC8]; /* fill up to 0x100 */
- } spi834x_t;
please put this into fsl_spi.h to reuse for different 8xxx family.
Can you confirm that the registers in 85xx are the same? If so, I'll move this.
Ben, at lease the 8610 has the same SPI as 834x.
The 8360 and 8568 with CPU mode have likely SPI as 834x.
Dave

Liu Dave wrote:
+typedef struct spi834x +{
u8 res0[0x20]; /* 0x0-0x01f reserved */
u32 mode; /* mode register */
u32 event; /* event register */
u32 mask; /* mask register */
u32 com; /* command register */
u32 tx; /* transmit register */
u32 rx; /* receive register */
u8 res1[0xC8]; /* fill up to 0x100 */
- } spi834x_t;
please put this into fsl_spi.h to reuse for different 8xxx family.
Can you confirm that the registers in 85xx are the same? If so, I'll move this.
Ben, at lease the 8610 has the same SPI as 834x.
The 8360 and 8568 with CPU mode have likely SPI as 834x.
I just looked up the RM for 8360, and for some reason its register offsets are a *bit* different than the 8349. I'll move this struct to fsl_spi.h, but we'll have to do some #ifdef magic to work with multiple processors, I guess.
regards, Ben

Liu Dave wrote:
+typedef struct spi834x +{
u8 res0[0x20]; /* 0x0-0x01f reserved */
u32 mode; /* mode register */
u32 event; /* event register */
u32 mask; /* mask register */
u32 com; /* command register */
u32 tx; /* transmit register */
u32 rx; /* receive register */
u8 res1[0xC8]; /* fill up to 0x100 */
- } spi834x_t;
please put this into fsl_spi.h to reuse for different 8xxx family.
Can you confirm that the registers in 85xx are the same? If so, I'll move this.
Ben, at lease the 8610 has the same SPI as 834x.
The 8360 and 8568 with CPU mode have likely SPI as 834x.
Dave
I don't have access to 8313 or 8610 reference manuals. Can you please verify the memory map of these two for me. I've verified that 8315 is identical.
regards, Ben

Liu Dave wrote:
I don't have access to 8313 or 8610 reference manuals. Can you please verify the memory map of these two for me. I've verified that 8315 is identical.
8313/8315/834x/8610 have same SPI.
Dave
Cool. Thanks.
Ben

Liu Dave wrote:
I don't have access to 8313 or 8610 reference manuals. Can you please verify the memory map of these two for me. I've verified that 8315 is identical.
8313/8315/834x/8610 have same SPI.
Dave
asm/immap_86xx.h doesn't have SPI registers listed in the memory map, so support for 8610 will have to wait.
I've incorporated your change requests and will see if there's any more feedback on Monday before reposting the patches.
regards, Ben

8313/8315/834x/8610 have same SPI.
and 837x
asm/immap_86xx.h doesn't have SPI registers listed in the memory map, so support for 8610 will have to wait.
I've incorporated your change requests and will see if there's any more feedback on Monday before reposting the patches.
Ok, also, I want to heard some feedback from other people.

In message 1200281058.3654.12.camel@localhost.localdomain you wrote:
please put this into fsl_spi.h to reuse for different 8xxx family.
fsl_spi.h might be a bit too general? How about non-8xxx Freescale processors?
Best regards,
Wolfgang Denk

Wolfgang Denk wrote:
In message 1200281058.3654.12.camel@localhost.localdomain you wrote:
please put this into fsl_spi.h to reuse for different 8xxx family.
fsl_spi.h might be a bit too general? How about non-8xxx Freescale processors? f
The naming convention was modeled after 'fsl_i2c', which surely isn't universal to all Freescale I2C controllers either. In Linux, this driver is called 'mpc83xx', which we've learned here is a bit too specialized. I'll happily change the name, but don't know what that should be.
regards, Ben

fsl_spi.h might be a bit too general? How about non-8xxx Freescale processors? f
The naming convention was modeled after 'fsl_i2c', which surely isn't universal to all Freescale I2C controllers either. In Linux, this driver is called 'mpc83xx', which we've learned here is a bit too specialized. I'll happily change the name, but don't know what that should be.
also, I have no idea for this name, how about the mpc8xxx_spi.c[h]?
Best Regards, Dave
participants (5)
-
Ben Warren
-
Dave Liu
-
Liu Dave
-
Liu Dave
-
Wolfgang Denk