u-boot-brain/drivers/spi/cf_spi.c
Tom Rini 83d290c56f SPDX: Convert all of our single license tags to Linux Kernel style
When U-Boot started using SPDX tags we were among the early adopters and
there weren't a lot of other examples to borrow from.  So we picked the
area of the file that usually had a full license text and replaced it
with an appropriate SPDX-License-Identifier: entry.  Since then, the
Linux Kernel has adopted SPDX tags and they place it as the very first
line in a file (except where shebangs are used, then it's second line)
and with slightly different comment styles than us.

In part due to community overlap, in part due to better tag visibility
and in part for other minor reasons, switch over to that style.

This commit changes all instances where we have a single declared
license in the tag as both the before and after are identical in tag
contents.  There's also a few places where I found we did not have a tag
and have introduced one.

Signed-off-by: Tom Rini <trini@konsulko.com>
2018-05-07 09:34:12 -04:00

336 lines
7.8 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
*
* (C) Copyright 2000-2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* Copyright (C) 2004-2009 Freescale Semiconductor, Inc.
* TsiChung Liew (Tsi-Chung.Liew@freescale.com)
*/
#include <common.h>
#include <spi.h>
#include <malloc.h>
#include <asm/immap.h>
struct cf_spi_slave {
struct spi_slave slave;
uint baudrate;
int charbit;
};
extern void cfspi_port_conf(void);
extern int cfspi_claim_bus(uint bus, uint cs);
extern void cfspi_release_bus(uint bus, uint cs);
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_SPI_IDLE_VAL
#if defined(CONFIG_SPI_MMC)
#define CONFIG_SPI_IDLE_VAL 0xFFFF
#else
#define CONFIG_SPI_IDLE_VAL 0x0
#endif
#endif
#if defined(CONFIG_CF_DSPI)
/* DSPI specific mode */
#define SPI_MODE_MOD 0x00200000
#define SPI_DBLRATE 0x00100000
static inline struct cf_spi_slave *to_cf_spi_slave(struct spi_slave *slave)
{
return container_of(slave, struct cf_spi_slave, slave);
}
static void cfspi_init(void)
{
volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
cfspi_port_conf(); /* port configuration */
dspi->mcr = DSPI_MCR_MSTR | DSPI_MCR_CSIS7 | DSPI_MCR_CSIS6 |
DSPI_MCR_CSIS5 | DSPI_MCR_CSIS4 | DSPI_MCR_CSIS3 |
DSPI_MCR_CSIS2 | DSPI_MCR_CSIS1 | DSPI_MCR_CSIS0 |
DSPI_MCR_CRXF | DSPI_MCR_CTXF;
/* Default setting in platform configuration */
#ifdef CONFIG_SYS_DSPI_CTAR0
dspi->ctar[0] = CONFIG_SYS_DSPI_CTAR0;
#endif
#ifdef CONFIG_SYS_DSPI_CTAR1
dspi->ctar[1] = CONFIG_SYS_DSPI_CTAR1;
#endif
#ifdef CONFIG_SYS_DSPI_CTAR2
dspi->ctar[2] = CONFIG_SYS_DSPI_CTAR2;
#endif
#ifdef CONFIG_SYS_DSPI_CTAR3
dspi->ctar[3] = CONFIG_SYS_DSPI_CTAR3;
#endif
#ifdef CONFIG_SYS_DSPI_CTAR4
dspi->ctar[4] = CONFIG_SYS_DSPI_CTAR4;
#endif
#ifdef CONFIG_SYS_DSPI_CTAR5
dspi->ctar[5] = CONFIG_SYS_DSPI_CTAR5;
#endif
#ifdef CONFIG_SYS_DSPI_CTAR6
dspi->ctar[6] = CONFIG_SYS_DSPI_CTAR6;
#endif
#ifdef CONFIG_SYS_DSPI_CTAR7
dspi->ctar[7] = CONFIG_SYS_DSPI_CTAR7;
#endif
}
static void cfspi_tx(u32 ctrl, u16 data)
{
volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
while ((dspi->sr & 0x0000F000) >= 4) ;
dspi->tfr = (ctrl | data);
}
static u16 cfspi_rx(void)
{
volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
while ((dspi->sr & 0x000000F0) == 0) ;
return (dspi->rfr & 0xFFFF);
}
static int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout,
void *din, ulong flags)
{
struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
u8 *spi_rd = NULL, *spi_wr = NULL;
static u32 ctrl = 0;
uint len = bitlen >> 3;
if (cfslave->charbit == 16) {
bitlen >>= 1;
spi_wr16 = (u16 *) dout;
spi_rd16 = (u16 *) din;
} else {
spi_wr = (u8 *) dout;
spi_rd = (u8 *) din;
}
if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
ctrl |= DSPI_TFR_CONT;
ctrl = (ctrl & 0xFF000000) | ((1 << slave->cs) << 16);
if (len > 1) {
int tmp_len = len - 1;
while (tmp_len--) {
if (dout != NULL) {
if (cfslave->charbit == 16)
cfspi_tx(ctrl, *spi_wr16++);
else
cfspi_tx(ctrl, *spi_wr++);
cfspi_rx();
}
if (din != NULL) {
cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
if (cfslave->charbit == 16)
*spi_rd16++ = cfspi_rx();
else
*spi_rd++ = cfspi_rx();
}
}
len = 1; /* remaining byte */
}
if ((flags & SPI_XFER_END) == SPI_XFER_END)
ctrl &= ~DSPI_TFR_CONT;
if (len) {
if (dout != NULL) {
if (cfslave->charbit == 16)
cfspi_tx(ctrl, *spi_wr16);
else
cfspi_tx(ctrl, *spi_wr);
cfspi_rx();
}
if (din != NULL) {
cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
if (cfslave->charbit == 16)
*spi_rd16 = cfspi_rx();
else
*spi_rd = cfspi_rx();
}
} else {
/* dummy read */
cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
cfspi_rx();
}
return 0;
}
static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave,
uint mode)
{
/*
* bit definition for mode:
* bit 31 - 28: Transfer size 3 to 16 bits
* 27 - 26: PCS to SCK delay prescaler
* 25 - 24: After SCK delay prescaler
* 23 - 22: Delay after transfer prescaler
* 21 : Allow overwrite for bit 31-22 and bit 20-8
* 20 : Double baud rate
* 19 - 16: PCS to SCK delay scaler
* 15 - 12: After SCK delay scaler
* 11 - 8: Delay after transfer scaler
* 7 - 0: SPI_CPHA, SPI_CPOL, SPI_LSB_FIRST
*/
volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
int prescaler[] = { 2, 3, 5, 7 };
int scaler[] = {
2, 4, 6, 8,
16, 32, 64, 128,
256, 512, 1024, 2048,
4096, 8192, 16384, 32768
};
int i, j, pbrcnt, brcnt, diff, tmp, dbr = 0;
int best_i, best_j, bestmatch = 0x7FFFFFFF, baud_speed;
u32 bus_setup = 0;
tmp = (prescaler[3] * scaler[15]);
/* Maximum and minimum baudrate it can handle */
if ((cfslave->baudrate > (gd->bus_clk >> 1)) ||
(cfslave->baudrate < (gd->bus_clk / tmp))) {
printf("Exceed baudrate limitation: Max %d - Min %d\n",
(int)(gd->bus_clk >> 1), (int)(gd->bus_clk / tmp));
return NULL;
}
/* Activate Double Baud when it exceed 1/4 the bus clk */
if ((CONFIG_SYS_DSPI_CTAR0 & DSPI_CTAR_DBR) ||
(cfslave->baudrate > (gd->bus_clk / (prescaler[0] * scaler[0])))) {
bus_setup |= DSPI_CTAR_DBR;
dbr = 1;
}
if (mode & SPI_CPOL)
bus_setup |= DSPI_CTAR_CPOL;
if (mode & SPI_CPHA)
bus_setup |= DSPI_CTAR_CPHA;
if (mode & SPI_LSB_FIRST)
bus_setup |= DSPI_CTAR_LSBFE;
/* Overwrite default value set in platform configuration file */
if (mode & SPI_MODE_MOD) {
if ((mode & 0xF0000000) == 0)
bus_setup |=
dspi->ctar[cfslave->slave.bus] & 0x78000000;
else
bus_setup |= ((mode & 0xF0000000) >> 1);
/*
* Check to see if it is enabled by default in platform
* config, or manual setting passed by mode parameter
*/
if (mode & SPI_DBLRATE) {
bus_setup |= DSPI_CTAR_DBR;
dbr = 1;
}
bus_setup |= (mode & 0x0FC00000) >> 4; /* PSCSCK, PASC, PDT */
bus_setup |= (mode & 0x000FFF00) >> 4; /* CSSCK, ASC, DT */
} else
bus_setup |= (dspi->ctar[cfslave->slave.bus] & 0x78FCFFF0);
cfslave->charbit =
((dspi->ctar[cfslave->slave.bus] & 0x78000000) ==
0x78000000) ? 16 : 8;
pbrcnt = sizeof(prescaler) / sizeof(int);
brcnt = sizeof(scaler) / sizeof(int);
/* baudrate calculation - to closer value, may not be exact match */
for (best_i = 0, best_j = 0, i = 0; i < pbrcnt; i++) {
baud_speed = gd->bus_clk / prescaler[i];
for (j = 0; j < brcnt; j++) {
tmp = (baud_speed / scaler[j]) * (1 + dbr);
if (tmp > cfslave->baudrate)
diff = tmp - cfslave->baudrate;
else
diff = cfslave->baudrate - tmp;
if (diff < bestmatch) {
bestmatch = diff;
best_i = i;
best_j = j;
}
}
}
bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j));
dspi->ctar[cfslave->slave.bus] = bus_setup;
return &cfslave->slave;
}
#endif /* CONFIG_CF_DSPI */
#ifdef CONFIG_CMD_SPI
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
return 1;
else
return 0;
}
void spi_init(void)
{
cfspi_init();
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct cf_spi_slave *cfslave;
if (!spi_cs_is_valid(bus, cs))
return NULL;
cfslave = spi_alloc_slave(struct cf_spi_slave, bus, cs);
if (!cfslave)
return NULL;
cfslave->baudrate = max_hz;
/* specific setup */
return cfspi_setup_slave(cfslave, mode);
}
void spi_free_slave(struct spi_slave *slave)
{
struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
free(cfslave);
}
int spi_claim_bus(struct spi_slave *slave)
{
return cfspi_claim_bus(slave->bus, slave->cs);
}
void spi_release_bus(struct spi_slave *slave)
{
cfspi_release_bus(slave->bus, slave->cs);
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
return cfspi_xfer(slave, bitlen, dout, din, flags);
}
#endif /* CONFIG_CMD_SPI */