armv7/exynos5420: Change SPI module to standard <spi-generic> interface.

The SPI module in Exynos 5420 didn't follow Coreboot's SPI API standard
(spi-generic.h) and will be a problem when we want to share SPI drivers.

This commit replaces exynos_spi_* by spi_* functions.

Note, exynos_spi_read is kept and changed to a static function because its usage
is different from the standard API "spi_xfer".

Change-Id: I6de301bc6b46a09f87b0336c60247fedbe844ca3
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Signed-off-by: Gabe Black <gabeblack@chromium.org>
Reviewed-on: http://review.coreboot.org/3710
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Hung-Te Lin 2013-06-26 20:16:13 +08:00 committed by Stefan Reinauer
parent 45d524d278
commit ffa5bada72
2 changed files with 76 additions and 18 deletions

View File

@ -22,17 +22,61 @@
#include <arch/io.h> #include <arch/io.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <spi_flash.h>
#include "cpu.h"
#include "spi.h" #include "spi.h"
#define EXYNOS_BASE_SPI1 ((void *)0x12d30000)
#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI #if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
# define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x) # define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x)
#else #else
# define DEBUG_SPI(x,...) # define DEBUG_SPI(x,...)
#endif #endif
struct exynos_spi_slave {
struct spi_slave slave;
struct exynos_spi *regs;
unsigned int fifo_size;
uint8_t half_duplex;
uint8_t frame_header; /* header byte to detect in half-duplex mode. */
};
static inline struct exynos_spi_slave *to_exynos_spi(struct spi_slave *slave)
{
return container_of(slave, struct exynos_spi_slave, slave);
}
void spi_init(void)
{
printk(BIOS_INFO, "Exynos SPI driver initiated.\n");
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
// TODO(hungte) Provide Exynos SPI device setup.
return NULL;
}
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
// TODO(hungte) Detect and check if BUS/CS is valid.
return 0;
}
void spi_cs_activate(struct spi_slave *slave)
{
struct exynos_spi *regs = to_exynos_spi(slave)->regs;
// TODO(hungte) Add some delay if too many transactions happen at once.
clrbits_le32(&regs->cs_reg, SPI_SLAVE_SIG_INACT);
}
void spi_cs_deactivate(struct spi_slave *slave)
{
struct exynos_spi *regs = to_exynos_spi(slave)->regs;
setbits_le32(&regs->cs_reg, SPI_SLAVE_SIG_INACT);
}
static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo, static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
void *dinp, void const *doutp, int i) void *dinp, void const *doutp, int i)
{ {
@ -75,8 +119,11 @@ static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
} }
/* set up SPI channel */ /* set up SPI channel */
int exynos_spi_open(struct exynos_spi *regs) int spi_claim_bus(struct spi_slave *slave)
{ {
struct exynos_spi_slave *espi = to_exynos_spi(slave);
struct exynos_spi *regs = espi->regs;
/* set the spi1 GPIO */ /* set the spi1 GPIO */
/* set pktcnt and enable it */ /* set pktcnt and enable it */
@ -103,8 +150,17 @@ int exynos_spi_open(struct exynos_spi *regs)
return 0; return 0;
} }
int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off) int spi_xfer(struct spi_slave *slave, const void *dout, unsigned int bitsout,
void *din, unsigned int bitsin)
{ {
// TODO(hungte) Invoke exynos_spi_rx_tx to transfer data.
return -1;
}
static int exynos_spi_read(struct spi_slave *slave, void *dest, uint32_t len,
uint32_t off)
{
struct exynos_spi *regs = to_exynos_spi(slave)->regs;
int upto, todo; int upto, todo;
int i; int i;
clrbits_le32(&regs->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */ clrbits_le32(&regs->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */
@ -125,8 +181,9 @@ int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off)
return len; return len;
} }
int exynos_spi_close(struct exynos_spi *regs) void spi_release_bus(struct spi_slave *slave)
{ {
struct exynos_spi *regs = to_exynos_spi(slave)->regs;
/* /*
* Let put controller mode to BYTE as * Let put controller mode to BYTE as
* SPI driver does not support WORD mode yet * SPI driver does not support WORD mode yet
@ -142,25 +199,25 @@ int exynos_spi_close(struct exynos_spi *regs)
clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
clrbits_le32(&regs->ch_cfg, SPI_CH_RST); clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
clrbits_le32(&regs->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); clrbits_le32(&regs->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
return 0;
} }
// SPI as CBFS media. // SPI as CBFS media.
struct exynos_spi_media { struct exynos_spi_media {
struct exynos_spi *regs; struct spi_slave *slave;
struct cbfs_simple_buffer buffer; struct cbfs_simple_buffer buffer;
}; };
static int exynos_spi_cbfs_open(struct cbfs_media *media) { static int exynos_spi_cbfs_open(struct cbfs_media *media) {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_open\n"); DEBUG_SPI("exynos_spi_cbfs_open\n");
return exynos_spi_open(spi->regs); return spi_claim_bus(spi->slave);
} }
static int exynos_spi_cbfs_close(struct cbfs_media *media) { static int exynos_spi_cbfs_close(struct cbfs_media *media) {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_close\n"); DEBUG_SPI("exynos_spi_cbfs_close\n");
return exynos_spi_close(spi->regs); spi_release_bus(spi->slave);
return 0;
} }
static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest, static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
@ -168,10 +225,10 @@ static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
int bytes; int bytes;
DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count); DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
bytes = exynos_spi_read(spi->regs, dest, count, offset); bytes = exynos_spi_read(spi->slave, dest, count, offset);
// Flush and re-open the device. // Flush and re-open the device.
exynos_spi_close(spi->regs); spi_release_bus(spi->slave);
exynos_spi_open(spi->regs); spi_claim_bus(spi->slave);
return bytes; return bytes;
} }
@ -197,9 +254,15 @@ int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
size_t buffer_size) { size_t buffer_size) {
// TODO Replace static variable to support multiple streams. // TODO Replace static variable to support multiple streams.
static struct exynos_spi_media context; static struct exynos_spi_media context;
static struct exynos_spi_slave eslave = {
.slave = { .bus = 1, .rw = SPI_READ_FLAG, },
.regs = samsung_get_base_spi1(),
.fifo_size = 64,
.half_duplex = 0,
};
DEBUG_SPI("initialize_exynos_spi_cbfs_media\n"); DEBUG_SPI("initialize_exynos_spi_cbfs_media\n");
context.regs = EXYNOS_BASE_SPI1; context.slave = &eslave.slave;
context.buffer.allocated = context.buffer.last_allocate = 0; context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address; context.buffer.buffer = buffer_address;
context.buffer.size = buffer_size; context.buffer.size = buffer_size;

View File

@ -86,11 +86,6 @@ struct exynos_spi {
#define SPI_RX_BYTE_SWAP (1 << 6) #define SPI_RX_BYTE_SWAP (1 << 6)
#define SPI_RX_HWORD_SWAP (1 << 7) #define SPI_RX_HWORD_SWAP (1 << 7)
/* API */
int exynos_spi_open(struct exynos_spi *regs);
int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off);
int exynos_spi_close(struct exynos_spi *regs);
/* Serve as CBFS media source */ /* Serve as CBFS media source */
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
void *buffer_address, void *buffer_address,